文章目录
- drl文件构成-rule部分
- rule示例
- rule name
- Attribute
- 全部属性说明
- no-loop 和 lock-on-active
- activation-group 和 agenda-group
drl文件构成-rule部分
drl文件构成,位于官网的第5章位置,也是drools作为规则引擎应用的最核心部分。
其中rule模块,包括属性(Attribute - rule)、条件(Condition - when)、结果(Action - then)是5.1.7、5.1.8、5.1.9 三小节部分内容。
- Rule Language Reference
官网链接:https://docs.drools.org/7.73.0.Final/drools-docs/html_single/index.html#_droolslanguagereferencechapter
rule示例
rule "rule_name"
// Attribute
// Attribute
when
// Conditions
then
// Actions
end
rule name
其中,rule_name 是全局唯一的,意思是在kie的工作内存中需要保持唯一。所以,安全起见,在整个项目中这个rule_name保持唯一就好了。因为是字符串类型,所以,约束较少,可以使用空格、中文等。不过对于实际应用中,一般会给出有规律的命名,比如同一种类型的规则,使用相同的前缀或后缀(这样也是在后期使用时,可以利用kie的api,可以明确执行约定的规则。)
Attribute
全部属性说明
位于rule和when之间的部分,是Attribute。属性一般作用于该条规则(rule),如执行优先级、触发时间限制等。
每个属性在官网中都有明确的描述
Attribute Value
@ salience
An integer defining the priority of the rule. Rules with a higher salience value are given higher priority when ordered in the activation queue.
含义:salience 后面的数字越大,优先级越高
’Example: salience 10
@ enabled
A Boolean value. When the option is selected, the rule is enabled. When the option is not selected, the rule is disabled.
含义:该规则是否启用
Example: enabled true
@ date-effective
A string containing a date and time definition. The rule can be activated only if the current date and time is after a date-effective attribute.
含义:该规则从指定的日期开始生效,代码增加:System.setProperty(“drools.dateformat”, “yyyy-MM-dd”); 可以指定日期格式
Example: date-effective “4-Sep-2018”
@ date-expires
A string containing a date and time definition. The rule cannot be activated if the current date and time is after the date-expires attribute.
含义:该规则在指定日期之前生效 ,代码增加:System.setProperty(“drools.dateformat”, “yyyy-MM-dd”); 可以指定日期格式
Example: date-expires “4-Oct-2018”
@ no-loop
A Boolean value. When the option is selected, the rule cannot be reactivated (looped) if a consequence of the rule re-triggers a previously met condition. When the condition is not selected, the rule can be looped in these circumstances.
含义:该规则结果改变造成的再次满足该规则条件,不会被触发。但其他规则结果改变造成的满足条件,会再次触发该规则。
Example: no-loop true
@ agenda-group
A string identifying an agenda group to which you want to assign the rule. Agenda groups allow you to partition the agenda to provide more execution control over groups of rules. Only rules in an agenda group that has acquired a focus are able to be activated.
Example: agenda-group “GroupName”
@ activation-group
A string identifying an activation (or XOR) group to which you want to assign the rule. In activation groups, only one rule can be activated. The first rule to fire will cancel all pending activations of all rules in the activation group.
Example: activation-group “GroupName”
@ duration
A long integer value defining the duration of time in milliseconds after which the rule can be activated, if the rule conditions are still met.
Example: duration 10000
@ timer
A string identifying either int (interval) or cron timer definitions for scheduling the rule.
含义:定时器,类似于java的定时器,定义了规则允许触发的频次
Example: timer ( cron:* 0/15 * * * ? ) (every 15 minutes)
@ calendar
A Quartz calendar definition for scheduling the rule.
含义:类似于定时器,语法不同,定义了规则允许触发的时间段
Example:
// Exclude non-business hours
calendars “* * 0-7,18-23 ? * *”
// Weekdays only, as registered in the KIE session
calendars “weekday”
@ auto-focus
A Boolean value, applicable only to rules within agenda groups. When the option is selected, the next time the rule is activated, a focus is automatically given to the agenda group to which the rule is assigned.
含义:作用于 agenda groups,分组内只要有一个规则标记了 auto-focus,则名称相同的 agenda groups 分组会被触发规则。
Example: auto-focus true
@ lock-on-active
A Boolean value, applicable only to rules within rule flow groups or agenda groups. When the option is selected, the next time the ruleflow group for the rule becomes active or the agenda group for the rule receives a focus, the rule cannot be activated again until the ruleflow group is no longer active or the agenda group loses the focus. This is a stronger version of the no-loop attribute, because the activation of a matching rule is discarded regardless of the origin of the update (not only by the rule itself). This attribute is ideal for calculation rules where you have a number of rules that modify a fact and you do not want any rule re-matching and firing again.
含义:无论规则结果是否修改,该规则至多触发一次。
Example: lock-on-active true
@ ruleflow-group
A string identifying a rule flow group. In rule flow groups, rules can fire only when the group is activated by the associated rule flow.
含义:规则流
Example: ruleflow-group “GroupName”
@ dialect
A string identifying either JAVA or MVEL as the language to be used for code expressions in the rule. By default, the rule uses the dialect specified at the package level. Any dialect specified here overrides the package dialect setting for the rule.
含义:规则语言, JAVA or MVEL,默认是java
Example: dialect “JAVA”
When you use Drools without the executable model, the dialect “JAVA” rule consequences support only Java 5 syntax. For more information about executable models, see Executable rule models.
以上属性基本都是常用属性。业务场景基本覆盖的到。
便于阅读,拿出几个初学者需要会“百度一下”的属性简单介绍一下。
no-loop 和 lock-on-active
no-loop:官网定义:如果规则的结果再次触发先前满足的条件,则无法重新激活(循环)规则。
说明这个属性只能管自己的结果改变(modify、update)造成的再次触发先前满足的条件。其他规则的结果造成的,它管不了。
lock-on-active:官网定义:仅适用于 rule flow groups 或 agenda groups. 这两种分组。这是一个更强大的无循环属性版本,因为无论更新的来源如何(而不仅仅是规则本身),匹配规则的激活都会被丢弃。
先不管适用啥分组,后面这句话的意思是 no-loop的一个升级版,无论是被谁的结果条件改变造成的,该规则都最多被触发一次。
总结一句话,如果只是使用no-loop,在不了解这两个属性区别之前,会造成死循环。
文字比较抽象,举例说明:
test方法:
@Test
public void testLoop() {
// 获取services
KieServices kieServices = KieServices.Factory.get();
// 获取container
KieContainer container = kieServices.getKieClasspathContainer();
// 获取session
KieSession kieSession = container.newKieSession();
Map<String, Object> globalMap = new HashMap<>();
kieSession.setGlobal("globalMap", globalMap);
Map<String, Object> conditionMap = new HashMap<>();
conditionMap.put("age", 30);
conditionMap.put("testKey", "test");
kieSession.insert(conditionMap);
// kieSession.fireAllRules();
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("map_rule_test"));
System.out.println(globalMap.get("testKey"));
System.out.println(conditionMap.get("userScore"));
System.out.println(conditionMap.get("sex"));
kieSession.dispose();
}
map_rule.drl
package rules;
import java.util.Map
global java.util.Map globalMap
rule "map_rule_test2"
// no-loop true
// lock-on-active
when
$map:Map($map["userScore"]<600)
then
modify($map){put("userScore", 500)};
System.out.println("触发了规则:map_rule_test2");
end
rule "map_rule_test1"
// no-loop true
// lock-on-active
when
$map:Map()
Object($map["age"]>20, $map["testKey"]=="test")
then
modify($map){put("userScore", 300),put("sex","女")};
globalMap.put("testKey","testValue");
System.out.println("触发了规则:map_rule_test1");
end
- 其中 map_rule_test2和map_rule_test1 分别注释了
// no-loop true
// lock-on-active
这种情况下,执行结果:只打印 触发了规则:map_rule_test2
因为 规则结果部分 modify($map){put(“userScore”, 500)}; 对map进行了修改,当没有 no-loop true 这个属性时,会触发再次执行该规则,条件得到满足,所以会继续执行。从而造成死循环,且test1不会被执行到。
由于规则执行死循环,test代码中的打印也不会触发到。
当 map_rule_test1 增加了属性 no-loop true 和 lock-on-active ,对结果无影响。
- map_rule_test1 和 map_rule_test2 的 no-loop true 和 lock-on-active 两个属性分别注释和放开的执行结果如下截图。
可以看到 当 两个规则,都加了 no-loop true 时,仍然会造成死循环。但任意一个加上 lock-on-active true 属性的时候,则可以终止死循环。当然执行结果是不同的。因为map的初始值 score属性为null,因此当test2规则加了属性的时候,由于test1的结果修改了属性,不会再次触发test2,所以执行结果没有触发test2这个规则。
activation-group 和 agenda-group
activation-group :该属性将若干个规则划分成一个组,统一命名。在执行的时候,具有相同activation-group 属性的规则中只要有一个被执行,其它的规则都不再执行。同时可以用类似salience之类属性来实现组内规则的执行优先级。
也就是说n个规则,具有相同的属性 activation-group ,但最多只有 1 个规则会被触发,当多个规则满足条件是,默认是按照drl书写的顺序第一个被触发,但可以使用 salience 属性来约定优先级。
agenda-group :若干个agenda-group分组,每个分组内有n个规则,在执行的时候,被focus的分组,组内的所有规则都可以被触发。
举例说明:
测试方法:
@Test
public void testGroup() {
// 获取services
KieServices kieServices = KieServices.Factory.get();
// 获取container
KieContainer container = kieServices.getKieClasspathContainer();
// 获取session
KieSession kieSession = container.newKieSession();
// 注意这行,是在代码中指定focus的分组。
// kieSession.getAgenda().getAgendaGroup("agenda002").setFocus();
// 触发规则
// kieSession.fireAllRules();
int ruleCount = kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("rule-group"));
System.out.println("执行了规则数量:" + ruleCount);
kieSession.dispose();
}
group_test.drl文件
package rules;
import java.util.Date
rule "rule-group-1"
salience 10
activation-group "testgroup"
when
then
System.out.println("activation-rule-1 .. ");
end
rule "rule-group-2"
salience 20
activation-group "testgroup"
when
then
System.out.println("activation-rule-2 .. ");
end
rule "rule-group-3"
agenda-group "agenda001"
when
then
System.out.println("agenda001-rule-3 .. ");
end
rule "rule-group-4"
agenda-group "agenda001"
auto-focus
when
then
System.out.println("agenda001-rule-4 .. ");
end
rule "rule-group-5"
agenda-group "agenda002"
when
then
System.out.println("agenda002-rule-5 .. ");
end
rule "rule-group-6"
agenda-group "agenda002"
when
then
System.out.println("agenda002-rule-6 .. ");
end
drl文件定义了 6 个规则,其中 activation-group “testgroup” 属性的2个、 agenda-group "agenda001"属性的2个、agenda-group "agenda002"属性的2个。
rule-group-1、rule-group-2 属性为 activation-group “testgroup” ,最多只有其中一个能执行,例子中,使用 salience 属性,将 rule-group-2 的优先级提高了。因此 rule-group-1 是不会执行到的。
agenda-group “agenda001” 因为有 auto-focus 属性,因此 rule-group-3、rule-group-4会被执行
rule-group-5、rule-group-6则不会被执行。
执行结果截图如下:
但代码中加入 kieSession.getAgenda().getAgendaGroup(“agenda002”).setFocus();时,
rule-group-2、 rule-group-3、rule-group-4、rule-group-5、rule-group-6,都会被执行。
执行结果截图如下: