隨筆 - 19, 文章 - 93, 評論 - 17, 引用 - 0
          數(shù)據(jù)加載中……

          (二): RETE算法

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

          1.Rete 算法

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

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

          ?

          Figure 1. Rete Nodes

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

          Figure 2 .?ObjectTypeNodes

          ObjectTypeNode 能夠傳播到 AlphaNodes, LeftInputAdapterNodes BetaNodes 。

          1-input 節(jié)點通常被稱為 AlphaNode AlphaNodes 被用來評估字面條件( literal conditions )。雖然, 1982 年的論文只提到了相等條件(指的字面上相等),很多 RETE 實現(xiàn)支持其他的操作。例如, Account.name = = “Mr Trout” 是一個字面條件。當(dāng)一條規(guī)則對于一種 object type 有多條的字面條件,這些字面條件將被鏈接在一起。這是說,如果一個應(yīng)用 assert 一個 account 對象,在它能到達下一個 AlphaNode 之前,它必須先滿足第一個字面條件。在 Dr. Forgy 的論文中,他用 IntraElement conditions 來表述。下面的圖說明了 Cheese AlphaNode 組合( name = = “cheddar” , strength = = “strong” ):


          Figure 3.?AlphaNodes

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

          <!--[if !supportEmptyParas]-->

          2-input 節(jié)點通常被稱為 BetaNode Drools 中有兩種 BetaNode JoinNode NotNode BetaNodes 被用來對 2 個對象進行對比。這兩個對象可以是同種類型,也可以是不同類型。

          我們約定 BetaNodes 2 個輸入稱為左邊( left )和右邊( right )。一個 BetaNode 的左邊輸入通常是 a list of objects 。在 Drools 中,這是一個數(shù)組。右邊輸入是 a single object 。兩個 NotNode 可以完成‘ exists ’檢查。 Drools 通過將索引應(yīng)用在 BetaNodes 上擴展了 RETE 算法。下圖展示了一個 JoinNode 的使用:

          Figure 4 .?JoinNode


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

          <!--[if !supportEmptyParas]-->

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

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

          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 ,一條規(guī)則是等于 $cheddar ,而另一條規(guī)則是不等于 $cheddar 。下面是這兩條規(guī)則的節(jié)點圖:

          Figure 5 .?Node Sharing

          從圖上可以看到,編譯后的 RETE 網(wǎng)絡(luò)中, AlphaNode 是共享的,而 BetaNode 不是共享的。上面說的相等和不相等就體現(xiàn)在 BetaNode 的不同。然后這兩條規(guī)則有各自的 Terminal Node 。

          <!--[if !supportEmptyParas]-->

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

          2. Leaps 算法:

          Production systems Leaps 算法使用了一種“ lazy ”方法來評估條件( conditions )。一種 Leaps 算法的修改版本的實現(xiàn),作為 Drools v3 的一部分,嘗試結(jié)合 Leaps RETE 方法的最好的特點來處理 Working Memory 中的 facts 。

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

          posted on 2006-12-03 09:53 BPM 閱讀(555) 評論(0)  編輯  收藏 所屬分類: 規(guī)則引擎

          主站蜘蛛池模板: 岑巩县| 特克斯县| 高陵县| 福泉市| 米泉市| 桦甸市| 鸡西市| 蒙城县| 兴城市| 香港| 宁武县| 和龙市| 神池县| 健康| 蕲春县| 巴彦淖尔市| 二手房| 翁源县| 怀仁县| 桐梓县| 南平市| 噶尔县| 白城市| 布拖县| 延长县| 永和县| 绍兴市| 曲靖市| 岐山县| 墨玉县| 化德县| 吉安市| 类乌齐县| 五家渠市| 元氏县| 吉木萨尔县| 泊头市| 日土县| 天水市| 来宾市| 霞浦县|