3. 规则定义与配置:规则的结构(条件+动作)、规则配置化设计、规则文件格式(DRL、JSON、YAML)
好,咱们进入第三章。这一章聊的是规则引擎的“骨架”——规则的定义与配置。
说实话,很多团队一开始做规则引擎,都栽在同一个坑里:规则写死了。业务一改,就得改代码、重新部署。这哪叫规则引擎?这叫硬编码。
所以,这一章的核心就三个字:配置化。把规则从代码里抽出来,变成可配置、可维护的独立资产。
3.1 规则的结构:条件 + 动作
规则的本质是什么?说白了就是:如果满足某个条件,就执行某个动作。
你想想看,不管是风控系统、优惠券发放,还是审批流程,底层逻辑都是这个。我习惯把规则拆成三个部分:
- 元数据:规则名称、版本号、生效时间、优先级。这些是给运维看的。
- 条件(Condition):触发规则的前提。可以是简单的字段比较,也可以是复杂的组合逻辑。
- 动作(Action):条件满足后执行的操作。比如“拒绝订单”、“发送短信”、“计算折扣”。
一个典型的规则结构(伪代码):
规则 "订单风控-高频交易" {
优先级: 10
条件: 当 用户.近1小时交易次数 > 5 且 用户.账户等级 == "普通"
动作: 标记订单为 "高风险",触发人工审核
}
我在项目中遇到过一种情况:业务方说“规则很简单,就两个条件”。结果一上线,发现条件之间还有隐含的优先级关系,导致误判率飙升。嗯,这里要注意:条件之间的逻辑关系(AND/OR/NOT)一定要显式定义,别靠猜。
3.2 规则配置化设计
规则配置化,不是简单地把规则塞进数据库就完事了。我见过最糟糕的设计:规则存在一个超大 JSON 字段里,业务方改规则得找开发写 SQL。这哪是配置化?这是换了个地方硬编码。
我个人习惯的配置化设计,要满足三个原则:
- 可读性:业务人员能看懂,甚至能自己改。别整一堆技术符号。
- 版本化:每次修改都要留痕,能回滚。我曾经因为没做版本管理,一次误操作导致线上规则全乱,回滚花了两个小时。
- 热加载:改完规则,不用重启服务就能生效。这是配置化的底线。
我的配置化设计经验:
我建议把规则拆成“规则头”和“规则体”。规则头存元数据(名称、版本、状态),规则体存具体的条件和动作。这样,查询规则列表时不用加载全部内容,性能好很多。
举个例子,一个简单的规则配置表设计:
| 字段 | 类型 | 说明 |
|---|---|---|
| rule_id | varchar(32) | 规则唯一标识 |
| rule_name | varchar(128) | 规则名称,业务方用 |
| version | int | 版本号,每次修改递增 |
| status | tinyint | 0-禁用,1-启用 |
| condition_json | text | 条件表达式(JSON格式) |
| action_json | text | 动作定义(JSON格式) |
| priority | int | 优先级,数字越小越优先 |
| effective_time | datetime | 生效时间 |
| expire_time | datetime | 失效时间 |
3.3 规则文件格式:DRL、JSON、YAML
规则写在哪?常见的有三种格式。我分别说说我的看法。
3.3.1 DRL(Drools Rule Language)
DRL 是 Drools 规则引擎的原生语言。如果你用 Drools,那 DRL 是首选。它的语法贴近自然语言,表达能力很强。
举个例子:
package com.example.rules
import com.example.model.Order
rule "大额订单折扣"
when
$order: Order(amount > 1000)
then
$order.setDiscount(0.1);
System.out.println("大额订单,享受9折优惠");
end
DRL 的好处是:与 Drools 引擎深度集成,性能好,支持复杂的推理。但缺点也很明显:学习曲线陡,业务人员基本看不懂。我一般只在后端团队内部使用 DRL,不会让业务方直接碰。
3.3.2 JSON
JSON 是通用格式,前后端都熟悉。我建议用 JSON 作为规则配置的存储格式,尤其是需要和前端规则编辑器配合时。
一个 JSON 格式的规则示例:
{
"ruleId": "R001",
"ruleName": "高频交易风控",
"priority": 10,
"condition": {
"operator": "AND",
"conditions": [
{ "field": "user.tradeCountLastHour", "operator": ">", "value": 5 },
{ "field": "user.level", "operator": "==", "value": "normal" }
]
},
"action": {
"type": "markOrder",
"params": {
"riskLevel": "high",
"needReview": true
}
}
}
JSON 的优点是:结构清晰,解析方便。但要注意,JSON 不支持注释,所以字段含义得靠文档说明。我习惯在 JSON 里加一个 description 字段,写清楚这条规则是干嘛的。
3.3.3 YAML
YAML 比 JSON 更简洁,可读性更好。如果你想让规则文件看起来像配置文件,YAML 是很好的选择。
同样的规则,用 YAML 写:
ruleId: R001
ruleName: 高频交易风控
priority: 10
condition:
operator: AND
conditions:
- field: user.tradeCountLastHour
operator: ">"
value: 5
- field: user.level
operator: "=="
value: normal
action:
type: markOrder
params:
riskLevel: high
needReview: true
YAML 支持注释,这是它比 JSON 强的地方。但 YAML 对缩进敏感,一不小心就会解析失败。我曾经因为一个空格问题,排查了半小时。所以,如果用 YAML,一定要加校验。
避坑指南:
我曾经在项目中混合使用 JSON 和 YAML 两种格式,结果运维搞混了,解析器报错。后来我统一了格式:存储用 JSON,展示用 YAML。JSON 作为标准格式,YAML 只用于人工查看和编辑。
3.4 知识体系结构图
下面这张图,帮你理清规则定义与配置的核心脉络:
好了,这一章的内容就这些。规则的结构、配置化设计、文件格式,这三块是规则引擎的基石。下一章我们会聊规则引擎的执行流程,到时候你会看到这些规则是怎么跑起来的。
本章小结:
- 规则的本质是“条件+动作”,但别忘了元数据
- 配置化设计要满足可读性、版本化、热加载
- DRL 适合后端内部,JSON 适合存储和传输,YAML 适合人工编辑
- 统一格式,避免混用