0

我被推荐使用 Drools 来计算分数。我是这个框架的新手,但经过一些小研究后,我发现它确实是一个很好的解决方案,因为评分规则会经常更新/调整,并且(看起来)很容易编写/更改/更新 Drools 规则。

背景:我必须使用的评分算法计算中间值,然后根据这些值计算最终分数。所以有一个叫做Person的模型,它有很多属性,其中一些可能是 null 或空的。评分算法会考虑所有这些字段并做出最终决定(评分)。

UPD:可以跳过中间值计算(理论上),但我 100% 确定规则会变得不清楚和混乱。

问题是:如何在各个规则之间保存(持久)这些中间值?从我从文档中可以看出,这是不可能的(?)或者我遗漏了一些东西。规则中没有变量这样的东西。

理想情况下,我会有一些只能在此规则集上访问的全局变量。它们具有初始值(如null或 0)。

假设我有calcIntrmdt1、calcIntrmdt2、calcIntrmdt3和一个规则calcFinalScore,它在所有之前的规则之后运行。如何将先前规则计算的内容传递给calcFinalScore

PS也许我的整个方法是错误的,如果是,请纠正我

4

1 回答 1

2

Drools确实支持“全局变量”——称为全局变量——但你不能针对它们编写规则。他们通常不鼓励,但在过去,这就是您通常从规则集中返回值的方式。

List这是一个将 a作为全局变量的简单示例:

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

但是,这对您不起作用,因为您无法在左侧(“何时”)与这些全局变量进行交互。


相反,您需要的是一个中间对象来处理您的中间计算。通常我会建议将这些值存储在对象本身上,但如果您有真正派生的数据,则没有合适的地方将其存储在您的模型中。

这是另一个简单的例子。在这里,我在一个 adhoc 对象中跟踪一些结果,因此我可以在后续规则中关闭它们。

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

declare关键字用于有效地定义 DRL 本身内的轻量级类。它不存在于 DRL 之外,也不能在 Java 中引用。因为我们只是在跟踪中间值,所以没关系。

第一条规则是查看我们的计算结果是否存在于工作记忆中。如果不是,它会插入一个。

inserts关键字在这里很关键。它告诉 Drools 在它的工作内存中有新数据,它需要重新评估任何后续规则以确定它们现在是否可以触发。

中间两条规则与结果对象交互并修改值。请注意,我不只是调用设置器(例如$calc.setIntermediateValue1( 42 )),而是使用modify. 与 类似insert,这让 Drools 知道工作内存中的这个特定对象已被修改,因此它重新评估依赖于该对象的任何规则并确定它现在是否可以执行。

最后一条规则采用所有中间计算值,并且(可能)对它们进行一些处理以找出“最终”计算值。

我的另一个答案谈到了insert使数据更改对其他规则可见的不同操作(等)。

于 2021-09-28T15:22:21.113 回答