1. Introduction

规则属性 is an additional specification that you can add to a business rule as 修改规则行为 . In the DRL file, you typically define rule attributes above the rule conditions and actions, 多个属性位于单独的行中 , in the following format:

 rule "rule_name"
    // Attribute
    // Attribute
    when
        // Conditions
    then
        // Actions
end

2. Common rule attributes

Rule properties explain Example
salience 定义规则优先级 , is an integer. When in 激活队列中排序 , salience的值越大 , priority 越高 . Salience 99
enabled Defines whether the rule is enabled. true to enable, false to disable, 默认值是true enabled true
date-effective A string containing time and date, the rule will only be activated when the current time is greater than date-effective . This time format can be modified, see the specific usage below date-effective "April-May-2022"
date-expires Set the expiration time of the rule, the time format is the same as above. date-expires "April-May-2022"
no-loop Boolean value, the default value is false , which defines whether the rule can be executed again when the 当前规则规则的结果 fact object has been modified. true: No, false: Yes, it may cause an infinite loop. Refers to the modification of the current rule. If another rule is modified, it will also cause the rule to be triggered. no-loop true
agenda-group Agenda groups allows you to partition agenda to provide more enforcement control over rule groups. 只有获得焦点的议程组中的规则才能被激活。 , 但是这个里面有个特例 , if a rule is not configured with agenda-group, but its pattern matching is successful, it will be assigned to the default group ( main ) , the rules of this main group are also executed. agenda-group "GroupName"
auto-focus Boolean, rule within 仅适用于Agenda-Group . When the value is true , the next time the rule is activated, the focus will be automatically given to this Agenda group auto-focus true
activation-group Indicates that the rules under this group 只有一个规则 will be executed, and the rest of the activated rules under this group will be cancelled. But rules activated by other groups may be enforced. activation-group "GroupName"
duration value of type long, if 在这个时间之后规则还成立 , then execute the rule duration 1000
timer A string identifying the int (interval) or cron timer definition used to schedule the rule. Example: timer ( cron: 0/15 ? ) (every 15 minutes)
calendar Defines the Quartz calendar for scheduling rules.
lock-on-active A boolean value that applies only to rules in a ruleflow group or agenda group. When this option is selected, the next time the rule's ruleflow group becomes active or the rule's agenda group gains focus, the rule cannot be activated again until the ruleflow group is no longer active or the agenda group loses focus. This is a stronger version of the no-loop property, since activations of matching rules are discarded regardless of the source of the update (not just the rules themselves). This property is great for calculating rules, where you have many rules that modify facts and you don't want any of the rules to rematch and fire again. lock-on-active true
dialect A string identifying JAVA or MVEL as the language used for code expressions in rules. By default, the rule uses the dialect specified at the package level. Any dialect specified here overrides the package dialect setting for that rule. dialect "JAVA"

3. Some rule attribute cases

The rule file and some core Java code are written here

1. Salience

Define the priority of rule execution. The larger the value of salience, the higher the priority.

1. Compilation of rule files

 rule "salience_rule_1"
    salience 4
    when
    then
        System.out.println("rule 1");
end

rule "salience_rule_2"
    salience 3
    when
    then
        System.out.println("rule 2");
end

// 此处优先级的值是动态获取来的
rule "salience_rule_3"
    salience $dynamicSalience
    when
        $dynamicSalience: Integer()
    then
        System.out.println("rule 3");
end

Notice:
Our priority value of salience_rule_3 动态 is from ---3cfcc696644b7fc7853c42c20298c0e6---, which is obtained from working memory.

2. Java code writing

 public class DroolsSalienceApplication {
    public static void main(String[] args) {
        KieServices kieServices = KieServices.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession("rule-attributes-ksession");

        // 向工作内存中插入一个Integer值,salience_rule_3 需要用到这个优先级
        kieSession.insert(10);

        // 只匹配规则名称是已 salience_ 开头的规则,忽略其余的规则
        kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("salience_"));

        kieSession.dispose();
    }
}

kieSession.insert(10); Insert a value here into working memory, which will match salience_rule_3 and then dynamically modify its priority.

3. Running results

 rule 3
rule 1
rule 2

Because the larger the value of salience , the higher the priority, so this is the order.

2. enabled

Defines whether the rule is enabled, true enabled false disabled

1. Writing rule files

 package rules

rule "enabled_rule_1"
    // 禁用此规则
    enabled false
    when
    then
        System.out.println("enabled_rule_1");
end

rule "enabled_rule_2"
    // 启用此规则,默认就是启用
    enabled true
    when
    then
        System.out.println("enabled_rule_2");
end

enabled_rule_2 this rule needs to run, enabled_rule_1 this rule cannot run.

2. Java code writing

 /**
 * 测试规则的启用和禁用
 */
public class DroolsEnabledApplication {
    public static void main(String[] args) {
        KieServices kieServices = KieServices.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession("rule-attributes-ksession");
        // 只匹配规则名称是已 enabled_ 开头的规则,忽略其余的规则
        kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("enabled_"));
        kieSession.dispose();
    }
}

nothing to pay attention to

3. Running results

 enabled_rule_2

It can be seen that only the rule enabled_rule_2 outputs the result, while enabled_rule_1 is disabled.

3. Date-effective

Define when the rule will be activated, only the current time > the rule time will be activated. 需要注意默认的时间格式 , which can be modified by java code.

1. Writing rule files

 package rules
import java.text.SimpleDateFormat
import java.util.Date

// 规则一:输出当前时间
rule "date_effective_rule_1"
    when
    then
        System.out.println("当前时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
end

// 规则二: 该规则会在2022-05-18 10:54:26之后被激活
rule "date_effective_rule_2"
    date-effective "2022-05-18 10:54:26"
    when
    then
        System.out.println("date_effective_rule_2执行了,规则允许被执行的时间应该在2022-05-18 10:54:26之后");
end

// 规则三: 该规则会在2023-05-18 10:54:26之后被激活
rule "date_effective_rule_3"
    date-effective "2023-05-18 10:54:26"
    when
    then
        System.out.println("date_effective_rule_3会在时间到了2023-05-18 10:54:26才激活");
end

Rule 1: Output the current time Rule 2: This rule will be activated after 2022-05-18 10:54:26 Rule 3: This rule will be activated after 2023-05-18 10:54:26

2. Java code writing

 /**
 * 测试规则在执行的时间之后才能执行
 */
public class DroolsDateEffectiveApplication {
    public static void main(String[] args) {
        // 设置日期格式,否则可能会报错(Wrong date-effective value: Invalid date input format: [2022-05-18 10:54:26] it should follow: [d-MMM-yyyy]]])
        System.setProperty("drools.dateformat", "yyyy-MM-dd HH:mm:ss");
        KieServices kieServices = KieServices.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession("rule-attributes-ksession");
        // 只匹配规则名称是已 date_effective_ 开头的规则,忽略其余的规则
        kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("date_effective_"));
        kieSession.dispose();
    }
}

Need to pay attention to System.setProperty("drools.dateformat", "yyyy-MM-dd HH:mm:ss"); this sentence, this modification date format in drools, because the date format written in the rule is date-effective "2023-05-18 10:54:26" and the default format is d-MMM-yyyy will report an error.

3. Running results

 当前时间:2022-05-18 10:59:38
date_effective_rule_2执行了,规则允许被执行的时间应该在2022-05-18 10:54:26之后

It can be seen that rule 2 is executed, but rule 3 is not executed, because rule 3 needs time to arrive 2023-05-18 10:54:26 to be executed, and the current time does not match.

4. Matters needing attention

If there is Wrong date-effective value: Invalid date input format: [2022-05-18 10:54:26] it should follow: [d-MMM-yyyy]]] how to solve this error, this is because the date format is incorrect. The following settings need to be made in the java code System.setProperty("drools.dateformat", "yyyy-MM-dd HH:mm:ss")

4. date-expires

Define the expiration time of the rule, that is, the rule cannot be used after this time. Similar to the usage of date-effective , it will not be demonstrated here.

5. no-loop

Defines whether the rule can be executed again when the result of ---1eee4522cede73c7c41641e5e4643635 当前规则 modifies the fact object. 可以防止死循环

1. Writing rule files

 package rules
import java.util.concurrent.TimeUnit
import java.text.SimpleDateFormat
import java.util.Date

rule "no_loop_rule_1"
    no-loop true
    when
        $i: Integer(intValue() < 20)
    then
        modify($i){
        }
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " no_loop_rule_1 i=" + $i);
end

rule "no_loop_rule_2"
    no-loop false

    when
        $i: Integer(intValue() < 20)
    then
        modify($i){
        }
        TimeUnit.SECONDS.sleep(1);
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " no_loop_rule_2 i=" + $i);
end

explain:
no_loop_rule_1 : no-loop true means that if the RHS part of the current rule modifies the Fact object, the rule will not be triggered again. If no_loop_rule_2 is modified, will this rule trigger? 答案是 will trigger, what if I don't want to be triggered? Then using lock-on-active can be achieved.
no_loop_rule_2 : no-loop false means that if the RHS part of the current rule is modified, the rule will be matched again.

2. Java code writing

 /**
 * 测试规则是否可以再次被执行
 */
public class DroolsNoLoopApplication {
    public static void main(String[] args) throws InterruptedException {
        System.setProperty("drools.dateformat", "yyyy-MM-dd HH:mm:ss");
        KieServices kieServices = KieServices.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession("rule-attributes-ksession");
        kieSession.insert(10);
        // 只匹配规则名称是已 no_loop_ 开头的规则,忽略其余的规则
        kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("no_loop_"));
        // 睡眠5s,使规则文件中的规则执行完
        TimeUnit.SECONDS.sleep(5);
        kieSession.dispose();
    }
}

The java code here sleeps for 5s to allow the rules to be executed.

3. Running results

 2022-05-18 11:42:29 no_loop_rule_1 i=10
2022-05-18 11:42:31 no_loop_rule_2 i=10
2022-05-18 11:42:31 no_loop_rule_1 i=10
2022-05-18 11:42:32 no_loop_rule_2 i=10

explain:
2022-05-18 11:42:29 no_loop_rule_1 i=10 : no_loop_rule_1 is triggered, because the RHS part uses modify to modify the object in the rule memory, but the rule has the attribute no-loop true, so the rule is not triggered again , that is, output only once.

`2022-05-18 11:42:30 no_loop_rule_2 i=10
2022-05-18 11:42:30 no_loop_rule_1 i=10` At this time, the rule no_loop_rule_2 is executed. Since the no-loop of the rule is false and the modify method is used, the rule is triggered many times. From the result , it seems that the rule no_loop_rule_1 is triggered again, shouldn't it be triggered because no-loop true is set? Because this is the trigger of no_loop_rule_1 caused by no_loop_rule_2, and no_loop is only valid for its own RHS modification.

doubt:
So if you replace no-loop with lock-on-active will the result be the same? You can try it yourself and see the results.

6. Agenda-group

The rules that have been successfully matched by the pattern are grouped, 只有获得焦点的组 before the rules can be executed. But there is a special column in this. If a rule is matched in the pattern and the match is successful, but no agenda-group is configured, then it will be assigned to the main group, this main The group's rules are always enforced.

The data structure of ---a906d082091f16890e8155b39148c98f agenda-group is similar to stack , and the active group is at the top of the stack. Refer to the following figure:

Reference link: https://stackoverflow.com/questions/6870192/understanding-agenda-group-in-drools

1. Writing rule files

 package rules

/**
    agenda-group 的数据结构类似与栈,激活的组会被放置在栈顶,
    `main`是默认组,总是存在的,即没有配置agenda-group的就是`main`,
    `main`总是会执行的。
*/

rule "agenda_group_001_rule_1"
    agenda-group "group-001"
    when
    then
        System.out.println("agenda_group_001_rule_1");
end

rule "agenda_group_001_rule_2"
    agenda-group "group-001"
    when
    then
        System.out.println("agenda_group_001_rule_2");
end

rule "agenda_group_002_rule_3"
    agenda-group "group-002"
    when
    then
        System.out.println("agenda_group_002_rule_3");
end

rule "agenda_group_no_group_rule_4"
    when
    then
        System.out.println("agenda_group_no_group_rule_4");
end

Note: There are actually 3 groups here, agenda_group_no_group_rule_4 if the pattern matches successfully, it will be assigned to main group, main will always be executed .

2. Java code writing

 /**
 * 测试规则分组
 */
public class DroolsAgendaGroupApplication {
    public static void main(String[] args) {
        // 设置日期格式,否则可能会报错(Wrong date-effective value: Invalid date input format: [2022-05-18 10:54:26] it should follow: [d-MMM-yyyy]]])
        System.setProperty("drools.dateformat", "yyyy-MM-dd HH:mm:ss");
        KieServices kieServices = KieServices.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession("rule-attributes-ksession");
    
        // 激活组
        kieSession.getAgenda().getAgendaGroup("group-001").setFocus();

        // 只匹配规则名称是已 agenda_group_ 开头的规则,忽略其余的规则
        kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("agenda_group_"));
        kieSession.dispose();
    }
}

Activate group-001 grouping.

3. Running results

 agenda_group_001_rule_1
agenda_group_001_rule_2
agenda_group_no_group_rule_4

explain:
agenda_group_no_group_rule_4 Why is it output? It doesn't define agenda-group ah, and we also activate group-001 grouping, it should not output ah. This is supposed to be assigned to the default main group after successful pattern matching for this rule, and the main group will definitely be executed.

7. Auto-focus

Set a agenda-group to get the focus by default, the same as using drools.setFocus(..) kieSession.getAgenda().getAgendaGroup("group-001").setFocus(); in the java code or ---34850c5dfd8f999f150c251c7419bd29--- in the drl file.

8. activation-group

The rule activated in this group, 同一个组下,只有一个规则可以执行 , the rest will be canceled. However, the rules activated in other groups can still be executed.

1. Writing rule files

 package rules

rule "activation_group_001_rule_1"
    activation-group "group-001"
    salience 1
    when
    then
        System.out.println("activation_group_001_rule_1");
end

rule "activation_group_001_rule_2"
    activation-group "group-001"
    salience 2
    when
    then
        System.out.println("activation_group_001_rule_2");
end

rule "activation_group_002_rule_3"
    activation-group "group-002"
    when
    then
        System.out.println("activation_group_002_rule_3");
end

rule "activation_group_no_group_rule_4"
    when
    then
        System.out.println("activation_group_no_group_rule_4");
end

activation-group "group-001" Here, the rules of this group are assigned a priority, and the rules with higher priority are executed first. After execution, the rules of this group are not executed.

2. Java code writing

 public class DroolsActivationGroupApplication {
    public static void main(String[] args) {
        System.setProperty("drools.dateformat", "yyyy-MM-dd HH:mm:ss");
        KieServices kieServices = KieServices.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession("rule-attributes-ksession");
        // 只匹配规则名称是已 activation_group_ 开头的规则,忽略其余的规则
        kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("activation_group_"));
        kieSession.dispose();
    }
}

3. Running results

 activation_group_001_rule_2
activation_group_002_rule_3
activation_group_no_group_rule_4

It can be seen that there are 2 rules in the group group-001 , but only one rule is executed.

9. Duration

The value of long type, in milliseconds, if 在这个时间之后规则还成立 , then execute this rule.

1. Writing rule files

 package rules
import java.text.SimpleDateFormat
import java.util.Date

rule "duration_rule_1"
    // 延迟1s后执行规则
    duration 1000
    when
        $i: Integer(intValue() < 10)
    then
        System.out.println(Thread.currentThread().getName() + ": " + 
        new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+ 
        " duration_rule_1 $i:"+$i);
end

Define the rule delay 1s and then execute it.

2. Java code writing

 /**
 * 在多少毫秒后,如果条件还成立,则触发该规则
 */
public class DroolsDurationApplication {
    public static void main(String[] args) throws InterruptedException {
        System.setProperty("drools.dateformat", "yyyy-MM-dd HH:mm:ss");
        KieServices kieServices = KieServices.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession("rule-attributes-ksession");

        FactHandle factHandle = kieSession.insert(3);
        // 只匹配规则名称是已 duration_ 开头的规则,忽略其余的规则
        new Thread(() -> {
            // 调用此方法会阻塞调用线程,直到 `kieSession.halt();`的调用
            System.out.println("当前时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            kieSession.fireUntilHalt(new RuleNameStartsWithAgendaFilter("duration_"));
        }, "fire-thread").start();

        // 如果修改这个值,使得规则的条件不成立,看规则是否还执行
        kieSession.update(factHandle, 4);

        TimeUnit.SECONDS.sleep(2);
        kieSession.halt();

        kieSession.dispose();
    }
}

Notice:
1. The method we call to execute all rules is not fireAllRules but fireUntilHalt .
2. The call of fireUntilHalt will block the thread until the halt method is called, so fireUntilHalt needs to be placed in another thread to call. And we observe the execution of the rule, which is also called in this thread.

3. Running results

 当前时间:2022-05-18 14:13:36
fire-thread: 2022-05-18 14:13:37 duration_rule_1 $i:4

As you can see, after the delay 1s the rule is executed.

4. Questions

If we modify the condition of the rule to invalid within 1s , will the rule still be executed? 答案: does not execute.

10. lock-on-active

Use with rule flow groups or agenda groups .

need:
We have 2 rules, and they belong to the same group. After the execution of rule 2, the value of the Fact object in the working memory has changed, causing rule 1 to meet the conditions for execution, and rule 1 has been executed once. The triggering of rule two causes the triggering of rule one. Use lock-on-active to achieve this.

1. Writing rule files

 package rules

import com.huan.drools.lockonactive.Person

rule "lock_on_active_rule_01"
    agenda-group "group-001"
    lock-on-active true
    when
        $p: Person(age < 18)
    then
        System.out.println("lock_on_active_rule_01: 用户:[" + $p.getName() + "]当前的年龄是:[" + $p.getAge() + "]");
 end

rule "lock_on_active_rule_02"
    agenda-group "group-001"
    when
        $p: Person(name == "张三")
    then
        modify($p){
            setAge(15)
        }
        System.out.println("lock_on_active_rule_02: 用户:[" + $p.getName() + "]当前的年龄是:[" + $p.getAge() + "]");
end

规则lock_on_active_rule_01lock-on-active true后,规则lock_on_active_rule_02 Fact lock_on_active_rule_01 ,此The rules are also not enforced.

2. Java code writing

 /**
 * 一个简单的实体类
 *
 * @author huan.fu
 * @date 2022/5/18 - 14:34
 */
@Getter
@Setter
@AllArgsConstructor
public class Person {
    private String name;
    private Integer age;
}

public class DroolsLockOnActiveApplication {
    public static void main(String[] args) {
        System.setProperty("drools.dateformat", "yyyy-MM-dd HH:mm:ss");
        KieServices kieServices = KieServices.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession("rule-attributes-ksession");
        // 激活组
        kieSession.getAgenda().getAgendaGroup("group-001").setFocus();

        Person person = new Person("张三", 20);
        kieSession.insert(person);

        // 只匹配规则名称是已 lock_on_active_ 开头的规则,忽略其余的规则
        kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("lock_on_active_"));
        kieSession.dispose();
    }
}

3. Running results

 lock_on_active_rule_02: 用户:[张三]当前的年龄是:[15]

It can be seen that only rule 2 is executed, indicating that the execution of rule 1 is blocked.

4. Complete code

https://gitee.com/huan1993/spring-cloud-parent/tree/master/drools/drools-drl-rule-attributes

5. Reference links

1. https://docs.drools.org/7.69.0.Final/drools-docs/html_single/index.html#rules-attributes-ref_drl-rules
2. https://stackoverflow.com/questions/6870192/understanding-agenda-group-in-drools


huan1993
218 声望34 粉丝

java工程师