drools中query的使用
一、背景
我们知道在drools中是存在工作内存的,我们的Fact对象会加入到工作内存中,同时我们自己也可以在drl文件中使用insert/modify/update/delete等方法,修改工作内存中对象的,那么我们怎么查询修改之后的工作内存的值呢?而drools的query可以帮助我们实现这个功能。
二、需求
1、无参数query的使用
2、有参数query的使用
3、java代码中openLiveQuery的使用
4、rule中使用query
三、前置需求
1、query的语法结构

query queryName(参数列表)
end
注意事项:
query的名字在同一个KIE base的所有包中必须要唯一,一般情况下我们全局唯一即可。query没有when和then的部分
2、java中如何获取query的结果
1、通过getQueryResults获取
QueryResults queryResults = kieSession.getQueryResults("query的名字",可选参数类表);
通过这种方式getQueryResults获取到的结果只会获取一次,如果工作内存中的数据发生了变化,则不会自动感知到。
2、通过openLiveQuery获取
kieSession.openLiveQuery("query的名字", new Object[]{可选参数}, new ViewChangedEventListener() {
@Override
public void rowInserted(Row row) {}
@Override
public void rowDeleted(Row row) { }
@Override
public void rowUpdated(Row row) {}
});
通过这种方式openLiveQuery是可以实时获取到结果的,当工作内存中的数据发生变化,这个地方是可以感知到的。
四、实现
此处只列出部分核心代码,一些无关的代码不列出。
1、无参数query的使用
1、drl文件编写
// 不带参数的查询
query "query01"
// 注意这个地方的 $p,java代码中需要用到
$p: Person(age < 18)
end
2、java文件编写
// 不带参数的query查询
QueryResults queryResults = kieSession.getQueryResults("query01");
queryResults.iterator().forEachRemaining(row -> {
// 那么这个地方的 $p 是怎么来的呢?其实是我们自己编写的drl query中写的
Person person = (Person) row.get("$p");
log.info("query01从工作内存中获取的query: {}", person);
});
2、有参数query的使用
1、drl文件编写
// 带参数的查询
query query02(Integer $age)
$p: Person(age < $age)
end
2、java文件编写
// 不带参数的query查询
// 带参数的query查询
queryResults = kieSession.getQueryResults("query02", 20);
queryResults.iterator().forEachRemaining(row -> {
Person person = (Person) row.get("$p");
log.info("query02从工作内存中获取的query: {}", person);
});
3、java代码中openLiveQuery的使用
1、drl文件编写
// 带参数的查询-查询工作内存Person对象的age的值小于外部传递进来的$age值
query query02(Integer $age)
$p: Person(age < $age)
end
// 定义一个规则,当规则内存中的Person的age小于18时,直接年龄+1
rule "rule_test_live_query_in_java"
no-loop true
when
$p: Person($age:age < 18)
then
modify($p){
// 此处修改了工作内存中age对象的值
setAge($p.getAge() + 1)
}
System.out.println("更新来规则内存中Person["+$p.getName()+"]的age:["+$p.getAge()+"]值");
end
解释:
1、定义查询query02查询工作内存中的对象。
2、rule_test_live_query_in_java里面存在一个 modify($p) 这个操作会导致更新工作内存中对象的值。
3、no-loop true表达的是当前规则是否可以多次执行,就我们定义的这个规则,如果修改后的age<18那么可能还会导致规则的重新出发,加了no-loop true则只会触发一次。
2、java文件编写
public static void main(String[] args) {
KieServices kieServices = KieServices.get();
KieContainer kieContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieContainer.newKieSession("query-ksession");
kieSession.addEventListener(new DebugRuleRuntimeEventListener());
kieSession.addEventListener(new DebugAgendaEventListener());
kieSession.addEventListener(new DebugProcessEventListener());
// 实时查询
kieSession.openLiveQuery("query02", new Object[]{20}, new ViewChangedEventListener() {
@Override
public void rowInserted(Row row) {
Person person = (Person) row.get("$p");
log.info("实时查询-query02向工作内存中插入Person: {}", person);
}
@Override
public void rowDeleted(Row row) {
Person person = (Person) row.get("$p");
log.info("实时查询-query02向工作内存中删除Person: {}", person);
}
@Override
public void rowUpdated(Row row) {
Person person = (Person) row.get("$p");
log.info("实时查询-query02向工作内存中更新Person: {}", person);
}
});
Person person1 = new Person("张三", 16);
kieSession.insert(person1);
kieSession.fireAllRules();
kieSession.dispose();
}
解释:
1、此处先使用了openLiveQuery查询。
2、让后向工作内存中insert(person1),并且触发了所有的规则fireAllRules。
3、输出结果
10:08:54.415 [main] INFO com.huan.drools.querys.DroolsLiveQueryApplication - 实时查询-query02向工作内存中插入Person: Person(name=张三, age=16)
更新来规则内存中Person[张三]的age:[17]值
10:08:54.420 [main] INFO com.huan.drools.querys.DroolsLiveQueryApplication - 实时查询-query02向工作内存中更新Person: Person(name=张三, age=17)
可以看到,openLiveQuery实时查询到了工作内存中变更的对象。
4、rule中使用query
drl文件编写
// 定义一个查询,Person#name 需要以$prefix开头
query personNameStartsWith(String $prefix)
Person(name.startsWith($prefix))
end
rule "rule_person_name_starts_with"
when
$p: Person($age:age < 18)
personNameStartsWith("张";) // 此处多个参数使用 , 分割,并且最后必须以 ; 结尾
then
System.out.println("在rule中使用query");
end
如果出现了如下异常Query's must use positional or bindings, not field constraints: "张" : [Rule name='rule_person_name_starts_with'],这个是因为我们在rule中调用query时,参数没有以;结尾。正确用法personNameStartsWith("张";)
?personNameStartsWith("张";) 和 personNameStartsWith("张";)是不一样的。The ? symbol means the query is pull only, once the results are returned you will not receive further results as the underlying data changes
五、完整代码
https://gitee.com/huan1993/spring-cloud-parent/tree/master/drools/drools-drl-query
六、参考链接
1、https://docs.drools.org/7.69.0.Final/drools-docs/html_single/index.html#drl-queries-con_drl-rules
drools中query的使用的更多相关文章
- (转载)MongoDB C#驱动中Query几个方法
MongoDB C#驱动中Query几个方法 Query.All("name", "a", "b");//通过多个元素来匹配数组 Query ...
- 使用JPA中@Query 注解实现update 操作
spring使用jpa进行update操作主要有两种方式: 1.调用保存实体的方法 1)保存一个实体:repository.save(T entity) 2)保存多个实体:repository.sav ...
- 【hql】spring data jpa中 @Query使用hql查询 问题
spring data jpa中 @Query使用hql查询 问题 使用hql查询, 1.from后面跟的是实体类 不是数据表名 2.字段应该用实体类中的字段 而不是数据表中的属性 实体如下 hql使 ...
- drools中Fact的equality modes
一.equality modes介绍 在drools中存在如下2种equality modes. 1.identity模式 identity:这是默认的情况.drools引擎使用IdentityHas ...
- drools中的条件 when
目录 1.介绍 2.语法结构 3.模式例子 3.1 单个对象匹配 3.2 匹配任何对象 3.3 带条件匹配 3.3.1 注意事项 3.4 嵌套属性的匹配 3.4.1 访问单个嵌套属性 3.4.2 访问 ...
- drools中then部分的写法
目录 1.背景 2.支持的方法 2.1 insert 插入对象到工作内存中 2.1.1 需求 2.1.2 drl文件编写 2.1.3 部分java代码编写 2.1.4 运行结果 2.1.5 结论 2. ...
- Elasticsearch DSL中Query与Filter的不同
Elasticsearch支持很多查询方式,其中一种就是DSL,它是把请求写在JSON里面,然后进行相关的查询. 举个DSL例子 GET _search { "query": { ...
- MongoDB C#驱动中Query几个方法 (转)
Query.All("name", "a", "b");//通过多个元素来匹配数组 Query.And(Query.EQ("nam ...
- hibernate中Query的list和iterator区别(续)
打开cache后query的list和iterator方法区别 将query 的cache打开的话,缓存的是query本身,以hql 生成的 sql ,再加上参数,分页等信息做为key值,而不是que ...
随机推荐
- stm32 中库函数、结构体、地址的强制类型转换、相应特殊功能寄存器之间的关系
以一个挂接在APB2上的外设函数使能为例 A : RCC_APB2PeriphClockCmd():时钟使能函数 1 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFI ...
- python学习笔记(六)——程序调试
在我们平时编写程序时,常常会遇到各种错误,俗称BUG.而我们程序猿的工作常常需要对程序进行调试,也就是所谓的debug. 程序调试是将编制的程序投入实际运行前,用手工或编译程序等方法进行测试,修正语法 ...
- c++中的左值和右值的理解
1.左值和右值的概念 C++中左值(lvalue)和右值(rvalue)是比较基础的概念,虽然平常几乎用不到,但C++11之后变得十分重要,它是理解 move/forward 等新语义的基础. 左值与 ...
- vue重构--H5--canvas实现粒子时钟
上一篇文章讲解了如何用js+canvas实现粒子时钟,本篇文章 ,主要是使用vue重构,让它在vue也能使用. 我们使用简单的方式重构,不使用vue工程,先加入vue cdn的地址,如下: <s ...
- 关于表达式&& 和 || 有多项的时候的取值
&& 表达式只有两项的时候,如果表达式为false, 返回为false 的那一个 ,为true的时候 返回最后一个值 || 只有两项的时候,返回为true 的那一个;都为fal ...
- 耗时一个月上架了一款微信小程序,赚了2022年的第一笔副收入
今天不谈技术,只谈经历. 前戏 相信有很多的程序员都有一个产品梦,希望有一款属于自己产品.毕竟工作中遇到的有些"脑残"的产品经理不是一个两个,最后不得不因为"技术服务于业 ...
- Android实现秒开效果
0x01 创建SplashActivity 新建一个Activity,取名为SplashActivity 0x02 新建资源 在res/drawable下新建一个splash.xml文件和名为ig_s ...
- Spring相关的API-ApplicationContext
1.ClassPathXmlApplicationContext 它是从类的根路径下加载配置文件推荐使用这种 public class UserController { public static v ...
- java_抽象类和接口
1.抽象类: 1.抽象类之所以被称为抽象类,就是因为它包含有抽象方法,只要含有抽象方法的类就叫抽象类. 2.抽象类中可以没有抽象方法,也可以抽象方法和非抽象方法共存. 3.抽象类和类一样是单继承的. ...
- netty系列之:java中的base64编码器
简介 什么是Base64编码呢?在回答这个问题之前,我们需要了解一下计算机中文件的分类,对于计算机来说文件可以分为两类,一类是文本文件,一类是二进制文件. 对于二进制文件来说,其内容是用二进制来表示的 ...