简体   繁体   English

如何推断 Drools 规则中的中间值

[英]How to infere intermediate values in Drools rules

I've been recommended to use Drools for score calculation.我被推荐使用 Drools 进行分数计算。 I'm new to this framework, but after a small research I see that it's indeed a good solution, because scoring rules are going to be updated/adjusted frequently and it's easy (it seems) to write/change/update Drools rules.我是这个框架的新手,但经过小型研究后,我发现它确实是一个很好的解决方案,因为评分规则将经常更新/调整,而且编写/更改/更新 Drools 规则(看起来)很容易。

Background : The scoring algorithm that I have to use calculates intermediate values and then based on these values calculates the final score.背景:我必须使用的评分算法计算中间值,然后根据这些值计算最终分数。 So there's the model called Person , it has a lot of properties, some of them might be null or empty.所以有一个名为Person的 model,它有很多属性,其中一些可能是 null 或空的。 And the scoring algorithm considers all these fields and makes final decision (score).评分算法会考虑所有这些字段并做出最终决定(评分)。

UPD: It's possible to skip intermediate values calculation (in theory), but I'm 100% sure the rules will become unclear and messy. UPD:可以跳过中间值计算(理论上),但我 100% 确定规则会变得不清楚和混乱。

The question is: How do I save(persist) these intermediate values between individual rules?问题是:如何在各个规则之间保存(持久化)这些中间值? From what I can see from the documentation, it's not possible (?) or I'm missing something.从文档中可以看出,这是不可能的(?)或者我遗漏了一些东西。 There's no such thing as variable in rules.规则中没有变量这样的东西。

Ideally I would have some global variables which are accessible only on this rule set.理想情况下,我会有一些只能在此规则集上访问的全局变量。 They have initial values (like null or 0).它们具有初始值(如null或 0)。

Let's say I have calcIntrmdt1, calcIntrmdt2, calcIntrmdt3 and one rule calcFinalScore which is ran after all previous rules.假设我有calcIntrmdt1、calcIntrmdt2、calcIntrmdt3和一个规则calcFinalScore ,它在所有先前的规则之后运行。 How to pass to the calcFinalScore what the previous rules have calculated?如何将先前规则计算的内容传递给calcFinalScore

PS Maybe my whole approach is wrong, correct me if so PS也许我的整个方法是错误的,如果是这样请纠正我

Drools does support "global variables" -- called globals -- but you can't write rules against them. Drools确实支持“全局变量”——称为全局变量——但您不能针对它们编写规则。 They're generally discouraged, but back in the day it's how you'd usually go about returning values from your rule set.他们通常会气馁,但在过去,您通常 go 关于从规则集中返回值的方式。

Here's a simple example with a List as a global:这是一个将List作为全局的简单示例:

global java.util.List result;

rule "All people whose name starts with 'M' will attend"
when
  $person: Person( name str[startsWith] "M" )
then
  result.add($person);
end

List<Person> attendees = new ArrayList<>();

KieSession session = this.getSession();
session.insert(person);
session.insert(person1);
session.insert(person2);
session.insert(person3);
session.insert(person4);
session.setGlobal("result", attendees);
session.fireAllRules();

// at this point, 'attendees' is populated with the result of the rules

This won't work for you , though because you can't interact with these globals on the left hand side ("when").这对您不起作用,因为您无法在左侧(“when”)与这些全局变量进行交互。


What you need, instead, is an intermediate object to haul around your intermediate calculations.相反,您需要的是一个中间值 object 来处理您的中间计算。 Usually I'd suggest storing these values on the objects themselves, but if you have truly derived data, there's nowhere appropriate to store it on your models.通常我建议将这些值存储在对象本身上,但如果您有真正派生的数据,则没有合适的地方将它存储在您的模型上。

Here's another simple example.这是另一个简单的例子。 Here I track some results in an adhoc object, so I can key off of them in a subsequent rule.在这里,我在临时 object 中跟踪一些结果,因此我可以在后续规则中关闭它们。

declare Calculations {
  intermediateValue1: int
  intermediateValue2: double
}

rule "Create tracker object"
when
  not(Calculations())
then
  insert(new Calculations())
end

rule "Calculate some intermediate value 1"
when
  $calc: Calculations()
  // some other conditions
then
  modify($calc) {
    setIntermediateValue1( 42 )
  }
end

rule "Calculate some other value using value 1 when > 20"
when
  $calc: Calculations( $value1: intermediateValue1 > 20 )
  // other conditions
then
  modify( $calc ) {
    setIntermediateValue2( $value1 * 3 )
  }
end

rule "Final calculation"
when
  $calc: Calculation( $value1: intermediateValue1 > 0,
                      $value2: intermediateValue2 > 0 )
  // other conditions
then
  // do the final calculation
end

The declare keyword is used to define, effectively, a lightweight class within the DRL itself. declare关键字用于在 DRL 本身内有效地定义轻量级 class。 It doesn't exist outside of the DRL and can't be referenced in Java. Since we're just tracking intermediate values, that's ok.它不存在于 DRL 之外,不能在 Java 中引用。因为我们只是跟踪中间值,所以没关系。

The first rule looks to see if we have an instance of our calculated results present in working memory. If it's not, it inserts one.第一条规则查看我们的计算结果实例是否存在于工作 memory 中。如果没有,它会插入一个。

The inserts keyword is critical here. inserts关键字在这里很关键。 It tells Drools that there's new data in its working memory, and that it needs to reevaluate any subsequent rules to determine if they're now valid to fire.它告诉 Drools 在其工作 memory 中有新数据,它需要重新评估任何后续规则以确定它们现在是否有效以触发。

The middle two rules interact with the results object and modify values.中间两条规则与结果 object 交互并修改值。 Note that instead of just calling the setter (eg. $calc.setIntermediateValue1( 42 ) ) I instead use modify .请注意,我不只是调用 setter(例如$calc.setIntermediateValue1( 42 ) ),而是使用modify Similar to insert , this lets Drools know that this particular object in working memory has been modified, so it reevaluates any rules that rely on this object and determine if it's now valid to execute.insert类似,这让 Drools 知道工作 memory 中的这个特定的 object 已经被修改,因此它重新评估依赖于这个 object 的任何规则,并确定它现在是否可以执行。

The last rule takes all of the intermediate calculated values and (presumably) does something with them to figure out the 'final' calculated value.最后一条规则采用所有中间计算值,并且(大概)对它们做一些事情来计算出“最终”计算值。

This other answer of mine talks a bit about the different operations ( insert , etc.) that make data changes visible to other rules. This other answer of mine 谈到了一些不同的操作( insert等),这些操作使数据更改对其他规则可见。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM