DROOLS RULE基礎知識學習整理

對于Drools Rule的理解

一個規(guī)則可以包含三個部分:

  • 屬性部分:定義當前規(guī)則執(zhí)行的一些屬性等,比如是否可被重復執(zhí)行膏萧、過期時間、生效時間等。
  • 條件部分(LHS):定義當前規(guī)則的條件丸冕,如 when Message(); 判斷當前workingMemory中是否存在Message對象。
  • 結果部分(RHS):這里可以寫普通java代碼薛窥,即當前規(guī)則條件滿足后執(zhí)行的操作胖烛,可以直接調(diào)用Fact對象的方法來操作應用。

屬性部分:

規(guī)則的屬性有以下幾種

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

該屬性的作用是將若干個規(guī)則劃分成一個組蜘欲,用一個字符串來給這個組命名,這樣在執(zhí)行的時候晌柬,具有相同activation-group 屬性的規(guī)則中只要有一個會被執(zhí)行姥份,其它的規(guī)則都將不再執(zhí)行。也就是說年碘,在一組具有相同activation-group 屬性的規(guī)則當中澈歉,只有一個規(guī)則會被執(zhí)行,其它規(guī)則都將不會被執(zhí)行屿衅。

  • auto-focus

用來在已設置了agenda-group 的規(guī)則上設置該規(guī)則是否可以自動獨取Focus埃难,如果該屬性設置為true,那么在引擎執(zhí)行時,就不需要顯示的為某個Agenda Group 設置Focus涡尘,否則需要忍弛。對于規(guī)則的執(zhí)行的控制,還可以使用Agenda Filter 來實現(xiàn)考抄。在Drools 當中细疚,提供了一個名為org.drools.runtime.rule.AgendaFilter 的Agenda Filter 接口,用戶可以實現(xiàn)該接口川梅,通過規(guī)則當中的某些屬性來控制規(guī)則要不要執(zhí)行疯兼。org.drools.runtime.rule.AgendaFilter 接口只有一個方法需要實現(xiàn),方法體如下: public boolean accept(Activation activation); 在該方法當中提供了一個Activation 參數(shù)贫途,通過該參數(shù)我們可以得到當前正在執(zhí)行的規(guī)則對象或其它一些屬性镇防,該方法要返回一個布爾值,該布爾值就決定了要不要執(zhí)行當前這個規(guī)則潮饱,返回true 就執(zhí)行規(guī)則来氧,否則就不執(zhí)行
與agenda-group配合使用,設置焦點的是否可以自動獲取boolean型香拉,默認值為false

  • agenda-group

Agenda Group 是用來在Agenda 的基礎之上啦扬,對現(xiàn)在的規(guī)則進行再次分組,具體的分組方法可以采用為規(guī)則添加agenda-group 屬性來實現(xiàn)凫碌。agenda-group 屬性的值也是一個字符串扑毡,通過這個字符串,可以將規(guī)則分為若干個Agenda Group盛险,默認情況下瞄摊,引擎在調(diào)用這些設置了agenda-group 屬性的規(guī)則的時候需要顯示的指定某個Agenda Group 得到Focus(焦點),這樣位于該Agenda Group 當中的規(guī)則才會觸發(fā)執(zhí)行苦掘,否則將不執(zhí)行
基于Agenda將規(guī)則分組换帜;只有當某個Agenda組獲取到焦點(focus)時,該組的規(guī)則才會被執(zhí)行string型鹤啡,默認值為MAIN

規(guī)則的調(diào)用與執(zhí)行是通過StatelessSession 或StatefulSession 來實現(xiàn)的惯驼,一般的順序是創(chuàng)建一個StatelessSession 或StatefulSession,將各種經(jīng)過編譯的規(guī)則的package 添加到session當中递瑰,接下來將規(guī)則當中可能用到的Global 對象和Fact 對象插入到Session 當中祟牲,最后調(diào)用fireAllRules 方法來觸發(fā)、執(zhí)行規(guī)則抖部。在沒有調(diào)用最后一步fireAllRules 方法之前说贝,所有的規(guī)則及插入的Fact 對象都存放在一個名叫Agenda 表的對象當中,這個Agenda 表中每一個規(guī)則及與其匹配相關業(yè)務數(shù)據(jù)叫做Activation慎颗,在調(diào)用fireAllRules 方法后乡恕,這些Activation 會依次執(zhí)行言询,這些位于Agenda 表中的Activation 的執(zhí)行順序在沒有設置相關用來控制順序的屬性時(比如salience 屬性),它的執(zhí)行順序是隨機的几颜,不確定的倍试。

  • no-loop

drools提供了一些api,可以對當前傳入workingMemory中的Fact對象進行修改或者個數(shù)的增減蛋哭,比如上述的update方法县习,就是將當前的workingMemory中的Message類型的Fact對象進行屬性更新,這種操作會觸發(fā)規(guī)則的重新匹配執(zhí)行谆趾,可以理解為Fact對象更新了躁愿,所以規(guī)則需要重新匹配一遍。update之后沪蓬,之前的修改都會生效彤钟。當然對Fact對象數(shù)據(jù)的修改并不是一定需要調(diào)用update才可以生效,簡單的使用set方法設置就可以完成跷叉,這里類似于java的引用調(diào)用逸雹,所以何時使用update是一個需要仔細考慮的問題,一旦不慎云挟,極有可能會造成規(guī)則的死循環(huán)梆砸。上述的no-loop true,即設置當前的規(guī)則园欣,只執(zhí)行一次帖世,如果本身的RHS部分有update等觸發(fā)規(guī)則重新執(zhí)行的操作,也不要再次執(zhí)行當前規(guī)則沸枯。

  • lock-on-active

當在規(guī)則上使用ruleflow-group屬性或agenda-group屬性的時候日矫,將lock-on-active 屬性的值設置為true,可避免因某些Fact對象被修改而使已經(jīng)執(zhí)行過的規(guī)則再次被激活執(zhí)行绑榴∧慕危可以看出該屬性與no-loop屬性有相似之處,no-loop屬性是為了避免Fact被修改或調(diào)用了insert彭沼、retract缔逛、update之類的方法而導致本規(guī)則再次激活執(zhí)行,這里的lock-on-active 屬性起同樣的作用姓惑,lock-on-active是no-loop的增強版屬性,它主要作用在使用ruleflow-group屬性或agenda-group屬性的時候按脚。lock-on-active屬性默認值為false于毙。與no-loop不同的是lock-on-active可以避免其他規(guī)則修改FACT對象導致規(guī)則的重新執(zhí)行。

  • date-effective辅搬、date-expires唯沮、enabled

顧名思義

  • salience

它的作用是用來設置規(guī)則執(zhí)行的優(yōu)先級脖旱,salience 屬性的值是一個數(shù)字,數(shù)字越大執(zhí)行優(yōu)先級越高介蛉,同時它的值可以是一個負數(shù)萌庆。默認情況下,規(guī)則的salience 默認值為0币旧,所以如果我們不手動設置規(guī)則的salience 屬性践险,那么它的執(zhí)行順序是隨機的
int型,默認值為0

  • rule-flow-group

基于ruleflow將規(guī)則分組string型吹菱,無默認值巍虫,作用是用來將規(guī)則劃分為一個個的組,然后在規(guī)則流當中通過使用ruleflow-group 屬性的值鳍刷,從而使用對應的規(guī)則
作用等同于agenda-group占遥。二選一即可

  • dialect:

該屬性用來定義規(guī)則當中要使用的語言類型,目前Drools支持兩種語言:mvel 和java输瓜,默認使用的java 語言

  • duration:

如果設置了該屬性瓦胎,那么規(guī)則將在該屬性指定的值之后在另外一個線程里觸發(fā)。該屬性對應的值為一個長整型尤揣,單位是毫秒
設置DRL文件開始執(zhí)行之后延遲多長時間開始執(zhí)行這條規(guī)則
long型搔啊,無默認值

條件部分(LHS)

  • when:規(guī)則條件開始。條件可以單個芹缔,也可以多個坯癣,多個條件一次排列,比如
when
        eval(true)
        $customer:Customer()
        $message:Message(status==0)

上述羅列了三個條件最欠,當前規(guī)則只有在這三個條件都匹配的時候才會執(zhí)行RHS部分示罗。

eval(true):是一個默認的api,true 無條件執(zhí)行芝硬,類似于 while(true)

$message:Message(status==0) 這句話標示的:當前的workingMemory存在Message類型并且status屬性的值為0的Fact對象蚜点,這個對象通常是通過外部java代碼插入或者在已執(zhí)行規(guī)則的RHS部分中insert進去的。

"$message"代表著當前條件的引用的Message實例拌阴。在后續(xù)的條件部分和RHS部分中绍绘,可以使用這個名稱對該FACT對象進行修改或者調(diào)用其方法〕僭撸可選陪拘。

條件可以有組合,比如:
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)

當滿足規(guī)則條件,則進入規(guī)則結果部分執(zhí)行喇辽。
RHS可以是純java代碼掌挚,比如:

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

RHS可以調(diào)用Fact的方法,比如

$message.setXXX(value);

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

insert:往當前workingMemory中插入一個新的Fact對象

update:更新workingMemory中對應的Fact對象菩咨,會觸發(fā)規(guī)則的再次執(zhí)行

modify:修改吠式,與update語法不同,結果都是更新操作

retract:刪除workingMemory中對應的Fact對象

以上操作可能會觸發(fā)規(guī)則的再次執(zhí)行旦委。具體看規(guī)則中no-loop與lock-on-active屬性的設置奇徒。

RHS也可以調(diào)用規(guī)則文件中定義的方法,方法的定義使用 function 關鍵字

function void console {
   System.out.println();
   StringUtils.getId();// 調(diào)用外部靜態(tài)方法缨硝,StringUtils必須使用import導入摩钙,getId()必須是靜態(tài)方法
}

關于規(guī)則執(zhí)行

插入Product(discount=1)執(zhí)行以下規(guī)則:

  • 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("被觸發(fā)了" + productObj.getDiscount());
    end

執(zhí)行結果為:

2
被觸發(fā)了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("被觸發(fā)了" + productObj.getDiscount());
    end

執(zhí)行結果為:

2
3
4
5
6
7
.....

結果分析:

第一條規(guī)則未設置no-loop屬性,當update后Working Memory中的Fact被修改查辩,重新觸發(fā)規(guī)則胖笛。
第二條規(guī)則未執(zhí)行是由于優(yōu)先級(salience)問題。更詳細的原因后續(xù)補充..

  • 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("被觸發(fā)了" + productObj.getDiscount());
    end

執(zhí)行結果為:"2"宜岛。分析如下:

rete算法會將fact匹配到的規(guī)則做記錄列表长踊,然后按照匹配列表中的規(guī)則RHS按照salience的次序執(zhí)行。
所以它是這樣一個過程:接受數(shù)據(jù)輸入萍倡、匹配業(yè)務規(guī)則身弊、做出業(yè)務決策。
當一條規(guī)則導致FACT變更時列敲,可能會導致以上過程重新執(zhí)行(未設置no-loop阱佛、lock-on-active屬性)

  • Demo 4
    第二條規(guī)則加入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("被觸發(fā)了" + productObj.getDiscount());
    end

執(zhí)行結果:"2"。結果分析如下:

詳見lock-on-active屬性

Drools Kie Api 中幾個核心概念:

  • KieServices

通過KieServices.Factory.get()方式獲得戴而,是一個單例的凑术、線程安全的,為其他Kie工具提供服務
KieServices是Kie項目的中心所意,通過其可以獲取的各種對象來完成規(guī)則構建淮逊、管理和執(zhí)行等操作
其中有的方法分為兩大類:getX()和newX(),其中扶踊,get只會返回一個對應單例對象的引用泄鹏,new則會重新創(chuàng)建一個對象

  • KieContainer

從KieServices中獲得,其會借助KieProject來初始化秧耗、構造KieModule并將放入KieRepository中
是一個給定的KieModule中所有KieBase的存放容器

  • KieRepository

KieRepository是一個單例對象命满,它是一個存放KieModule的倉庫,KieModule由kmodule.xml文件定義.

  • KieProject

KieContainer可以通過KieProject來查找KieModule定義的信息绣版,并根據(jù)這些信息構造KieBase和KieSession胶台;
KieProject 為物理概念;通過KieProject中的KieModule文件可定義KieBase杂抽、KieSession。

  • ClasspathKieProject

ClasspathKieProject實現(xiàn)了KieProject接口,它提供了根據(jù)類路徑中的META-INF/kmodule.xml文件構造KieModule的能力

  • KieBase

KieBase就是一個知識倉庫晌杰,包含了若干的規(guī)則缀遍、流程、方法等杭朱,但是不包含運行時的數(shù)據(jù)

  • KieSession

KieSession就是一個跟Drools引擎打交道的會話阅仔,其基于KieBase創(chuàng)建
KieContainer創(chuàng)建KieSession是一種較為方便的做法,其實他本質(zhì)上是從KieBase中創(chuàng)建出來

  • 幾個核心概念之間的關系

KieProject即一個規(guī)則工程弧械,為物理概念其對應的邏輯概念為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 對應的值是命名空間。規(guī)則引擎會根據(jù)這里定義的包來查找規(guī)則定義文件抖甘∪劝埃可以定義多個包,以逗號分隔衔彻。

每一個kbase下面包含一個或多個ksession薇宠。

每一個ksession都有一個唯一的名字(name),不能重復米奸。

下面內(nèi)容為純摘錄部分昼接,待后續(xù)整理

使用規(guī)則工程(最終形態(tài)為k-jar)
首先創(chuàng)建KieServices
然后通過getKieClasspathContainer方法獲得KieContainer
KieContainer根據(jù)KieProject中的kmodule文件(ClasspathKieProject實現(xiàn)的)
創(chuàng)建KieModule并放入KieRepository
然后KieContainer創(chuàng)建KieBase
之后KieBase創(chuàng)建KieSession規(guī)則會話到規(guī)則引擎
通過KieSession即可執(zhí)行規(guī)則或Process。

20161228141343265.png
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末悴晰,一起剝皮案震驚了整個濱河市慢睡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌铡溪,老刑警劉巖漂辐,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異棕硫,居然都是意外死亡髓涯,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門哈扮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纬纪,“玉大人蚓再,你說我怎么就攤上這事“鳎” “怎么了摘仅?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長问畅。 經(jīng)常有香客問我娃属,道長,這世上最難降的妖魔是什么护姆? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任矾端,我火速辦了婚禮,結果婚禮上卵皂,老公的妹妹穿的比我還像新娘秩铆。我一直安慰自己,他們只是感情好渐裂,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布豺旬。 她就那樣靜靜地躺著,像睡著了一般柒凉。 火紅的嫁衣襯著肌膚如雪族阅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天膝捞,我揣著相機與錄音坦刀,去河邊找鬼。 笑死蔬咬,一個胖子當著我的面吹牛鲤遥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播林艘,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼盖奈,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了狐援?” 一聲冷哼從身側響起钢坦,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎啥酱,沒想到半個月后爹凹,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡镶殷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年禾酱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡颤陶,死狀恐怖颗管,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情指郁,我是刑警寧澤忙上,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站闲坎,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏茬斧。R本人自食惡果不足惜腰懂,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望项秉。 院中可真熱鬧绣溜,春花似錦、人聲如沸娄蔼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽岁诉。三九已至锚沸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涕癣,已是汗流浹背哗蜈。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留坠韩,地道東北人距潘。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像只搁,于是被迫代替她去往敵國和親音比。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348