drools中query的用法小结(drools query)

网友投稿 238 2022-07-29


目录一、背景二、需求三、前置需求1、query的语法结构2、java中如何获取query的结果四、实现1、无参数query的使用1、drl文件编写2、java文件编写2、有参数query的使用1、drl文件编写2、java文件编写3、java代码中openLiveQuery的使用1、drl文件编写2、java文件编写3、输出结果4、rule中使用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/drooZoQhtUls-drl-query

六、参考链接

1、https://docs.drools.org/7.69.0.Final/drools-docs/html_single/index.html#drl-queries-con_drl-rules


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java细数IO流底层原理到方法使用
下一篇:SpringBoot通过AOP与注解实现入参校验详情(springboot aop注解)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~