Friday, June 22, 2007

Accumulate Functions (Edson Tirelli)

As we get closer to the release, everything is taking its final shape. This week was the time to get Accumulate CE ready for the release. For those who missed, Accumulate is a very powerful new Conditional Element for Drools 4.0, released next month. It allows you to operate on sets of data.

The general syntax for it is:

ResultPattern( fieldconstraint* )
from accumulate ( SourcePattern( fieldconstraint* )
init( code )
action( code )
reverse( code )
result( code ) )

Basically what accumulate does is execute the init code block, then "iterate" over the facts that match the SourcePattern executing the action code block for each of the facts and finally executing the result code block. The given result is matched against the ResultPattern and in case it evaluates to true, the condition matches. The reverse code block is optional and its function is to improve performance when retracting or modifying facts that had previously matched the SourcePattern.

Well, nothing better than a sample to get things more clear.

Rule: apply 10% discount to orders that include at least US$ 100,00 of toys.

rule "Discount for orders that include US$100,00 of toys"
$o : Order()
$toysTotal : Number( doubleValue > 100 )
from accumulate( OrderItem( order == $o, type == "toy", $value : value ),
init( double total = 0; ),
action( total += $value; ),
reverse( total -= $value; ),
result( new Double( total ) ) )
$o.setDiscountPercentage( 10 );

As you can see in the example above, accumulate is really flexible and powerful. As each of the code blocks are either Java or MVEL code blocks, one can really do any kind of operation in there.

But then, someone can say: "Well, accumulate is pretty flexible and powerful, but I don't want to keep writing code for common operations like the above". So, that is something we were playing with during this week. We really want to provide you all the flexibility you need, but we also want to provide you with simplicity for the common cases. So, Accumulate Functions comes to the rescue.

You now have the possibility of using predefined functions to simplify accumulate usage for common cases. For instance, the rule above is using accumulate to perform a sum of values. The same rule can be written like that:

rule "Discount for orders that include US$100,00 of toys"
$o : Order()
$toysTotal : Number( doubleValue > 100 )
from accumulate( OrderItem( order == $o, type == "toy", $value : value ),
sum( $value ) )
$o.setDiscountPercentage( 10 );

Much more simple now. What if you want a rule that tells you how much it would cost you a raise of X% for each department?

rule "Total raise"
$dpt : Department( $raise : raise )
$total : Number()
from accumulate( Employee( dept == $dpt, $salary : salary ),
sum( $salary * $raise ) )
$dpt.setSalaryIncreaseValue( $total );

So, you can use any expression as a parameter to accumulate functions. We added most common used functions for use out of the box, like sum, average, count, min, max, etc.

But you say: "I liked the functions, but I have a custom function that I would like to provide to my users write rules with. Can I implement that function and provide to them, so that they don't need to keep writing it themselves?"

Our answer is: "Of course!" ;)

We made Accumulate Functions pluggable and as simple as we could make them, so you can easily provide new functions for your users to use. For instance, pretend you have a very complex calculation that you need to do to get the cost of a given stock trade operation. Your users are writing rules to your specialist system to enable it to advise on which operations are more profitable, and so they have several rules that need to calculate such stock trade operation costs.
To develop a new accumulate function, the only thing you need to do is create a java class that implements the AccumulateFunction interface. The interface basically has a method that correspond to each of the Accumulate operations: init, action, reverse and result. Here you can see how easy it is to implement things like the average function.

Finally, to wire your function into the system you can either call an API (addAccumulateFunction()) or define a property. The property can be defined either in a configuration file or as a system property:


drools.accumulate.function.average = org.drools.base.accumulators.AverageAccumulateFunction

As simple as that.

Hope you all enjoy.

Happy Drooling!


  1. Hi there,

    Are you going to follow up with a Drools/JBoss Rules with a book just like ANTLR ?

    OR will there be a kick-ass version of Jboss Rules which will be supplemented by a killer book ?

    Thank you,


  2. We would love to make a book, but probably not enough hours in the day :(

  3. Hi,

    I am in web analytics industry. Do you think drools may help here? Domain model for me will have Dimensions and Metrics only and different combinations of them. Rules for my application will be several transformation on data and then a very small atomic rule that compare two fields in a table.

    Do you think we can apply drool here with a flexibility of writing more transformation rules on the go?

    Thanks in advance,

  4. "I am in web analytics industry. Do you think drools may help here? "


    If you have any further questions please continue with them at the user mailing list:

  5. Is there a need to create a java class that implements the AccumulateFunction interface? How?

  6. This is the right blog for anyone who wants to find out about this topic. You realize so much its almost hard to argue with you . You definitely put a new spin on a topic thats been written about for years. Great stuff, just great!

    MOrning Desert Safari

  7. Percentage Calculator AppThursday, April 18, 2019

    You can try to use percentage calculator app on google play, Percent calculator app uses values calculate percentage increase or decrease and convert fraction to percentage: Check out: percentage calculator android app on google play