Drools中update()未触发规则重燃问题咨询
问题背景
使用Drools 7.73.0有状态会话,配置了以下两条规则:
rule "MYRULES_10" when prod : Product(sku != "1") $txt1 : TextOption(sku == "mm", value == "A") then prod.setOptionEnabled( "to2", false, "Not available rule 10" ); end // rule values at B11, header at B5 rule "MYRULES_11" when prod : Product(sku != "1") $opt1 : TextChoiceOption(sku == "mt") exists (OptionValue(optionValueValue in ("val1")) from $opt1.value) $txt1 : TextOption(sku == "mm") then $txt1.setValue("A"); update($txt1); end
当前现象:
- MYRULES_11可正常触发,且
setValue("A")已正确设置值,但update($txt1)无法触发MYRULES_10执行; - 初始调用
fireAllRules()后立即再次调用,MYRULES_10仍不触发; - 将第一个会话的所有事实导入第二个会话执行
fireAllRules(),MYRULES_10和MYRULES_11会依次触发; - 若初始就将
mm事实的value设为"A",MYRULES_10先触发,随后MYRULES_11触发。
原因分析及解决方案
1. TextOption类的equals/hashCode未包含value属性
Drools依赖对象的equals()和hashCode()方法判断事实是否发生变更。如果TextOption类的这两个方法没有将value字段纳入判断逻辑,即使调用setValue("A")修改了值,Drools会认为该事实没有变化,不会触发依赖该事实的规则重新匹配。
解决办法:
修改TextOption类的equals()和hashCode()方法,确保包含value字段,保证当value变化时,对象的相等性判断和哈希值也会同步改变。
2. 联合条件未被重新评估
MYRULES_10的条件是同时匹配Product(sku != "1")和TextOption(sku == "mm", value == "A")两个事实。当MYRULES_11更新TextOption后,Drools需要重新检查这两个事实的组合是否满足条件。如果Product事实未被标记为需要重新评估,可能导致联合条件的匹配逻辑未被触发。
验证与解决:
在MYRULES_11的then块中添加update(prod);,强制Drools重新评估涉及Product的联合条件:
then $txt1.setValue("A"); update($txt1); update(prod); // 强制触发联合条件重新匹配 end
如果修改后MYRULES_10能正常触发,说明问题出在联合条件的重新评估机制上。
3. 议程状态或规则执行标记问题
第一次fireAllRules()执行时,MYRULES_11更新TextOption后,Drools的议程可能未将MYRULES_10加入待执行队列;第二次调用fireAllRules()时,由于内部状态未正确重置,导致MYRULES_10仍未被匹配。
验证与解决:
- 检查规则是否设置了
no-loop属性(默认未设置,但需确认全局配置或继承规则),该属性会阻止规则因自身触发的更新重执行,但此处MYRULES_10由其他规则触发,可能性较低; - 在
update($txt1)后,通过kSession.getAgenda().getActivations()查看议程中是否有MYRULES_10的激活项,确认是否被正确加入待执行队列。
额外验证点
- 确认TextOption的
getValue()方法正确返回设置的"A"值,避免getter逻辑错误导致Drools获取不到正确值; - 检查工作内存中是否存在符合条件的Product事实,确保MYRULES_11执行后该事实仍存在且
sku != "1"。
内容的提问来源于stack exchange,提问作者Jeff

