Drools规则重复触发规避方案及替代技术咨询
基于Drools的重复规则触发优化方案及替代思路
针对你在百万级数据对象校验中遇到的「避免规则重复触发、减少人工审批」需求,以下是具体的实现方案:
一、Drools框架内可行方案
1. 自定义规则触发快照与哈希校验
给数据对象扩展存储字段,记录已触发规则的ID及对应属性的哈希值,在规则判断阶段前置对比哈希,仅当属性变更时触发规则:
- 给数据对象添加
ruleTriggerHistory(如Map<String, String>),存储规则名→属性哈希的映射 - 规则中针对关联属性计算哈希,与历史记录对比,不一致才触发审批逻辑
- 哈希计算仅针对规则关联的关键属性,避免全量计算浪费性能
示例规则代码:
rule "HighAmountApproval" when $obj: DataObject( amount > 10000, // 对比当前属性哈希与历史记录 ruleTriggerHistory["HighAmountApproval"] != HashUtils.calculateHash(amount, status) ) then // 触发审批流程逻辑 String currentHash = HashUtils.calculateHash($obj.getAmount(), $obj.getStatus()); $obj.getRuleTriggerHistory().put("HighAmountApproval", currentHash); // 同步更新数据库中的历史记录 end
注:HashUtils可自行实现,比如用Apache Commons的HashCodeBuilder组合属性生成哈希值
2. 利用AgendaFilter做全局规则过滤
实现Drools的AgendaFilter接口,在规则触发前从数据库加载历史记录,过滤掉属性未变更的规则,无需修改现有规则逻辑:
public class RuleHistoryFilter implements AgendaFilter { private final DataObject currentObj; private final RuleHistoryDAO historyDAO; private final Map<String, List<String>> rulePropertyMap; // 预定义规则-属性映射表 public RuleHistoryFilter(DataObject currentObj, RuleHistoryDAO historyDAO) { this.currentObj = currentObj; this.historyDAO = historyDAO; this.rulePropertyMap = loadRulePropertyMapping(); // 从配置文件加载规则关联属性 } @Override public boolean accept(Activation activation) { String ruleName = activation.getRule().getName(); RuleHistoryRecord history = historyDAO.findByObjIdAndRule(currentObj.getId(), ruleName); if (history == null) return true; // 无历史记录,允许触发 // 计算当前对象对应规则的属性哈希 String currentHash = calculateRuleHash(currentObj, rulePropertyMap.get(ruleName)); return !currentHash.equals(history.getParamHash()); } private String calculateRuleHash(DataObject obj, List<String> properties) { // 仅针对规则关联的属性计算哈希 HashCodeBuilder builder = new HashCodeBuilder(); for (String prop : properties) { builder.append(BeanUtils.getProperty(obj, prop)); } return builder.toHashCode() + ""; } }
使用时在会话中设置过滤器:
StatelessKieSession kieSession = kieContainer.newStatelessKieSession(); kieSession.setAgendaFilter(new RuleHistoryFilter(dataObject, historyDAO)); kieSession.execute(dataObject);
二、替代技术思路
1. 切换为DMN决策模型
如果Drools的规则表达式难以捕获评估参数,可以改用Drools DMN(决策模型和符号):
- DMN明确定义决策的输入、输出参数,便于直接记录决策快照
- 每个决策节点的输入参数可直接提取存储,更新时对比输入参数的哈希即可判断是否需要重新决策
2. ORM层变更追踪
在JPA/Hibernate等ORM层实现属性变更监听,仅触发与变更属性关联的规则:
- 用
@EntityListeners监听对象的preUpdate事件,记录变更的属性列表 - 根据预定义的「规则-属性映射表」,仅执行关联了变更属性的规则
3. 事件驱动的规则触发
将属性变更转化为事件,仅当关联事件发生时触发对应规则:
- 用Spring Event或Axon Framework发布属性变更事件(如
AmountChangedEvent) - 规则仅监听特定事件,无对应事件时不触发校验逻辑
三、性能优化补充
针对百万级数据场景,可搭配以下优化:
- 用Redis缓存规则触发历史哈希,减少数据库查询次数
- 批量处理对象时,先分组过滤已触发且属性未变更的对象,再送入Drools校验
内容的提问来源于stack exchange,提问作者skyman lee
相关产品推荐
相关产品推荐

