4. 规则表达与语法:DRL规则语言、IF-THEN结构、规则优先级与冲突解决
好,咱们今天聊聊规则引擎里最核心的东西——规则怎么写,怎么排优先级,怎么解决冲突。
说实话,我见过不少团队,规则写得跟天书似的,最后维护成本高得吓人。其实规则表达这件事,说白了就是两件事:怎么把业务逻辑说清楚,以及多条规则打架时听谁的。
4.1 DRL规则语言:规则引擎的“普通话”
DRL(Drools Rule Language)是Drools规则引擎的原生语言。我个人习惯把它叫做“规则界的普通话”——虽然各家引擎都有自己的方言,但DRL的语法结构基本是通用的。
一个典型的DRL规则长这样:
rule "逾期金额大于1000且信用分低于600"
when
$loan: Loan(overdueAmount > 1000)
$user: User(creditScore < 600)
then
$loan.setRiskLevel("高");
System.out.println("触发高风险规则");
end
嗯,这里要注意几个关键点:
- rule:规则的名字,最好起得有意义,别叫“rule1”、“rule2”这种
- when:条件部分,说白了就是“如果”
- then:动作部分,就是“那么”
- $loan:变量绑定,方便后面引用
4.2 IF-THEN结构:规则引擎的“骨架”
其实不管什么规则引擎,底层都是IF-THEN结构。你想想看,业务规则本质上就是“如果发生了A,那么就执行B”。
我见过最坑的写法是什么?把IF-THEN嵌套了七八层。比如:
// 千万别这么写!
if (条件A) {
if (条件B) {
if (条件C) {
// 动作
}
}
}
这种写法,维护起来简直要命。我在项目中遇到过,一个规则改了三个月,最后发现是嵌套逻辑搞错了。
正确的做法是扁平化:
rule "规则1"
when
条件A
条件B
条件C
then
// 动作
end
DRL里的when部分,多个条件默认是“且”的关系。如果你想用“或”,可以用||或者or关键字。
4.3 规则优先级:谁先谁后?
规则多了,总有个先后顺序。DRL里用salience来控制优先级。数值越大,优先级越高。
rule "高优先级规则"
salience 100
when
// 条件
then
// 动作
end
rule "低优先级规则"
salience 10
when
// 条件
then
// 动作
end
我曾经犯过一个错:给所有规则都设了salience,但没注意数值范围。结果后来加规则时,发现优先级乱套了。从那以后,我定了个规矩:salience用100的倍数,留出中间值给后续扩展。
| 优先级级别 | salience值 | 适用场景 |
|---|---|---|
| 最高 | 1000 | 黑名单、强制拒绝 |
| 高 | 500 | 高风险规则 |
| 中 | 100 | 常规规则 |
| 低 | 10 | 默认规则、兜底规则 |
4.4 冲突解决:规则打架怎么办?
规则冲突,说白了就是两条规则都满足条件,但结果互相矛盾。比如一条说“通过”,另一条说“拒绝”。
DRL里解决冲突有几种策略:
- salience优先:谁优先级高听谁的
- 加载顺序:如果salience相同,先加载的先执行
- 自定义冲突策略:可以自己写逻辑
还有一种常见的冲突场景:规则覆盖。比如规则A说“年龄大于30通过”,规则B说“年龄大于40拒绝”。那35岁的人怎么办?
我的建议是:明确规则的边界。要么用更精确的条件,要么用优先级来区分。比如:
rule "年龄30-40通过"
salience 100
when
$user: User(age > 30, age <= 40)
then
$user.setResult("通过");
end
rule "年龄大于40拒绝"
salience 200
when
$user: User(age > 40)
then
$user.setResult("拒绝");
end
这样,35岁的人只匹配第一条规则,45岁的人只匹配第二条规则,完美避开冲突。
4.5 知识体系总览
下面这张图,是我自己总结的规则表达与语法的核心结构。你把它记在脑子里,写规则时就不会跑偏。
嗯,这张图基本把这一章的核心内容都串起来了。你写规则时,就照着这个结构来,不会出大问题。
公众号:蓝海资料掘金营,微信deep3321