guangnian0412's BLOG

          Java in my life

          常用鏈接

          統計

          積分與排名

          我關注的Blog

          最新評論

          JBoss Rules 學習(二): RETE算法

          JBoss Rules 學習(一):什么是Rule中,我們介紹了JBoss Rules中對Rule的表示,其中提到了JBoss Rule中主要采用的RETE算法來進行規則匹配。下面將詳細的介紹一下RETE算法在JBoss Rule中的實現,最后隨便提一下JBoss Rules中也可以使用的另一種規則匹配算法Leaps。

          1.Rete 算法

          Rete 在拉丁語中是 ”net” ,有網絡的意思。 RETE 算法可以分為兩部分:規則編譯( rule compilation )和運行時執行( runtime execution )。

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

          ?

          Figure 1. Rete Nodes

          根節點( RootNode )是所有的對象進入網絡的入口。然后,從根節點立即進入到 ObjectTypeNode ObjectTypeNode 的作用是使引擎只做它需要做的事情。例如,我們有兩個對象集: Account Order 。如果規則引擎需要對每個對象都進行一個周期的評估,那會浪費很多的時間。為了提高效率,引擎將只讓匹配 object type 的對象通過到達節點。通過這種方法,如果一個應用 assert 一個新的 account ,它不會將 Order 對象傳遞到節點中。很多現代 RETE 實現都有專門的 ObjectTypeNode 。在一些情況下, ObjectTypeNode 被用散列法進一步優化。

          Figure 2 .?ObjectTypeNodes

          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” ):


          Figure 3.?AlphaNodes

          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 的使用:

          Figure 4 .?JoinNode


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

          Terminal nodes 被用來表明一條規則已經匹配了它的所有條件( conditions )。 在這點,我們說這條規則有了一個完全匹配( full match )。在一些情況下,一條帶有“或”條件的規則可以有超過一個的 terminal node 。

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

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


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

          這里我們先不探討這兩條 rule 到的是什么意思,單從一個直觀的感覺,這兩條 rule 在它們的 LHS 中基本都是一樣的,只是最后的 favouriteCheese ,一條規則是等于 $cheddar ,而另一條規則是不等于 $cheddar 。下面是這兩條規則的節點圖:

          Figure 5 .?Node Sharing

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

          RETE 算法的第二個部分是運行時( runtime )。當一個應用 assert 一個對象,引擎將數據傳遞到 root node 。從那里,它進入 ObjectTypeNode 并沿著網絡向下傳播。當數據匹配一個節點的條件,節點就將它記錄到相應的內存中。這樣做的原因有以下幾點:主要的原因是可以帶來更快的性能。雖然記住完全或部分匹配的對象需要內存,它提供了速度和可伸縮性的特點。當一條規則的所有條件都滿足,這就是完全匹配。而只有部分條件滿足,就是部分匹配。(我覺得引擎在每個節點都有其對應的內存來儲存滿足該節點條件的對象,這就造成了如果一個對象是完全匹配,那這個對象就會在每個節點的對應內存中都存有其映象。)

          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 。如此反復。



          posted on 2006-06-01 17:06 guangnian 閱讀(13504) 評論(4)  編輯  收藏 所屬分類: JBoss Rules(Drools)

          評論

          # re: JBoss Rules 學習(二): 一些專業術語的解釋 2006-06-01 18:13 kebo

          也在看jboss rules,可惜英文太爛.謝謝你的分享  回復  更多評論   

          # re: JBoss Rules 學習(二): RETE算法 2007-01-31 11:46 lmh

          十分謝謝你的分享  回復  更多評論   

          # re: JBoss Rules 學習(二): RETE算法,有不明白的地方。。。能解釋一下嗎? 2007-07-10 10:23 china

          古典的 Leaps 方法將所有的 asserted 的 facts ,按照其被 asserted 在 Working Memory 中的順序( FIFO ),放在主堆棧中。它一個個的檢查 facts ,通過迭代匹配 data type 的 facts 集合來找出每一個相關規則的匹配。當一個匹配的數據被發現時,系統記住此時的迭代位置以備待會的繼續迭代,并且激發規則結果( consequence )。當結果( consequence )執行完成以后,系統就會繼續處理處于主堆棧頂部的 fact 。如此反復。
          =====================
          按照其被 asserted 在 Working Memory 中的順序( FIFO ),放在主堆棧中。

          ==============
          堆棧是先進后出(FILO),如何按照先進先出(FIFO)放???


          當一個匹配的數據被發現時,系統記住此時的迭代位置以備待會的繼續迭代,并且激發規則結果( consequence )。當結果( consequence )執行完成以后,系統就會繼續處理處于主堆棧頂部的 fact 。如此反復。

          ============
          既然“當結果( consequence )執行完成以后,系統就會繼續處理處于主堆棧頂部的 fact ?!?,那你先前“系統記住此時的迭代位置以備待會的繼續迭代”是用來做什么的???難道“當結果( consequence )執行。。。。。?!崩锏摹Y果’不是“。。。。且激發規則結果( consequence )?!钡摹Y果’嗎??

            回復  更多評論   

          # re: JBoss Rules 學習(二): RETE算法[未登錄] 2008-05-28 15:20 fish

          drools 文檔中的一句話頗有啟發作用“SQL as a simplistic Inference Engine(SQL 數據庫就是一個最簡單的推理機)”  回復  更多評論   

          主站蜘蛛池模板: 彭山县| 右玉县| 溆浦县| 新巴尔虎右旗| 武邑县| 斗六市| 福建省| 福贡县| 繁峙县| 修武县| 岐山县| 巴林右旗| 昆明市| 革吉县| 加查县| 凤山市| 丰台区| 阿巴嘎旗| 昌邑市| 牡丹江市| 盘锦市| 突泉县| 石河子市| 芷江| 旺苍县| 临邑县| 邢台县| 津南区| 长沙县| 舒兰市| 宾川县| 呼和浩特市| 子洲县| 辉县市| 西畴县| 搜索| 宁安市| 鄱阳县| 巴中市| 离岛区| 大同县|