目录

1、背景

此处介绍一下droolsthen部分的写法,以及一些内置的方法,比如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 结论

  1. insert可以向工作内存中插入Fact对象。
  2. insert方法调用后,会导致模式的重新匹配,导致之前不会执行的规则,重新执行。
  3. 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 结论

  1. insertLogical可以向工作内存中插入Fact对象。
  2. insertLogical方法调用后,会导致模式的重新匹配,导致之前不会执行的规则,重新执行。
  3. 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 结论

  1. update会导致模式的重新匹配。
  2. 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 结论

  1. modify会导致模式的重新匹配。
  2. modify会修改工作对象内存中的值。
  3. 一般情况下使用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、Customerage小于60

输出: 没有输出。

2、Customerage大于60并且level=1,没有Car

输出: level1

3、Customerage大于60并且level=1,有Car

输出: level1 我执行了

4、Customerage大于60并且level=2,没有Car

输出: level2

5、Customerage大于60并且level=2,有Car

输出: level2

6、Customerage大于60并且level=3,没有Car

输出: levelOther

7、Customerage大于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部分的写法的更多相关文章

  1. drools中的条件 when

    目录 1.介绍 2.语法结构 3.模式例子 3.1 单个对象匹配 3.2 匹配任何对象 3.3 带条件匹配 3.3.1 注意事项 3.4 嵌套属性的匹配 3.4.1 访问单个嵌套属性 3.4.2 访问 ...

  2. ORACLE 查询一个数据表后通过遍历再插入另一个表中的两种写法

    ORACLE 查询一个数据表后通过遍历再插入另一个表中的两种写法 语法 第一种: 通过使用Oracle语句块  --指定文档所有部门都能查看 declare cursor TABLE_DEPT and ...

  3. web工程中URL地址的写法

    在开发中我们不可避免的要碰到许多需要写URL地址的情况,这常常让我们感到头疼.下面笔者推荐一种简单的做法.URL地址分为绝对路径和相对路径两种.相对路径又分为相对资源路径和相对根路径.显然绝对路径在开 ...

  4. jQuery 1.4.4 中 function( window, undefined ) 写法原因

    读 jQuery 1.4.4 版本代码的时候,发现下面的写法: (function( window, undefined ) { ... // code goes here })(window); w ...

  5. 关于 jQuery中 function( window, undefined ) 写法的原因

    今天在读 jQuery 源码的时候,发现下面的写法: (function(window,undefined){ ...// code goes here })(window); window 作为参数 ...

  6. C++<algorithm>中sort的比较函数写法(转)

    转自:http://www.wl566.com/biancheng/98907.html C++<algorithm>中sort的比较函数写法,有需要的朋友可以参考下. 定义排序函数: 方 ...

  7. QT中.pro文件的写法

    QT中.pro文件的写法   qmake 变量 含义 #xxxx 注释, 从“#”开始,到这一行结束 SOURCES 指定源文件 SOURCES = *.cpp 对于多源文件,可用空格分开 SOURC ...

  8. thinkphp <volist>标签中 <if> 判断的写法

    thinkphp <volist>标签中 <if> 判断的写法 <volist name="data" id="vo"> & ...

  9. 整理:WPF中Xaml中绑定枚举的写法

    原文:整理:WPF中Xaml中绑定枚举的写法 目的:在Combobox.ListBox中直接绑定枚举对象的方式,比如:直接绑定字体类型.所有颜色等枚举类型非常方便 一.首先用ObjectDataPro ...

随机推荐

  1. flex布局中父容器属性部分演示效果

    如图可见flex的属性分为父容器和子容器的属性共12个.关于这些属性具体代表什么意思,网上有很多教程的文章,自觉不能写得比别人更好,所以这里主要写了一些例子关于父容器属性效果的演示,希望可以帮助大家理 ...

  2. Vue-router实现单页面应用在没有登录情况下,自动跳转到登录页面

    这是我做前端一来的第一篇文章,都不知道该怎么开始了.那就直接奔主题吧.先讲讲这个功能的实现场景吧,我们小组使用vue全家桶实现了一个单页面应用,最初就考虑对登录状态做限制.比如登录后不能后退到登录页面 ...

  3. electron制作聊天界面(仿制qq)

    效果图: 样式使用scss和flex布局 这也是制作IM系统的最后一个界面了!在制作之前参考了qq和千牛 需要注意的点 qq将滚动条美化了 而且在无操作的情况下是不会显示的 滚动条美化 ::-webk ...

  4. hdfs对文件的增删改查

    源代码: pom.xml: <?xml version="1.0" encoding="UTF-8"?> <project xmlns=&qu ...

  5. 在Wireshark中使用过滤器——显示过滤器

    在Wireshark运行过程中选择搜索(Ctrl-F),第一个默认的搜索选项就是显示过滤器. 显示过滤器用于捕获文件,用来告诉Wireshark只显示那些符合过滤条件的数据包. 显示过滤器比捕获过滤器 ...

  6. 不同标准下的C语言常量范围的默认类型的检测 (测试样例为C90与C99)

    不同标准下的C语言常量范围的默认类型的检测 一.C90与C99标准下的不同常量范围的默认类型     C90标准下对不同常量范围默认类型的检测实现及运行结果: C99标准下对不同范围默认类型的检测实现 ...

  7. redis的基础命令操作

    文章目录 前言 一.字符串类型 二.哈希类型 三.列表类型 四.集合类型 五.有序集合类型 六.通过命令 前言 redis的数据结构 redis存储的是key,value格式的数据,其中的key是字符 ...

  8. Spring的事务控制-基于xml方式

    介绍:该程序模拟了转账操作,即Jone减少500元,tom增加500元 1.导入坐标 <dependency> <groupId>junit</groupId> & ...

  9. 领域驱动模型DDD(二)——领域事件的订阅/发布实践

    前言 凭良心来说,<微服务架构设计模式>此书什么都好,就是选用的业务过于庞大而导致代码连贯性太差,我作为读者来说对于其中采用的自研框架看起来味同嚼蜡,需要花费的学习成本实在是过于庞大,不仅 ...

  10. hashlib加密模块、logging日志模块

    hashlib模块 加密:将明文数据通过一系列算法变成密文数据 目的: 就是为了数据的安全 基本使用 基本使用 import hashlib # 1.先确定算法类型(md5普遍使用) md5 = ha ...