Rete網絡算法

原文鏈接:https://blog.csdn.net/u012373815/article/details/53869097

Rete算法是Charles Forgy在1979年的論文中首次提出的,針對基於規則知識表現的模式匹配算法。目前來說,大部分規則引擎還是基於rete算法作爲核心,但都有所改進,比如drool,jess等等,下面介紹rete算法的概念

1.rete 算法

Rete算法是一種高效的模式匹配算法用來實現產生式規則系統
(空間換時間,用內存換取匹配速度)

它是高效的算法,它通過緩存避免了相同條件多次評估的情況,但是帶來了大量的內存使用

Rete 在拉丁語中是 ”net” ,有網絡的意思;Rete算法通過規則條件生成了一個網絡,每個規則條件是網絡中的一個節點


rete可以被分爲兩部分:規則編譯和運行時執行。規則編譯是指根據規則集生成推理網絡的過程,運行時執行指將數據送入推理網絡進行篩選的過程。

2.規則編譯

規則編譯就是根據規則文件推理生成網絡的過程。下面展示一下推理後的網絡節點圖。(大家只用看一下,心裏有個印象就好,下面我會分析講解)

圖一
這裏寫圖片描述

2.1 Root Node:

(如圖一的黑色節點) 根節點(RootNode)是所有對象進入網絡的入口,然後進入到TypeNode

2.2 Type Node

(有的叫ObjectTypeNode,圖一的紅色節點): type Node 就是我們的fact 也就是我們規則所用到的pojo;每個fact 就是一個 type node。 type Node 就是類型檢查,引擎只讓匹配Object 類型的對象到達節點,它能夠傳播到 AlphaNodes、LeftInputAdapterNodes (作爲betaNodes的左端輸入節點)和 BetaNodes

舉例:有兩個fact ,Person 和cheese 。那麼節點圖就如下所示。

這裏寫圖片描述

2.3 Alpha Node

:(圖一的藍色節點)用來評估字面條件,例如。person.age>10 這就是一個 alpha node 節點,當一條規則有多條字面條件,這些字面條件被鏈接到一起。

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

舉例 1:條件 Cheese (name=”cheddar” ,strengh==”strong”)

解釋:name 和 strengh 都是對象Cheese 的屬性,且name 和 strengh兩個條件的關係是且,必須同時滿足拿麼節點圖如下所示:

這裏寫圖片描述


舉例 2:在舉例1 的條件上添加另外一條規則 Cheese (name=”cheddar” ,age>10)

解釋:name 和 age 都是對象Cheese 的屬性,且name 和 age兩個條件的關係是且,必須同時滿足,拿麼結合舉例1的節點圖,如下所示:

這裏寫圖片描述

此時我們發現我門共享了(name==“cheddar“) 節點。

2.4 Bate Node:

(如圖一的綠色節點)用來對2個對象進行對比、檢查。約定BetaNode的2個輸入稱爲左邊(Join Node)和右邊。左邊通常是一個a list of objects,右邊(NotNode)通常是 a single object。每個Bate節點都有自己的終端節點等組成

BetaNode 具有記憶功能。左邊的輸入被稱爲 Beta Memory,會記住所有到達過的語義。右邊的輸入成爲 Alpha Memory,會記住所有到達過的對象。


舉例:條件 Cheese (name=”cheddar” ) Person(favouriteiteCheese==”cheese.name”)。

解釋:這個兩個對象Cheese和Person 的關聯操作。Cheese的name=”cheddar” 且cheese.ame ==favouriteiteCheese。那麼節點圖如下所示。

這裏寫圖片描述

圖中黃色的node 我門稱爲LeftInputAdapterNode,這個節點的作用是將一個single Object轉化爲一個單對象數組(single Object Tuple),傳播到JoinNode節點。因爲我們上面提到過左邊輸入通常是a list of objects。


舉例2:

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

網絡圖如下:

這裏寫圖片描述

Drools 通過節點的共享來提高規則引擎的性能。因爲很多的規則可能存在部分相同的模式,節點的共享允許我們對內存中的節點數量進行壓縮,以提供遍歷節點的過程

從圖上可以看到,編譯後的RETE網絡中,AlphaNode是共享的,而BetaNode不是共享的。上面說的相等和不相等就體現在BetaNode的不同。然後這兩條規則有各自的Terminal Node。

2.5 創建 rete 網絡

Rete 算法的編譯結果是創建了規則集對應的 Rete 網絡 , 它是一個事實可以在其中流動的圖。創建 rete 網絡的過程 [1]如下:

1) 創建根節點;
2) 加入一條規則

a. 取出規則中的一個模式 ,(模式就是規則中的最小一個匹配項例如(age>10,age<20)拿麼age>10 就是一個模式,age<20 就是另一個模式。)檢查模式中的參數類型,如果是新類型(也就是新的fact類型),則加入一個類型節點;

b. 檢查模式  對應的 Alpha 節點是否已存在,如果存在則記錄下節點位置,如果沒有則將模式  作爲一個 Alpha 節點加入到網絡中,同時根據 Alpha 節點的模式建立 Alpha 內存表;

c. 重複 b 直到所有的模式處理完畢;

d. 組合 Beta 節點,按照如下方式: Beta 左輸入節點爲 Alpha(1),右輸入節點爲 Alpha(2) 。Beta(i) 左輸入節點爲 Beta(i-1),右輸入節點爲 Alpha(i) i>2 並將兩個父節點的內存表內聯成爲自己的內存表; 

e. 重複 d 直到所有的 Beta 節點處理完畢;

f. 將動作(Then 部分)封裝成葉節點(Action 節點)作爲 Beta(n) 的輸出節點;

3) 重複 2) 直到所有規則處理完畢; 執行完上述步驟,建立的 rete 網絡圖

3. 運行時執行

WME :存儲區儲存的最小單位是工作存儲區元素(Working Memory Element,簡稱WME),WME是爲事實建立的元素,是用於和非根結點代表的模式進行匹配的元素。

Token:是WME的列表,包含有多個WME,(在Forgy的論文中,把Token看成是WME的列表或者單個WME,爲了闡述方便,本文將把Token只看成WME的列表)

(1)如果WME的類型和根節點的後繼結點TypeNode(alpha結點的一種)所指定的類型相同,則會將該事實保存在該TypeNode結點對應的alpha存儲區中,該WME被傳到後繼結點繼續匹配,否則會放棄該WME的後續匹配;

TypeNode存儲: 每次一個AlphaNode被加到一個 ObjectTypeNode的時候,就以字面值(literal value)也就是file 作爲key,以AlphaNode作爲value加入HashMap。當一個新的實例進入ObjectTypeNode的時候,不用傳遞到每 一個AlphaNode,它可以直接從HashMap中獲得正確的AlphaNode,避免了不必要的字面檢查。

(2)如果WME被傳遞到alpha結點,則會檢測WME是否和該結點對應的模式相匹配,若匹配,則會將該事實保存在該alpha結點對應的存儲區中,該WME被傳遞到後繼結點繼續匹配,否則會放棄該WME的後續匹配;

alpha 存儲:檢測WME是否和該結點對應的模式相匹配,若匹配,則會將該事實保存在該alpha結點對應的存儲區中,該WME被傳遞到後繼結點繼續匹配

(3)如果WME被傳遞到beta結點的右端,則會加入到該beta結點的right存儲區,並和left存儲區中的Token進行匹配(匹配動作根據beta結點的類型進行,例如:join,projection,selection),匹配成功,則會將該WME加入到Token中,然後將Token傳遞到下一個結點,否則會放棄該WME的後續匹配;

bate存儲區:

每個非根結點都有一個存儲區。其中1-input(alpha)結點有alpha存儲區和一個輸入口;

2-input(bate)結點有left存儲區和right存儲區和左右兩個輸入口,其中left存儲區是beta存儲區,right存儲區是alpha存儲區。存儲區儲存的最小單位是工作存儲區元素(Working Memory Element,簡稱WME),WME是爲事實建立的元素,是用於和非根結點代表的模式進行匹配的元素。

(4)如果Token被傳遞到beta結點的左端,則會加入到該beta結點的left存儲區,並和right存儲區中的WME進行匹配(匹配動作根據beta結點的類型進行,例如:join,projection,selection),匹配成功,則該Token會封裝匹配到的WME形成新的Token,傳遞到下一個結點,否則會放棄該Token的後續匹配;

(5)如果WME被傳遞到beta結點的左端,將WME封裝成僅有一個WME元素的WME列表做爲Token,然後按照(4)所示的方法進行匹配;

(6)如果Token傳遞到終結點,則和該根結點對應的規則被激活,建立相應的Activation,並存儲到Agenda當中,等待激發。

(7)如果WME被傳遞到終結點,將WME封裝成僅有一個WME元素的WME列表做爲Token,然後按照(6)所示的方法進行匹配;

以上是RETE算法對於不同的結點,來進行WME或者token和結點對應模式的匹配的過程。


4. Rete 算法的特點:

a. Rete 算法是一種啓發式算法,不同規則之間往往含有相同的模式,因此在 beta-network 中可以共享 BetaMemory 和 betanode。如果某個 betanode 被 N 條規則共享,則算法在此節點上效率會提高 N 倍。

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

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

5. Rete 算法的不足:

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

b. RETE 算法使用了β存儲區存儲已計算的中間結果, 以犧牲空間換取時間, 從而加快系統的速度。然而β存儲區根據規則的條件與事實的數目而成指數級增長, 所以當規則與事實很多時, 會耗盡系統資源 [3]。
針對 Rete 算法的特點和不足,在應用或者開發基於 Rete 算法的規則引擎時,提出如下建議:

    a. 容易變化的規則儘量置後匹配,可以減少規則的變化帶來規則庫的變化。
    b. 約束性較爲通用或較強的模式儘量置前匹配,可以避免不必要的匹配。
    c. 針對 Rete 算法內存開銷大和事實增加刪除影響效率的問題,技術上應該在 alpha 內存和 beata 內存中,只存儲指向內存的指針,並對指針建裏索引(可用 hash 表或者非平衡二叉樹)。
    d. Rete 算法 JoinNode 可以擴展爲 AndJoinNode 和 OrJoinNode,兩種節點可以再進行組合 [5]。

備註:此文轉載,實屬好文,如有侵權,聯繫刪除。

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