drools中then部分的写法
1、背景
此处介绍一下drools中then部分的写法,以及一些内置的方法,比如insert/delete/modify等等。同时也介绍一下rule的继承,和在when中实现if else if 等操作。
2、支持的方法
drools提供了一些内置的方法,这些方法会修改drools的工作内存中Fact对象的值。从而会导致重新进行模式匹配。
2.1 insert 插入对象到工作内存中
insert是向工作内存中插入对象,同时会导致重新进行规则的模式匹配。同时当规则不满足时,不会自动删除。
2.1.1 需求
当发生火灾Fire时,向工作内存中插入一个Alarm对象,告警发生后,删除工作内存中的Fire对象,然后检测Alarm对象是否还存在。
2.1.2 drl文件编写
package rules
import com.huan.drools.insertmethod.Fire
import com.huan.drools.insertmethod.Alarm
rule "insert_发生火灾时,往工作内存中插入告警对象"
when
$fire: Fire()
then
System.out.println("1、发生火灾时,往工作内存中插入告警对象");
insert(new Alarm($fire));
end
rule "insert_当规则内存中存在告警对象,进行告警,然后删除火灾对象"
when
$fire: Fire()
$alarm: Alarm( fire == $fire )
then
System.out.println("2、进行告警,然后删除对应的火灾对象");
end
rule "insert_检测告警对象是否还是存在-01"
when
Alarm()
then
System.out.println("3、insert 插入的告警对象还存在");
// 删除工作内存中的Fire对象
delete($fire);
end
rule "insert_检测告警对象不存在"
when
not Alarm()
then
System.out.println("3、insert 插入的告警对象不存在");
end
此处使用的是 insert进行插入
2.1.3 部分java代码编写
// 将火灾对象插入到工作内存中
kieSession.insert(new Fire());
// 只触发规则名称以 insert_ 开头的规则
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("insert_"));
2.1.4 运行结果
1、发生火灾时,往工作内存中插入告警对象
2、进行告警,然后删除对应的火灾对象
3、insert 插入的告警对象还存在
2.1.5 结论
insert可以向工作内存中插入Fact对象。insert方法调用后,会导致模式的重新匹配,导致之前不会执行的规则,重新执行。insert方法插入到工作内存的对象,在规则不成立时,不会自动删除,需要手动删除,注意和insertLogical的区别
2.2 insertLogical 插入对象到工作内存中
insert是向工作内存中插入对象,同时会导致重新进行规则的模式匹配。同时当规则不满足时,会自动删除。
2.2.1 需求
当发生火灾Fire时,向工作内存中插入一个Alarm对象,告警发生后,删除工作内存中的Fire对象,然后检测Alarm对象是否还存在。
2.2.2 drl文件编写
package rules
import com.huan.drools.Fire
import com.huan.drools.Alarm
rule "insertLogical_发生火灾时,往工作内存中插入告警对象"
when
$fire: Fire()
then
System.out.println("1、发生火灾时,往工作内存中插入告警对象");
insertLogical(new Alarm($fire));
end
rule "insertLogical_当规则内存中存在告警对象,进行告警,然后删除火灾对象"
when
$fire: Fire()
$alarm: Alarm( fire == $fire )
then
System.out.println("2、进行告警,然后删除对应的火灾对象");
delete($fire);
end
rule "insertLogical_检测告警对象是否还是存在-01"
when
Alarm()
then
System.out.println("3、insertLogical 插入的告警对象还存在");
end
rule "insertLogical_检测告警对象不存在"
when
not Alarm()
then
System.out.println("3、insertLogical 插入的告警对象不存在");
end
此处使用的是insertLogical插入
2.2.3 部分java代码编写
kieSession.insert(new Fire());
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("insertLogical_"));
2.2.4 运行结果
1、发生火灾时,往工作内存中插入告警对象
2、进行告警,然后删除对应的火灾对象
3、insertLogical 插入的告警对象不存在
2.2.5 结论
insertLogical可以向工作内存中插入Fact对象。insertLogical方法调用后,会导致模式的重新匹配,导致之前不会执行的规则,重新执行。insertLogical方法插入到工作内存的对象,在规则不成立时,会自动删除注意和insert的区别
2.3、update 更新工作内存中的对象
update: 使用它来指定要更新的字段和整个相关Fact,并将更改通知 Drools 引擎。 Fact发生更改后,您必须在更改可能受更新值影响的另一个事实之前调用 update。 为避免此添加步骤,请改用 modify 方法。
2.3.1 需求
规则一: 当工作内存中存在火灾对象Fire,并且名字name为空时触发规则,同时在设置火灾的名字为大火灾。
规则二: 当火灾存在名字时,输出火灾名字
2.3.2 drl 文件编写
package rules
import com.huan.drools.Fire
import com.huan.drools.Alarm
rule "update_当存在火灾对象时,设置一个火灾的名字"
when
$fire: Fire(name == null)
then
System.out.println("1、设置火灾名字");
$fire.setName("大火灾");
update($fire)
end
rule "update_当火灾对象存在名字时触发"
when
$fire: Fire(name != null)
then
System.out.println("2、火灾对象的名字为: " + $fire.getName());
end
2.3.3 部分java文件编写
kieSession.insert(new Fire());
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("update_"));
2.3.4 运行结果
1、设置火灾名字
2、火灾对象的名字为: 大火灾
2.3.4 结论
update会导致模式的重新匹配。update会修改工作对象内存中的值。
2.4、modify 更新工作内存中的对象
modify: 使用它来指定要为Fact对象修改的字段并将更改通知 Drools 引擎。 此方法提供了一种结构化的事实更新方法。 它将更新操作与 setter 调用相结合以更改对象字段。
2.4.1 需求
规则一: 当工作内存中存在火灾对象Fire,并且名字name为空时触发规则,同时在设置火灾的名字为大火灾。
规则二: 当火灾存在名字时,输出火灾名字
2.4.2 drl 文件编写
package rules
import com.huan.drools.Fire
import com.huan.drools.Alarm
rule "modify_当存在火灾对象时,设置一个火灾的名字"
when
$fire: Fire(name == null)
then
System.out.println("1、设置火灾名字");
modify($fire){
setName("大火灾")
}
end
rule "modify_当火灾对象存在名字时触发"
when
$fire: Fire(name != null)
then
System.out.println("2、火灾对象的名字为: " + $fire.getName());
end
2.4.3 部分java文件编写
kieSession.insert(new Fire());
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("modify_"));
2.4.4 运行结果
1、设置火灾名字
2、火灾对象的名字为: 大火灾
2.4.5 结论
modify会导致模式的重新匹配。modify会修改工作对象内存中的值。- 一般情况下使用
modify,不要使用update。
2.5 delete 删除工作内存中的对象
用法:delete(<object>)
retract也是和delete一样的效果,但是推荐使用delete。
3、drools变量的简单使用
package rules
rule "drools_变量的使用"
when
eval(true)
then
System.out.println("Match激活的当前触发规则: " + drools.getMatch());
System.out.println("当前触发规则的名字: " + drools.getRule().getName());
// System.out.println("终止规则执行fireUntilHalt(): " + drools.getKieRuntime().halt());
// System.out.println("激活AgendaGroup组: " + drools.getKieRuntime().getAgenda().getAgendaGroup( "CleanUp" ).setFocus());
System.out.println("获取所有全局变量: " + drools.getKieRuntime().getGlobals());
// System.out.println("设置全局变量:" + drools.getKieRuntime().setGlobal("username","huan"); );
// System.out.println("获取查询结果:" + drools.getKieRuntime().getQueryResults());
end
4、规则的继承
4.1 需求
规则一: 如果用户(customer)的年龄(age)大于60岁,则打0.9折。
规则二: 在规则一的基础上,如果用户有车(car),则可以免费停车(freeParking)。
4.2 drl文件编写
package rules
import com.huan.drools.Customer
import com.huan.drools.Car
rule "rule_extends_规则一"
when
$c: Customer(age > 60)
then
modify($c){
setDiscount(0.9)
}
System.out.println("触发规则一:用户年龄>60岁,打0.9折");
end
// 规则二继承规则一的条件
rule "rule_extends_规则二" extends "rule_extends_规则一"
when
$car: Car()
then
modify($car){
setFreeParking(true)
}
System.out.println("触发规则二:用户有车,免费停车");
end
此处rule_extends_规则二继承了rule_extends_规则一,所以规则一的条件也继承了。
4.3 部分java代码
Car car = new Car();
Customer customer = new Customer();
customer.setAge(65);
kieSession.insert(customer);
kieSession.insert(car);
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("rule_extends_"));
客户有车,并且年龄是65岁,满足上方的规则一和规则二
4.4 运行结果
触发规则一:用户年龄>60岁,打0.9折
触发规则二:用户有车,免费停车
4.5 结论
可以看到在rule上使用extends关键字,可以实现规则的继承。
5、使用do[...]语法重写上方继承的例子
5.1 需求
只要用户大于60岁,直接打0.9折,如果还有车,则可以免费停车。
5.2 drl文件编写
package rules
import com.huan.drools.Customer
import com.huan.drools.Car
rule "命名结果_rule"
when
$c: Customer(age > 60)
do[giveDiscount] // 当上方的条件成立时执行 then [giveDiscount]
$car: Car() // 此条件成立时,执行默认的 then
then
modify($car){
setFreeParking(true)
};
System.out.println("用户有车,免费停车");
then [giveDiscount]
modify($c){
setDiscount(0.9)
};
System.out.println("用户年龄>60岁,打0.9折");
end
解释: 见上方的规则文件里的注视
5.3 部分java代码编写
Car car = new Car();
Customer customer = new Customer();
customer.setAge(65);
kieSession.insert(customer);
kieSession.insert(car);
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("命名结果_"));
5.4 运行结果
用户年龄>60岁,打0.9折
用户有车,免费停车
也实现了需求
5.5 结论
通过when中使用 do[名字] 然后 then then 名字 也可以实现。
6、实现 if else if 的效果
6.1 需求
完成类似 if else if else效果。见下方的各种执行结果。
6.2 规则文件
rule "if else-if"
when
$customer: Customer(age > 60) // 规则内存中存在Customer对象,并且age>60
if($customer.getLevel() == 1) do[level1] // 用户的级别是1,执行then[level1],然后继续执行下方的条件
else if ($customer.getLevel() == 2) break[level2] // 用户的级别是2,执行then[level2],不在执行下方的条件
else do[levelOther] // 其他的level级别,执行then[levelOther],然后在执行下方的条件
Car()
then
System.out.println("我执行了");
then[level1]
System.out.println("level1");
then[level2]
System.out.println("level2");
then[levelOther]
System.out.println("levelOther");
end
6.3 执行结果图

6.4 各种执行结果-也就是上图的解释
1、Customer的age小于60。
输出: 没有输出。
2、Customer的age大于60并且level=1,没有Car。
输出: level1
3、Customer的age大于60并且level=1,有Car。
输出: level1 我执行了
4、Customer的age大于60并且level=2,没有Car。
输出: level2
5、Customer的age大于60并且level=2,有Car。
输出: level2
6、Customer的age大于60并且level=3,没有Car。
输出: levelOther
7、Customer的age大于60并且level=3,有Car。
输出: levelOther 我执行了
6.5 do和 break 有什么区别
do:执行完之后,还会继续判断后面的执行条件。 (即还会执行后面的Car判断,根据是否有Car获取不同的结果)
break:执行完之后,不会在判断后面的执行条件。(即忽略了后面的Car判断,rule执行完了)
7、完整代码
https://gitee.com/huan1993/spring-cloud-parent/tree/master/drools/drools-drl-then
8、参考文档
1、https://docs.drools.org/7.69.0.Final/drools-docs/html_single/index.html#drl-rules-THEN-con_drl-rules
drools中then部分的写法的更多相关文章
- drools中的条件 when
目录 1.介绍 2.语法结构 3.模式例子 3.1 单个对象匹配 3.2 匹配任何对象 3.3 带条件匹配 3.3.1 注意事项 3.4 嵌套属性的匹配 3.4.1 访问单个嵌套属性 3.4.2 访问 ...
- ORACLE 查询一个数据表后通过遍历再插入另一个表中的两种写法
ORACLE 查询一个数据表后通过遍历再插入另一个表中的两种写法 语法 第一种: 通过使用Oracle语句块 --指定文档所有部门都能查看 declare cursor TABLE_DEPT and ...
- web工程中URL地址的写法
在开发中我们不可避免的要碰到许多需要写URL地址的情况,这常常让我们感到头疼.下面笔者推荐一种简单的做法.URL地址分为绝对路径和相对路径两种.相对路径又分为相对资源路径和相对根路径.显然绝对路径在开 ...
- jQuery 1.4.4 中 function( window, undefined ) 写法原因
读 jQuery 1.4.4 版本代码的时候,发现下面的写法: (function( window, undefined ) { ... // code goes here })(window); w ...
- 关于 jQuery中 function( window, undefined ) 写法的原因
今天在读 jQuery 源码的时候,发现下面的写法: (function(window,undefined){ ...// code goes here })(window); window 作为参数 ...
- C++<algorithm>中sort的比较函数写法(转)
转自:http://www.wl566.com/biancheng/98907.html C++<algorithm>中sort的比较函数写法,有需要的朋友可以参考下. 定义排序函数: 方 ...
- QT中.pro文件的写法
QT中.pro文件的写法 qmake 变量 含义 #xxxx 注释, 从“#”开始,到这一行结束 SOURCES 指定源文件 SOURCES = *.cpp 对于多源文件,可用空格分开 SOURC ...
- thinkphp <volist>标签中 <if> 判断的写法
thinkphp <volist>标签中 <if> 判断的写法 <volist name="data" id="vo"> & ...
- 整理:WPF中Xaml中绑定枚举的写法
原文:整理:WPF中Xaml中绑定枚举的写法 目的:在Combobox.ListBox中直接绑定枚举对象的方式,比如:直接绑定字体类型.所有颜色等枚举类型非常方便 一.首先用ObjectDataPro ...
随机推荐
- ES6-11学习笔记--对象的扩展
属性简洁表示法 属性名表达式 Objec.is() 扩展运算符 与 Object.assign() in 对象的遍历方式 属性简洁表示法: 如果属性key跟变量名一样,可简写 let name = ...
- javascript当中嵌套函数
3)嵌套函数例 3.3.1<head> <meta http-equiv="content-type" content="text/html; c ...
- java中当static块和构造函数同时出现,顺序是?
静态块先于构造函数执行 class Student { int age; String name; static int count; public Student() { ...
- .NET如何快速比较两个byte数组是否相等
目录 前言 评测方案 几种不同的方案 For循环 Memcmp 64字长优化 SIMD Sse Avx2 SequenceCompare 总结 参考文献 前言 之前在群里面有群友问过一个这样的问题,在 ...
- python---希尔排序的实现
def shell_sort(alist): """希尔排序""" n = len(alist) gap = n // 2 # 插入算法执行 ...
- Spring集成web环境(手动实现)
1.创建UserDao接口及其实现类UserDaoImpl(接口代码省略) public class UserDaoImpl implements UserDao { @Override public ...
- SSM整合_年轻人的第一个增删改查_查找
写在前面 SSM整合_年轻人的第一个增删改查_基础环境搭建 SSM整合_年轻人的第一个增删改查_查找 SSM整合_年轻人的第一个增删改查_新增 SSM整合_年轻人的第一个增删改查_修改 SSM整合_年 ...
- Java基础语法Day_04
第11节 开发工具-IDEA day04_01_集成开发环境IDE的概述 day04_02_IntelliJ-IDEA的安装 day04_03_IDEA的项目结构 day04_04_IDEA的Hell ...
- python学习-Day38-HTML
目录 前端 简介 什么是前端 什么是后端 前端特点 前端主要技术: 前端相关技能 关于 HTTP 的知识在这里 HTML 什么是HTML HTML 实例 实例解析 HTML 标签 HTML 元素 HT ...
- [STL] deque 双端队列