Механизму правил drools не хватает памяти для небольшого файла правил

Я написал код Java, который использует механизм правил drools. Когда я пытался проверить производительность кода, добавляя все больше и больше правил в файл правил (.drl). Программа перестала работать, когда я упаковал 100000 правил в файл правил размером 14 МБ.

Мой файл правил выглядит так (макет правил):

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

Вот кусок кода, который применяет правила:

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();

Он завершился в строке, выполняющей addPackageFromDrl, со следующей ошибкой:

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)

Не работает, даже если я запускаю его с параметром -Xms1024m. Я не думаю, что ему понадобится так много памяти. И я применял правила только к одному факту (объекту).

Что занимает так много оперативной памяти? Разве я не должен помещать столько правил (100000) в один файл правил?


person Nasreddin    schedule 03.06.2015    source источник


Ответы (3)


Ну, я бы не назвал файл, содержащий 100 000 правил, "маленьким", что, согласно моему любимому словарю, означает "мало или мало", а 100 000 - это не просто "несколько". Если у этого эксперимента есть серьезная подоплека, стоит пересмотреть свой подход — скорее всего, вы на ложном пути.

Тем не менее, это не совсем механизм правил Drools, у которого не хватает памяти: это компилятор Java, который не может обработать такой объем исходного кода в одном файле Java.

  • Использование нескольких файлов DRL должно решить проблему OOM.
  • Кроме того, может помочь попытка версии 6.x, поскольку генерация кода и компиляция изменились между 5.x и 6.x.
  • Однако вполне вероятно, что любой содержательный набор правил, состоящий из 100 000 правил, вызовет проблемы, когда вы действительно достигнете этапа выполнения.
person laune    schedule 04.06.2015
comment
В ситуации с таким количеством правил лучше создать один файл drl для каждого правила? Я не понимаю, как это будет иметь меньший объем памяти при загрузке того же количества правил. - person Nasreddin; 04.06.2015
comment
Один файл на одно правило попадет в другую крайность. 100000 файлов вряд ли удобно. - Меньший объем памяти во время компиляции связан с меньшим объемом кода. Что касается исполнения, это может быть другой вопрос, но вы еще не там. - person laune; 04.06.2015
comment
если я разобью его на несколько файлов drl, мне нужно будет вызвать rbase.addPackage(pbuilder.getPackage()); только один раз, пока я запускаю pbuild. addPackageFromDrl(drlfile) несколько раз, верно? - person Nasreddin; 04.06.2015
comment
Я думаю, вам не следует вызывать методы PackageBuilder - этого нет в стабильном API. В Drools 5.x вы должны использовать KnowledgeBuilder, вызывать метод add(...) один раз для каждого ресурса DRL и getKnowledgePackages() для извлечения всех пакетов, которые нужно поместить в базу знаний. - person laune; 04.06.2015
comment
изменен на KnowledgeBuilder и получил ошибку невозможности инициировать службу, вызванную ClassNotFoundException из первой строки KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();. Я использую 6.0.0.Final версию drools-core. И, согласно другому сообщению, на которое вы ответили, link, я добавил зависимость kie-internal. Все та же ошибка. - person Nasreddin; 05.06.2015
comment
Вам нужно несколько банок из дистрибутива Drools в пути к классам. - person laune; 05.06.2015

Я считаю, что в Drools версии 6.0 и более поздних версиях вместо базы знаний требуется KIE. Вот что я использую:

     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();

Но я не думаю, что это основная причина проблемы пространства кучи Java!! (у меня тоже такая же проблема)

person Manjula    schedule 30.11.2015

Привет, проблема может заключаться в том, что запуск правил вставляет новые факты и в конечном итоге заканчивается память. Два способа обработки: 1. добавить истину без цикла 2. Написать условия так, чтобы правила срабатывали только при выполнении условий.

правило «выдать дочерний пропуск», когда $ch:Person (возраст ‹ 10) не (существует ChildPass (childid == $ch.id)) тогда ChildPass $chpass = new ChildPass(); $chpass.id= $ch.id; вставить ($ ч); конец

person Manjula    schedule 03.03.2016