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_01
加lock-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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。