规则语言与语法:DRL语法基础
说到规则引擎,DRL(Drools Rule Language)是绕不开的核心语言。我刚开始接触Drools时,第一反应是:这不就是另一种if-else吗?后来踩了几个坑才明白,DRL的威力远不止条件判断那么简单。
DRL语法,说白了就是一套专门描述业务规则的领域特定语言。它让你能用接近自然语言的方式,把复杂的业务逻辑写清楚。我个人习惯把DRL文件看作一个「规则容器」,里面装的是一个个独立的规则单元。
条件(When)与动作(Then)
每个DRL规则都长这样:
rule "规则名称"
when
// 条件部分
then
// 动作部分
end
when后面跟的是条件,then后面是满足条件后要执行的动作。嗯,这里有个关键点:when里的条件不是简单的布尔表达式,而是模式匹配。
举个例子:
rule "风控-交易金额超限"
when
$t : Transaction(amount > 10000)
then
System.out.println("交易金额超限:" + $t.getAmount());
$t.setRiskLevel("HIGH");
end
看到$t了吗?这是绑定变量。它把匹配到的Transaction对象抓出来,后面then里就能直接用。我在项目中遇到过新手把$t写成t,结果编译报错半天找不出原因。记住,DRL里变量名带$是约定俗成的写法,虽然不是强制,但建议遵守。
规则属性(salience、no-loop等)
规则属性是控制规则行为的「开关」。我刚开始用的时候觉得这些属性可有可无,直到有一次线上规则执行顺序乱了,才意识到属性的重要性。
| 属性名 | 作用 | 我的经验 |
|---|---|---|
| salience | 优先级,数值越大越先执行 | 默认0,我习惯用10的倍数,方便中间插规则 |
| no-loop | 防止规则自身循环触发 | 默认false,建议大部分规则设为true |
| activation-group | 同一组内只执行一条规则 | 互斥场景必备,比如风控通过/拒绝 |
| date-effective | 规则生效日期 | 促销活动规则常用,省得写定时任务 |
salience 是最常用的属性。为什么?因为规则引擎的执行顺序不是你写代码的顺序,而是按salience排序。我曾经在项目中遇到一个bug:两条规则都匹配了同一笔交易,结果优先级低的先执行,把状态改了,优先级高的后执行反而报错。后来给每条规则都配了salience,问题就解决了。
rule "高风险交易拦截"
salience 100
no-loop true
when
$t : Transaction(amount > 50000)
then
$t.setStatus("BLOCKED");
end
rule "中风险交易标记"
salience 50
no-loop true
when
$t : Transaction(amount > 10000)
then
$t.setStatus("REVIEW");
end
类型声明与全局变量
类型声明,说白了就是在DRL文件里定义Java类。为什么要这么做?有时候你不想为了一个简单的POJO单独建一个Java文件,直接在规则文件里声明更方便。
declare RiskResult
riskLevel : String
score : int
reason : String
end
这样声明后,RiskResult就能在规则里直接用了。我个人习惯把风控结果类都声明在规则文件里,因为每个项目的风控维度都不一样,写在Java里反而耦合度高。
全局变量 是另一个实用功能。它允许你在规则里访问外部传入的对象,比如日志记录器、配置信息等。
global org.slf4j.Logger logger
global java.util.Map configMap
rule "记录高风险交易"
when
$t : Transaction(amount > 100000)
then
logger.warn("高风险交易:{}", $t.getId());
String threshold = (String) configMap.get("high_risk_threshold");
System.out.println("当前阈值:" + threshold);
end
这里要注意:全局变量不能在规则里修改值,只能读取。为什么?因为规则引擎是多线程执行的,全局变量修改会导致线程安全问题。我曾经犯过这个错,在规则里改了全局Map的值,结果并发时数据全乱了。
- DRL的when部分做模式匹配,不是简单的if判断
- salience控制执行顺序,建议用10的倍数
- no-loop默认设为true,避免死循环
- 类型声明适合风控结果类,减少Java代码耦合
- 全局变量只读不写,保证线程安全
最后说一句,DRL语法看着简单,但真正用好需要积累。我刚开始写规则时,一个文件里塞了几十条规则,后来发现维护起来想死。建议你按业务模块拆分规则文件,每个文件不超过20条规则。这样既清晰又好维护。
这张图展示了一个DRL文件的基本结构。每个规则都包含属性和逻辑体,规则之间通过salience控制执行顺序。实际项目中,你可能会有几十个这样的规则文件,按业务模块组织好。
好了,DRL语法基础就聊到这儿。记住三个核心:条件怎么写、动作怎么配、属性怎么设。把这些搞明白,你就能写出靠谱的风控规则了。
公众号:蓝海资料掘金营,微信deep3321