关于java:drools中query的使用

一、背景

咱们晓得在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

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理