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.