Объявить локальную переменную правила с помощью Drools

Можно ли создать локальную переменную в определении локального правила с помощью механизма правил Drools?

Я написал пример кода, но он не компилируется. Этот пример просто демонстрирует идею локального объявления (я знаю, что это неправильно)

/*...*/
    rule "Test local Variable"
        when
            String $departmentName = "Music";
        then
            System.out.println($departmentName);
    end
/*...*/

Сообщение об ошибке:

org.drools.CheckedDroolsException: There were errors in the rule source: [ERR 101] Line 25:2 no viable alternative at input 'String' in rule "Test local Variable"

Позиция [25,2] определяется строкой:

String $departmentName = "Music";

person Andre Pastore    schedule 28.01.2011    source источник


Ответы (2)


Начиная с Drools 5 невозможно объявлять произвольные переменные в условиях. Вы можете привязать переменные к фактам и атрибутам:

when
   Person( $name : name )
then
   // $name is bound to each name of each person in the working memory
end
person Edson Tirelli    schedule 28.01.2011
comment
Я спросил об этом, потому что мне нужно искать один и тот же ключ в разных экземплярах карты. И у меня есть несколько правил с такой же структурой. Спасибо за четкую помощь! - person Andre Pastore; 28.01.2011
comment
Вы можете определить свои ключи как статические константы в классе Java и использовать их, если это имеет для вас смысл. Пример: MyFact( aMapAttribute[MyClass.MY_KEY] == someValue ). - person Edson Tirelli; 31.01.2011
comment
Да, это обычная переменная. Обратите внимание, что использование $ в качестве первого символа переменной является просто соглашением. Переменную можно было бы назвать бананом, и она бы работала точно так же. - person Edson Tirelli; 06.12.2013

Drools 5 может определять локальные переменные только для правил, которые являются фактами или полями фактов:

when
    $city : City()               // a Fact
    Person ($name : firstName)   // a Fact property
then
    System.out.println("city="+$city+", name="+$name);
end

Однако вы можете эмулировать произвольную локальную переменную (т. е. не свойство Fact или Fact), используя карту, как это предлагается в ответе Эдсона:

when
    $myParamList : eval(DroolsRuleLocalVariable.setVariable("myParamList", Arrays.asList(1,2,3) ))
    // warn: you must use eval() and not a Drools condition because the Drools condition will be cached so the setVariable method will not be called
then
    System.out.println("myParamList="+(List<Integer>)DroolsRuleLocalVariable.getVariable("myParamList"));

    // remember to cleanup the variables for the next rule to be executed
    DroolsRuleLocalVariable.clear(); 
end

Класс DroolsRuleLocalVariable выглядит следующим образом:

package com.mypackage;

import java.util.HashMap;
import java.util.Map;

/**
 * Manage Drools rule local variables.
 * A local variable can be read/written in the "when" (CONDITION) and in the "then" (consequence/ACTION) parts.
 * The "then" part must cleanup the local variables otherwise they are available for the next executed rule.
 * 
 * Note: Drools 5 cannot create rule local variables, see
 * http://stackoverflow.com/questions/4830117/declare-local-rule-variable-using-drools
 * 
 *
 */
public class DroolsRuleLocalVariable {
    private static Map<String,Object> ruleLocalVariables = new HashMap<>();

    /**
     * Sets the variable variableName to the variableValue value. If the
     * variable is not defined, create a new variable.
     * The method returns true in order to be evaluated in Drools CONDITION, e.g.:
     *  
     *  eval(DroolsRuleLocalVariable.setVariable("myParamList", Arrays.asList($param) ))
     * 
     * @see #clear() the clear method should be called in the ACTION of the decision table
     * @param variableName the variable name
     * @param variableValue the variable value
     * @return always true
     */
    public static boolean setVariable(String variableName, Object variableValue) {
        ruleLocalVariables.put(variableName, variableValue);
        return true;
    }

    /**
     * Returns the variable value or null if the variable is not defined.
     * The variable must be casted to the original type.
     * Usage:
     *  eval(DroolsRuleLocalVariable.getVariable("myParamList"))
     * 
     * @param variableValue
     * @return
     */
    public static Object getVariable(String variableName) {
        Object value = ruleLocalVariables.get(variableName);
        return value;
    }

    /**
     * Clears the local variables. This method MUST be called in the ACTION part of the decision table.
     */
    public static void clear() {
        ruleLocalVariables.clear();
    }
}
person Julien Kronegg    schedule 10.06.2016