Accumulate function (sum) on values in an ArrayList - unexpected behaviour (Drools 6.1.0.Final)

3,999 views
Skip to first unread message

Emiel2014

unread,
Nov 7, 2014, 11:44:19 AM11/7/14
to drools...@googlegroups.com
Hi there - I'm encountering some unexpected behaviour of Drools (6.1.0.Final) when using a simple accumulate function (sum) on a couple of ArrayLists. For example, I have two ArrayLists, both containing random amounts, e.g. [1, 2, 3] and [4, 5, 6].  What I'm trying to get is the sum of the values stored in the ArrayLists from a specific index number. E.g. index 2 should give me 7, index 3; 9. The index number itself is however depended on a different variable ($Timer.getTick() in my example). The condition I'm using is (Data.Amount() are the Arrays):

$Timer : Timer(true)
$Calculate : Number() from accumulate( $Data : Data(true),
sum($Data.getAmount().get($Timer.getTick())) ) 

$Timer.getTick() starts at 0 and is increased by 1 on a annual basis according to a pseudo-clock in combination with a cron expression used to trigger the rule that performs the update.

Now, what I get as result is for every cycle: 5. That means, that although the $Timer.getTick() is updated every cycle (starting at 0 and adding up to 1, 2, 3, 4, etc), the index reference in the accumulate function uses only 0. First thoughts were that $Timer.getTick() wasn't updated properly, but it does. If I use as condition $Timer : Timer( $Timer.getTick() == 2), the result I get is 9 (only triggered when getTick == 2 of course, but the summation is correct). 

What I found out was that :
(i) if I insert another variable in working memory (e.g. $Index.getTick()) and equal that variable to the value of $Timer.getTick()
(ii) put this new variable in the condition part of the rule with the accumulate function including a link with the value of $Timer.getTick(), or in code:

$Timer : Timer(true)
$Index : DetermineIndex( $Chrono.getTick() == $Index.getTick() )
$Calculate : Number() from accumulate( $Data : Data(true),
sum($Data.getAmount().get($Timer.getTick())) )
(for ease of reference, the part in bold is different to the first condition stated above)

The results I then get are 5, 7 and 9. Just as I expected. 

Do I somehow miss something? I would expect in the end both rules aren't different as it comes to the condition and accumulate part. Nevertheless, the results are clearly different.

Anyone having an idea on this (below a simple example in code (except for the maybe the cron/pseudo clock part easy to reproduce)?

Thanks
Emiel

declare Timer
Tick : int
Interval : String
end

rule "Insert Timer"
when
eval(true)
then
Timer $Timer = new Timer();
$Timer.setTick(0);
$Timer.setInterval("years")
insert($Timer);
end

//The 'Tick' is updated on an annual basis (running a pseudo-clock and using a cron expression to trigger the update):
rule "Timer - Year cycle"
salience 10
no-loop
timer (cron: 00 00 00 1 1 ? )
when
$Timer : Timer( "years".equals($Timer.getInterval()) )
then
$Timer.setTick($Timer.getTick()+1);
update($Timer);
end

declare Data
Amount : java.util.ArrayList
end

rule "Fill data arrays"
when
eval(true)
then
Data $Data = new Data();
$Data.setAmount(new java.util.ArrayList<Double>());
$Data.getAmount().add(1.0);
$Data.getAmount().add(2.0);
$Data.getAmount().add(3.0);

insert($Data);
end

rule "Fill data array 2"
when
eval(true)
then
Data $Data = new Data();
$Data.setAmount(new java.util.ArrayList<Double>());

$Data.getAmount().add(4.0);
$Data.getAmount().add(5.0);
$Data.getAmount().add(6.0);

insert($Data);
end

rule "Print Data objects in memory"
when
$Data : Data(true)
then
System.out.println("Data objects in memory contain: " +
$Data.getAmount());
end

rule "Sum"
salience -1
when
$Timer : Timer(true)
$Calculate : Number() from accumulate( $Data : Data(true),
sum($Data.getAmount().get($Timer.getTick())) )
then
System.out.println("[Test] Outcome of the accumulate. $Calculate = " +
$Calculate);
end

declare DetermineIndex
Tick : int
end

rule "Insert Index"
when
eval(true)
then
DetermineIndex $Index = new DetermineIndex();
$Index.setTick(0);
insert($Index);
end

rule "Equal Index tick and Timer tick"
when
$Timer : Timer(true)
$Index : DetermineIndex( $Index.getTick() < $Timer.getTick() )
then
$Index.setTick($Timer.getTick());
update($Index);
end

rule "Sum with 'determine'index"
salience -2
when
$Timer : Timer(true)
$Index : DetermineIndex( $Chrono.getTick() == $Index.getTick() )
$Calculate : Number() from accumulate( $Data : Data(true),
sum($Data.getAmount().get($Timer.getTick())) )
then
System.out.println("[Test] Outcome of the accumulate (with extra condition on index). $Calculate = " +
$Calculate);
System.out.println("[Test] Tick from Timer class is: " +
$Chrono.getTick());
System.out.println("[Test] Tick from Index class is: " +
$Chrono.getTick());
end

Davide Sottara

unread,
Dec 6, 2014, 4:09:48 PM12/6/14
to drools...@googlegroups.com, Mario Fusco
Emiel,
you are right, this is indeed an issue. Right now the accumulator function is opaque with respect to the $Timer variable,
so the engine does not realize that the function needs to be re-evaluated.
This needs to be fixed.

Your second example works because the accumulation is a child of the join you have in DetermineIndex. When that join
is rebuilt after the update, the accumulate is consequently recomputed.

Thanks for reporting this
Davide

--
You received this message because you are subscribed to the Google Groups "Drools Usage" group.
To unsubscribe from this group and stop receiving emails from it, send an email to drools-usage...@googlegroups.com.
To post to this group, send email to drools...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/drools-usage/179e4a1d-76f3-42a1-9da5-400f5725175d%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Emiel2014

unread,
Oct 31, 2016, 5:21:31 AM10/31/16
to Drools Usage, mario...@gmail.com
Hi Davide,

I realize the issue is from end 2014, but thanks for you reply. Based on that I've been working around my initial issue since then. I was just wondering - I'm currently refactoring part of my rule base - is this 'issue' (still) on a backlog to be fixed? I noticed the behaviour is still the same under 6.4.0.Final.

Thanks!
Emiel 

Op zaterdag 6 december 2014 22:09:48 UTC+1 schreef Davide Sottara:

veena rao

unread,
Jun 29, 2017, 7:11:08 AM6/29/17
to Drools Usage, mario...@gmail.com
Hi,
     accumulate ($sum: Repe(objectId == getEventKey(), "REP".equals(())); $count: count($sum); $count.equals($shortCount))

    If i use accumulate like this work..But using this way doesnt work why?
accumulate ($sum: Rep(objectId == getEventKey(), "REP".equals(getRepType())); $count: count($sum); $count == $shortCount)


$count and $shortCount are both integer
Reply all
Reply to author
Forward
0 new messages