我希望“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
答案 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
的赋值;它甚至会引用什么是模棱两可的。)
这种方法的缺点是,如果您在任何其他规则中更新工作记忆(例如,通过调用 insert
、modify
、update
等),您最终可能会再次触发此规则,因为左侧的条件仍将保持有效和匹配。为了缓解这种情况,您可以利用 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
。),此版本将不会重新触发。