在
JBoss Rules 學習(一):什么是Rule
中,我們介紹了JBoss Rules中對Rule的表示,其中有很多JBoss Rules框架的專業術語,下面對這些術語作出進一步的解釋,可以使JBoss Rules更加容易理解。
1.Rete
算法
:
Rete
在拉丁語中是
”net”
,有網絡的意思。
RETE
算法可以分為兩部分:規則編譯(
rule compilation
)和運行時執行(
runtime execution
)。
編譯算法描述了規則如何在
Production Memory
中產生一個有效的辨別網絡。用一個非技術性的詞來說,一個辨別網絡就是用來過濾數據。方法是通過數據在網絡中的傳播來過濾數據。在頂端節點將會有很多匹配的數據。當我們順著網絡向下走,匹配的數據將會越來越少。在網絡的最底部是終端節點(
terminal nodes
)。在
Dr Forgy
的
1982
年的論文中,他描述了
4
種基本節點:
root , 1-input, 2-input and terminal
。
根節點是所有的對象進入網絡的入口。然后,從根節點立即進入到
ObjectTypeNode
。
ObjectTypeNode
的作用是使引擎只做它需要做的事情。例如,我們有兩個對象集:
Account
和
Order
。如果規則引擎需要對每個對象都進行一個周期的評估,那會浪費很多的時間。為了提高效率,引擎將只讓匹配
object type
的對象通過到達節點。通過這種方法,如果一個應用
assert
一個新的
account
,它不會將
Order
對象傳遞到節點中。很多現代
RETE
實現都有專門的
ObjectTypeNode
。在一些情況下,
ObjectTypeNode
被用散列法進一步優化。
1-input
節點通常被稱為
AlphaNode
。
AlphaNodes
被用來評估字面條件(
literal conditions
)。雖然,
1982
年的論文只提到了相等條件(指的字面上相等),很多
RETE
實現支持其他的操作。例如,
Account.name = = “Mark”
是一個字面條件。當一條規則對于一種
object type
有多條的字面條件,這些字面條件將被鏈接在一起。這是說,如果一個應用
assert
一個
account
對象,在它能到達下一個
AlphaNode
之前,它必須先滿足第一個字面條件。在
Dr. Forgy
的論文中,他用
IntraElement conditions
來表述。上一段提到的
ObjectTypeNode
是一種特殊的
AlphaNode
。
2-input
節點通常被稱為
BetaNode
。
BetaNodes
被用來對
2
個對象進行對比。這兩個對象可以是同種類型,也可以是不同類型。一個
BetaNode
的左邊輸入通常是
a list of objects
。右邊輸入是
a single object
。在一些情況下,一個規則引擎可能實現一些
BetaNodes
來處理
existential conditions (
‘與’條件
)
和
negated conditional element
(‘非’條件)。很多現代的
RETE
實現通過
hash
或
b-tree indexes
來優化
BetaNodes
。
Terminal nodes
被用來表明一條規則已經匹配了它的所有條件(
conditions
)。在一些情況下,一條帶有“或”條件的規則可以有超過一個的
terminal node
。從一個
RETE
網絡的觀點來看,一條帶有“或”條件的規則實際上只是
2
個擁有很多共享節點的節點。
RETE
算法的第二個部分是運行時(
runtime
)。當一個應用
assert
一個對象,引擎將數據傳遞到
root node
。從那里,它進入
ObjectTypeNode
并沿著網絡向下傳播。當數據匹配一個節點的條件,節點就將它記錄到相應的內存中。這樣做的原因有以下幾點:主要的原因是可以帶來更快的性能。雖然記住完全或部分匹配的對象需要內存,它提供了速度和可伸縮性的特點。當一條規則的所有條件都滿足,這就是完全匹配。而只有部分條件滿足,就是部分匹配。(我覺得引擎在每個節點都有其對應的內存來儲存滿足該節點條件的對象,這就造成了如果一個對象是完全匹配,那這個對象就會在每個節點的對應內存中都存有其映象。)
<!--[if !supportEmptyParas]-->
2.Leaps
算法:
Production systems
的
Leaps
算法使用了一種“
lazy
”方法來評估條件(
conditions
)。一種
Leaps
算法的修改版本的實現,作為
Drools v3
的一部分,嘗試結合
Leaps
和
RETE
方法的最好的特點來處理
Working Memory
中的
facts
。
古典的
Leaps
方法將所有的
asserted
的
facts
,按照其被
asserted
在
Working Memory
中的順序(
FIFO
),放在主堆棧中。它一個個的檢查
facts
,通過迭代匹配
data type
的
facts
集合來找出每一個相關規則的匹配。當一個匹配的數據被發現時,系統記住此時的迭代位置以備待會的繼續迭代,并且激發規則結果(
consequence
)。當結果(
consequence
)執行完成以后,系統就會繼續處理處于主堆棧頂部的
fact
。如此反復。
<!--[if !supportEmptyParas]-->
3.RuleBase:
一個
RuleBase
包含了多個將被使用的規則包(
packages of rules
)。當規則改變時,一個
rulebase
將被產生并且緩存,直到規則再次變化。
一個
rulebase instance
是線程安全的,所有你可以在你的應用中,讓一個
rulebase instance
在多個線程中共享。對于一個
rulebase
的最通常的操作是產生一個新的
WorkingMemory
。
這個
rulebase
保持著到它所產生的
WorkingMemoryd
的弱引用,所以在長時間運行的
WorkingMemory
中,如果
rules
發生改變,這些
WorkingMemory
可以即使的根據最新的
rules
進行更新,而不必重啟
WorkingMemory
。
4.WorkingMemory:
WorkingMemory
基本上就是已經載入所有的
rules
,并且準備啟動的
rule engine
。它保持了所有被
asserted
進
WorkingMemory
的數據的引用,直到取消(
retracted
)。并且它是與你的系統進行交互的地方。
WorkingMemory
是有狀態對象。它們的生命周期可長可短。如果從一個短生命周期的角度來同一個引擎進行交互,意味著你可以使用
RuleBase
對象來為每個
session
產生一個新的
WorkingMemory
,然后在結束
session
后
discard
這個
WorkingMemory
(產生一個
WorkingMemory
是一個廉價的操作)。另一種形式,就是在一個相當長的時間中(例如一個
conversation
),保持一個
WorkingMemory
,并且對于新的
facts
保持持續的更新。
4.1 Facts
Facts
是從你的應用中,被
assert
進
WorkingMemory
中的對象(
beans
)。
Facts
是規則可以訪問的任意的
java
對象。規則引擎中的
facts
并不是“
clone
”
facts
,它只是持有到你的應用中數據的引用。
4.2 Assertion
“Assertion”
是將
facts
告訴
WorkingMemory
的動作,例如
WorkingMemory.assertObject (yourObject)
。當你
assert
一個
fact
。它將被檢查是否匹配規則。當你完成
assert facts
之后,你還要調用“
fireAllRules()
”方法來啟動匹配。
(
WorkingMemory.assertObject(yourObjcet)
只是進行
assertion
的一種
regular
方法,還存在有一種稱為
logical assertion
的動作)。
4.3 Retraction
基本上就是
assert
的逆操作。當你
retract
一個
fact
,
WorkingMemory
將不再跟蹤那個
fact
。任何依賴那個
fact
的
rules
將不被激活。注意:完全有可能存在某條規則是依賴于一個
fact
的“不存在”(
non existence
)。在這種情況下,
retract
一個
fact
將導致一條規則被激活。
4.4 Modification
規則引擎必須知道什么時候一個
fact
被改變了,因為依賴此
fact
的
rule
會因此而被再次激發。當你修改一個
fact
的時候,就告訴了規則引擎它的狀態已經改變了。
4.5 Globals
Globals
是一個能夠被傳進規則引擎的命名的對象。大多數這些對象被用來作為靜態信息或服務。這些服務被用在一條規則的
RHS
,或者可能是從規則引擎返回對象的一種方法。
4.6 Property Change Listener
如果你的
fact
對象是
java bean
,你可以為它們實現一個
property change listener
,然后把它高數規則引擎。這意味著,當一個
fact
改變時,規則引擎將會自動知道,并進行響應的動作。
Proxy libraries
將會幫助實現這一切。
4.7 Stateless and Statefull Sessions
基于
RETE
算法的規則引擎是有狀態的規則引擎。有狀態帶來的好處是改變能夠被通知和累計
facts
(
accumulating facts
)。
盡管如此,在很多情況下,所有提供給規則引擎的的
facts
都是最新的,緊接著規則被激活。在這種情況下僅僅需要一種無狀態的模式。
JSR-94 API
指定了有狀態和無狀態的模式,但是在
native API
中的等價物僅僅是創建一個新的
WorkingMemory
實例,然后當
session
結束時刪除它。
<!--[if !supportEmptyParas]-->?
5. Agenda:
Agenda
是
RETE
的一個特點。它是內存中的一個區域,在規則和匹配的
facts
被激發之前,它們被保存在這里,稱為“
activations
”。
引擎工作在一個“
2
階段”模式下:
<!--[if !supportLists]--> 1)? <!--[endif]--> WorkingMemory actions :assert新的facts,修改存在的facts和retract facts都是WorkingMemory actions。這些動作從一條規則的RHS或是java code中被觸發。
<!--[if !supportLists]--> 2)? <!--[endif]--> Agenda evaluation(rule actions在這里被激發)。
注意:這個過程是一個輪流發生的過程,一條規則的激發可能引起
WorkingMemory actions
的發生。當
WorkingMemory actions
發生時,應該沒有規則正在被激發。
fireAllRules()
方法引起
Agenda evaluation
,最終“
activations
”激發。這個過程一直重復直到
Agenda
被清空,此時控制權就回到應用程序中。
5.1 Conflict Resultion
當有多條
rules
在
agenda
中,就需要解決沖突。當激發一條規則時,會對
WorkingMemory
產生副作用。規則引擎需要知道規則要以什么順序來激發(例如,激發
rule A
可能會引起
rule B
被從
agenda
中移除。)
Drools
采取的沖突解決策略有
4
種,按照優先級排列如下:
Salience
,
FIFO
(先進先出),
Total Recency
和
Load order
。
優先級最高,也是最易懂的策略是“
Salience
”,即優先級,
user
可以為某個
rule
指定一個高一點的優先級(通過附給它一個比較大的數字)。高
Salience
的
rule
將會被優先激發。
優先級最低的策略是
Load order
,就是按照
rule
被聲明的順序。
5.2 Agenda Groups
Agenda Groups
是劃分
Agenda
中
rules
(其實是“
activations
”)的一種方法。在任意一個時刻,只有一個
group
擁有“
focus
”,這意味著只有在那個
group
中的
activations for rules
才是有效的。
5.3 Filters
Filter
是
filter
接口的可選實現,用來允許或禁止一個
activation
能夠被激發。