一、背景

我们知道在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. stm32 中库函数、结构体、地址的强制类型转换、相应特殊功能寄存器之间的关系

    以一个挂接在APB2上的外设函数使能为例 A : RCC_APB2PeriphClockCmd():时钟使能函数 1 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFI ...

  2. python学习笔记(六)——程序调试

    在我们平时编写程序时,常常会遇到各种错误,俗称BUG.而我们程序猿的工作常常需要对程序进行调试,也就是所谓的debug. 程序调试是将编制的程序投入实际运行前,用手工或编译程序等方法进行测试,修正语法 ...

  3. c++中的左值和右值的理解

    1.左值和右值的概念 C++中左值(lvalue)和右值(rvalue)是比较基础的概念,虽然平常几乎用不到,但C++11之后变得十分重要,它是理解 move/forward 等新语义的基础. 左值与 ...

  4. vue重构--H5--canvas实现粒子时钟

    上一篇文章讲解了如何用js+canvas实现粒子时钟,本篇文章 ,主要是使用vue重构,让它在vue也能使用. 我们使用简单的方式重构,不使用vue工程,先加入vue cdn的地址,如下: <s ...

  5. 关于表达式&& 和 || 有多项的时候的取值

    && 表达式只有两项的时候,如果表达式为false, 返回为false 的那一个 ,为true的时候    返回最后一个值 ||  只有两项的时候,返回为true 的那一个;都为fal ...

  6. 耗时一个月上架了一款微信小程序,赚了2022年的第一笔副收入

    今天不谈技术,只谈经历. 前戏 相信有很多的程序员都有一个产品梦,希望有一款属于自己产品.毕竟工作中遇到的有些"脑残"的产品经理不是一个两个,最后不得不因为"技术服务于业 ...

  7. Android实现秒开效果

    0x01 创建SplashActivity 新建一个Activity,取名为SplashActivity 0x02 新建资源 在res/drawable下新建一个splash.xml文件和名为ig_s ...

  8. Spring相关的API-ApplicationContext

    1.ClassPathXmlApplicationContext 它是从类的根路径下加载配置文件推荐使用这种 public class UserController { public static v ...

  9. java_抽象类和接口

    1.抽象类: 1.抽象类之所以被称为抽象类,就是因为它包含有抽象方法,只要含有抽象方法的类就叫抽象类. 2.抽象类中可以没有抽象方法,也可以抽象方法和非抽象方法共存. 3.抽象类和类一样是单继承的. ...

  10. netty系列之:java中的base64编码器

    简介 什么是Base64编码呢?在回答这个问题之前,我们需要了解一下计算机中文件的分类,对于计算机来说文件可以分为两类,一类是文本文件,一类是二进制文件. 对于二进制文件来说,其内容是用二进制来表示的 ...