美文网首页
DROOLS RULE基础知识学习整理

DROOLS RULE基础知识学习整理

作者: RyanLee_ | 来源:发表于2018-08-01 14:37 被阅读697次

    对于Drools Rule的理解

    一个规则可以包含三个部分:

    • 属性部分:定义当前规则执行的一些属性等,比如是否可被重复执行、过期时间、生效时间等。
    • 条件部分(LHS):定义当前规则的条件,如 when Message(); 判断当前workingMemory中是否存在Message对象。
    • 结果部分(RHS):这里可以写普通java代码,即当前规则条件满足后执行的操作,可以直接调用Fact对象的方法来操作应用。

    属性部分:

    规则的属性有以下几种

    activation-group、agenda-group、auto-focus、date-effective、date-expires、dialect、duration、duration-value、enabled、lock-on-active、no-loop、ruleflow-group、salience

    几个重要的属性:

    • activation-group

    该属性的作用是将若干个规则划分成一个组,用一个字符串来给这个组命名,这样在执行的时候,具有相同activation-group 属性的规则中只要有一个会被执行,其它的规则都将不再执行。也就是说,在一组具有相同activation-group 属性的规则当中,只有一个规则会被执行,其它规则都将不会被执行。

    • auto-focus

    用来在已设置了agenda-group 的规则上设置该规则是否可以自动独取Focus,如果该属性设置为true,那么在引擎执行时,就不需要显示的为某个Agenda Group 设置Focus,否则需要。对于规则的执行的控制,还可以使用Agenda Filter 来实现。在Drools 当中,提供了一个名为org.drools.runtime.rule.AgendaFilter 的Agenda Filter 接口,用户可以实现该接口,通过规则当中的某些属性来控制规则要不要执行。org.drools.runtime.rule.AgendaFilter 接口只有一个方法需要实现,方法体如下: public boolean accept(Activation activation); 在该方法当中提供了一个Activation 参数,通过该参数我们可以得到当前正在执行的规则对象或其它一些属性,该方法要返回一个布尔值,该布尔值就决定了要不要执行当前这个规则,返回true 就执行规则,否则就不执行
    与agenda-group配合使用,设置焦点的是否可以自动获取boolean型,默认值为false

    • agenda-group

    Agenda Group 是用来在Agenda 的基础之上,对现在的规则进行再次分组,具体的分组方法可以采用为规则添加agenda-group 属性来实现。agenda-group 属性的值也是一个字符串,通过这个字符串,可以将规则分为若干个Agenda Group,默认情况下,引擎在调用这些设置了agenda-group 属性的规则的时候需要显示的指定某个Agenda Group 得到Focus(焦点),这样位于该Agenda Group 当中的规则才会触发执行,否则将不执行
    基于Agenda将规则分组;只有当某个Agenda组获取到焦点(focus)时,该组的规则才会被执行string型,默认值为MAIN

    规则的调用与执行是通过StatelessSession 或StatefulSession 来实现的,一般的顺序是创建一个StatelessSession 或StatefulSession,将各种经过编译的规则的package 添加到session当中,接下来将规则当中可能用到的Global 对象和Fact 对象插入到Session 当中,最后调用fireAllRules 方法来触发、执行规则。在没有调用最后一步fireAllRules 方法之前,所有的规则及插入的Fact 对象都存放在一个名叫Agenda 表的对象当中,这个Agenda 表中每一个规则及与其匹配相关业务数据叫做Activation,在调用fireAllRules 方法后,这些Activation 会依次执行,这些位于Agenda 表中的Activation 的执行顺序在没有设置相关用来控制顺序的属性时(比如salience 属性),它的执行顺序是随机的,不确定的。

    • no-loop

    drools提供了一些api,可以对当前传入workingMemory中的Fact对象进行修改或者个数的增减,比如上述的update方法,就是将当前的workingMemory中的Message类型的Fact对象进行属性更新,这种操作会触发规则的重新匹配执行,可以理解为Fact对象更新了,所以规则需要重新匹配一遍。update之后,之前的修改都会生效。当然对Fact对象数据的修改并不是一定需要调用update才可以生效,简单的使用set方法设置就可以完成,这里类似于java的引用调用,所以何时使用update是一个需要仔细考虑的问题,一旦不慎,极有可能会造成规则的死循环。上述的no-loop true,即设置当前的规则,只执行一次,如果本身的RHS部分有update等触发规则重新执行的操作,也不要再次执行当前规则。

    • lock-on-active

    当在规则上使用ruleflow-group属性或agenda-group属性的时候,将lock-on-active 属性的值设置为true,可避免因某些Fact对象被修改而使已经执行过的规则再次被激活执行。可以看出该属性与no-loop属性有相似之处,no-loop属性是为了避免Fact被修改或调用了insert、retract、update之类的方法而导致本规则再次激活执行,这里的lock-on-active 属性起同样的作用,lock-on-active是no-loop的增强版属性,它主要作用在使用ruleflow-group属性或agenda-group属性的时候。lock-on-active属性默认值为false。与no-loop不同的是lock-on-active可以避免其他规则修改FACT对象导致规则的重新执行。

    • date-effective、date-expires、enabled

    顾名思义

    • salience

    它的作用是用来设置规则执行的优先级,salience 属性的值是一个数字,数字越大执行优先级越高,同时它的值可以是一个负数。默认情况下,规则的salience 默认值为0,所以如果我们不手动设置规则的salience 属性,那么它的执行顺序是随机的
    int型,默认值为0

    • rule-flow-group

    基于ruleflow将规则分组string型,无默认值,作用是用来将规则划分为一个个的组,然后在规则流当中通过使用ruleflow-group 属性的值,从而使用对应的规则
    作用等同于agenda-group。二选一即可

    • dialect:

    该属性用来定义规则当中要使用的语言类型,目前Drools支持两种语言:mvel 和java,默认使用的java 语言

    • duration:

    如果设置了该属性,那么规则将在该属性指定的值之后在另外一个线程里触发。该属性对应的值为一个长整型,单位是毫秒
    设置DRL文件开始执行之后延迟多长时间开始执行这条规则
    long型,无默认值

    条件部分(LHS)

    • when:规则条件开始。条件可以单个,也可以多个,多个条件一次排列,比如
    when
            eval(true)
            $customer:Customer()
            $message:Message(status==0)
    

    上述罗列了三个条件,当前规则只有在这三个条件都匹配的时候才会执行RHS部分。

    eval(true):是一个默认的api,true 无条件执行,类似于 while(true)

    $message:Message(status==0) 这句话标示的:当前的workingMemory存在Message类型并且status属性的值为0的Fact对象,这个对象通常是通过外部java代码插入或者在已执行规则的RHS部分中insert进去的。

    "$message"代表着当前条件的引用的Message实例。在后续的条件部分和RHS部分中,可以使用这个名称对该FACT对象进行修改或者调用其方法。可选。

    条件可以有组合,比如:
    Message(status==0 || (status > 1 && status <=100))

    如果条件全部是 &&关系,可以使用“,”来替代,但是两者不能混用

    • Drools提供了十二中类型比较操作符:

    > , >= , < , <= , == , !=
    contains / not contains / memberOf / not memberOf /matches/ not matches

    contains, not contains:顾名思义

    memberOf:判断某个Fact属性值是否在某个集合中。

    not memberOf:顾名思义

    matches:正则表达式匹配,与java不同的是,不用考虑'/'的转义问题

    not matches:顾名思义

    结果部分(RHS)

    当满足规则条件,则进入规则结果部分执行。
    RHS可以是纯java代码,比如:

    then
           System.out.println("OK"); //会在控制台打印出ok
    end
    

    RHS可以调用Fact的方法,比如

    $message.setXXX(value);

    RHS可以使用Drools 原生的方法:

    insert:往当前workingMemory中插入一个新的Fact对象

    update:更新workingMemory中对应的Fact对象,会触发规则的再次执行

    modify:修改,与update语法不同,结果都是更新操作

    retract:删除workingMemory中对应的Fact对象

    以上操作可能会触发规则的再次执行。具体看规则中no-loop与lock-on-active属性的设置。

    RHS也可以调用规则文件中定义的方法,方法的定义使用 function 关键字

    function void console {
       System.out.println();
       StringUtils.getId();// 调用外部静态方法,StringUtils必须使用import导入,getId()必须是静态方法
    }
    

    关于规则执行

    插入Product(discount=1)执行以下规则:

    • Demo 1
    import com.drools.model.Product;
    rule updateDistcount
        salience 9
        no-loop true
        when
            productObj:Product(discount > 0);
        then
            productObj.setDiscount(productObj.getDiscount() + 1);
            System.out.println(productObj.getDiscount());
            update(productObj);
        end
    rule otherRule
        salience 1
        when
        productObj : Product(discount > 1);
        then
        System.out.println("被触发了" + productObj.getDiscount());
        end
    

    执行结果为:

    2
    被触发了2

    • Demo 2
      去掉no-loop
    import com.drools.model.Product;
    rule updateDistcount
        salience 9
        /*no-loop true*/
        when
            productObj:Product(discount > 0);
        then
            productObj.setDiscount(productObj.getDiscount() + 1);
            System.out.println(productObj.getDiscount());
            update(productObj);
        end
    rule otherRule
        salience 1
        when
        productObj : Product(discount > 1);
        then
        System.out.println("被触发了" + productObj.getDiscount());
        end
    

    执行结果为:

    2
    3
    4
    5
    6
    7
    .....

    结果分析:

    第一条规则未设置no-loop属性,当update后Working Memory中的Fact被修改,重新触发规则。
    第二条规则未执行是由于优先级(salience)问题。更详细的原因后续补充..

    • Demo 3
      去掉update操作
    import com.drools.model.Product;
    rule updateDistcount
        salience 9
        no-loop true
        when
            productObj:Product(discount > 0);
        then
            productObj.setDiscount(productObj.getDiscount() + 1);
            System.out.println(productObj.getDiscount());
            /*update(productObj);*/
        end
    rule otherRule
        salience 1
        when
        productObj : Product(discount > 1);
        then
        System.out.println("被触发了" + productObj.getDiscount());
        end
    

    执行结果为:"2"。分析如下:

    rete算法会将fact匹配到的规则做记录列表,然后按照匹配列表中的规则RHS按照salience的次序执行。
    所以它是这样一个过程:接受数据输入、匹配业务规则、做出业务决策。
    当一条规则导致FACT变更时,可能会导致以上过程重新执行(未设置no-loop、lock-on-active属性)

    • Demo 4
      第二条规则加入lock-on-active true
    package org.drools.example.api.dynamic
    
    import org.drools.example.api.model.Product
    rule updateDistcount
        salience 9
        no-loop true
        when
            productObj:Product(discount > 0);
        then
            productObj.setDiscount(productObj.getDiscount() + 1);
            System.out.println(productObj.getDiscount());
            update(productObj);
        end
    rule otherRule
        lock-on-active true
        salience 1
        when
        productObj : Product(discount > 1);
        then
        System.out.println("被触发了" + productObj.getDiscount());
        end
    

    执行结果:"2"。结果分析如下:

    详见lock-on-active属性

    Drools Kie Api 中几个核心概念:

    • KieServices

    通过KieServices.Factory.get()方式获得,是一个单例的、线程安全的,为其他Kie工具提供服务
    KieServices是Kie项目的中心,通过其可以获取的各种对象来完成规则构建、管理和执行等操作
    其中有的方法分为两大类:getX()和newX(),其中,get只会返回一个对应单例对象的引用,new则会重新创建一个对象

    • KieContainer

    从KieServices中获得,其会借助KieProject来初始化、构造KieModule并将放入KieRepository中
    是一个给定的KieModule中所有KieBase的存放容器

    • KieRepository

    KieRepository是一个单例对象,它是一个存放KieModule的仓库,KieModule由kmodule.xml文件定义.

    • KieProject

    KieContainer可以通过KieProject来查找KieModule定义的信息,并根据这些信息构造KieBase和KieSession;
    KieProject 为物理概念;通过KieProject中的KieModule文件可定义KieBase、KieSession。

    • ClasspathKieProject

    ClasspathKieProject实现了KieProject接口,它提供了根据类路径中的META-INF/kmodule.xml文件构造KieModule的能力

    • KieBase

    KieBase就是一个知识仓库,包含了若干的规则、流程、方法等,但是不包含运行时的数据

    • KieSession

    KieSession就是一个跟Drools引擎打交道的会话,其基于KieBase创建
    KieContainer创建KieSession是一种较为方便的做法,其实他本质上是从KieBase中创建出来

    • 几个核心概念之间的关系

    KieProject即一个规则工程,为物理概念其对应的逻辑概念为KieModule。
    KieProject包含了一个kmodule.xml文件。其中定义了kmodule、kbase和ksession等属性。

    kmodule.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
        <kbase name="SimpleRuleKBase" packages="com.us.person">
            <ksession name="simpleRuleKSession"/>
        </kbase>
    </kmodule>
    

    kmodule里面包含了一个或多个kbase。

    每一个kbase都有一个唯一的名字(name),不能重复。

    packages 对应的值是命名空间。规则引擎会根据这里定义的包来查找规则定义文件。可以定义多个包,以逗号分隔。

    每一个kbase下面包含一个或多个ksession。

    每一个ksession都有一个唯一的名字(name),不能重复。

    下面内容为纯摘录部分,待后续整理

    使用规则工程(最终形态为k-jar)
    首先创建KieServices
    然后通过getKieClasspathContainer方法获得KieContainer
    KieContainer根据KieProject中的kmodule文件(ClasspathKieProject实现的)
    创建KieModule并放入KieRepository
    然后KieContainer创建KieBase
    之后KieBase创建KieSession规则会话到规则引擎
    通过KieSession即可执行规则或Process。

    20161228141343265.png

    相关文章

      网友评论

          本文标题:DROOLS RULE基础知识学习整理

          本文链接:https://www.haomeiwen.com/subject/wvfrvftx.html