[rules-users] Reading DRL file with large number of rules

Wolfgang Laun wolfgang.laun at gmail.com
Sun Feb 7 10:04:46 EST 2010


There are several techniques available for quickly locating an object based
on a key, as was done by the simple rule in the original posting. They vary
w.r.t. setup time, access time and memory requirement. Here are the
times (in seconds, on a 1 year old laptop) for 20000 random keys of length
13, made up from digits.

array: create 20000 elements    0.066
array: locate 20000 elements    0.024
map: create 20000 elements    0.020
map: locate 20000 elements    0.024
trie: create 20000 elements    0.028
trie: locate 20000 elements    0.025

'array' uses Arrays.sort and Arrays.binarySearch. 'map' uses
a HashMap, and 'trie' is a slapdash implementation of this
well-known data structure. Increasing the number of entries will,
eventually, show the superiority of HashMap, but its memory
requirement is certainly higher than that of an array.

I cannot claim that any of these solutions would be applicable for
the original problem where the consequence of the presented
rule inserts another fact, which might lead to more rules firing, etc.
But such techniques might be considered up front, reducing
rule-based processing to those "second generation" facts.

Using literal data in a (large) number of similar statements is always
an indication that an alternative approach should be investigated
where multiplicity is put into data instead of code.

-W

2010/2/6 Edson Tirelli <ed.tirelli at gmail.com>:
>     Hi All,
>
> "There is nothing in that which would gain from Drools' Rete algorithm with
> its superior "many-patterns-many-object" matching capabilities."
>
> I know Wolfgang knows all this, but I think we need to clarify this
> statement for the general public of the list. Assuming all the rules are
> indeed like he described (very simple, with a single alpha constraint), then
> there are efficient and simple ways to implement it without a rules engine,
> but that is not by using "if". At least he would have to use a hashing
> technique, or the performance would be roughly linear on number of rules (
> O(r) ) when in Drools, that does use hashing techniques for alpha
> constraints, it is constant ( O(1) ). Also, it depends on the non-functional
> requirements he has, like lifecycle management.
>
>      In any case, I decided to take the bate and implement a quick example
> for this. I changed the HelloWorld example in Drools to generate 20k rules
> in the same format you have:
>
> rule "rule X"
>     dialect "mvel"
> when
>     Message( message == "X" )
> then
>     System.out.println( X );
> end
>
>     Replacing X by the number of the rule. Then I parse, compile and build a
> kbase for these rules and fire the rules for a single object. This is
> **NOT** a benchmark, so I am just giving you a rough idea of the hardware...
> I am running it on my laptop, with other stuff on. My laptop is a 2-years
> old lenovo, dual core, 2Gb memory. I am running with -Xmx1024M.
>
>     Results I got (in ms):
>
> 1. Generating Package   ...done. 163 ms
> 2. Dumping source       ...done. 280897 ms
> 3. Parsing and compiling...done. 40557 ms
> 4. Creating kbase       ...done. 79512 ms
> 5. Firing rules         ...done. 29 ms
>
>     Please note that steps 1 and 2 are the rules generation. You don't have
> that, since your source code is ready for processing, right? Step 3 is
> executed by the KnowledgeBuilder and step 4 is the
> kbase.addKnowledgePackages().
>
>     Again, this is a very simple case showing that it is possible to parse,
> compile and load 20k rules quite easily in a drools kbase. Also remember
> that kbases are designed to be shared, so you should incur that cost once
> and then create sessions (that are really light to create) reusing the
> kbase.
>
>     Finally, there are obviously room to improve, since the compilation and
> kbase building is single thread today. We want to move to multi-thread
> compilation in the future. That should improve things a bit.
>
>    The source code I used is bellow.
>
>    Cheers,
>        Edson
>
>
> public class DroolsTest {
>
>     private static final int NUMBER_OF_RULES = 20000;
>
>     public static final void main(String[] args) {
>         try {
>             // load up the knowledge base
>             KnowledgeBase kbase = readKnowledgeBase();
>             StatefulKnowledgeSession ksession =
> kbase.newStatefulKnowledgeSession();
>             //KnowledgeRuntimeLogger logger =
> KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test");
>             // go !
>             long ts = System.currentTimeMillis();
>             Message message = new Message();
>             message.setMessage("5");
>             message.setStatus(Message.HELLO);
>             ksession.insert(message);
>             ksession.fireAllRules();
>             System.out.print("5. Firing rules         ...");
>             System.out.println("done.
> "+(System.currentTimeMillis()-ts)+"ms");
>             //logger.close();
>         } catch (Throwable t) {
>             t.printStackTrace();
>         }
>     }
>
>     private static KnowledgeBase readKnowledgeBase() throws Exception {
>         KnowledgeBuilder kbuilder =
> KnowledgeBuilderFactory.newKnowledgeBuilder();
>
>         System.out.print("1. Generating Package   ...");
>         long ts = System.currentTimeMillis();
>         PackageDescr pkg = generatePackageDescr();
>         System.out.println("done. "+(System.currentTimeMillis()-ts)+"ms");
>
>         System.out.print("2. Dumping source       ...");
>         ts = System.currentTimeMillis();
>         String source = new DrlDumper(  ).dump( pkg );
>         //System.out.println(source);
>         System.out.println("done. "+(System.currentTimeMillis()-ts)+"ms");
>
>         System.out.print("3. Parsing and compiling...");
>         ts = System.currentTimeMillis();
>         kbuilder.add(ResourceFactory.newReaderResource( new StringReader(
> source ) ), ResourceType.DRL);
>         KnowledgeBuilderErrors errors = kbuilder.getErrors();
>         if (errors.size() > 0) {
>             for (KnowledgeBuilderError error: errors) {
>                 System.err.println(error);
>             }
>             throw new IllegalArgumentException("Could not parse
> knowledge.");
>         }
>         System.out.println("done. "+(System.currentTimeMillis()-ts)+"ms");
>
>         System.out.print("4. Creating kbase       ...");
>         ts = System.currentTimeMillis();
>         KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
>         kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
>         System.out.println("done. "+(System.currentTimeMillis()-ts)+"ms");
>         return kbase;
>     }
>
>     private static PackageDescr generatePackageDescr() {
>         PackageDescr result = new PackageDescr("org.drools.test");
>         result.addImport( new ImportDescr("com.sample.DroolsTest.Message")
> );
>         for( int i = 1; i <= NUMBER_OF_RULES; i++ ) {
>             RuleDescr rule = new RuleDescr("rule "+i);
>             AttributeDescr dialect = new AttributeDescr("dialect", "mvel");
>             AndDescr lhs = new AndDescr();
>             PatternDescr pat = new PatternDescr("Message");
>             FieldConstraintDescr constr = new
> FieldConstraintDescr("message");
>             LiteralRestrictionDescr restr = new
> LiteralRestrictionDescr("==",String.valueOf( i ));
>             constr.addRestriction( restr );
>             pat.addConstraint( constr );
>             lhs.addDescr( pat );
>             rule.addAttribute( dialect );
>             rule.setLhs( lhs );
>             rule.setConsequence( "System.out.println("+i+");\n" );
>             result.addRule( rule );
>         }
>         return result;
>     }
>
>     public static class Message {
>
>         public static final int HELLO = 0;
>         public static final int GOODBYE = 1;
>
>         private String message;
>
>         private int status;
>
>         public String getMessage() {
>             return this.message;
>         }
>
>         public void setMessage(String message) {
>             this.message = message;
>         }
>
>         public int getStatus() {
>             return this.status;
>         }
>
>         public void setStatus(int status) {
>             this.status = status;
>         }
>
>     }
>
> }
>
>
>
> 2010/2/6 Wolfgang Laun <wolfgang.laun at gmail.com>
>>
>> Have you tried increasing the heap size for the JVM?
>>
>> "20K rules [of the same] simple form" sounds as if you are
>> trying to use a hammer where a screwdriver would be appropriate.
>> If your description is correct, these 20K rules would be nothing
>> but 20K if statements, in disguised form. There is nothing
>> in that which would gain from Drools' Rete algorithm with
>> its superior "many-patterns-many-object" matching capabilities.
>>
>> -W
>>
>> On Sat, Feb 6, 2010 at 12:42 PM, kpowerinfinity
>> <kpowerinfinity at gmail.com> wrote:
>> > Hello,
>> >
>> > We are trying to run a DRL file that has more than 20K rules, all of
>> > which have the simple form:
>> >
>> >
>> >
>> > rule "testpeoplenumber"
>> >        salience 100
>> >        dialect "mvel"
>> >        when
>> >                LineItem( inventoryItemCode == "8903210392090")
>> > then
>> >                InventoryItem fact0 = new InventoryItem();
>> >                fact0.setCategoryCode( "ONPROMO" );
>> >                insert(fact0 );
>> > end
>> >
>> > However, the rule file is not getting parsed by the builder, and
>> > either takes a very long time (well over half an hour), or gives a
>> > Heap Overflow exception. We tried with a smaller file (about 1K rules,
>> > and the situation is the same).
>> >
>> > The parsing code is:
>> > org.drools.KnowledgeBaseConfiguration kbc =
>> > org.drools.KnowledgeBaseFactory.newKnowledgeBaseConfiguration(null,
>> > cl);
>> >            org.drools.KnowledgeBase kbase =
>> > org.drools.KnowledgeBaseFactory.newKnowledgeBase(kbc);
>> >                org.drools.builder.KnowledgeBuilderConfiguration
>> > knowledgeBuilderConfig =
>> >
>> > org.drools.builder.KnowledgeBuilderFactory.newKnowledgeBuilderConfiguration(null,
>> > cl);
>> >            org.drools.builder.KnowledgeBuilder builder =
>> > org.drools.builder.KnowledgeBuilderFactory.newKnowledgeBuilder(kbase,
>> > knowledgeBuilderConfig);
>> >            org.drools.builder.impl.KnowledgeBuilderImpl builderImpl =
>> > builder as org.drools.builder.impl.KnowledgeBuilderImpl;
>> >
>> >
>> >  builder.add(org.drools.io.ResourceFactory.newFileResource(filename),
>> >                    org.drools.builder.ResourceType.DRL);
>> >
>> > We are using Drools v5. We've tried both with the java jar as well as
>> > in .NET (using IKVM to compile it).
>> >
>> > Any help in understanding why this is happening and how it can be
>> > avoided will be appreciated.
>> >
>> > Warm Regards
>> > Krishna.
>> >
>> > --
>> > http://kpowerinfinity.wordpress.com
>> > http://www.linkedin.com/in/kpowerinfinity
>> > _______________________________________________
>> > rules-users mailing list
>> > rules-users at lists.jboss.org
>> > https://lists.jboss.org/mailman/listinfo/rules-users
>> >
>>
>> _______________________________________________
>> rules-users mailing list
>> rules-users at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/rules-users
>
>
>
> --
>  Edson Tirelli
>  JBoss Drools Core Development
>  JBoss by Red Hat @ www.jboss.com
>
> _______________________________________________
> rules-users mailing list
> rules-users at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/rules-users
>
>




More information about the rules-users mailing list