【java規則引擎】之規則引擎解釋

轉載:http://www.open-open.com/lib/view/open1417528754230.htmlhtml

現實生活中,規則無處不在。法律、法規和各類制度均是;對於企業級應用來講,在IT技術領域,不少地方也應用了規則,好比路由表,防火牆策略,乃至角色權限控制(RBAC),或者Web框架中的URL匹配。不論是那種規則,都規定了一組肯定的條件和此條件所產生的結果。

舉一個例子:

IF

汽車是紅色
車是運動型的
駕駛員是男性
駕駛員在16-25歲之間
THEN

保險費用增長20%

從這個例子能夠看出:

每條規則都是一組條件決定的一系列結果
一條規則可能與其餘規則共同決定最終結果。好比例子中的規則只產生了增量,還須要與肯定基數的規則共同做用才能決定最終的費率
可能存在條件互相交叉的規則,此時有必要規定規則的優先級
規則做爲一種知識,其典型運用就是經過實際狀況,根據給定的一組規則,得出結論。這個結論多是某種靜態的結果,也多是須要進行的一組操做。這種 規則的運用過程叫作推理。若是由程序來處理推理過程,那麼這個程序就叫作推理機/推理引擎。推理引擎根據知識表示的不一樣採起的控制策略也是不一樣的,常見的 類型包括基於神經網絡、基於案例和基於規則的推理機。其中,基於規則的推理機易於理解、易於獲取、易於管理,被普遍採用。這種推理引擎被稱爲「規則引 擎」。


規則引擎起源於基於規則的專家系統(專家系統CLIPS: 源於1984年NASA的人工智能項目,現已開源,由C編寫。),而基於規則的專家系統又是專家系統的其中一個分支。專家系統屬於人工智能的範疇,它模仿 人類的推理方式,使用試探性的方法進行推理,並使用人類能理解的術語解釋和證實它的推理結論。基於規則的專家系統(RBES)包括三部分:Rule Base(knowledge base)、Working Memory(fact base)和Inference Engine。它們的結構以下系統所示:node

推理引擎(Inference Engine)包括三部分:模式匹配器(Pattern Matcher)、議程(Agenda)和執行引擎(Execution Engine)。推理引擎經過決定哪些規則知足事實或目標,並授予規則優先級,知足事實或目標的規則被加入議程。

模式匹配器決定選擇執行哪一個規則,什麼時候執行規則;
議程管理模式匹配器挑選出來的規則的執行次序;
執行引擎負責執行規則和其餘動做。
和人類的思惟相對應,規則引擎中也存在兩種推理方式:正向推理(Forward-Chaining)和反向推理(Backward-Chaining)。

正向推理也叫演繹法,由事實驅動,從 一個初始的事實出發,不斷地應用規則得出結論。首先在候選隊列中選擇一條規則做爲啓用規則進行推理,記錄其結論做爲下一步推理時的證據。如此重複這個過程,直到再無可用規則可被選用或者求得了所要求的解爲止。
反向推理也叫概括法,由目標驅動,首先提出某個假設,而後尋找支持該假設的證據,若所需的證據都能找到,說明原假設是正確的;若不管如何都找不到所須要的證據,則說明原假設不成立,此時須要另作新的假設。
將事實與規則進行匹配的算法。常見的模式匹配算法有RETE,LFA,TREAI,LEAPS。Rete算法是目前效率最高的一個演繹法推理算法,許多規則引擎都是基於Rete算法來進行推理計算的。

推理引擎的推理步驟以下:模式匹配、衝突消解、執行引擎。

將初始數據(fact)輸入 Working Memory 。
使用 Pattern Matcher 比較規則庫(rule base)中的規則(rule)和數據(fact)。
若是執行規則存在衝突(conflict),即同時激活了多個規則,將衝突的規則放入衝突集合。
解決衝突,將激活的規則按順序放入Agenda。
使用執行引擎執行Agenda中的規則。重複步驟2至5,直到執行完畢全部Agenda中的規則。
規則引擎的做用:

規則外部化,即有利於規則知識的複用,也可避免改變規則時帶來的代碼變動問題
由規則引擎使用某種算法進行推理過程,不須要編寫複雜晦澀的邏輯判斷代碼
開發人員的不須要過多關注邏輯判斷,能夠專一於邏輯處理

RETE算法

Rete在拉丁語中是「net」,有網絡的意思。Rete算法由Carnegie Mellon University的Dr Charles L. Forgy設計發明,是一個用來實現產生式規則系統(production/inference)的高效模式匹配算法。

RETE算法能夠分爲兩部分:規則編譯(rule compilation)和運行時執行(runtime execution)。

規則編譯===>是指根據規則集生成推理網絡的過程。

運行時執行===>指將數據送入推理網絡進行篩選的過程。

相關概念:

事實(Fact):對象之間及對象屬性之間的關係
規則(rule):是由條件和結論構成的推理語句,通常表示爲if…Then。一個規則的if部分稱爲LHS(left-hand-side),then部分稱爲RHS(right hand side)。
模式(module):就是指IF語句的條件。這裏IF條件多是有幾個更小的條件組成的大條件。模式就是指的不能在繼續分割下去的最小的原子條件。
RETE推理網絡的生成過程:從規則集{規則1,規則2……..}中拿出一條來,根據必定算法,變成RETE推理網絡的節點。不斷循環將全部規則都處理完,RETE推理網絡就生成了。RETE網絡主要分爲兩個部分,alpha網絡和beta網絡。以下圖所示。算法

 

alpha網絡:過濾working memory,找出符合規則中每個模式的集合,生成alpha memory(知足該模式的集合)。有兩種類型的節點,過濾type的節點和其餘條件過濾的節點(我以爲這兩種是依照須要設定的,也並不必定須要兩種節點)。
Beta網絡:有兩種類型的節點Beta Memory和Join Node。前者主要存儲Join完成後的集合。後者包含兩個輸入口,分別輸入須要匹配的兩個集合,由Join節點作合併工做傳輸給下一個節點。
在一個產生式系統中,主要流程能夠分爲如下步驟:

Match:找出符合LHS部分的working memory集合
Confilict resolution:選出一個條件被知足的規則
Act:執行RHS的內容
返回1
RETE算法主要改進Match的處理過程,經過構建一個網絡進行匹配。



具體過程以下:

建立root節點(根節點),推理網絡的入口。
拿到規則1,從規則1中取出模式1(前面說了,模式就是最小的原子條件,因此規則模式的關係是1:n)。
a)   檢查模式1中的參數類型,若是是新類型,添加一個類型節點。

b)   檢查模式1對應的Alpha節點是否存在,若是存在記錄下節點的位置;若是沒有,將模式1做爲一個Alpha節點加入到網絡中。同時根據Alpha節點創建Alpah內存表。

c)   重複b,直處處理完全部模式。

d)   組合Beta節點:Beta(2)左輸入節點爲Alpha(1),右輸入節點爲Alpha(2);Beta(i)左輸入節點是Beta(i-1),右輸入節點爲Alpha(i),並將兩個父節點的內存表內聯成爲本身的內存表

e)   重複d,直到全部Beta節點處理完畢

f)   將動做Then部分封裝成最後節點作爲Beta(n)

重複2,直到全部規則處理完畢
下面是一個從網上找得例子:


規則P1:

LHS:

C1:(年紀:研2)
C2:(性別:男)
C3:(身材:較瘦)
C4:(身高:大於175cm)
RHS:

標點符數組

Rete算法優於傳統的模式匹配算法的特色

狀態保存。事實集合中的每次變化,其匹配後的狀態都被保存再alpha和beta節點中。在下一次事實集合發生變化時,絕大多數的結果都不須要變 化,rete算法經過保存操做過程當中的狀態,避免了大量的重複計算。Rete算法主要是爲那些事實集合變化不大的系統設計的,當每次事實集合的變化很是劇 烈時,rete的狀態保存算法效果並不理想。
節點共享


Drools中用到的RETE算法

編譯算法描述了規則如何在Production Memory中產生一個有效的辨別網絡。用一個非技術性的詞來講,一個辨別網絡就是用來過濾數據。方法是經過數據在網絡中的傳播來過濾數據。在頂端節點將 會有不少匹配的數據。當咱們順着網絡向下走,匹配的數據將會愈來愈少。在網絡的最底部是終端節點(terminal nodes)。在Dr Forgy的1982年的論文中,他描述了4種基本節點:root, 1-input, 2-input and terminal。

下圖是Drools中的RETE節點類型:網絡

 

根節點(RootNode)是全部的對象進入網絡的入口。而後,從根節點當即進入到ObjectTypeNode。ObjectTypeNode的 做用是使引擎只作它須要作的事情。例如,咱們有兩個對象集:Account和Order。若是規則引擎須要對每一個對象都進行一個週期的評估,那會浪費不少 的時間。爲了提升效率,引擎將只讓匹配object type的對象經過到達節點。經過這種方法,若是一個應用assert一個新的account,它不會將Order對象傳遞到節點中。不少現代RETE實 現都有專門的ObjectTypeNode。在一些狀況下,ObjectTypeNode被用散列法進一步優化。數據結構

ObjectTypeNode可以傳播到AlphaNodes,LeftInputAdapterNodes和BetaNodes。

1-input節點一般被稱爲AlphaNode。AlphaNodes被用來評估字面條件(literal conditions)。雖然,1982年的論文只提到了相等條件(指的字面上相等),不少RETE實現支持其餘的操做。例如,Account.name == 「Mr Trout」是一個字面條件。當一條規則對於一種object type有多條的字面條件,這些字面條件將被連接在一塊兒。這是說,若是一個應用assert一個account對象,在它能到達下一個 AlphaNode 以前,它必須先知足第一個字面條件。在Dr. Forgy的論文中,他用IntraElement conditions來表述。下面的圖說明了Cheese的AlphaNode組合(name == 「cheddar」,strength == 「strong」):框架

Drools經過散列法優化了從ObjectTypeNode到AlphaNode的傳播。每次一個AlphaNode被加到一個 ObjectTypeNode的時候,就以字面值(literal value)做爲key,以AlphaNode做爲value加入HashMap。當一個新的實例進入ObjectTypeNode的時候,不用傳遞到每 一個AlphaNode,它能夠直接從HashMap中得到正確的AlphaNode,避免了沒必要要的字面檢查。



2-input節點一般被稱爲BetaNode。Drools中有兩種BetaNode:JoinNode和NotNode。BetaNodes被用來對2個對象進行對比。這兩個對象能夠是同種類型,也能夠是不一樣類型。



咱們約定BetaNodes的2個輸入稱爲左邊(left)和右邊(right)。一個BetaNode的左邊輸入一般是a list of objects。在Drools中,這是一個數組。右邊輸入是a single object。兩個NotNode能夠完成‘exists’檢查。Drools經過將索引應用在BetaNodes上擴展了RETE算法。下圖展現了一個 JoinNode的使用:ide

 

注意到圖中的左邊輸入用到了一個LeftInputAdapterNode,這個節點的做用是將一個single Object轉化爲一個單對象數組(single Object Tuple),傳播到JoinNode節點。由於咱們上面提到過左邊輸入一般是a list of objects。

Terminal nodes被用來代表一條規則已經匹配了它的全部條件(conditions)。 在這點,咱們說這條規則有了一個徹底匹配(full match)。在一些狀況下,一條帶有「或」條件的規則能夠有超過一個的terminal node。

Drools經過節點的共享來提升規則引擎的性能。由於不少的規則可能存在部分相同的模式,節點的共享容許咱們對內存中的節點數量進行壓縮,以提供遍歷節點的過程。下面的兩個規則就共享了部分節點:性能

 1 rule
 2     when
 3         Cheese( $chedddar : name  ==  " cheddar "  )
 4         $person : Person( favouriteCheese  ==  $cheddar )
 5     then
 6         System.out.println( $person.getName()  +   "  likes cheddar "  );
 7 end
 8 
 9 rule
10     when
11         Cheese( $chedddar : name  ==   " cheddar "  )
12         $person : Person( favouriteCheese  !=  $cheddar )
13     then
14         System.out.println( $person.getName()  +   "  does likes cheddar "  );
15 end
View Code

從圖上能夠看到,編譯後的RETE網絡中,AlphaNode是共享的,而BetaNode不是共享的。上面說的相等和不相等就體如今BetaNode的不一樣。而後這兩條規則有各自的Terminal Node。


RETE算法的第二個部分是運行時(runtime)。當一個應用assert一個對象,引擎將數據傳遞到root
node。從那裏,它進入ObjectTypeNode並沿着網絡向下傳播。當數據匹配一個節點的條件,節點就將它記錄到相應的內存中。這樣作的緣由有以
 
下幾點:主要的緣由是能夠帶來更快的性能。雖然記住徹底或部分匹配的對象須要內存,它提供了速度和可伸縮性的特色。當一條規則的全部條件都知足,這就是完
 
全匹配。而只有部分條件知足,就是部分匹配。(我以爲引擎在每一個節點都有其對應的內存來儲存知足該節點條件的對象,這就形成了若是一個對象是徹底匹配,那
 這個對象就會在每一個節點的對應內存中都存有其映象。)測試

參考連接:

引用地址:http://www.biaodianfu.com/rules-engine.html

 

另外一篇帶有案例的博客:http://hhw3.blog.163.com/blog/static/2690966201301065929233/

Java規則引擎對提交給引擎的Java數據對象進行檢索,根據這些對象的當前屬性值和它們之間的關係,從加載到引擎的規則集中發現符合條件的規則,建立 這些規則的執行實例。這些實例將在引擎接到執行指令時、依照某種優先序依次執行。通常來說,Java規則引擎內部由下面幾個部分構成:工做內存 (Working Memory)即工做區,用於存放被引擎引用的數據對象集合;規則執行隊列,用於存放被激活的規則執行實例;靜態規則區,用於存放全部被加載的業務規則, 這些規則將按照某種數據結構組織,當工做區中的數據發生改變後,引擎須要迅速根據工做區中的對象現狀,調整規則執行隊列中的規則執行實例。Java規則引 擎的結構示意圖如圖4所示。

當引擎執行時,會根據規則執行隊列中的優先順序逐條執行規則執行實例,因爲規則的執行部分可能會改變工做區的數據對象,從而會使隊列中的某些規則執行實例 由於條件改變而失效,必須從隊列中撤銷,也可能會激活原來不知足條件的規則,生成新的規則執行實例進入隊列。因而就產生了一種「動態」的規則執行鏈,造成 規則的推理機制。這種規則的「鏈式」反應徹底是由工做區中的數據驅動的。    任何一個規則引擎都須要很好地解決規則的推理機制和規則條件匹配的效率問題。規則條件匹配的效率決定了引擎的性能,引擎須要迅速測試工做區中的數據對 象,從加載的規則集中發現符合條件的規則,生成規則執行實例。1982年美國卡耐基·梅隆大學的Charles L. Forgy發明了一種叫Rete算法,很好地解決了這方面的問題。目前世界頂尖的商用業務規則引擎產品基本上都使用Rete算法。

相關文章
相關標籤/搜索