3. 规则语法设计:DRL语法基础、条件表达式、动作脚本、规则优先级与冲突解决
规则语法是规则引擎的核心语言,它决定了业务人员如何描述风控逻辑、工程师如何维护规则库。本章以 Drools Rule Language(DRL)为蓝本,讲解规则语法的四大支柱:基础语法结构、条件表达式、动作脚本以及优先级与冲突解决策略。掌握这些内容后,你将能够设计出可读、可维护、高性能的风控规则集。
3.1 DRL 语法基础
DRL 是一种声明式规则语言,每条规则由 rule 关键字定义,包含 when(条件)和 then(动作)两个主要部分。一个典型的 DRL 规则文件结构如下:
package com.risk.engine.rules
import com.risk.engine.model.Transaction
import com.risk.engine.model.UserProfile
rule "高风险交易拦截"
salience 100
no-loop true
when
$tx: Transaction( amount > 10000, currency == "CNY" )
$user: UserProfile( riskLevel == "HIGH" )
then
$tx.setBlocked(true);
$tx.setReason("高风险用户大额交易");
update($tx);
end
关键语法元素:
| 元素 | 说明 | 示例 |
|---|---|---|
package |
规则包名,用于逻辑分组 | package com.risk.engine.rules |
import |
导入 Java 或 POJO 类 | import com.risk.engine.model.Transaction |
rule ... end |
规则体定义 | rule "规则名称" ... end |
when |
条件部分(LHS) | when $tx: Transaction( amount > 10000 ) |
then |
动作部分(RHS) | then $tx.setBlocked(true); |
salience |
优先级数值,越大越优先 | salience 100 |
no-loop |
防止规则自身触发循环 | no-loop true |
payment、login、coupon),便于后期维护和权限管理。
3.2 条件表达式:模式匹配与约束
条件表达式是规则引擎的“眼睛”,它从工作内存(Working Memory)中筛选出符合条件的事实对象。DRL 支持丰富的条件表达方式:
3.2.1 基本字段约束
// 数值比较
$tx: Transaction( amount >= 5000, amount <= 50000 )
// 字符串匹配
$user: UserProfile( city == "Beijing", riskLevel in ("HIGH", "CRITICAL") )
// 布尔判断
$tx: Transaction( isCrossBorder == true )
// 空值检查
$tx: Transaction( merchantId != null )
3.2.2 复合条件与绑定变量
// 绑定变量并在后续条件中引用
$tx: Transaction( $amt: amount, $mid: merchantId )
$merchant: Merchant( id == $mid, riskScore > 80 )
// 此时 $amt 可在 then 部分使用
3.2.3 条件组合与嵌套
// 使用 || 和 && 组合条件
$tx: Transaction( (amount > 10000 && currency == "USD") || (amount > 50000 && currency == "CNY") )
// 使用 exists 和 not 判断存在性
not ( SuspiciousIp( ip == $tx.ipAddress ) )
exists ( BlacklistCard( cardNo == $tx.cardNo ) )
$tx.getHistory().size() > 10),这会降低模式匹配效率。建议将计算结果预置为事实对象的字段,或使用 eval() 函数(但 eval 会破坏索引优化,谨慎使用)。
3.3 动作脚本:规则触发后的行为
动作脚本(RHS)是规则触发后执行的代码块,通常用于修改事实、记录日志、调用外部服务或产生事件。动作脚本应保持轻量、幂等、可追溯。
3.3.1 常用动作类型
| 动作类型 | DRL 示例 | 说明 |
|---|---|---|
| 修改事实 | $tx.setBlocked(true); update($tx); |
修改后必须调用 update() 通知引擎 |
| 插入新事实 | insert(new AuditLog($tx.getId(), "BLOCKED")); |
插入审计日志对象到工作内存 |
| 删除事实 | retract($tx); |
从工作内存中移除对象 |
| 调用服务 | riskService.sendAlert($tx.getUserId(), "HIGH_RISK"); |
通过全局变量或 Spring 上下文调用 |
| 设置全局变量 | drools.getWorkingMemory().setGlobal("result", "BLOCK"); |
将结果传递到规则引擎外部 |
3.3.2 动作脚本最佳实践
rule "设备指纹异常-自动处置"
salience 80
when
$device: DeviceFingerprint( anomalyScore > 0.9 )
$session: Session( deviceId == $device.deviceId )
then
// 1. 修改事实
$session.setForceLogout(true);
update($session);
// 2. 插入审计
AuditLog log = new AuditLog();
log.setEventType("DEVICE_ANOMALY");
log.setDetail("设备异常分数: " + $device.getAnomalyScore());
insert(log);
// 3. 调用外部服务(通过全局变量注入)
alertService.sendNotification($session.getUserId(), "您的账号存在异常登录,已强制下线");
end
3.4 规则优先级与冲突解决
当多个规则的条件同时满足时,引擎需要决定执行顺序。风控场景中,优先级错误可能导致误放行或误拦截。DRL 提供以下机制:
3.4.1 显式优先级:Salience
salience 是一个整数值,默认值为 0。数值越大,优先级越高,越先执行。
rule "黑名单拦截" salience 100
when $user: UserProfile( blacklisted == true )
then $user.setBlocked(true); end
rule "VIP用户豁免" salience 50
when $user: UserProfile( vipLevel >= 5 )
then $user.setBlocked(false); end
上述场景中,如果用户既是黑名单又是 VIP,黑名单拦截 先执行(salience 100),将用户拦截;随后 VIP用户豁免 执行(salience 50),又将拦截取消。这可能导致逻辑错误,需要引入冲突解决策略。
3.4.2 冲突解决策略
| 策略 | 机制 | 适用场景 |
|---|---|---|
| Salience 排序 | 按 salience 值降序执行 | 明确业务优先级,如“黑名单优先于白名单” |
| 议程分组(Agenda Group) | 将规则分组,按组顺序执行 | 分阶段处理:先校验、再决策、后处置 |
| 激活组(Activation Group) | 同一组内只执行一条规则 | 互斥决策:如“通过”和“拒绝”不能同时生效 |
| 规则流(Rule Flow) | 通过流程图控制规则执行顺序 | 复杂业务流程编排 |
3.4.3 使用 Activation Group 解决互斥
rule "高风险-拒绝交易"
activation-group "decision"
salience 100
when $tx: Transaction( riskScore > 90 )
then $tx.setDecision("REJECT"); end
rule "中风险-人工审核"
activation-group "decision"
salience 50
when $tx: Transaction( riskScore > 70 && riskScore <= 90 )
then $tx.setDecision("REVIEW"); end
rule "低风险-自动通过"
activation-group "decision"
salience 0
when $tx: Transaction( riskScore <= 70 )
then $tx.setDecision("APPROVE"); end
三个规则属于同一个 activation-group "decision",引擎只会执行其中 salience 最高且条件满足的那一条,确保每笔交易只有一个最终决策。
3.5 规则语法设计全景图
下图展示了 DRL 规则语法的完整结构,从包声明到动作执行,以及优先级与冲突解决机制在规则执行流程中的位置:
3.6 规则优先级设计模式
在实际风控项目中,规则数量可能达到数百甚至数千条,合理的优先级设计至关重要。以下是三种常见设计模式:
| 模式 | Salience 分配策略 | 典型场景 |
|---|---|---|
| 金字塔模式 | 黑名单/白名单 100,高风险 80,中风险 50,低风险 20 | 先执行强规则,后执行弱规则,避免弱规则覆盖强规则 |
| 阶段模式 | 校验阶段 100,决策阶段 50,处置阶段 0 | 结合 Agenda Group 分阶段执行,每阶段内再按 salience 排序 |
| 互斥模式 | 同一 Activation Group 内,按业务权重分配 salience | 决策互斥:拒绝 > 人工审核 > 自动通过 |
3.7 本章小结
规则语法设计是风控规则引擎的基石。通过本章学习,你应掌握:
- DRL 基础结构:package、import、rule、when、then 的完整写法
- 条件表达式:字段约束、绑定变量、复合条件、存在性判断
- 动作脚本:事实修改、插入、删除、服务调用、全局变量
- 优先级与冲突解决:salience、agenda-group、activation-group 的适用场景