简体   繁体   中英

drools rule engine runs out of memory on a small rule file

I wrote a java code that uses drools rule engine. When I was trying to test the performance of the code by adding more and more rules to the rule file(.drl). The program stopped working when I packed 100000 rules in a 14MB rule file.

My rule file looks like this (mock-up rules):

package drools.rules

import drools.DicomImage

rule "PHI rule0"

    when
        $di : DicomImage(boolName == true)
    then
        System.out.println("rule 0 is applied");
end

rule "PHI rule1"

    when
        $di : DicomImage(boolName == true)
    then
        System.out.println("rule 1 is applied");
end

rule "PHI rule2"

    when
        $di : DicomImage(boolName == true)
    then
        System.out.println("rule 2 is applied");
end

Here is piece of the code that applies the rules:

String filename = "rule100000.drl";
Reader reader = new InputStreamReader(ApplyDicomRules.class.getResourceAsStream(filename));
PackageBuilder pBuilder = new PackageBuilder();
pbuilder.addPackageFromDrl(reader);

Rulebase rbase = RuleBaseFactory.newRuleBase();
rbase.addPackage(pbuilder.getPackage());

runRules();

It exited at line doing addPackageFromDrl with the following error:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
 at java.lang.Throwable.printStackTrace(Unknown Source)
 at org.eclipse.jdt.internal.compiler.util.Util.getExceptionSummary(Util.java:627)
 at org.eclipse.jdt.internal.compiler.Compiler.handleInternalException(Compiler.java:587)
 at org.eclipse.jdt.internal.compiler.Compiler.compile(Compiler.java:522)
 at org.drools.compiler.commons.jci.compilers.EclipseJavaCompiler.compile(EclipseJavaCompiler.java:405)
 at org.drools.compiler.commons.jci.compilers.AbstractJavaCompiler.compile(AbstractJavaCompiler.java:49)
 at org.drools.compiler.rule.builder.dialect.java.JavaDialect.compileAll(JavaDialect.java:405)
 at org.drools.compiler.compiler.DialectCompiletimeRegistry.compileAll(DialectCompiletimeRegistry.java:46)
 at org.drools.compiler.compiler.PackageRegistry.compileAll(PackageRegistry.java:107)
 at org.drools.compiler.compiler.PackageBuilder.compileAll(PackageBuilder.java:1317)
 at org.drools.compiler.compiler.PackageBuilder.compileAllRules(PackageBuilder.java:968)
 at org.drools.compiler.compiler.PackageBuilder.addPackage(PackageBuilder.java:956)
 at org.drools.compiler.compiler.PackageBuilder.addPackageFromDrl(PackageBuilder.java:452)
 at org.drools.compiler.compiler.PackageBuilder.addPackageFromDrl(PackageBuilder.java:428)
 at drools.ApplyDicomRules.initializeDrools(ApplyDicomRules.java:65)
 at drools.ApplyDicomRules.main(ApplyDicomRules.java:26)

Does not work even if I run it with -Xms1024m. I don't think it is going to need that much memory anyway. And I was only applying the rules to a single fact (object).

What is taking so much ram? Am I not supposed to put that many rules (100000) in one rule file?

Well, I wouldn't call a file containing 100000 rules "small", which, according to my favourite dictionary, means "few in number or little in amount", and 100000 isn't just "a few". If this experiment has any serious background you should reconsider your approach - most likely, you are on the wrong track.

That, said, it isn't exactly the Drools Rule Engine either that runs out of memory: it is the Java compiler that can't handle this amount of source code in a single Java file.

  • Using several DRL files should circumvent the OOM problem.
  • Also, trying a 6.x version might help since code generation and compilation has changed between 5.x and 6.x.
  • However, it is quite likely that any meaningful set of rules comprising 100000 is going to cause problems when you really reach the execution stage.

In Drools version 6.0 and later, I believe it need KIE instead of KnowledgeBase. Here is something I use:

     KieServices kieServices = KieServices.Factory.get();
     KieFileSystem kfs = kieServices.newKieFileSystem();
     FileInputStream fis = new FileInputStream(path to your .drl file);
     kfs.write(path to your drl file,kieServices.getResources().newInputStreamResource( fis ));
     KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll();
     Results results = kieBuilder.getResults();
    if( results.hasMessages( Message.Level.ERROR ) ){
        System.out.println( results.getMessages() );
        throw new IllegalStateException( "### errors ###" );
    }

    KieContainer kieContainer = kieServices.newKieContainer( kieServices.getRepository().getDefaultReleaseId() );
    KieBaseConfiguration config = kieServices.newKieBaseConfiguration();

But I dont think this is teh root cause for the problem of Java Heap Space!! (Me too facing the same problem)

Hi the problem could be firing of the rules inserts new facts and runs out of memory eventually. Two ways to handle: 1. add a no-loop true 2. To write the conditions such that the rules are fired only when the conditions are met.

rule "issue child pass" when $ch:Person (age < 10) not(exists ChildPass (childid == $ch.id)) then ChildPass $chpass = new ChildPass(); $chpass.id= $ch.id; insert($ch); end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM