drools規則引擎初探


1.drools是什么

Drools是為Java量身定制的基於Charles  Forgy的RETE算法的規則引擎的實現。具有了OO接口的RETE,使得商業規則有了更自然的表達。

Rule是什么呢?

 

一條規則是對商業知識的編碼。一條規則有 attributes ,一個 Left Hand Side ( LHS )和一個 Right Hand Side ( RHS )。Drools 允許下列幾種 attributes : salience , agenda-group , no-loop , auto-focus , duration , activation-group  。

規則的 LHS 由一個或多個條件( Conditions )組成。當所有的條件( Conditions )都滿足並為真時, RHS 將被執行。 RHS 被稱為結果( Consequence )。 LHS 和 RHS 類似於

if(<LHS>){

<RHS>

}

下面介紹幾個術語:

對新的數據和被修改的數據進行規則的匹配稱為模式匹配( Pattern Matching )。進行匹配的引擎稱為推理機( Inference Engine )。被訪問的規則稱為 ProductionMemory ,被推理機進行匹配的數據稱為 WorkingMemory 。 Agenda 管理被匹配規則的執行。推理機所采用的模式匹配算法有下列幾種: Linear , RETE , Treat , Leaps 。這里注意加紅的地方,對數據的修改也會觸發重新匹配,即對 WorkingMemory中的數據進行了修改。

然后規則引擎大概是這個樣子的:

這個圖也很好理解,就是推理機拿到數據和規則后,進行匹配,然后把匹配的規則和數據傳遞給Agenda。

規則引擎實現了數據同邏輯的完全解耦。規則並不能被直接調用,因為它們不是方法或函數,規則的激發是對 WorkingMemory 中數據變化的響應。結果( Consequence ,即 RHS )作為 LHS events 完全匹配的 Listener 。

數據被 assert 進 WorkingMemory 后,和 RuleBase 中的 rule 進行匹配(確切的說應該是 rule 的 LHS ),如果匹配成功這條 rule 連同和它匹配的數據(此時就叫做 Activation )一起被放入 Agenda ,等待 Agenda 來負責安排激發 Activation (其實就是執行 rule 的 RHS ),上圖中的菱形部分就是在 Agenda 中來執行的, Agenda 就會根據沖突解決策略來安排 Activation 的執行順序。

下面附上drools規則引擎的執行過程

 

2.rete算法

參考鏈接:Rete Algorithm

rete在拉丁文里是net network的意思,這個算法由 Charles Forgy  博士在他的博士論文里提到。

這個算法可以分為兩個部分,一個是如何編譯規則,一個是如何執行。原話(The Rete algorithm can be broken into 2 parts: rule compilation and runtime execution.)

rule compilation 就是如何通過對所有規則進行處理,生成一個有效的辨別網絡。而一個辨別網絡,則對數據進行過濾,使數據一步步往下傳送。數據剛進入網絡,有很多的匹配條件,這里可以理解為:邏輯表達式為true or false,然后在網絡里往下傳遞的時候,匹配的條件越來越少,最后到達一個終止節點。

在這個論文里Dr Charles描述了這么幾個節點,Node:

2.rete算法

參考鏈接:Rete Algorithm

rete在拉丁文里是net network的意思,這個算法由 Charles Forgy  博士在他的博士論文里提到。

這個算法可以分為兩個部分,一個是如何編譯規則,一個是如何執行。原話(The Rete algorithm can be broken into 2 parts: rule compilation and runtime execution.)

rule compilation 就是如何通過對所有規則進行處理,生成一個有效的辨別網絡。而一個辨別網絡,則對數據進行過濾,使數據一步步往下傳送。數據剛進入網絡,有很多的匹配條件,這里可以理解為:邏輯表達式為true or false,然后在網絡里往下傳遞的時候,匹配的條件越來越少,最后到達一個終止節點。

在這個論文里Dr Charles描述了這么幾個節點,Node:

 

這里對其中的幾個節點做一下簡單介紹,另外說一下如何運作的。

    • 首先,root node是所有的對象都可以進入的節點,也是辨別網絡的一個入口,這個可以理解為一個虛節點,其實可能並不存在。
    • 然后立馬進入到ObjectTypeNode節點,這是一個對象類型節點。很明顯,這里承載的是一個對象,可以理解為是java中的某個new Object(),在這個算法里,這個節點的作用就是為了保證不做一些無用功,什么無用功呢,就是不是對每個規則,進入的對象都要去辨別一遍,而是確定的對象類型,去做跟他相關的辨別,其實就是match。那么怎么做到呢?這里用到了一個hashMap,每次進入網絡的對象,都會在這個map中通過hash,找到一個對應的辨別路徑去辨別,即match。附上英文原文:(

      Drools extends Rete by optimizing the propagation from ObjectTypeNode to AlphaNode using hashing. Each time an AlphaNode is added to an ObjectTypeNode it adds the literal value as a key to the HashMap with the AlphaNode as the value. When a new instance enters the ObjectType node, rather than propagating to each AlphaNode, it can instead retrieve the correct AlphaNode from the HashMap,thereby avoiding unnecessary literal checks.)


      一個圖來說明:

所有經過ObjectTypeNode的對象都會走到下一個節點,下一個節點可以是下面的幾種:AlphaNodes, LeftInputAdapterNodes and BetaNodes。后面兩個節點是AlphaNodes節點的一些變種,AlphaNodes節點是用來判斷一些條件的。可以理解為一些邏輯表達式的計算。

下面開始上圖:

  • 這個圖就是傳遞進一個Cheese對象,然后依次判斷是否滿足條件:1.判斷name是否是“cheddar”,2.如果判斷1通過了,繼續判斷strength是否是strong。這是最簡單了一種情況了,這里附上對應的規則描述,后面會繼續講解:
    rule "cheessRule" when
    $cheese:Cheese(name == "cheddar" && strength == "strong")
    then
    ......
    end

3.maven依賴

這里列了一些后面的一些例子需要用到的maven依賴

<!--kie api 構建kie虛擬文件系統,關聯decisiontable和drl文件,很關鍵 -->
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
</dependency>
<!-- 規則引擎核心包,里面包含了RETE引擎和LEAPS 引擎-->
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
</dependency>
<!-- 決策表依賴-->
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-decisiontables</artifactId>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-templates</artifactId>
</dependency>

4.規則文件:.drl or xls

我們一般用到的也就這兩種形式,一個是drl文件,是drools規則引擎提供的最原生的方式,語法很簡單,具體語法見

還有一個是決策表,決策表可以是xls也可以是csv,我們一般用xls比較多。而且好理解。xls就是一個excel文件。ps:在使用的過程中,遇到很多坑,其中一個最大的坑是mac系統的問題,這里后面會安利。

drl文件

首先來看下drl文件,這個在第2條講解node的時候已經提到過了。
舉例:



rule "ageUp12" when
 $student: Student(age > 2)
then
 $student.ageUp12();
end

rule "nameMax" when
 $student: Student(name == "max")
then
 $student.nameMax();
retract($student);
end
簡單說明:以第一個rule為例
  • package 定義了規則文件的一個命名空間,和java中的package無關。
  • import 這里可以有多個,就是在規則文件里引用到的java類。
  • rule 用來定義一個規則,這里名字不可重復,后面跟一個when關鍵字,翻譯過來就是,規則 名ageUp12,當滿足......
  • when 和then之間是邏輯表達式,也就是辨別條件,其中$student:Student(age >2)這里其實包含了兩個意思,一個是滿足age>2的Student對象,一個是把這個對象賦值給$student變量,這樣后面就可以引用這個變量了。邏輯表達式寫在小括號里,如果是多個條件,可以用逗號分隔,如$sutdent :Student(age > 2,name=="max")
  • then和end之間來定義action,即當滿足age>2的時候,做什么操作,這里可以像在java方法里一樣,調用任何一個java類的方法,只要import了這個類且在前面定義了這個變量

第二個例子可以看到有個retract($student),這里是用到了drools內部提供的一個函數,具體見后續關於drools語法介紹的博客


決策表(decisiontable)

決策表就是一個excel文件,可以是xls(xlsx暫不支持)或者csv是個表格,看上去也很直觀,即便是不懂代碼的人看了也能看懂,不像drl文件那么多語法。關鍵的一點是:decisiontable也是最終轉成drl文件來讓drools規則引擎來解析執行的。*.xls到*.drl的轉換這個在后面的wiki會說到。

直接上圖吧

這里可以暫時忽略那些背景色,只是為了好區分沒個模塊的作用

這里忽略文件開始的空行,從有數據的第一行開始解釋說明:

第一行,第一列:RuleSet 第二列。這里RuleSet可以省略的,累似drl文件中的package

第二行,第一列:Import 第二列具體的java類,這里和drl文件里的Improt相對應,多個引用類用逗號分隔

第三行,是個對這個決策表的說明

第四行,第一列:RuleTable FirstDecisionTable 這一行很關鍵 指明這是一個決策表,並且下面的幾行都是具體的規則,就好比上面幾行是一些准備條件,下面才是真正干活的地方,這里來個說明

第五行,CONDITION行,這一行可以有兩種列名:CONDITION ACTION。CONDITION列就是drl里的辨別條件,  ACTION則是具體的操作,即滿足前面幾列的CONDITION的條件后,會執行什么操作,這里CONDITION一定在ACTION前面,ACTION可以有多個列, 單個ACTION里的多個操作用逗號分隔,末尾要加分號結尾這里很重要,不然會有解析錯誤

第六行,緊挨着CONDITION的一行,可以在這里聲明下面要用的到對象,對應drl文件里的$student:Student()

第七行,是辨別條件邏輯表達式,如:student.getAge()==$param則對應drl里的age==12這里$param是對應列每個單元格的值,然后這里需要特別說明下,針對於非字符串,如整數,小數等,可以直接使用$param,但是如果單元格里是字符串,則需要加雙引號。(ps:mac里的雙引號是斜的,一定要保證是豎着"的)另外,如果有多個值,可以用逗號隔開,然后可以用$1,$2提取變量值,如第一個ACTION里的student.doAction1($1,"$2")

第八行仍然是注釋行,可以添加每一個CONDITON ACTION列的說明。

下面的每一行就是對應的某些條件的取值了。

參考:decisionTable

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM