Drool学习记录(二) Kie Session、Truth maintenance

article/2025/9/8 18:07:39

参考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();

运行结果
6.PNG
所以在一个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);

7.PNG
你可能会问为什么我没有在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会不会处理这种状况。执行结果:
8.PNG
可以看到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();

9.PNG

可以看到运行的结果没有符合我们的预期,明明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

同样的主程序运行一遍,其效果如下:
10.PNG
可见逻辑插入会自动撤销掉IsChild的fact,其结果符合我们的预期。


http://chatgpt.dhexx.cn/article/VpeCEWBK.shtml

相关文章

drool 7.x 属性 : no-loop

drool 7.x 属性 : no-loop 测试类参考:https://blog.csdn.net/qq_21383435/article/details/82872537 实体类:com.secbro.drools.model.Product 规则:/Users/lcc/IdeaProjects/AllTest/drools_test7/src/main/resources/rules.blog/noLoopSession.drl package rules.blogim…

Drool实战系列(一)之入门程序

Drools官网地址为:https://www.drools.org/ maven环境 入门程序例子如下: 项目结构截图: 一、导入pom文件 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation"http://…

drool 7.x 属性:duration

规则 package com.rulesimport entity.Pingdeclare Ping@role(event) // 要把插入的数据声明为event,默认是fact,@expires(20s) // 用来显示设置事件的过期时间,也就是说过了这个时间,该事件就会从会话中移除,不能再使用 endrule "testComplexEvent1"du…

drool-6.5的自学demo

先丢代码地址 https://gitee.com/a247292980/drools 再丢pom.xml <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://maven…

Drool学习记录(一) 概念、Helloworld

1 关于规则引擎 基于知识库和规则的专家系统是早期最主流的人工智能&#xff0c;不同于现在流行的基于统计、机器学习的智能算法&#xff0c;基于规则的算法相对来说更加直观和易于理解&#xff0c;毕竟如果简单理解的话&#xff0c;就是定义好了If-Than结构&#xff0c;从而让…

LiteFlow vs Drool的规则引擎深度对比

规则引擎的定义 两款框架的异同点 规则表达式 和Java的数据交换 API以及集成 侵入性耦合比较 规则的学习成本 是否有语言插件 规则的存储 规则的变更能否实时改变逻辑 是否有界面形态来支持 框架的性能表现 结语 Drools是一款老牌的java规则引擎框架&#xff0c;早…

Drools概述和基本原理

目录 ​编辑 一、Drools是什么&#xff1f; 二、Drools使用场景 三、Drool架构内容 3.1 总体架构 3.2 构成内容说明 3.2.1 Rules 3.2.2 Production memory 3.2.3 Facts 3.2.4 Working memory 3.2.5 Pattern matcher 3.2.6 Agenda 四、为什么要用规则引擎&#xff1f; 4.1 声明…

Uipath Workbook与Excel差别

学习目标&#xff1a; 了解Uipath Workbook与Excel 两组差别 Workbook 使用Workbook: 1.所有工作簿活动都将在后台执行。 2.不需要安装Microsoft Excel&#xff0c;只需在Excel应用程序中不打开文件&#xff0c;就可以更快、更可靠地进行某些操作。 3.仅适用于.xls和.xlsx文件…

Workbook.SaveAs方法

Workbook.SaveAs(FileName, FileFormat, Password, WriteResPassword, ReadOnlyRecommended, CreateBackup, AccessMode, ConflictResolution, AddToMru, TextCodepage, TextVisualLayout, Local) excel vba 保存代码 Sub 保存工作簿() ThisWorkbook.Save .save相当于按…

Workbook

工作需要。话不多说。 我们来看传统的poi。使用HSSFWorkbook创建2003格式为xls后缀的文档。如下&#xff1a; [html] view plain copy public String toTotal() { String strs "40288b163a72fd15013a730d44430004,40288b163a72fd15013a730d44430004," &q…

excel workbook

引用不同的workbook 1.索引号 workbooks.item&#xff08;3&#xff09;workbooks&#xff08;3&#xff09; 2.名称 当新建的文件&#xff0c;并没有保存的时候 workbooks(“book1”) 当已经存在的文件&#xff0c;要加上后缀 workbooks(“book1.xls”) workbook信息 cell…

UserWarning: Workbook contains no default style, apply openpyxl‘s default warn no default style 解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。 本文主要介绍了UserWarning: W…

VBA基础,工作簿workbook相关的方法和属性

0 我觉得VBA和VB,VBS最大的区别就在A&#xff08;application&#xff09;上了 所以application里的 workbook , worksheet range ,cell等应该是VBA语言的核心&#xff0c;最复杂内容了 本身VBA里的VB语言部分&#xff0c;其实和很多语言语法结构也差不多每种语言的差别一在…

Python操作excel文件创建workbook和批量创建Sheet

第一步&#xff0c;创建workbook和sheet from openpyxl import WorkbookwbWorkbook() wb.create_sheet(index1,title"sheet2")wb.save(test1.xlsx)创建成功&#xff0c;workbook 名称test1&#xff0c;有sheet 和sheet2两张表 第二步&#xff0c;批量创建多个sheet …

SpringBoot使用Workbook读取excel中内容

SpringBoot使用Workbook读取excel中内容 maven文件中导入依赖 获取excel文件 FileInputStream fileInputStream new FileInputStream("文件路径");获取Workbook对象 Workbook workbook new XSSFWorkbook(fileInputStream);获取Sheet对象 Sheet sheet workbook.…

已解决ModuleNotFoundError: No module named ‘Workbook‘

已解决&#xff08;python xlwt库写入Excel表格报错&#xff09;ModuleNotFoundError: No module named ‘Workbook‘ 文章目录 报错代码报错翻译报错原因解决方法千人全栈VIP答疑群联系博主帮忙解决报错 报错代码 粉丝群里的一个小伙伴&#xff0c;想用xlwt库写入Excel表格的…

【干货】Python:load_workbook用法(持续更新)

【干货】Python中load_workbook用法&#xff08;持续更新&#xff09; 功能方法示例文件模块读取导入excel表格获取Sheet查看行与列查看单元格批量访问数据 功能 读取excel文件&#xff0c;并进行操作 方法 示例文件 本文用到的示例文件为一个excel表格&#xff0c;含有名为…

【Python_笔记】openpyxl中Workbook()和.load_workbook()区别

记录学习旅程~ 欢迎各位道友指教与交流~ 准备开始实操时发现一个问题&#xff0c;即Workbook()是创建一个类对象&#xff0c;而load_workbook()是一个方法加载存在的excel。 由于在学习openpyxl时吸取了不同教程&#xff0c;按照读取→编辑→再编辑→保存的逻辑列举了常用的基…

POI(excel)中WorkBook和Sheet应用实践总结

WorkBook定义 工作簿的高级表现形式&#xff0c;是sheet的上级对象。一个excel就是一个工作簿&#xff0c;一个工作簿含有多个工作表(sheet)。 【1】WorkBook两种创建形式 ① 使用直接对象 // 03版本 .xls org.apache.poi.hssf.usermodel.HSSFWorkbook or //07版本 .xls…