JVS-Rules决策表与规则流设计实战(附源码分析)

摘要

规则引擎的核心价值在于将业务决策从代码中解耦,实现规则的热部署与可视化维护。本文以JVS-Rules为例,深入解析决策表(Decision Table)与规则流(Rule Flow)的设计原理与实现细节,包含元数据模型、规则编译、执行引擎、源码片段及性能优化策略。通过一个完整的贷款审批案例,展示如何将复杂的if-else逻辑转换为可配置的规则,并对比硬编码与规则引擎的维护成本差异。

1. 为什么需要规则引擎?

传统业务规则实现方式为硬编码:

复制代码
java

if (loanAmount > 500000 && creditScore < 600) {
    result = "REJECT";
} else if (loanAmount > 100000 && creditScore < 650) {
    result = "MANUAL_REVIEW";
} else {
    result = "APPROVE";
}

这种方式的痛点:

  • 规则变更需要修改代码、重新编译、测试、上线,周期长(通常数天)。

  • 业务人员无法直接参与规则维护。

  • 规则数量膨胀后,代码难以阅读和维护("箭头代码"现象)。

规则引擎通过将规则定义与执行分离,实现了规则的动态管理和可视化编排。

2. JVS-Rules整体架构

JVS-Rules采用前后端分离架构:

  • 前端:Vue3 + Element Plus,提供决策表、规则流、决策树的可视化编辑器。

  • 后端:Spring Boot + MyBatis Plus,核心模块包括规则解析器、Rete++算法引擎、规则仓库管理。

  • 存储:MySQL存储规则元数据(决策表行/列、规则流节点/边),业务数据不侵入。

核心类图

复制代码
text

RuleEngine (接口)
  └── RetePlusEngine (实现)
        ├── RuleCompiler (将决策表编译为Rete网络)
        ├── FactRepository (事实对象管理)
        └── Agenda (规则冲突解决策略)

3. 决策表(Decision Table)深度解析

决策表是用表格形式表示规则集合,适用于条件组合较多的场景(如折扣、风控、评分卡)。

3.1 元数据模型

决策表存储在数据库中的核心表结构(简化):

复制代码
sql

-- 决策表主表
CREATE TABLE `decision_table` (
  `id` varchar(32) PRIMARY KEY,
  `name` varchar(128) NOT NULL,
  `input_fields` json COMMENT '输入字段定义:[{name, type, label}]',
  `output_fields` json COMMENT '输出字段定义',
  `hit_policy` varchar(20) DEFAULT 'FIRST' COMMENT '命中策略:FIRST/ALL/UNIQUE'
);

-- 决策表规则行
CREATE TABLE `decision_rule` (
  `id` varchar(32) PRIMARY KEY,
  `table_id` varchar(32) NOT NULL,
  `priority` int DEFAULT 0,
  `conditions` json COMMENT '条件表达式列表',
  `actions` json COMMENT '动作赋值列表'
);
3.2 规则编译过程

以贷款审批决策表为例:

金额范围 信用分范围 审批结果
>500,000 <600 拒绝
>100,000 <650 人工审核
* * 批准

编译步骤

  1. 解析输入字段(loanAmount, creditScore)和输出字段(result)。

  2. 将每一行规则转换为Rete网络中的节点。

  3. 生成Java表达式或MVEL脚本。

源码片段(规则编译核心,来自JVS-Rules开源仓库简化):

复制代码
java

public class DecisionTableCompiler {
    public static RuleSet compile(DecisionTable table) {
        RuleSet ruleSet = new RuleSet();
        for (DecisionRule rule : table.getRules()) {
            String condition = buildCondition(rule.getConditions());
            String action = buildAction(rule.getActions());
            Rule r = new Rule(rule.getId(), condition, action);
            ruleSet.addRule(r);
        }
        return ruleSet;
    }
    
    private static String buildCondition(List<Condition> conds) {
        // 将条件列表拼接为Java表达式,如 "loanAmount > 500000 && creditScore < 600"
        if (conds.isEmpty()) return "true";
        return conds.stream()
            .map(c -> c.getField() + " " + c.getOp() + " " + c.getValue())
            .collect(Collectors.joining(" && "));
    }
}
3.3 运行时执行流程(Rete++算法)

JVS-Rules采用的Rete++算法是经典Rete的改进版本,主要优化了节点共享和内存占用。

执行流程

  1. 业务系统调用规则引擎API,传入事实对象(如LoanApplication)。

  2. 事实对象被插入Rete网络的根节点,沿网络向下传播。

  3. 在Alpha节点(单条件匹配)中进行属性判断。

  4. 在Beta节点(多条件组合)中进行交叉匹配。

  5. 命中规则后,将规则实例加入Agenda。

  6. 根据命中策略(FIRST)取出最高优先级规则,执行动作(设置结果字段)。

  7. 返回执行结果。

性能数据:在4核8G环境下,包含50条规则的决策表,单次匹配平均耗时<5ms。

4. 规则流(Rule Flow)设计

规则流用于编排多个规则集或决策表的执行顺序,支持串行、并行、条件分支。

4.1 规则流模型(数据库表结构)
复制代码
java

public class DecisionTableCompiler {
    public static RuleSet compile(DecisionTable table) {
        RuleSet ruleSet = new RuleSet();
        for (DecisionRule rule : table.getRules()) {
            String condition = buildCondition(rule.getConditions());
            String action = buildAction(rule.getActions());
            Rule r = new Rule(rule.getId(), condition, action);
            ruleSet.addRule(r);
        }
        return ruleSet;
    }
    
    private static String buildCondition(List<Condition> conds) {
        // 将条件列表拼接为Java表达式,如 "loanAmount > 500000 && creditScore < 600"
        if (conds.isEmpty()) return "true";
        return conds.stream()
            .map(c -> c.getField() + " " + c.getOp() + " " + c.getValue())
            .collect(Collectors.joining(" && "));
    }
}
4.2 规则流执行引擎(源码解析)

使用有向无环图(DAG)遍历算法,支持条件分支:

复制代码
java

public class RuleFlowExecutor {
    public void execute(RuleFlow flow, Map<String, Object> facts) {
        Node start = flow.getStartNode();
        Queue<Node> queue = new LinkedList<>();
        queue.add(start);
        while (!queue.isEmpty()) {
            Node current = queue.poll();
            if (current.getNodeType() == NodeType.RULE_SET) {
                // 执行关联的决策表或规则集
                ruleEngine.fire(current.getRuleSetId(), facts);
            }
            List<Edge> outgoing = flow.getOutgoingEdges(current.getId());
            for (Edge edge : outgoing) {
                // 检查边的条件表达式(如果有)
                if (edge.getCondition() == null || evaluate(edge.getCondition(), facts)) {
                    queue.add(edge.getToNode());
                }
            }
        }
    }
}
4.3 可视化设计器实现要点

JVS-Rules前端使用Vue + 拖拽库(如vue-drag-drop)实现规则流的可视化编辑。后端存储采用JSON格式保存流程定义,前端通过canvas或SVG渲染节点和连线。节点的属性配置通过动态表单实现。

5. 实践案例:银行贷款审批系统

业务规则

  1. 金额>50万且信用分<600 → 拒绝。

  2. 金额>10万且信用分<650 → 人工审核。

  3. 其他 → 批准,同时计算利率:信用分>750给予0.8折优惠。

传统硬编码:约150行Java代码,包含多个if-else嵌套。变更规则需要修改代码、编译、测试、部署,平均耗时2天。

JVS-Rules实现

  • 创建决策表,包含3行规则(拒绝、人工审核、批准)。

  • 创建第二个决策表,计算利率折扣。

  • 创建规则流:先执行审批决策表,若批准则执行利率计算决策表。

  • 规则修改时,业务人员在Web界面编辑决策表,保存后立即生效。

效果对比

维度 硬编码 JVS-Rules
首次开发时间 2天 2小时
规则变更耗时 平均2天(含测试部署) 2分钟
业务人员参与度 可自行维护简单规则
规则数量上限 受代码复杂度限制 支持上千条

6. 性能优化与最佳实践

  • 规则编译缓存 :决策表编译后的Rete网络可缓存,避免重复编译。使用ConcurrentHashMap存储编译后的RuleSet对象。

  • 索引优化:常用字段(如金额区间)建立哈希索引加速匹配。在Alpha节点中为每个字段值创建唯一索引。

  • 批量事实处理:对于批处理场景,使用无状态会话并行执行,注意线程安全。

  • 避免过于复杂的决策表:超过50列或100行的决策表可拆分为多级规则流,提升可维护性。

7. 总结

JVS-Rules通过决策表和规则流的设计,将传统硬编码的业务规则转换为可视化、可热部署的配置。本文从元数据模型、编译原理、执行引擎、性能优化等维度进行了深度剖析,并附带了关键源码片段。对于需要频繁变更业务规则的企业系统(如金融风控、电商促销、供应链决策),规则引擎是降低维护成本的利器。开发者可通过JVS-Rules官方文档获取完整的部署和开发指南。

相关推荐
心之伊始7 小时前
Dubbo 3 Consumer 调用链路源码分析:从 Proxy 到 Cluster、Directory、Router、LoadBalance
java·微服务·dubbo·源码分析·服务治理
SL-staff8 小时前
AI视觉检测+规则引擎+BI大屏:制造业质检闭环方案实战
人工智能·计算机视觉·视觉检测·规则引擎·jvs物联网平台·bi大屏·缺陷等级判定
心之伊始17 小时前
LangChain4j RAG 实战:Java 后端如何把本地文档接入 Embedding 检索链路
java·架构·源码分析·csdn
SL-staff2 天前
(一)数据源配置 —— JVS-Rules规则引擎 V2.5 操作说明介绍
数据库·jar·规则引擎·数据源·jvs-rules·api 接口·jvs低代码
心之伊始2 天前
Spring Cloud Gateway RequestRateLimiter 实战:Redis 令牌桶限流从配置到本地压测验证
java·架构·源码分析·csdn
程序员三明治2 天前
RAG 元数据的作用与管理:让知识库回答可追溯、可过滤、可维护
人工智能·llm·知识库·元数据·rag·java后端
luoyayun3613 天前
Qt + FFmpeg 实战:获取音视频文件基础属性、流信息和元数据
qt·ffmpeg·音视频·元数据·获取音视频文件属性
心之伊始5 天前
MySQL EXPLAIN 执行计划实战:从 type、Extra 到慢 SQL 定位与优化
java·架构·源码分析·csdn
心之伊始5 天前
Spring Boot Actuator + Micrometer 自定义业务指标:不只是健康检查
java·架构·源码分析·csdn