開源規則流引擎實踐

1. 基於 rete 算法的規則引擎

在 AI 領域,產生式系統是一個很重要的理論,產生式推理分爲正向推理和逆向推理產生式,其規則的通常形式是:IF 條件 THEN 操做。rete 算法是實現產生式系統中正向推理的高效模式匹配算法,經過造成一個 rete 網絡進行模式匹配,利用基於規則的系統的時間冗餘性和結構類似性特徵 [8],提升系統模式匹配效率。本文將介紹的 Drools 引擎就是利用 rete 算法對規則進行分析,造成 rete 網絡,對模式進行匹配。 java

1.1 rete 算法研究

1.1.1 rete 算法概述 node

Rete 算法最初是由卡內基梅隆大學的 Charles L.Forgy 博士在 1974 年發表的論文中所闡述的算法 , 該算法提供了專家系統的一個高效實現。自 Rete 算法提出之後 , 它就被用到一些大型的規則系統中 , 像 ILog、Jess、JBoss Rules 等都是基於 RETE 算法的規則引擎 [7]正則表達式

Rete 在拉丁語中譯爲」net」,即網絡。Rete 匹配算法是一種進行大量模式集合和大量對象集合間比較的高效方法,經過網絡篩選的方法找出全部匹配各個模式的對象和規則。 算法

其核心思想是將分離的匹配項根據內容動態構造匹配樹,以達到顯著下降計算量的效果。Rete 算法能夠被分爲兩個部分:規則編譯和規則執行 [7]。當 Rete 算法進行事實的斷言時,包含三個階段:匹配、選擇和執行,稱作 match-select-act cycle。 數據庫

1.1.2 rete 算法相關概念 數組

Rete 算法規則相關的概念有以下幾個: 服務器

Fact:已經存在的事實,它是指對象之間及對象屬性之間的多元關係,爲簡單起見,事實用一個三元組來表示:(標識符 ^ 屬性 值)[1],例如以下事實: 網絡

w1:(B1 ^ on B2) w6:(B2 ^color blue) 
 w2:(B1 ^ on B3) w7:(B3 ^left-of B4) 
 w3:(B1 ^ color red) w8:(B3 ^on table) 
 w4:(B2 ^on table) w9:(B3 ^color red) 
 w5:(B2 ^left-of B3)

Rule:規則,包含條件和行爲兩部分,條件部分又叫左手元(LHS),行爲部分又叫右手元(RHS)。條件部分能夠有多條條件,而且能夠用 and 或 or 鏈接 [1]。其通常形式以下: session

(name-of-this-production 
 LHS /*one or more conditions*/ 
 --> 
 RHS /*one or more actions*/ 
 ) 
例如,下面的例子:
 (find-stack-of-two-blocks-to-the-left-of-a-red-block 
 (^on) 
 (^left-of) 
 (^color red) 
 --> 
 ...RHS... 
 ) 
 Patten:模式,也就是規則的條件部分,是已知事實的泛化形式,是未實例化的多元關係 [1]。好比,前面的那條規則的條件部分:
 (^on) 
 (^left-of) 
 (^color red) 
 Rete 網絡的概念 [1][9][10]以下:

RootNode:Rete 網絡的根節點,全部對象經過 Root 節點進入網絡。 架構

ObjectTypeNode:對象類型節點,保證所傳入的對象只會進入本身類型所在的網絡,提升了工做效率。

AlphaNode:Alpha 節點是規則的條件部分的一個模式,一個對象只有和本節點匹配成功後,才能繼續向下傳播。

JoinNode:用做鏈接(jion)操做的節點,至關於 and,至關於數據庫的錶鏈接操做,屬於 betaNode 類型的節點。BetaNode 節點用於比較兩個對象和它們的字段。兩個對象多是相同或不一樣的類型。咱們將這兩個輸入稱爲左和右。BetaNode 的左輸入一般是一組對象的數組。BetaNode 具備記憶功能。左邊的輸入被稱爲 Beta Memory,會記住全部到達過的語義。右邊的輸入成爲 Alpha Memory,會記住全部到達過的對象。

NotNode:根據右邊輸入對左邊輸入的對象數組進行過濾,兩個 NotNode 能夠完成‘ exists ’檢查。

LeftInputAdapterNodes:將單個對象轉化成對象數組。

Terminal Nodes 被用來代表一條規則已經匹配了它的全部條件(conditions)。

圖 1 展現的是一個簡單的 rete 網絡:

圖 1. RETE 網絡
圖 1. RETE 網絡

1.1.3 建立 rete 網絡

Rete 算法的編譯結果是建立了規則集對應的 Rete 網絡 , 它是一個事實能夠在其中流動的圖。建立 rete 網絡的過程 [1]以下: 1) 建立根節點; 2) 加入一條規則 1 (Alpha 節點從 1 開始,Beta 節點從 2 開始 ); a. 取出規則中的一個模式 1,檢查模式中的參數類型,若是是新類型,則加入一個類型節點; b. 檢查模式 1 對應的 Alpha 節點是否已存在,若是存在則記錄下節點位置,若是沒有則將模式 1 做爲一個 Alpha 節點加入到網絡中,同時根據 Alpha 節點的模式創建 Alpha 內存表; c. 重複 b 直到全部的模式處理完畢; d. 組合 Beta 節點,按照以下方式: Beta(2) 左輸入節點爲 Alpha(1),右輸入節點爲 Alpha(2) Beta(i) 左輸入節點爲 Beta(i-1),右輸入節點爲 Alpha(i) i>2 並將兩個父節點的內存表內聯成爲本身的內存表; e. 重複 d 直到全部的 Beta 節點處理完畢; f. 將動做(Then 部分)封裝成葉節點(Action 節點)做爲 Beta(n) 的輸出節點; 3) 重複 2) 直到全部規則處理完畢; 執行完上述步驟,創建的 rete 網絡以下圖 2 (a 圖爲含有 3 個規則的 rete 網絡,b 圖爲含有一個規則的 rete 網絡 ):

圖 2. beta-network and alpha-network
圖 2. beta-network and alpha-network

上圖(a 圖和 b 圖),他們的左邊的部分都是 beta-network, 右邊都是 alpha-network, 圓圈是 join-node。右邊的 alpha-network 是根據事實庫和規則條件構建的,其中除 alpha-network 節點的節點都是根據每一條規則條件的模式 , 從事實庫中 match 過來的,即在編譯構建網絡的過程當中靜態創建的。只要事實庫是穩定的,RETE 算法的執行效率應該是很是高的,其緣由就是已經經過靜態的編譯,構建了 alpha-network。左邊的 beta-network 表現出了 rules 的內容,其中 p1,p2,p3 共享了許多 BetaMemory 和 join-node, 這樣能加快匹配速度。

1.1.4 Rete 算法的匹配過程

匹配過程以下: 1) 對於每一個事實,經過 select 操做進行過濾,使事實沿着 rete 網達到合適的 alpha 節點。2) 對於收到的每個事實的 alpha 節點,用 Project( 投影操做 ) 將那些適當的變量綁定分離出來。使各個新的變量綁定集沿 rete 網到達適當的 bete 節點。3) 對於收到新的變量綁定的 beta 節點,使用 Project 操做產生新的綁定集,使這些新的變量綁定沿 rete 網絡至下一個 beta 節點以致最後的 Project。4) 對於每條規則,用 project 操做將結論實例化所需的綁定分離出來。

若是把 rete 算法類比到關係型數據庫操做,則事實集合就是一個關係,每條規則就是一個查詢,再將每一個事實綁定到每一個模式上的操做看做一個 Select 操做,記一條規則爲 P,規則中的模式爲 c1,c2,…,ci, Select 操做的結果記爲 r(ci), 則規則 P 的匹配即爲 r(c1)◇r(c2)◇…◇(rci)。其中◇表示關係的鏈接(Join)操做。

Rete 網絡的鏈接(Join)和投影 (Project) 和對數據庫的操做形象對好比圖 3 所示:

圖 3. join and project

1.1.5 Rete 算法的特色、不足和建議 Rete 算法有以下特色:

a. Rete 算法是一種啓發式算法,不一樣規則之間每每含有相同的模式,所以在 beta-network 中能夠共享 BetaMemory 和 betanode。若是某個 betanode 被 N 條規則共享,則算法在此節點上效率會提升 N 倍。

b. Rete 算法因爲採用 AlphaMemory 和 BetaMemory 來存儲事實,當事實集合變化不大時,保存在 alpha 和 beta 節點中的狀態不須要太多變化,避免了大量的重複計算,提升了匹配效率。

c. 從 Rete 網絡能夠看出,Rete 匹配速度與規則數目無關,這是由於事實只有知足本節點纔會繼續向下沿網絡傳遞。

Rete 算法的不足:

a. 事實的刪除與事實的添加順序相同, 除了要執行與事實添加相同的計算外, 還須要執行查找, 開銷很高 [3]。

b. RETE 算法使用了β存儲區存儲已計算的中間結果, 以犧牲空間換取時間, 從而加快系統的速度。然而β存儲區根據規則的條件與事實的數目而成指數級增加, 因此當規則與事實不少時, 會耗盡系統資源 [3]。

針對 Rete 算法的特色和不足,在應用或者開發基於 Rete 算法的規則引擎時,提出以下建議:

a. 容易變化的規則儘可能置後匹配,能夠減小規則的變化帶來規則庫的變化。

b. 約束性較爲通用或較強的模式儘可能置前匹配,能夠避免沒必要要的匹配。

c. 針對 Rete 算法內存開銷大和事實增長刪除影響效率的問題,技術上應該在 alpha 內存和 beata 內存中,只存儲指向內存的指針,並對指針建裏索引(可用 hash 表或者非平衡二叉樹)。

d. Rete 算法 JoinNode 能夠擴展爲 AndJoinNode 和 OrJoinNode,兩種節點能夠再進行組合 [5]。

1.2 基於 Rete 算法的 drools 開源規則引擎

1.2.1 Drools 規則引擎簡介

Drools 具備一個易於訪問企業策略、易於調整以及易於管理的開源業務 規則引擎,符合業內標準,速度快、效率高。業務分析師或審覈人員能夠利用它輕鬆查看業務規則,從而檢驗已編碼的規則是否執行了所需的業務規則。其前身是 Codehaus 的一個開源項目叫 Drools,最近被歸入 JBoss 門下,改名爲 JBoss Rules,成爲了 JBoss 應用服務器的規則引擎。

Drools 被分爲兩個主要的部分:編譯和運行時。編譯是將規則描述文件按 ANTLR 3 語法進行解析,對語法進行正確性的檢查,而後產生一種中間結構「descr」,descr 用 AST 來描述規則。目前,Drools 支持四種規則描述文件,分別是:drl 文件、 xls 文件、brl 文件和 dsl 文件,其中,經常使用的描述文件是 drl 文件和 xls 文件,而 xls 文件更易於維護,更直觀,更爲被業務人員所理解。運行時是將AST傳到PackageBuilder,由PackagBuilder來產生RuleBase,它包含了一個或多個 Package 對象。

Drools 的語法規則將在實踐中介紹,下面分析 drools 的原理。

1.2.2 Drools 規則引擎原理

Drools 中的 Rete 算法被稱爲 ReteOO,表示 Drools 爲面向對象系統(Object Oriented systems)加強並優化了 Rete 算法。

在 Drools 中,規則被存 放在 Production Memory(規則庫)中,推理機要匹配的 facts(事實)被存在 Working Memory(工做內存)中。當時事實被插入到工做內存中後,規則引擎會把事實和規則庫裏的模式進行匹配,對於匹配成功的規則再由 Agenda 負責具體執行推理算法中被激發規則的結論部分,同時 Agenda 經過沖突決策策略管理這些衝突規則的執行順序,Drools 中規則衝突決策策略有:(1) 優先級策略 (2) 複雜度優先策略 (3) 簡單性優先策略 (4) 廣度策略 (5) 深度策略 (6) 裝載序號策略 (7) 隨機策略 [5][6]

圖 4. Drools 的原理示意圖
圖 4. Drools 的原理示意圖

回頁首

2. 應用實踐

2.1 需求描述

在汽車保險行業中,每一個地區都會有本身的車險投保規則,並且這些投保規則會常常變更,爲適應這樣的業務需求,能夠採用 drools 開源規則引擎。 在本文介紹的例子中,具體業務需求是:應用應該可以根據前臺傳入的車輛信息和地區信息,從車輛和套餐的關係配置中匹配這輛車可用的套餐;而後,根據從套餐 配置中獲取套餐信息,套餐信息中包含了該套餐可用的險別(如車損險、乘客責任和盜搶險諸如之類的稱之爲險別);最後從險別配置中獲取險別信息。

2.2 需求分析

因爲每一個地區的規則不同,因此要對規則進行分組,每一個地區的車輛和套餐的關係配置和套餐配置要分別在不一樣的文件中,而險別是不變信息,各個地區用同一個險別配置。車輛和套餐的關係配置放在一個 RuelTable 中,套餐配置放在另外一個 RuelTable 中,這兩個 RuelTable 在用一個 xls 文件中描述便可。

這 樣配置後,每次引擎先根據地區代碼執行相應的規則文件;進入規則文件後,再根據車輛信息過濾套餐找出適合這輛車的套餐,而後更新傳入的對象,這時會從新匹 配規則(已經匹配過的不該該再匹配,後面代碼中會介紹);而後再匹配套餐,匹配後,更新對象;最後進入險別對應的文件匹配險別。

2.3 代碼實踐

首先,創建 Drools BRMS 應用。Drools BRMS 是一個管理和編譯規則和規則流的 Web 應用程序,能夠部署在大部分的支持 J2SE 1.5 的 Web 容器下,如 Tomcat6。Drools BRMS 架構體系分爲三大部分,第一部分是 UI 層,提供了一個基於 Ajax 技術的業務規則編輯、管理工具。第二部分是規則文件倉庫層,將規則文件統一保持在文件系統或關係數據庫。最後一個是 Drools 的核心引擎,用來對用戶提交的規則文件進行驗證、編譯和部署。開發人員經過規則文件的編輯部署,生成了包含 rule 的 package 對象,這是引擎可直接操做的內存對象。BRMS 經過一個 URL 提供對這個對象的 HTTP 訪問。第三方能夠經過 Agent 相關 API 來訪問這個 URL,程序自動下載這個 Package 對象就直接能夠在規則引擎運行,獲得規則執行的結果。

而後,將 BOM(Business Object Model 業務規則引擎所要操做的對象 )、規則流文件(圖 2-2 所對應的文件)和規則文件(圖 2-3 和圖 2-4 所對應的文件)上傳到 BRMS 中。下面對各個文件進行介紹。

圖 5 描述的是 BOM 對象,分別是 GeProposalInfo、GeCar、GeComboArea、GeCombo 和 GeKind,他們的關係從圖中能夠很明顯的看出,這裏再也不贅述。

圖 5. BOM 類
圖 5. BOM 類

圖 6 中,開始節點是表示流程的開始。在 diverge 分枝節點處按 GeComboArea 裏的 AreaCode 屬性值有四個分枝,這四個分枝按優先級只要有一個知足條件就繼續向下執行。diverge 分枝節點有 And、Xor 和 Or 三種類型,其含義分別是執行全部分枝、執行按優先級首先符合條件的分枝、執行全部符合條件的分枝。RuleTask 規則任務節點對應的是這個 RuleGroup 規則組裏的規則。執行完地區層次的規則後,進入 converge 聚合節點,此節點等待分枝節點中任何一個節點執行完畢後執行。converge 分枝節點有 And、Xor、n-of-m 和 Discriminator 四種類型,其含義分別是等待全部分枝執行完畢、按優先級只等待一個分枝執行完、等待一個分枝執行完,但每一個分枝執行完後會致使繼續等待下一個分枝執行和等待在 m 個分枝中有 n 個分枝執行完畢。規則任務節點 Rule_Kind 是執行 Rule_Kind 規則組裏的規則。結束節點標誌着規則流執行完畢。

圖 6. 規則流
圖 6. 規則流

圖 7 和圖 8 分別是 beijing.xls 和 kind.xls 的截圖。在決策表中,不一樣做用的表格用不一樣顏色區分。在黑色區中,有一個 RuleTable 關鍵詞,它表示本決策表從這開始,解析的時候也就是從這按從上到下和從左到右的順序開始解析,其後是表名稱。CONDITION 是代表此列爲條件的關鍵詞。和並列中 pi:GeProposalInfo 的意思是從 workmemory 中選取類型爲 GeProposalInfo 的一個對象賦值給 pi。car.carType matches ".*$param.*"的含義是查看 pi 中對象 car 中的 carType 屬性值是否包含此列單元格中的值。".*$param.*"爲正則表達式,$param 爲對單元格中值的引用。Matches 是一個操做。RULEFLOW-GROUP 是對規則分組的關鍵字,它和規則任務節點對應。PRIORITY 設置規則執行優先級,數值越大越先被執行。ACTION 是規則的行爲部分,能夠在單元格中寫 java 代碼。另外,單元格中有內容表示執行匹配或執行 java 代碼,沒有內容表示什麼都不作,跳過。

圖 7. 規則表定義一
圖 7. 規則表定義一
圖 8. 規則表定義二
圖 8. 規則表定義二

圖 9 是 beijing.xls 和 kind.xls 裏的規則生成的 rete 網絡。在編寫規則中,咱們採用了本文的建議 a(將容易變化的規則儘可能放後)和 b(將強約束條件放前),這樣產生的 rete 網絡匹配效率會更高。如圖 2-5 中,在紅色節點(類型節點)下會有對 updateFlag 的三個分枝,updateFlag 是強約束條件且不會變化太大,僅在此節點上,匹配效率就提升了三分之一。

圖 9. 生成的 Rete 網絡
圖 9. 生成的 Rete 網絡

最後,咱們對咱們的應用程序端的調用作一下闡述。

第一步:建立規則庫

點擊查看代碼清單

第二步:建立 workmemory 並插入對象

建立 workmemory 對象 ksession
 StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
 設置初始值
		GeComboArea ca = new GeComboArea();
		ca.setAreaCode("010");
		GeCar c=new GeCar();
		c.setCarAge(9);
		c.setCarPrice(15000);
		c.setCarType("華晨 bmw11 年款");
		GeProposalInfo pi=new GeProposalInfo();
		pi.setCar(c);
		pi.setComboArea(ca);
 將 pi 插入 workmemory 中,此時會構建 rete 網絡
		ksession.insert(pi);

第三步:執行規則流和規則

激活規則流
 ksession.startProcess("com.sample.ruleflow");
 激活規則
		ksession.fireAllRules();

第四步:釋放資源

ksession.dispose();

回頁首

3. 總結

本文經過深刻剖析 rete 算法和基於 rete 算法的規則引擎,發現了算法中存在的問題,提出了算法改進的意見,同時也闡述了在應用規則引擎時應該注意的問題,並經過實例對規則引擎進行了實踐。

相關文章
相關標籤/搜索