参考Drools官方文档(3.1 KIE Session和3.2 Inference and truth maintenance in the Drools engine),学习关于Kie Session和Truth maintenace的内容。这两节内容虽然很基础,但是感觉官方文档说的还是不够明了,尤其是Stateless Session和Stateful Session的区别,和insert()和insertLogical()的区别,官方文档给出的样例没有很好的体现出来,下面我尝试用我自己的例子来理解一下

1 Stateless Session和Stateful Session的区别

按照官方解释,Stateless Session每次调用会话是独立的,不保存上次调用的数据状态,而Stateful Session正相反。相对来说,Stateful Session更加容易理解,也更为常用,我们先写一个Stateful Session的例子。
先定义一个Person类

package drools.samples.domain;public class Person {private String name;private int age;public Person(String name,int age){this.name=name;this.age=age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}

再定义一个规则文件statefulSampleRule.drl,逻辑很简单,如果一个person小于18岁,打印"xxx is a child",否则打印"xxx is a adult"。

package drools.samples.rules.statefulSampleRuleimport drools.samples.domain.Personrule "Age < 18"
when$a : Person(age < 18)
thenSystem.out.println($a.getName()+" is a child");
endrule "Age > 18"
when$a : Person(age >= 18)
thenSystem.out.println($a.getName()+" is a adult");
end

在kmodule.xml里定义一个名为"statefulTest"的ksession

<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule"><kbase name="stateful" packages="drools.samples.rules.statefulSampleRule"><ksession name="statefulTest"/></kbase>
</kmodule>

写个执行程序,我们先把这个person对象的年龄设成16,执行下rule,然后我们再动态地更新年龄为25,重新执行下rule

KieServices kieServices = KieServices.Factory.get();
KieContainer kContainer = kieServices.getKieClasspathContainer();
KieSession kSession = kContainer.newKieSession("statefulTest");Person p1 = new Person("Tom", 16);
FactHandle factHandle=kSession.insert(p1);
kSession.fireAllRules();
p1.setAge(25);
kSession.update(factHandle, p1,"age");
kSession.fireAllRules();

运行结果

所以在一个stateful session里,允许我们更新fact的状态并重新触发规则evaluate。
我们继续写个stateless session的例子。定义一个规则文件statelessSampleRule.drl,其实和statefulSampleRule.drl一样

package drools.samples.rules.statelessSampleRule
import drools.samples.domain.Person
rule "Age < 18"
when$a : Person(age < 18)
thenSystem.out.println($a.getName()+" is a child");
endrule "Age > 18"
when$a : Person(age >= 18)
thenSystem.out.println($a.getName()+" is a adult");
end

在kmodule.xml里定义一个名为"statelessTest"的ksession,主要加上"stateless"的属性

<kbase name="stateless" packages="drools.samples.rules.statelessSampleRule"><ksession name="statelessTest" type="stateless"/></kbase>

执行程序和结果

KieServices kieServices = KieServices.Factory.get();
KieContainer kContainer = kieServices.getKieClasspathContainer();
StatelessKieSession kSession = kContainer.newStatelessKieSession("statelessTest");Person p1 = new Person("Tom", 16);
kSession.execute(p1);


你可能会问为什么我没有在stateless的例子里去更新age,这是因为查看StatelessKieSession的接口,你会发现根本就不提供更新fact的操作,并且stateless session的接口只提供了execute接口,因此stateless session的不同点就表现在这里,你无法在一个stateless session里去更新fact,一个fact只会有一次存入Working memory的操作。
我看网上有人认为stateless session在执行规则时会忽略fact的更新从而不重新触发rule,在我看来不是这样的。我们修改下statelessSampleRule.drl

package drools.samples.rules.statelessSampleRule
import drools.samples.domain.Personrule "Age < 18"
when$a : Person(age < 18)
thenSystem.out.println($a.getName()+"'age is less 18");
endrule "Age 16"
when$a : Person(age == 16)
thenSystem.out.println($a.getName()+"'age is 16");modify($a){setAge(25)}
endrule "Age 25"
when$a : Person(age == 25)
thenSystem.out.println($a.getName()+"'age is 25");modify($a){setAge(17)}
end

在这个规则文件里,我们特意指定fact进行更新,看看stateless session会不会处理这种状况。执行结果:

可以看到stateless session仍然正确处理了中间的fact变化,结果其实和stateful session是一样的,stateless session只是在你第二次调execute时不会和第一次调execute有关联。

2 insert()和insertLogical()的区别

2.1 Inference

在Drools规则语法中,insert操作的目的是为了进行推断(inference),即根据已有fact推断一些中间fact,由此进一步的决定action。站在程序员的角度,其实就相当于生成中间变量。例如我们现在要删选出名为Tom的child,我们可以这样写规则:

rule "A child named Tom"
when:$p : Person(name=="Tom",age<18)
thenSystem.out.println("The child Tom is here");
end

这个规则的condition里有age和name两个判断条件,这样写在这个例子没问题,但是如果考虑规模的提升和后期的维护,我们应该拆成两个condition,那么我们就可以用insert在执行过程中生成中间fact。我们像下面这样写规则,注意IsChild我们同样需要在引擎外定义好。

rule "Age < 18"
when$p : Person(age < 18)
theninsert(new IsChild($p));System.out.println($p.getName()+" is a child");
endrule "Name is Tom"
when:$p : Person(name=="Tom")IsChild(person==$p)
thenSystem.out.println("The child Tom is here");
end

2.2 insertLogical

简单情况下,用insert就足够了,但更多的情况下应该用insertLogical方法。我们看看官网的说明:insertLogical执行逻辑插入操作,通过Drools内置的truth maintenance手段,当逻辑插入的fact不再满足规则的条件时将自动撤销(retracted)。依旧有点难以理解,而且如果你自己写demo测试的话很多时候用insertLogical和insert的结果是一样的。按照我的理解,这两者的关键区别是在是否自动撤销,也就是说用insert插入到Working memory的fact,除非你手动撤销,不然的话是一直存在的,你在更新一个fact后,更新前的状态仍然存在;而insertLogical则会自动撤销掉所有不满足规则条件的fact。
我们先用insert写个这样的规则,在判断person是child还是adult后插入一个IsChild或者IsAdult的fact,接着判断当前空间是否存在IsChild。先定义好IsChild和IsAdult类:

public class IsChild {private Person person;public IsChild(Person person){this.person=person;}public Person getPerson() {return person;}public void setPerson(Person person) {this.person = person;}
}
public class IsAdult {private Person person;public IsAdult(Person person){this.person=person;}public Person getPerson() {return person;}public void setPerson(Person person) {this.person = person;}
}

规则文件:

rule "Age < 18"
when$p : Person(age < 18)
theninsert(new IsChild($p));System.out.println($p.getName()+" is a child");
endrule "Age >= 18"
when$p : Person(age >= 18)
theninsert(new IsAdult($p));System.out.println($p.getName()+" is a adult");
endrule "no child fact now"
whennot(IsChild())
thenSystem.out.println("There is no child fact now");
end

然后我们输入一个16岁的person,执行后再更新成25岁再次执行:

KieServices kieServices = KieServices.Factory.get();
KieContainer kContainer = kieServices.getKieClasspathContainer();
KieSession kSession = kContainer.newKieSession("insertTest");Person p1 = new Person("Tom", 16);FactHandle factHandle=kSession.insert(p1);
kSession.fireAllRules();p1.setAge(25);
kSession.update(factHandle, p1,"age");
kSession.fireAllRules();

可以看到运行的结果没有符合我们的预期,明明Tom的年龄更新成了25岁,引擎却没有输出"There is no child fact now",也就是说仍然有IsChild的fact存在
我们再用insertLogicl重写下规则:

rule "Age < 18"
when$p : Person(age < 18)
theninsertLogical(new IsChild($p));System.out.println($p.getName()+" is a child");
endrule "Age >= 18"
when$p : Person(age >= 18)
theninsertLogical(new IsAdult($p));System.out.println($p.getName()+" is a adult");
endrule "no child fact now"
whennot(IsChild())
thenSystem.out.println("There is no child fact now");
end

同样的主程序运行一遍,其效果如下:

可见逻辑插入会自动撤销掉IsChild的fact,其结果符合我们的预期。

Drool学习记录(二) Kie Session、Truth maintenance相关推荐

  1. MySQL学习记录 (二) ----- SQL数据查询语句(DQL)

    相关文章: <MySQL学习记录 (一) ----- 有关数据库的基本概念和MySQL常用命令> <MySQL学习记录 (二) ----- SQL数据查询语句(DQL)> &l ...

  2. Android动画学习记录二(属性动画、估值器和插值器)

    Android动画学习记录二(属性动画.估值期和插值器) Android动画学习记录二(属性动画.估值期和插值器) Android动画学习记录二(属性动画.估值期和插值器) 一.补间动画缺陷 二.属性 ...

  3. HTML学习记录二:html标签(五):超链接标签

    HTML学习记录二:html标签(五):超链接标签 一.超链接标签写法 二.超链接标签的属性 三.超链接的锚点用法 四.链接分类 一.超链接标签写法 在 HTML 标签中, 标签用于定义超链接,作用是 ...

  4. 大数据之spark学习记录二: Spark的安装与上手

    大数据之spark学习记录二: Spark的安装与上手 文章目录 大数据之spark学习记录二: Spark的安装与上手 Spark安装 本地模式 Standalone 模式 基本配置 步骤1: 复制 ...

  5. [大数据技术与应用省赛学习记录二]——模块一(HADOOP完全分布式集群搭建)

    **在操作前,先梳理一下HADOOP完全分布式需要做些什么,不然像无头的苍蝇一样,永远不知道做什么.因为我本人比赛是一台服务器Centos 7,与三台客户端Ubuntu 18.04,所以以物理机的角度 ...

  6. Openzeppelin学习记录二:utils模块(SafeMath.sol+SafeCast.sol)

    Openzeppelin学习记录一:access模块(AccessControl.sol+Ownable.sol) Openzeppelin学习记录 2.Utils 2.1 Math 2.2 Safe ...

  7. UE4 学习记录二 给角色添加骨架,皮肤,及运动动画

    这只是用来记录我学习UE4过程的,可能帮不到你,先说声抱歉.为了防止误导他人,请勿转载,请勿转载,请勿转载. 本文的主题是给角色添加骨架.皮肤.运动动动画.总章目录(https://blog.csdn ...

  8. Hibernate学习笔记二:Session

    Session概述 Session是Hibernate提供的最主要的接口,它提供了基本的保存, 更新, 删除和加载 Java 对象的方法. Session 具有一个缓存, 位于缓存中的对象称为持久化对 ...

  9. 项目管理概述学习记录(二)

    1.      为什么需要项目管理 项目管理可以带来下面的优势,也确保了项目可以按时按需完成: ⑴合理安排项目的进度,有效使用项目资源,确保项目能够按期完成,并降低项目成本.通过项目管理中的工作分解结 ...

  10. 【java并发编程艺术学习】(四)第二章 java并发机制的底层实现原理 学习记录(二) synchronized...

    章节介绍 本章节主要学习 Java SE 1.6 中为了减少获得锁 和 释放锁 时带来的性能消耗 而引入的偏向锁 和 轻量级锁,以及锁的存储结构 和 升级过程. synchronized实现同步的基础 ...

最新文章

  1. 条件注释判断浏览器!--[if !IE]!--[if IE]!--[if lt IE 6]!--[if gte IE 6]
  2. 如何利用遗传算法进行自变量降维
  3. LINUX上MYSQL优化三板斧
  4. 十分流行的自举法(Bootstrapping )为什么有效
  5. iptables防DDOS***和CC***设置
  6. 4、Python —— 函数
  7. 网易云推出了一组程序猿の真实写照【文末有彩蛋】
  8. window.showModalDialog介绍
  9. 出现这些迹象,说明你面试可能没戏了
  10. Appium安装过程
  11. python设计模式12-代理模式
  12. 2013年云计算发展展望:混合云即将起飞
  13. vue把jade转换为html,vue 使用Jade模板写html,stylus写css的方法
  14. STM32—TIMx输出PWM信号驱动MG996R舵机
  15. codeforces_946D_Timetable(分组背包)
  16. (三)Android系统启动流程
  17. 群晖Docker部署Microsoft SQL Server 2019
  18. python多维数组分位数的求取
  19. RuoYi-Vue部署服务器流程
  20. WebView-WebView状态和加载方式

热门文章

  1. 卸载不了mysql2008_卸载SQL2008遇到的问题及解决办法
  2. 【Pygame实战】怀旧经典—这款给娃的棋类游戏,你还记得叫什么吧?(一定要收藏)
  3. 马踏棋盘(骑士周游问题)
  4. 图书管理系统/库存管理系统等计算机毕业论文设计
  5. 屏幕分辨率修改工具SwitchResX for Mac
  6. Android使用keytool-importkeypair生成系统签名
  7. 机器人技术基础pdf
  8. chrome升级后无高级-断续访问
  9. 实验第七节——用户chaincode相关操作
  10. 3DS更新R4烧录卡内核