一、背景

我们知道在drools中是存在工作内存的,我们的Fact对象会加入到工作内存中,同时我们自己也可以在drl文件中使用insert/modify/update/delete等方法,修改工作内存中对象的,那么我们怎么查询修改之后的工作内存的值呢?而droolsquery可以帮助我们实现这个功能。

二、需求

1、无参数query的使用

2、有参数query的使用

3、java代码中openLiveQuery的使用

4、rule中使用query

三、前置需求

1、query的语法结构

query queryName(参数列表)

end

注意事项:

  1. query的名字在同一个KIE base的所有包中必须要唯一,一般情况下我们全局唯一即可。
  2. query没有whenthen的部分

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的使用的更多相关文章

  1. (转载)MongoDB C#驱动中Query几个方法

    MongoDB C#驱动中Query几个方法 Query.All("name", "a", "b");//通过多个元素来匹配数组 Query ...

  2. 使用JPA中@Query 注解实现update 操作

    spring使用jpa进行update操作主要有两种方式: 1.调用保存实体的方法 1)保存一个实体:repository.save(T entity) 2)保存多个实体:repository.sav ...

  3. 【hql】spring data jpa中 @Query使用hql查询 问题

    spring data jpa中 @Query使用hql查询 问题 使用hql查询, 1.from后面跟的是实体类 不是数据表名 2.字段应该用实体类中的字段 而不是数据表中的属性 实体如下 hql使 ...

  4. drools中Fact的equality modes

    一.equality modes介绍 在drools中存在如下2种equality modes. 1.identity模式 identity:这是默认的情况.drools引擎使用IdentityHas ...

  5. drools中的条件 when

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

  6. 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. ...

  7. Elasticsearch DSL中Query与Filter的不同

    Elasticsearch支持很多查询方式,其中一种就是DSL,它是把请求写在JSON里面,然后进行相关的查询. 举个DSL例子 GET _search { "query": { ...

  8. MongoDB C#驱动中Query几个方法 (转)

    Query.All("name", "a", "b");//通过多个元素来匹配数组 Query.And(Query.EQ("nam ...

  9. hibernate中Query的list和iterator区别(续)

    打开cache后query的list和iterator方法区别 将query 的cache打开的话,缓存的是query本身,以hql 生成的 sql ,再加上参数,分页等信息做为key值,而不是que ...

随机推荐

  1. Tcp三次握手四次挥手个人学习

    最近想跳槽,学习了tcp中的三次握手与四次挥手,特意记录下,加深记忆 SYN 代表请求创建连接 FIN 表示请求关闭连接 ACK 代表确认接受,不管是三次握手还是四次分手,在回应的时候都会加上ACK= ...

  2. 原来 flexbox 是这么工作的

    Flexbox 是一种 CSS 布局机制,可以说是目前浏览器原生支持的最好.使用最广泛的布局机制了.本文通过一些例子来说明 Flexbox 布局的工作原理,可以让我们更好的使用 Flexbox. 与 ...

  3. 【Flutter】Flutter C/C++ 插件的开发 (支持 windows、macos、ios、android )

    一个各平台调用 C/C++ 源码的例子,如何共享代码,配置相关的编译 官方的例子:https://docs.flutter.dev/development/platform-integration/c ...

  4. 告别尬聊,解锁秀场+社交新玩法(内含源码+Demo)

    直播已成为用户的生活习惯之一 艾媒咨询数据显示:2021年直播用户规模达到6.35亿人,在线直播用户以年轻群体为主,24岁及以下用户占比49%,30岁以下用户接近8成. 众所周知,Z世代用户是一个社交 ...

  5. jquery+html5实现单张图片上传预览

    js: if (window.File && window.FileReader && window.FileList && window.Blob){ ...

  6. 纯JS实现KeyboardNav(学习笔记)二

    纯JS实现KeyboardNav(学习笔记)二 这篇博客只是自己的学习笔记,供日后复习所用,没有经过精心排版,也没有按逻辑编写 这篇主要是添加css,优化js编写逻辑和代码排版 GitHub项目源码 ...

  7. ubantu系统之安装notepadqq

    Ubuntu下的安装方法:     sudo add-apt-repository ppa:notepadqq-team/notepadqq     sudo apt-get update     s ...

  8. DB2表数据导出、导入及常用sql使用总结

      一.DB2数据的导出: export to [path(例:D:"TABLE1.ixf)]of ixf select [字段(例: * or col1,col2,col3)] from ...

  9. 关于json对象的使用小结!

    json是前后端数据交互的关键.后端提供的接口中的数据几乎都是通过json来表现的,所以,需要对这个json做一些小结: 这里要推进谷歌的插件Fehelp前端助手,这个可以清楚的看到json的数据: ...

  10. Windows中Nginx配置nginx.conf不生效解决方法(路径映射)

    Windows中Nginx配置nginx.conf不生效解决方法 今天在做Nginx项目的时候,要处理一个路径映射问题, location /evaluate/ { proxy_pass http:/ ...