Drools - 当满足子列表中的条件时仅触发一次

时间:2021-07-14 14:21:22

标签: drools

我希望“then”子句只执行一次,但它正在为列表中匹配的每个子对象执行。

如果列表中的任何一项满足我想突破的条件,并且只执行一次 then 子句。

rule "Profile - Delinquent"  
    when  
        $c : CreditReportAll( $creditLiability : creditLiability )  
        $cs: CreditLiability( paymentPatternData.contains("X")) from $creditLiability  
    then  
        CreditUserSegment $cu = new CreditUserSegment();  
        $cu.setSegmentCode("delinquent");  
        $c.addUserSegmentToList($cu);  
    end

1 个答案:

答案 0 :(得分:2)

为了仅在 $creditLiability 列表中的任何项目满足条件时触发规则一次,您需要编写规则以使其不会遍历列表,或者您需要更新您的规则,一旦它确实触发,它就会改变工作记忆中的事实,不允许它再次触发。

无迭代

最简单的方法是将规则更改为不遍历列表。为此,我们使用 exists 关键字,如下所示:

rule "Profile - Delinquent"  
when
  $c : CreditReportAll( $creditLiability : creditLiability )
  exists( CreditLiability( paymentPatternData.contains("X")) from $creditLiability )
then  
  CreditUserSegment $cu = new CreditUserSegment();  
  $cu.setSegmentCode("delinquent");  
  $c.addUserSegmentToList($cu);  
end

exists 关键字将在存在至少一个与所需条件匹配的元素时匹配。请注意,我们不再将变量分配给结果,因为它没有任何意义(例如,这里没有 $cs 的赋值;它甚至会引用什么是模棱两可的。)

这种方法的缺点是,如果您在任何其他规则中更新工作记忆(例如,通过调用 insertmodifyupdate 等),您最终可能会再次触发此规则,因为左侧的条件仍将保持有效和匹配。为了缓解这种情况,您可以利用 no-loop rule attribute(取决于您的设置)。否则,您将需要更新您的规则(或工作内存中的数据),以便您的规则不再有效。

使规则无效

另一种只触发规则一次的方法是使规则在触发一次后不再有效。一个简单的方法(在这种情况下可能不是最佳实践)是将一个标志插入工作内存并检查它的存在。在这种情况下,我将使用一个简单的字符串“DELINQUENT”作为标志。

rule "Profile - Delinquent"  
when
  not(String(this == "DELINQUENT"))
  $c : CreditReportAll( $creditLiability : creditLiability )
  $cs: CreditLiability( paymentPatternData.contains("X")) from $creditLiability  
then  
  CreditUserSegment $cu = new CreditUserSegment();  
  $cu.setSegmentCode("delinquent");  
  $c.addUserSegmentToList($cu);
  insert("DELINQUENT");
end

当规则触发时,它会在工作内存中插入一个字符串,上面写着“DELINQUENT”。规则条件使得规则仅在工作内存中不存在此字符串时才触发。因此,在第一次执行后,除非规则收回该字符串,否则规则将不会再次执行。

此解决方案增加了规则执行的内存占用,因为工作内存中有更多信息。然而,与其他解决方案(更优雅)不同的是,如果另一个规则重新触发执行(例如,通过 update。),此版本将不会重新触发。