產生式規則和Rete算法解析

    Rete可以發音爲REH-te或者RAY-tay,在拉丁語中有“網絡”的含義,Rete算法是Charles Forgy博士1974年發明的一個算法。後來成爲了產生式規則系統(Production Rule System)的大腦。Drools就是基於產生式規則系統演化而來的。

產生式規則

    產生式規則是一種常用的知識表示方法,它以"IF-THEN"的形式表現了因果關係。這種形式的規則反映了人類求解(一類?)問題的行爲特徵,可以通過循環的應用這些規則來解決問題。

……
R3:IF 某動物是有蹄類動物 AND 有長脖子 AND 有長腿 AND 身上有暗斑點 THEN 該動物是長頸鹿(問題解決)
R4:IF 某動物是有蹄類動物 AND 身上有黑色條紋 THEN 該動物是斑馬(問題解決)
……
R8:IF 動物是哺乳動物 AND 嚼反動物 THEN 該動物是有蹄類動物
……
R10:IF 某動物有奶 THEN該動物是哺乳動物
……

    例如有以上一些產生式規則,給出"有奶"、"嚼反"、"長脖子"、"長腿"、"身上有暗斑點"條件(也稱爲事實 facts),就可以求解出問題的答案是“長頸鹿”。

    對於此類問題,自然想到的實現方法是逐條檢查規則,但是如上面的例子,有些知識是在推理的過程中得到的,如“哺乳動物”、“蹄類動物”,而規則不一定按照理想的順序排列,爲了能解決問題,只能循環多次,直到解決問題。對於龐大的規則集,這樣做顯然效率是非常低的。Rete算法爲產生式規則系統提供了非常高效的實現。

產生式規則系統結構

    在介紹Rete算法之前,簡單介紹以下產生式規則系統的結構。如圖所示,規則存儲於產生式內存(Production Memory),需要評估的事實(facts)被插入工作內存(Working Memory)中,在其中被修改或撤出。一個含有大量規則和事實的系統可能導致在一次事實評估中,多條規則爲真,這種情形被稱爲衝突。代理(Agenda)將使用衝突解決策略管理衝突規則的執行順序。


Rete算法

    Rete算法可以分爲規則編譯和運行時執行兩個部分,其中編譯算法是Rete算法的精髓所在,描述瞭如何處理規則生成一個高效的鑑別網絡(Discrimination network)。鑑別網絡可以理解爲用於過濾在其中傳遞的數據的網絡。Forgy博士描述了Rete算法網絡中的四類節點:


  • 根節點:所有對象進入網絡的入口,在一個網絡中只有一個根節點。
  • 單輸入節點:可分爲ObjectTypeNode, AlphaNode, LeftInputAdapterNode等。
  • 雙輸入節點:包含JoinNode和NotNode。JoinNode和NotNode也屬於用於比較兩個對象和其域的BetaNodes。
  • 終端節點:到達一個終端節點,表示單條規則匹配了所有的條件,網絡中有多個終端節點。當單條規則中有or時,也會產生多個終端節點。

ObjectTypeNode

事實從根節點進入Rete網絡後,會立即進入ObjectTypeNode節點,ObjectTypeNode提供了按對象類型過濾對象的能力,通過此類節點可使規則引擎不做額外的工作。如下圖,Cheese類型的事實進入網絡後,只需經過Cheese ObjectTypeNode之後的節點。

AlphaNode

AlphaNode節點的作用是評估字面的條件,如下圖,評估了Cheese事實的name和strength屬性值。AlphaNode之間是串行的,即只要其中一個節點不滿足,事實就被過濾掉了。

JoinNode和LeftInputAdapterNode

如前所述,雙輸入節點JoinNode是一類BetaNode,BetaNode的輸入被稱作左輸入和右輸入,其中左輸入通常是一個對象列表(元組),而右輸入是一個單個對象,可以實現對象是否在列表中存在的檢查。LeftInputAdapterNode的作用是輸入一個對象,傳播爲一個單對象列表(元組)。如圖所示,JoinNode的左輸入爲一個經過LeftInputAdapterNode傳播後的列表,右輸入爲一個Person對象。

Drools規則和Rete算法的例子

// rule 1
when
    Cheese( $cheddar : name == "cheddar" )
    $person : Person( favouriteCheese == $cheddar )
then
    System.out.println( $person.getName() + " likes cheddar" );
end
// rule 2
when
    Cheese( $cheddar : name == "cheddar" )
    $person : Person( favouriteCheese != $cheddar )
then
    System.out.println( $person.getName() + " does not like cheddar" );
end


    圖示的Rete網絡除了展示了代碼塊中的Drools規則,還體現了Rete算法中節點共享的特徵,此特徵減少了網絡中結點的冗餘。

參考資料

1. 產生式規則表示法

2. 產生式表示法

3. Drools官方文檔

4. Rete算法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章