Бесконечная рекурсия в слюнах после изменения версии с v7.20 на v7.21 - PullRequest
3 голосов
/ 03 июля 2019

При изменении версии в drools-compiler с 7.20.0.Final на 7.21.0.Final некоторые правила рекурсивно повторяются.

Код в github:

Рабочая версия

Рекурсивно-циклическая версия

Изменение между рабочей и циклической версией

Подробнее

Когда я запускаю правило, чья часть then изменяет факт, уже проверенный в части when:

rule "rule 1.1"
  when
    $sampleDomain: SampleDomain(instanceVariable2 == "Value of instance variable")
  then
    System.out.println("Rule 1.1 fired");
    modify($sampleDomain){
            setInstanceVariable1(3)
    }
end

он не рекурсивно зацикливается.

Но когда я вызываю другое правило, которое вызывает статическую функцию из другого класса:

rule "rule 1.2"
  when
    $sampleDomain: SampleDomain(CoreUtils.anotherFunction())
  then
    System.out.println("Rule 1.2 fired");
    modify($sampleDomain){
            setInstanceVariable1(3)
    }
end

, он зацикливается рекурсивно.

класс со статической функцией:

import com.drool_issue.domain.SampleDomain;

public class CoreUtils {

    public static boolean anotherFunction() {
        System.out.println("anotherFunction() inside CoreUtils");
        return true;
    }

    public static boolean anotherFunction(SampleDomain sampleDomain) {
        System.out.println("anotherFunction(SampleDomain sampleDomain) inside CoreUtils");
        return true;
    }

}

Файл моего домена:

public class SampleDomain {
    private int instanceVariable1;
    private String instanceVariable2;
    private int instanceVariable3;


    public int getInstanceVariable1() {
        return instanceVariable1;
    }
    public void setInstanceVariable1(int instanceVariable1) {
        this.instanceVariable1 = instanceVariable1;
    }
    public String getInstanceVariable2() {
        return instanceVariable2;
    }
    public void setInstanceVariable2(String instanceVariable2) {
        this.instanceVariable2 = instanceVariable2;
    }
    public int getInstanceVariable3() {
        return instanceVariable3;
    }
    public void setInstanceVariable3(int instanceVariable3) {
        this.instanceVariable3 = instanceVariable3;
    }



}

Это вызывается только после изменения версии с 7.20.0.Final на 7.21.0.Final.Любое предположение о том, в чем может быть проблема?

Когда я продолжил изучать проблему, я тоже это увидел.

Когда мы добавляем две функции в класс SampleDomain, то есть

    public boolean anotherFunction() {
        return true;
    }

    public boolean anotherFunction(SampleDomain sampleDomain) {
        return true;
    }

и используйте это в правиле, например:

rule "rule 1.4"
  when
    $sampleDomain: SampleDomain(anotherFunction())
  then
    System.out.println("Rule 1.4 fired");
    modify($sampleDomain){
            setInstanceVariable1(3)
    }
end

и

rule "rule 1.5"
  when
    $sampleDomain: SampleDomain(anotherFunction($sampleDomain))
  then
    System.out.println("Rule 1.5 fired");
    modify($sampleDomain){
            setInstanceVariable3(4)
    }
end

они также рекурсивно зацикливаются.

Код в github:

Рекурсивное зацикливание при использовании нестатических методов

Изменение между рабочей и выше версией

Также, когда любойстатического метода делается нестатичным, тогда вызывается метод из класса домена, даже если статический метод указан в правиле.

Здесь следует отметить следующие части кода:

Правило, где вызывается статический метод.

Другое правило, которое также вызывает статический метод.

Модификатор статического доступаудалено из функций, которые ранее были статическими.

Код в github:

Странное поведение при удалении статического модификатора для функций.

Изменение между рабочей и более поздней версиями

Все это вызывается в версиях после 7.20.0.Finalт.е. 7.21.0.Final, 7.22.0.Final и 7.23.0.Final

1 Ответ

1 голос
/ 15 июля 2019

Фильтрация на основе реактивности свойств не может быть применена к внешней функции, так как мы не знаем, что внутренняя функция (статический метод) делает внутренне.

Чтобы уточнить это: Давайте начнем с свойства реактивности;всякий раз, когда мы используем ключевые слова modify или update в соответствии с правилом, мы уведомляем движок, что правила, которые фильтруют похожие типы объектов, должны повторно оценивать объект снова.Эта переоценка по умолчанию происходит для всего объекта.То есть до тех пор, пока изменяется одно свойство объекта, правила будут рассматривать его как новый объект для сопоставления.Это может привести к некоторым проблемам, когда мы не хотим пересматривать правило для некоторых изменений.Механизмы контроля петли, такие как отсутствие петли и блокировка при включении, могут быть полезны в этих ситуациях.Однако, если мы хотим, чтобы правило контролировало изменения только некоторых свойств, нам нужно написать очень сложные условия.Кроме того, если в будущем модель изменится для большой базы правил, вам может потребоваться изменить множество правил, чтобы избежать нежелательного повторного выполнения правил.К счастью, Drools предоставляет функцию, позволяющую двигателю обойти эту проблему.Это позволяет разработчикам правил определять атрибуты bean-компонента, которые следует отслеживать, если они обновляются в рабочей памяти.Эта функция может быть определена в модели данных (как Java-классы, так и объявленные типы), которые используются в правилах, и называется компонентами, реагирующими на свойства.

Чтобы использовать эту функцию, сначала нужно отметить типычто мы будем использовать в правилах с аннотацией Property Reactive.Эта аннотация позволяет механизму знать, что всякий раз, когда объект этого типа добавляется в рабочую память, должна применяться специальная фильтрация его изменений.Эта аннотация может быть добавлена ​​к классу Java (на уровне класса) или объявленному типу (сразу после первой строки, определяющей имя типа) следующим образом: В классе Java:

@PropertyReactive public class Customer {     ... }

В объявленном типе:

    declare PropertyReactiveOrder        
        @propertyReactive
        discount: Discount
        totalItems: Integer
        total: Double    
    end 

Мы также можем сделать все свойства типов реактивными, добавив PropertySpecificOption.ALWAYS к параметру компоновщика.

Примечание. Изменения бинов свойства, реагирующие на свойства, будут сообщаться в механизм правил только с помощью команды изменения.ключевое слово.Ключевое слово update не сможет определить разницу между атрибутами изменяемого компонента.

Реактивность свойств была введена в Drools 5.4, но, поскольку использование этой функции считается хорошей практикой, и при корректностии с точки зрения производительности, он был включен по умолчанию в Drools 7.0.

Теперь еще раз к нашей проблеме, хотя с реактивностью свойств вещи кардинально изменились, и он действовал как детектор изменения мелкозернистых свойств, который позволяет Drools немного лучше понять, что происходит внутри RHSнаших правил, или, по крайней мере, внутри операции modify ().Функции все еще являются черным ящиком для него, создавая эту проблему.

...