流口水积累正在更新一个无关紧要的事实 [英] Drools accumulate is updating an irrelevant fact

查看:98
本文介绍了流口水积累正在更新一个无关紧要的事实的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Drools中使用累加时,将针对未更新的事实评估并触发一条规则。


以下是规则:


< pre class = lang-java prettyprint-override> 规则 WidgetsPerUser;

$ user时:User()
累加(
小部件(checkIsUser($ user));
$ widgetCount:sum(1)

然后
System.out.println($ user +具有 + $ widgetCount +窗口小部件);
结尾

想法很简单:计算小部件的数量用户的$ c>个对象。 checkIsUser()是一个简单的相等检查,但表示不能使用索引的检查。


这是Drools 7.0的示例输出。 0.Final:

 -调用所有规则-
User5有10个小部件
User4有10个小部件
User3有10个小部件
User2有10个小部件
User1有10个小部件

小部件从User3移至User1

-调用所有规则-
User5有10个小部件
User3有9个小部件
User1有11个小部件

这里我们有5个 User 事实已插入内存,并且所有开始的 Widget 计数为10。第一次调用for fireAllRules 显示正确的打印,因为所有 User 事实都已插入到内存中。接下来是一个更新,其中 Widget 从User3移到了User1。存在预期的输出,但是User5没有理由显示为已更新。


以可视方式突出显示该问题:

  User5有10个小部件(不应触发User5!)

(正确忽略了User4)

User3有9个小部件(正确触发了User3)

(正确忽略了User2)

User1有11个小部件(正确触发了User1)

User5与User2或User4不同的唯一方法是它是最后添加的用户事实,为什么它的行为有所不同?


这是额外的评估吗?预期?


请注意,问题不在于如何避免或解决额外的触发器。

解决方案

我本人在流口水核心附近挖了一些答案。我发现以下内容(在7.0.0版和7.39.0版中):


在评估累积节点 PhreakAccumulateNode.doRightUpdates 的更新的方法中code>,在方法 doRightUpdatesProcessChildren (用于左右元组之间的匹配)之前,出现以下代码:

  //如果LeftTupleMemory为空,则没有匹配项可修改
if(leftTuple!= null){
if (leftTuple.getStagedType()== LeftTuple.NONE){
trgLeftTuples.addUpdate(leftTuple); //< ----
}
doRightUpdatesProcessChildren(ARGS);
}

基于此,无论内存中的元组是否匹配,更新作为累加的一部分的事实后,第一个左元组(在这种情况下为User5)将始终被视为匹配。


我查看了另一个beta节点 JoinNode 。该节点的代码类似于 AccumulateNode ,但是它缺少第一个左元组的此附加更新,这使我相信它是偶然添加的,并且没有出现的原因。


我对此表示正确吗?


When using an accumulate in Drools, a rule is evaluated and triggered for a fact that wasn’t updated.

Here is the rule:

rule "WidgetsPerUser"
    when
        $user : User()
        accumulate(
            Widget ( checkIsUser($user) ); 
            $widgetCount : sum(1)
        )
    then
        System.out.println($user + " has " +  $widgetCount + " widgets");
end

The idea is simple: count the number of Widget objects per User. checkIsUser() is a simple equality check, but represents a check that cannot use indexing.

Here is sample output from Drools 7.0.0.Final:

-- Calling fire all rules --
User5 has 10 widgets
User4 has 10 widgets
User3 has 10 widgets
User2 has 10 widgets
User1 has 10 widgets

Widget moved from User3 to User1

-- Calling fire all rules --
User5 has 10 widgets
User3 has 9 widgets
User1 has 11 widgets

Here we have 5 User facts inserted into memory, and all have a starting Widget count of 10. The first call for fireAllRules displays the correct prints, as all User facts are inserted into memory. Next is an update, where a Widget is moved from User3 to User1. The expected output is present, however User5 has no reason to be displayed as being updated.

To visually highlight the issue:

User5 has 10 widgets    (User5 should NOT be triggered!)

                        (User4 is correctly ignored)

User3 has 9 widgets     (User3 is correctly triggered)

                        (User2 is correctly ignored)

User1 has 11 widgets    (User1 is correctly triggered)

The only way User5 differs from User2 or User4 is that it was the last user fact added, so why does it behave differently?

Is this extra evaluation expected? What purpose does it serve?

Note that the question is not about how to avoid or work around the extra trigger.

解决方案

I dug around the drools core myself to get some answers. I found the following (in both versions 7.0.0 and 7.39.0):

In the method that evaluates the updates for the accumulate node PhreakAccumulateNode.doRightUpdates, just before the method doRightUpdatesProcessChildren (which is used for matching between left and right tuples), the following code is present:

// if LeftTupleMemory is empty, there are no matches to modify
if ( leftTuple != null ) {
   if ( leftTuple.getStagedType() == LeftTuple.NONE ) {
         trgLeftTuples.addUpdate( leftTuple ); //<----
   }
   doRightUpdatesProcessChildren( ARGS );
}

Based on this, regardless of there being a match within the tuples in the memory, if there is an update of a fact that is part of an accumulate, the first left tuple (in this case User5) will always be treated as being matched.

I took a look at another beta node JoinNode. The code for that node is similar to the AccumulateNode, however it is missing this additional update of the first left tuple, leading me to believe that it is accidentally added, and has no reason to be present.

Am I correct with this?

这篇关于流口水积累正在更新一个无关紧要的事实的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆