Drools学习
几篇参考的博客:
全局Global参数设置:https://www.cnblogs.com/wwjj4811/p/15294523.html
fireAllRules使用指定规则名:https://blog.csdn.net/u013115157/article/details/52487001
规则引擎高级语法:https://blog.csdn.net/qq_36305027/article/details/106562422?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_title~default-0.essearch_pc_relevant&spm=1001.2101.3001.4242.1
pom依赖
包括Drools相关依赖、lombak依赖、junit单元测试依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>7.23.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>7.23.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-decisiontables</artifactId>
<version>7.23.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-templates</artifactId>
<version>7.23.0.Final</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
<version>7.23.0.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<version>2.5.4</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
<version>1.18.16</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
</dependencies>
配置文件设置
在classpath下配置drools配置文件,文件的路径为resource/META-INF/kmodule.xml,该配置文件必须在这个目录下,放到其他地方无法生效
<?xml version="1.0" encoding="UTF-8" ?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule">
<!--
name:指定kbase的名称,可以任意,但是需要唯⼀
packages:指定规则⽂件的⽬录,需要根据实际情况填写,否则⽆法加载到规则⽂件
default:指定当前kbase是否为默认
-->
<kbase name="myKbase1" packages="rules" default="true">
<!--
name:指定ksession名称,可以任意,但是需要唯⼀
default:指定当前session是否为默认
-->
<ksession name="ksession-rule" default="true"/>
</kbase>
</kmodule>
配置文件参数配置
规则类定义
规则类其实就是一个普通的class类
import com.drools.demo.entity;
import lombok.Data;
/**
* @author groundless
* @Date 2021/11/29 16:02
* @Description person
*/
@Data
public class Person {
private String name;
private int age;
}
package com.drools.demo.entity;
import lombok.Data;
/**
* @author groundless
* @Date 2021/11/29 16:55
* @Description RuleBack (后面用于global对象返回使用)
*/
@Data
public class RuleBack {
private String desc;
}
规则文件
规则文件定义到resource/rule文件夹下
rules.drl
import com.drools.demo.entity.Person
import javax.management.Descriptor
import com.drools.demo.entity.RuleBack;
dialect "mvel"
global RuleBack ruleBack;
rule "rules"
when
$person : Person(age >= 18 && age <= 60)
then
System.out.println("rules");
ruleBack.setDesc("rules back");
$person.setName("rules");
end
personRules.drl
import com.drools.demo.entity.Person;
import com.drools.demo.entity.RuleBack;
dialect "mvel"
global RuleBack ruleBack;
rule "personRules"
when
$s : Person(name == '111')
then
System.out.println("personRules");
$s.setName("personRules");
ruleBack.setDesc("personRule back");
end
规则调用
public void test(Person person){
// 获取规则引擎服务
KieServices kieServices = KieServices.Factory.get();
// 创建规则容器
KieContainer container = kieServices.getKieClasspathContainer();
// 获取规则session
KieSession kieSession = container.newKieSession("all-rules");
// 加载校验对象
kieSession.insert(person);
RuleBack ruleBack = new RuleBack();
// 设置全局参数
kieSession.setGlobal("ruleBack", ruleBack);
// 执行规则校验
int i = kieSession.fireAllRules(); // 所有的规则都进行匹配一遍
// int i = kieSession.fireAllRules(new RuleNameEqualsAgendaFilter("rules1")); // 匹配指定名称的规则
// int i = kieSession.fireAllRules(new RuleNameMatchesAgendaFilter("all-rules")); // 通过正则匹配满足要求的规则
// int i = kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("rules")); // 匹配以指定名称开头的规则
// kieSession.fireAllRules(new RuleNameEndsWithAgendaFilter("rules")); // 匹配以指定名称结尾的规则
// 关闭session
kieSession.dispose();
}
Drools语法
规则文件构成
drl是Drools Rule Language的缩写。在规则⽂件中编写具体的规则内容。
⼀套完整的规则⽂件内容构成如下:
- package:包名,package对应的不⼀定是真正的⽬录,可以任意写com.abc,同⼀个包下的drl⽂ 件可以相互访问
- import:⽤于导⼊类或者静态⽅法
- global:全局变量
- function:⾃定义函数
- query:查询
- rule end:规则体
规则语法结构
⼀个规则通常包括三个部分:属性部分(attribute) 、条件部分(LHS)和结果部分(RHS)
rule "ruleName" //rule关键字,表示规则开始,参数为规则的唯⼀名称
attributes //规则属性,是rule与when之间的参数,为可选项
when //关键字,后⾯是规则的条件部分
LHS //Left Hand Side,是规则的条件部分
then //后⾯跟规则的结果部分
RHS //是规则的结果或⾏为
end //表示⼀个规则的结束
条件部分
LHS(Left Hand Side):是规则的条件部分的通⽤名称。它由零个或多个条件元素组成。如果LHS 为空,则它将被视为始终为true的条件元素。 (左⼿边)
LHS部分由⼀个或者多个条件组成,条件⼜称为pattern。
pattern的语法结构为:绑定变量名:Object(Field约束)
其中绑定变量名可以省略,通常绑定变量名的命名⼀般建议以$开始。如果定义了绑定变量名,就可以 在规则体的RHS部分使⽤此绑定变量名来操作相应的Fact对象。Field约束部分是需要返回true或者false 的0个或多个表达式。
rule "rules"
when
$person : Person(age >= 18)
then
System.out.println("rules");
ruleBack.setDesc("rules back");
$person.setName("rules");
end
如果 LHS 部分为空的话,那么引擎会⾃动添加⼀个 eval(true)的条件,由于该条件总是返回 true,所 以 LHS 为空的规则总是返回 true
1.约束连接
在 LHS 当中,可以包含 0~n 个条件,多个pattern之间可以采⽤“&&” (and) 、 “||”(or)和“,”(and) 来实现,也可以不写,默认连接为and。
2.⽐较操作符
在 Drools当中共提供了⼗⼆种类型的⽐较操作符, 分别是: >、 >=、 <、 <=、 = =、 !=、 contains、 not contains、memberof、not memberof、matches、not matches;在这⼗⼆种类型的 ⽐较操作符当中,前六个是⽐较常⻅也是⽤的⽐较多的⽐较操作符
符号 | 说明 |
---|---|
> | 大于 |
< | 小于 |
>= | 大于等于 |
<= | 小于等于 |
== | 等于 |
!= | 不等于 |
contains | 检查⼀个Fact对象的某个属性值是否包含⼀个指 定的对象值 |
not contains | 检查⼀个Fact对象的某个属性值是否不包含⼀个 指定的对象值 |
memberOf | 判断⼀个Fact对象的某个属性是否在⼀个或多个 集合中 |
not memberOf | 判断⼀个Fact对象的某个属性是否不在⼀个或多 个集合中 |
matches | 判断⼀个Fact对象的属性是否与提供的标准的 Java正则表达式进⾏匹配 |
not matches | 判断⼀个Fact对象的属性是否不与提供的标准的 Java正则表达式进⾏匹配 |
结果部分
在 Drools 当中,在 RHS ⾥⾯,提供了⼀些对当前 Working Memory 实现快速操作的宏宏函数或对 象, ⽐如 insert/insertLogical、 update 和 retract 就可以实现对当前 Working Memory中的 Fact 对象进⾏新增、删除或者是修改
-
insert
函数insert的作⽤与我们在Java类当中调⽤StatefulKnowledgeSession对象的insert⽅法的作⽤相同, 都是⽤来将⼀个 Fact 对象插⼊到当前的 Working Memory 当中 需注意:⼀旦调⽤ insert 宏函数,那么 Drools 会重新与所有的规则再重新匹配⼀次, 对于没有设置 no-loop 属性为 true 的规则,如果条件满⾜,不管其之前是否执⾏过都会再执⾏⼀次,这个特性不仅 存在于 insert 宏函数上,后⾯介绍的 update、retract 宏函数同样具有该特性,所以在某些情况下因考 虑不周调⽤ insert、update 或 retract 容易发⽣死循环rule "rule5" when eval(true); //默认成⽴ then Person p=new Person(); p.setName("张三"); insert(cus); System.out.println("测试Drools提供的内置⽅法insert 触发..."); end
-
update
update函数意义与其名称⼀样, ⽤来实现对当前Working Memory当中的 Fact进⾏更新,⽤来告诉当 前的 Working Memory 该 Fact 对象已经发⽣了变化。
rule "rule5" when $p:Person(name == "张三") then $p.setName("李四"); pudate($p); System.out.println("测试Drools提供的内置⽅update 触发..."); end
-
retract
retract⽤来将 Working Memory 当中某个 Fact 对象从 Working Memory 当中删除rule "rule5" when $p:Person(name == "张三") then retract($p); System.out.println("测试Drools提供的内置⽅retract 触发..."); end
属性部分
属性名 | 说明 |
---|---|
salience | 指定规则执⾏优先级 |
dialect | 指定规则使⽤的语⾔类型,取值为java和mvel |
enabled | 指定规则是否启⽤ |
date-effective | 指定规则⽣效时间 |
date-expires | 指定规则失效时间 |
activation-group | 激活分组,具有相同分组名称的规则只能有⼀个 规则触发 |
agenda-group | 议程分组,只有获取焦点的组中的规则才有可能 触发 |
timer | 定时器,指定规则触发的时间 |
auto-focus | ⾃动获取焦点,⼀般结合agenda-group⼀起使 ⽤ |
no-loop | 防⽌死循环 |