DROOLS RULE基础知识学习整理

对于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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,264评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,549评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,389评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,616评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,461评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,351评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,776评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,414评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,722评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,760评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,537评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,381评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,787评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,030评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,304评论 1 252
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,734评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,943评论 2 336