Tuesday 6 November 2007

Banking on Rules Part II

Creating a RuleFlow


In this example, we are going to create a simple RuleFlow and add it to our Banking example from Part I.

Paul Browne has already posted an excellent blog on this topic, which has a slightly more complicated example.

Caveat


This example is so simple, that it would actually be easier done with an Agenda-Group, but the purpose of this post is to demonstrate a very simple example of RuleFlow. I will post a more complicated one later on.

Pre-Requisites


In order to run this example you will need Eclipse with the latest Drools plug-in (Eclipse Workbench). Eclipse can be downloaded from http://www.eclipse.org/ and the Eclipse Workbench can be downloaded from http://labs.jboss.com/drools/downloads.html.

Step 1 - Creating the Rules


For those who have already downloaded the examples in Drools Part I, I am going to use that code as the starting point for this.

Our first task, is to create a rule and allocate it to a ruleflow-group so that we can use the RuleFlow to include and exclude
rules. To do this, copy rule07.drl to rule08.drl and rename the rules to be prefixed with "Rule 08" instead of "Rule 07". Now, add the ruleflow-group entries for "Rule 08 - Credit" and "Rule 08 - Debit":

rule08.drl

package simple;

import net.tplusplus.drools.bankingondrools1.*;

rule "Rule 08 - Credit"
    ruleflow-group "CreditGroup"
    salience 100
    when
        AccountingPeriod( $start : start, $end : end )
        $cashflow : AllocatedCashflow( $account : account, $date : date <= $end, $amount : amount, type==TypedCashflow.CREDIT )
        not AccountingPeriod( start < $start)
    then
        System.out.println("Credit: "+$date+" :: "+$amount);
        
        $account.setBalance($account.getBalance()+$amount);
        System.out.println("Account: "+$account.getAccountNo()+" - new balance: "+$account.getBalance());
            
        retract($cashflow);
end

rule "Rule 08 - Debit"
    ruleflow-group "DebitGroup"
    salience 100
    when
        AccountingPeriod( $start : start, $end : end )
        $cashflow : AllocatedCashflow( $account : account, $date : date <= $end, $amount : amount, type==TypedCashflow.DEBIT )
        not AccountingPeriod( start < $start)
    then
        System.out.println("Debit: "+$date+" :: "+$amount);
        
        $account.setBalance($account.getBalance()-$amount);
        System.out.println("Account: "+$account.getAccountNo()+" - new balance: "+$account.getBalance());
            
        retract($cashflow);
end

rule "Rule 08 - Retract Accounting Period"
    salience 50
    when
        $accountingPeriod : AccountingPeriod( $start : start, $end : end )
        not AccountingPeriod( start < $start)
    then
        System.out.println("Retracting Accounting Period: "+$start+" - "+$end);
        retract($accountingPeriod);
end

Open the class net.tplusplus.drools.bankingondrools1.RuleRunner and add the following method:

RuleRunner.java

    public static void simple8()
    throws Exception
    {
        Account acc1 = new Account(1);
        Account acc2 = new Account(2);
        
        Object[] facts =
        {
            new AllocatedCashflow(acc1,new SimpleDate("01/01/2007"), TypedCashflow.CREDIT, 300.00),
            new AllocatedCashflow(acc1,new SimpleDate("05/02/2007"), TypedCashflow.CREDIT, 100.00),
            new AllocatedCashflow(acc2,new SimpleDate("11/03/2007"), TypedCashflow.CREDIT, 500.00),
            new AllocatedCashflow(acc1,new SimpleDate("07/02/2007"), TypedCashflow.DEBIT, 800.00),
            new AllocatedCashflow(acc2,new SimpleDate("02/03/2007"), TypedCashflow.DEBIT, 400.00),
            new AllocatedCashflow(acc1,new SimpleDate("01/04/2007"), TypedCashflow.CREDIT, 200.00),
            new AllocatedCashflow(acc1,new SimpleDate("05/04/2007"), TypedCashflow.CREDIT, 300.00),
            new AllocatedCashflow(acc2,new SimpleDate("11/05/2007"), TypedCashflow.CREDIT, 700.00),
            new AllocatedCashflow(acc1,new SimpleDate("07/05/2007"), TypedCashflow.DEBIT, 900.00),
            new AllocatedCashflow(acc2,new SimpleDate("02/05/2007"), TypedCashflow.DEBIT, 100.00),
            
            new AccountingPeriod(new SimpleDate("01/01/2007"),new SimpleDate("31/03/2007")),
            new AccountingPeriod(new SimpleDate("01/04/2007"),new SimpleDate("30/06/2007"))
            
        };
        
        new RuleRunner().runRules(new String[]{"/simple/rule08.drl"},facts);        
    }


This gives us the ability to use a RuleFlow to include rule "Rule 08 - Credit" and not rule "Rule 08 - Debit" by specifying the ruleflow-group "CreditGroup", and vice versa by specifying the ruleflow-group "DebitGroup".

Now, modify the main method in RuleRunner to comment out calls to all the methods except rule08(). This will just tidy up the output, and exclude output from Banking On Drools - Part I:

RuleRunner.java

    public static void main(String[] args)
    throws Exception
    {
        //simple1();
        //simple2();
        //simple3();
        //simple4();
        //simple5();
        //simple6();
        //simple7();
        simple8();
    }


So far, all we have done is allocate two rules to RuleFlow groups. What happens if we run the code as it stands without introducing a RuleFlow?

Run the class RuleRunner, and we get the output:

output:

Loading file: /simple/rule08.drl
Inserting fact: AllocatedCashflow[account=Account[accountNo=1,balance=0.0],
date=Mon Jan 01 00:00:00 GMT 2007,type=Credit,amount=300.0]
Inserting fact: AllocatedCashflow[account=Account[accountNo=1,balance=0.0],
date=Mon Feb 05 00:00:00 GMT 2007,type=Credit,amount=100.0]
Inserting fact: AllocatedCashflow[account=Account[accountNo=2,balance=0.0],
date=Sun Mar 11 00:00:00 GMT 2007,type=Credit,amount=500.0]
Inserting fact: AllocatedCashflow[account=Account[accountNo=1,balance=0.0],
date=Wed Feb 07 00:00:00 GMT 2007,type=Debit,amount=800.0]
Inserting fact: AllocatedCashflow[account=Account[accountNo=2,balance=0.0],
date=Fri Mar 02 00:00:00 GMT 2007,type=Debit,amount=400.0]
Inserting fact: AllocatedCashflow[account=Account[accountNo=1,balance=0.0],
date=Sun Apr 01 00:00:00 BST 2007,type=Credit,amount=200.0]
Inserting fact: AllocatedCashflow[account=Account[accountNo=1,balance=0.0],
date=Thu Apr 05 00:00:00 BST 2007,type=Credit,amount=300.0]
Inserting fact: AllocatedCashflow[account=Account[accountNo=2,balance=0.0],
date=Fri May 11 00:00:00 BST 2007,type=Credit,amount=700.0]
Inserting fact: AllocatedCashflow[account=Account[accountNo=1,balance=0.0],
date=Mon May 07 00:00:00 BST 2007,type=Debit,amount=900.0]
Inserting fact: AllocatedCashflow[account=Account[accountNo=2,balance=0.0],
date=Wed May 02 00:00:00 BST 2007,type=Debit,amount=100.0]
Inserting fact: AccountingPeriod[start=Mon Jan 01 00:00:00 GMT 2007,
end=Sat Mar 31 00:00:00 BST 2007]
Inserting fact: AccountingPeriod[start=Sun Apr 01 00:00:00 BST 2007,
end=Sat Jun 30 00:00:00 BST 2007]
Retracting Accounting Period: Mon Jan 01 00:00:00 GMT 2007
- Sat Mar 31 00:00:00 BST 2007
Retracting Accounting Period: Sun Apr 01 00:00:00 BST 2007
- Sat Jun 30 00:00:00 BST 2007

From the output, we can see that neither the Credit Rule nor the Debit Rule ran.

So, if we allocate a Rule to a RuleFlow Group, then we need to find some way of specifying the RuleFlow Group to run if we are to include these rules.

Step 2 - Modifying the RuleRunner


Our next step is to modify the RuleRunner runRules() method to allow us to specify a all the RuleFlows for the rule engine, and the initial RuleFlow Group to use.

To do this we need to overload the RunRules() method in RuleRunner to provide the RuleFlows and the process to start, as follows:

RuleRunner.java

    public void runRules(String process, String[] ruleflows, String[] rules, Object... facts)
    throws Exception
    {        
        RuleBase ruleBase = RuleBaseFactory.newRuleBase();
        PackageBuilder builder = new PackageBuilder();        
        
        for(String ruleflow : ruleflows)
        {
            builder.addRuleFlow( new InputStreamReader(
                    RuleRunner.class.getResourceAsStream( ruleflow ) ) );
        }
        
        for(String ruleFile : rules)
        {
            System.out.println("Loading file: "+ruleFile);
            builder.addPackageFromDrl(new InputStreamReader(this.getClass().getResourceAsStream(ruleFile)));
        }
        
        Package pkg = builder.getPackage();        
        ruleBase.addPackage(pkg);
        
        WorkingMemory workingMemory = ruleBase.newStatefulSession();    

        for(Object fact : facts)
        {
            System.out.println("Inserting fact: "+fact);
            workingMemory.insert(fact);
        }

        workingMemory.startProcess(process);
        workingMemory.fireAllRules();
    }

Step 3 - Creating the RuleFlow


By now we have allocated two of our rules to RuleFlow Groups and have provided a runRules() method that allows us to specify RuleFlows and a starting RuleFlow Group. Now, we need to create the RuleFlow.

To do this we are going to use the Eclipse Workbench (for Drools).

Open the Drools perspective and first let's create a source folder for our ruleflows:

Create a new source folder called ruleflows:



In Package Explorer, right click on the new ruleFlow folder and select New -> Other. From the Wizard select RuleFlow File.



Click on Next, and enter the filename creditFlows



Click on finish and eclipse will open the creditFlows.rf document in the graphical editor as follows:



Our next step is to create a simple ruleFlow for processing credits only.

The editor pane already contains a Start element. Next, we need to place a RuleFlowGroup on the editor, by clicking on RuleFlowGroup element in the left pane and then clicking on the edit pane below the Start element.

Repeat the process with the End element and place them in the editor as shown below:



Now we need to create the connections between the elements. Click on the ConnectionCreation element in the left pane and click on the Start element in the editor pane. Move the cursor to the RuleSet element and click again. A connection will be created between the two elements.

Repeat the process to connect the RuleSet element to the End element. Your edit pane should now look like:



Ok. So far we have a rule flow diagram with a Start, RuleFlow, and End element connected. This is all pretty much meaningless, however, until we set the properties in the ruleflow so that it is associated with a ruleflow group.

We want this ruleflow to execute the Credit rule that we created earlier in rule08.drl

rule08.drl

rule "Rule 08 - Credit"
    ruleflow-group "CreditGroup"
    salience 100
    when
        AccountingPeriod( $start : start, $end : end )
        $cashflow : AllocatedCashflow( $account : account, $date : date <= $end, $amount : amount, type==TypedCashflow.CREDIT )
        not AccountingPeriod( start < $start)
    then
        System.out.println("Credit: "+$date+" :: "+$amount);
        
        $account.setBalance($account.getBalance()+$amount);
        System.out.println("Account: "+$account.getAccountNo()+" - new balance: "+$account.getBalance());
            
        retract($cashflow);
end

This means we need to set up our ruleflow to call the ruleflow-group "CreditGroup".

So, here we go:

Click on the RuleSet element in the editor pane and then click on the properties tab.

Set the Name to CreditFlow, and set the RuleFlowGroup to CreditGroup (same as the ruleflow-group in the rule above).

The screen shot is show below:



The name simply gives our element a display name that should be meaningful to us as we review the ruleflow diagram. The important property is the RuleFlowGroup which should be the same as the RuleFlowGroup of the rules that we want to include in this RuleFlow.

Finally, we need to set the properties for the CreditFlows ruleFlow itself. Click anywhere in the design screen to display the properties for the ruleFlow.

Set the properties as follows:

Connection Layout = Shortest Path
Id = credits
Name = creditFlows
Package = simple
Version = 1




The Id is the id by which we will indentify this ruleflow when we want to invoke it. To start this process we will call workingMemory.startProcess("credits"). The name is simply the name by which we want to identify this ruleflow. The package is the same package as that to which our rules belong (see rule08.drl), and the version is our latest version.

Specifying the RuleFlow to Run


Now let’s modify our simple8() method in RuleRunner to call our ruleflow.

    public static void simple8()
    throws Exception
    {
        Account acc1 = new Account(1);
        Account acc2 = new Account(2);
        
        Object[] facts =
        {
            new AllocatedCashflow(acc1,new SimpleDate("01/01/2007"), TypedCashflow.CREDIT, 300.00),
            new AllocatedCashflow(acc1,new SimpleDate("05/02/2007"), TypedCashflow.CREDIT, 100.00),
            new AllocatedCashflow(acc2,new SimpleDate("11/03/2007"), TypedCashflow.CREDIT, 500.00),
            new AllocatedCashflow(acc1,new SimpleDate("07/02/2007"), TypedCashflow.DEBIT, 800.00),
            new AllocatedCashflow(acc2,new SimpleDate("02/03/2007"), TypedCashflow.DEBIT, 400.00),
            new AllocatedCashflow(acc1,new SimpleDate("01/04/2007"), TypedCashflow.CREDIT, 200.00),
            new AllocatedCashflow(acc1,new SimpleDate("05/04/2007"), TypedCashflow.CREDIT, 300.00),
            new AllocatedCashflow(acc2,new SimpleDate("11/05/2007"), TypedCashflow.CREDIT, 700.00),
            new AllocatedCashflow(acc1,new SimpleDate("07/05/2007"), TypedCashflow.DEBIT, 900.00),
            new AllocatedCashflow(acc2,new SimpleDate("02/05/2007"), TypedCashflow.DEBIT, 100.00),
            
            new AccountingPeriod(new SimpleDate("01/01/2007"),new SimpleDate("31/03/2007")),
            new AccountingPeriod(new SimpleDate("01/04/2007"),new SimpleDate("30/06/2007"))
            
        };
        
        String[] ruleFiles = { "/simple/rule08.drl" };
        String[] ruleFlows = { "/creditFlows.rfm" };
        
        new RuleRunner().runRules("credits",ruleFlows,ruleFiles,facts);        
    }


Finally, let's compile the project and run it.

output:

Loading file: /simple/rule08.drl
...
Credit: Sun Mar 11 00:00:00 GMT 2007 :: 500.0
Account: 2 - new balance: 500.0
Credit: Mon Feb 05 00:00:00 GMT 2007 :: 100.0
Account: 1 - new balance: 100.0
Credit: Mon Jan 01 00:00:00 GMT 2007 :: 300.0
Account: 1 - new balance: 400.0
Retracting Accounting Period: Mon Jan 01 00:00:00 GMT 2007
- Sat Mar 31 00:00:00 BST 2007
Retracting Accounting Period: Sun Apr 01 00:00:00 BST 2007
- Sat Jun 30 00:00:00 BST 2007


Notice, now we have all the Credits being applied, but no Debits!!


Saturday 3 November 2007

Benchmarking Drools

In my earlier post I said that I hadn't had a chance to run a speed-test on Drools to compare using Drools to sort values with using Java. Last week I did just that and have learned a lot about tuning Drools along the way.

I have included all the source code in an appendix at the end of this post, along with a link to all the zipped source.

Objective


The objective is to determine how to best use the Drools rule engine depending on the number of Facts, type of rules, and requirements of the system including performance, scalability and maintainability.

The Approach


A simple problem will be passed to the Drools rule engine for solution. The different approaches used in the solution will include the use of stateful and stateless sessions, using the rule engine to sort and order facts, passing the rule engine pre-ordered and sorted facts, and modifying the rules themselves to measure changes in performance.

The Problem


The problem is basically to aggregate credit and debit cashflows into accounting periods and determine the account balance at the end of each period after all the cashflows have been applied.

Caveats


This problem is quite a simple one and using the Drools rule engine for such a task is very much taking a sledgehammer to crack a nut - unless we were expecting to introduce more rules and facts into the equation later.

Expectations


  • I would expect a stateful session to be faster if the RuleBase is cached

  • I would expect a stateless session (which can be applied to this problem) to be faster than a stateful session

  • I would expect better performance if the cashflows are aggregated into accounting periods and passed to the rule engine for each accounting period in turn.

The Tests


The tests are broken down into nine test sets (numbered 1 to 9 below). Each test set provides a different solution to the problem and all test sets provide exactly the same output.

Each test set is run several times with a different number of facts each time. For each set of facts supplied, the test set is run through several iterations and the fastest, slowest, and average time to complete processing is measured in milliseconds.

The tests themselves evolved with findings and feedback and so the final set of nine tests is listed below:

  1. Stateful Session

    A new RuleBase is created for each iteration and then all the facts are inserted together into a stateful session.

    The rule engine orders the accounting periods and aggregates the facts into each accounting period in turn before calculating the end of period balance by applying the credits and debits to the relevant bank account.

  2. Stateful Session with cached RuleBase

    A new RuleBase is created for each different set of Facts and is then cached and reacquired for each iteration. All the facts are inserted together into a stateful session.

    The rule engine orders the accounting periods and aggregates the facts into each accounting period in turn before calculating the end of period balance by applying the credits and debits to the relevant bank account.

  3. Stateful, Cached,Condition elements grouped within rules

    A new RuleBase is created for each different set of Facts and is then cached and reacquired for each iteration. All the facts are inserted together into a stateful session.

    The rule engine orders the accounting periods and aggregates the facts into each accounting period in turn before calculating the end of period balance by applying the credits and debits to the relevant bank account.

    Within the rules themselves, the Condition elements are grouped together as per the example below:

    This condition set shows two AccountingPeriod conditions separated with a Cashflow condition:

    AccountingPeriod( $start : start, $end : end )
    $cashflow : Cashflow( $account : account, $date : date <= $end
    && date >= $start, $amount : amount, type==Cashflow.DEBIT )
    not AccountingPeriod( start < $start)

    In the condition set below, we have grouped the AccountingPeriod conditions:

    AccountingPeriod( $start : start, $end : end )
    not AccountingPeriod( start < $start)
    Cashflow( $account : account, $date : date <= $end
    && date >= $start, $amount : amount, type==Cashflow.CREDIT )


  4. Stateful, Cached, Group, long for sorting

    A new RuleBase is created for each different set of Facts and is then cached and reacquired for each iteration. All the facts are inserted together into a stateful session.

    The rule engine orders the accounting periods and aggregates the facts into each accounting period in turn before calculating the end of period balance by applying the credits and debits to the relevant bank account.

    Within the rules themselves, the Condition elements are grouped together.

    When ordering the AccountingPeriods and aggregating the Cashflows, this is done using a long primitive representation of the period start and end dates and the cashflow date instead of a Date object.

  5. Stateful, Cached, Group, Long for sorting

    A new RuleBase is created for each different set of Facts and is then cached and reacquired for each iteration. All the facts are inserted together into a stateful session.

    The rule engine orders the accounting periods and aggregates the facts into each accounting period in turn before calculating the end of period balance by applying the credits and debits to the relevant bank account.

    Within the rules themselves, the Condition elements are grouped together.

    When ordering the AccountingPeriods and aggregating the Cashflows, this is done using a Long object representation of the period start and end dates and the cashflow date instead of a Date object.

  6. Stateful, Cached, Grouped, Facts inserted by Accounting Period

    A new RuleBase is created for each different set of Facts and is then cached and reacquired for each iteration.

    The accounting periods are ordered, and the cashflows are aggregated for each accounting period in turn.

    Each accounting period is then processed in turn and all the facts for each accounting period are inserted into a stateful session and the results for that period are obtained.

    Within the rules themselves, the Condition elements are grouped together.

  7. Stateless, Cached, Grouped, Facts inserted by Accounting Period

    A new RuleBase is created for each different set of Facts and is then cached and reacquired for each iteration.

    The accounting periods are ordered, and the cashflows are aggregated for each accounting period in turn.

    Each accounting period is then processed in turn and all the facts for each accounting period are inserted into a stateless session and the results for that period are obtained.

    Within the rules themselves, the Condition elements are grouped together.

  8. Stateless, Cached, Grouped, Facts inserted by Accounting Period, using the accumulate method

    A new RuleBase is created for each different set of Facts and is then cached and reacquired for each iteration.

    The accounting periods are ordered, and the cashflows are aggregated for each accounting period in turn.

    Each accounting period is then processed in turn and all the facts for each accounting period are inserted into a stateless session and the results for that period are obtained.

    Within the rules themselves, the Condition elements are grouped together, and the accumulate method is used to total the credits and debits respectively.

  9. Plain Java method

    All the sorting, aggregating and balance calculations are done in Java.

Test Results


I have quoted below the results for 588 facts being inserted into the rule engine, with the rules being repeated through 50 iterations to get the average time in milliseconds to process the cashflows and obtain the account balance for each accounting period.

1 - 79 ms - Stateful
2 - 27 ms - Stateful, Cached
3 - 9 ms - Stateful, Cached, group conditions
4 - 21 ms - Stateful, Cached, group conditions, long primitive
5 - 21 ms - Stateful, Cached, group conditions, Long
6 - 6 ms - Stateful, Cached, group conditions, aggregate cashflows
7 - 6 ms - Stateless
8 - 4 ms - Statless, Accumulate
9 - 1 ms - Java

All the results for each set of tests, grouped by number of Facts and number of iterations are detailed in Appendix A: Results

Discussion of the Results


  • Caching v Non-Caching RuleBase

    Test1 and Test2 both use the rule file test01.drl. All the facts are asserted in one go and sorted within the rules. The Facts are then retracted once they have been used. This makes writing the rules easier, as you don’t have to worry about Facts hanging around that could influence other rules or even re-fire completed rules.

    Caching the RuleBase does show a marked improvement, but that improvement becomes less marked as the number of Facts increases.

  • Grouping Condition Elements

    Test3, groups the conditions in the rule files. For this it uses test02.drl.

    In test01.drl we have:

    AccountingPeriod( $start : start, $end : end )
    $cashflow : Cashflow( $account : account, $date : date <= $end
    && date >= $start, $amount : amount, type==Cashflow.DEBIT )
    not AccountingPeriod( start < $start)

    in test02.drl we have:

    AccountingPeriod( $start : start, $end : end )
    not AccountingPeriod( start < $start)
    Cashflow( $account : account, $date : date <= $end
    && date >= $start, $amount : amount, type==Cashflow.CREDIT )

    Simply changing the order from AccountingPeriod, Cashflow, not AccountingPeriod to AccountingPeriod, not AccountingPeriod, Cashflow has reduced the average time from 27ms to 9ms!!
    Note that this performance improvement continues throughout all the test sets, regardless of the number of Facts.

  • Using long and Long for Sorting

    Test4, and Test5 use test03.drl and test04.drl respectively, and so use long primitive and Long instead of Date for sorting. This does not show an improvement over sorting with Dates.

    Note, however, that the compareTo() and equals() method in the Cashflow object use the Date object for testing and, so these results may have been rendered invalid, depending on any use of the Collections Api within the rule engine. I may change those methods later and try it again.

  • Aggregating Cashflows before Inserting into Drools

    Test6 uses test05.drl, and collates all the Cashflows for each period and then inserts them into the rule engine for each accounting period in turn. This again, shows a marked improvement from 21ms to 6ms and this scale of improvement is consistent across all the test sets.

  • Using a Stateless Session

    Test7 uses test05.drl and uses a stateless session. Not suprisingly this test has consistently similar results to Test6 across all the test sets.

  • Using the accumulate() method

    Test8, uses test06.drl which again uses a stateless session, but uses the accumulate() method within the rules and does not retract the cashflows. This shows an improvement over Test7 which becomes more marked as the number of Facts increases.

  • Plain Java method

    Test9, is a simple java method that performs all the cashflows. Not surprisingly, this is the fastest approach. As the number of rules increases, however, we may see a difference. Certainly, the complexity of the java code as the rules increased would increase much more, and Drools does offer other facilities over the java solution including the BPM.

Summary


It is important to decide when to use Stateful sessions and when to use Stateless sessions. For this problem, Stateless was sufficient. If facts are modified during the rule process or new rules are generated or inserted, then a Stateful session is required.

Collating and sorting Facts before inserting them into the rule engine can show a marked improvement. This will have to be thought through beforehand as there are times when this is not practical.

Grouping condition elements within the rules themselves can have a marked improvement on performance and using new features such as the accumulate method show additional marked improvements.

Appendix A: Results


Average time in ms to process 16 Facts,
JVM arguments: -Xms512M -Xmx512m



Average time in ms to process 588 Facts,
JVM arguments: -Xms512M -Xmx512m



Average time in ms to process 4020 Facts,
JVM arguments: -Xms512M -Xmx512m



Average time in ms to process 96112 Facts,
JVM arguments: -Xms512M -Xmx512m



Average time in ms to process 1921936 Facts,
JVM arguments: -Xms1512M -Xmx1512m



The Source


The source code for this benchmark test is split into 3 projects

  • The Lib Project

    This project contains common classes used by all projects. SimpleDate extends the Date class to allow instantiation from Strings, and TimedResults is used for timing the rule engine, providing methods to retrieve fastest, slowest and average times.

  • The RuleRunner Project

    This project contains the classes that interface with the Drools engine. You will need to download the latest version of Drools bin and include the jars in this project.

    This project contains 4 classes so far: The Fact interface must be implemented by any facts that are to be inserted into the rule engine; and Globals must be inserted as Global objects. To use stateful sessions within Drools you need to instantiate a StatefulRunner and to instantiate a stateless session you need to instantiate a StatelessRunner.

  • The SpeedTest Project
    This project contains all the code and rules for the benchmark tests. The main class is net.tplusplus.test.drools.speedtest.SpeedTest1.

For more discussion of the source, refer to the next post - Banking on Drools Part II.

Download the Source


The source code for these tests can be downloaded here