在 drools 中使用 EXISTS 关键字满足条件时从 WHEN 部分获取值

Getting value from WHEN part while a condition meets using EXISTS keyword in drools

rule "attaching AV and impact rating"
agenda-group "evaluate likelihood"
dialect "java"
when
     Application($threatList:getThreatList())
     $av:AttackVector()
     exists  $threat:Application.Threats(impact == "Disclose Information")from $threatList
     exists  AttackVector($av == AttackVector.REQUEST_MANIPULATION)
then
     RiskRating riskRating=new RiskRating($threat.getImpactRating(),$av.getLikelihood(),$av.getName());
     insertLogical(riskRating);
end

我正在努力在上述规则的 THEN 部分获取对象 $threat。如果我运行上面的规则,它说:

Rule Compilation error : [Rule name='attaching AV and impact rating']
referee/security/attack/Rule_attaching_AV_and_impact_rating1426933818.java (7:1053) : $threat cannot be resolved

如果我遍历它并在 THEN 部分获取值,它会生成笛卡尔积并在会话中多次插入这些值。当我得到笛卡尔积时,我的规则看起来像这样。

rule "attaching AV and impact rating"
agenda-group "evaluate likelihood"
dialect "java"
when
     Application($threatList:getThreatList())
     $av:AttackVector()
     exists  $threat:Application.Threats(impact == "Disclose Information")from $threatList
     $threat:Application.Threats(impact == "Disclose Information")from $threatList
     exists  AttackVector($av == AttackVector.REQUEST_MANIPULATION)
then
     RiskRating riskRating=new RiskRating($threat.getImpactRating(),$av.getLikelihood(),$av.getName());
     insertLogical(riskRating);
end

如何在没有笛卡尔积的情况下获取 THEN 部分中 $threat 的值?

完全删除 exists 操作。

rule "attaching AV and impact rating"
agenda-group "evaluate likelihood"
dialect "java"
when
     Application($threatList:getThreatList())
     $av: AttackVector()
     $threat: Application.Threats(impact == "Disclose Information")from $threatList
     exists(AttackVector($av == AttackVector.REQUEST_MANIPULATION))
then
     RiskRating riskRating=new RiskRating($threat.getImpactRating(),$av.getLikelihood(),$av.getName());
     insertLogical(riskRating);
end

exists的意思是“工作记忆中有一个东西像这样匹配这些conditions/looks”。它不用于实际提取或提供对该匹配实例的引用。只需删除运算符,它就会按照您的需要工作——如果有一个 Application.Threats 符合您的条件,规则就会触发并将匹配值分配给 $threat 变量。

你 运行 的事实是你有 多重 威胁,这意味着你的情况,这就是为什么你有多个规则触发器-- 每次匹配 Application.Threats 触发一次。 exists 关键字缓解了这一点,因为它只关心至少存在一个匹配项,但您没有得到引用(因为如果有四个匹配项,哪一个将分配给变量?这没有意义,逻辑上。)

因此您需要更改规则,使其不会触发多次,而只会在找到匹配项时触发一次。通常你会通过让后果对工作记忆做一些事情来做到这一点,从而使规则不再有资格被解雇。在您的示例中,您插入了一个 RiskRating 对象;然后,您可以检查您的条件中是否不存在风险评级:

not( RiskRating( /* insert criteria here or leave empty */ ) )

或者,您可以从工作记忆中撤回您的规则存在或匹配所依赖的内容。例如,如果你以后不需要它,你可以收回攻击向量:

retract( $av )

另一种选择可能是尝试将您的 getThreatList() 实施更新为 return Set,这样您就不会重复(假设威胁被认为是重复的,基于 'impact' 字段。)或者您可以尝试从正在 returned 的威胁列表中删除所有符合条件的 Application.Threats 实例。

我们对您的用例或规则集知之甚少,无法知道您需要什么数据或它看起来像什么,但归根结底,您只需要规则触发一次且仅触发一次,所以要做到这一点,您需要以某种方式更新规则以了解它不再有效。