RIP RETE时间获得PHREAKY
我剛剛完成了我稱為PHREAK的新規(guī)則算法的一些高級文檔,這是混合推理中的一個(gè)文字游戲。 它仍然有點(diǎn)粗糙和高水平,但希望仍然很有趣。 它建立在ReteOO之上,非常好閱讀。
ReteOO算法
ReteOO是在3、4和5系列發(fā)行版中開發(fā)的。 它采用RETE算法并應(yīng)用了眾所周知的增強(qiáng)功能,現(xiàn)有的學(xué)術(shù)文獻(xiàn)都涵蓋了所有這些增強(qiáng)功能:
- 節(jié)點(diǎn)共享
共享同時(shí)應(yīng)用于Alpha和Beta網(wǎng)絡(luò)。 Beta網(wǎng)絡(luò)共享始終來自根模式。
- 字母索引
具有許多子級的Alpha節(jié)點(diǎn)使用哈希查找機(jī)制,以避免測試每個(gè)結(jié)果。
- Beta索引連接,不存在節(jié)點(diǎn)和存在節(jié)點(diǎn)使用哈希索引它們的內(nèi)存。 這減少了相等檢查的聯(lián)接嘗試。 最近,范圍索引已添加到“不存在”中。
- 基于樹的圖
聯(lián)接匹配不包含對其父項(xiàng)或子項(xiàng)匹配的任何引用。 刪除將不得不再次重新計(jì)算所有聯(lián)接匹配,這涉及到重新創(chuàng)建所有那些聯(lián)接匹配對象,以便能夠找到應(yīng)刪除元組的網(wǎng)絡(luò)部分。 這稱為對稱傳播。 樹形圖提供了父級和子級引用,因此刪除僅需遵循這些引用即可。 這是不對稱傳播。 結(jié)果更快,對GC的影響更小,并且更可靠,因?yàn)橹档母牟粫诓煌ㄖ娴那闆r下導(dǎo)致內(nèi)存泄漏。
- 就地修改
傳統(tǒng)的RETE將修改實(shí)現(xiàn)為刪除+插入。 這將導(dǎo)致所有聯(lián)接元組都經(jīng)過GC處理,其中許多作為插入的一部分再次被重新創(chuàng)建。 相反,就地修改傳播為單遍,檢查每個(gè)節(jié)點(diǎn)
- 反應(yīng)性
也稱為“新觸發(fā)條件”。 允許更精細(xì)的反應(yīng)性來更新。 模式可以對特定屬性的更改做出反應(yīng),而忽略其他屬性。 這樣可以減輕遞歸問題,并有助于提高性能。
- 子網(wǎng)
否,“存在”和“累積”可以各自具有嵌套的條件元素,這些條件元素構(gòu)成了子網(wǎng)。
- 向后鏈接
支持用于反向鏈接的Prolog樣式派生樹。 該實(shí)現(xiàn)是基于堆棧的,因此對于大型圖不存在方法遞歸問題。
- 懶惰真相維護(hù)
真相維護(hù)會產(chǎn)生運(yùn)行時(shí)成本,無論是否使用TMS,都會產(chǎn)生運(yùn)行時(shí)成本。 惰性TMS僅在首次使用時(shí)將其打開。 此外,它僅針對該對象類型啟用,因此其他對象類型不會產(chǎn)生運(yùn)行時(shí)成本。
- 基于堆的議程
議程使用二進(jìn)制堆隊(duì)列按顯著性對規(guī)則匹配進(jìn)行排序,而不是使用任何線性搜索或維護(hù)方法。
- 動態(tài)規(guī)則
可以在運(yùn)行時(shí)添加和刪除規(guī)則,而引擎仍將填充數(shù)據(jù)。
PHREAK算法
Drools 6引入了一種新算法,試圖解決RETE的一些核心問題。 該算法不是從頭開始重寫的方法,它結(jié)合了ReteOO的所有現(xiàn)有代碼及其所有增強(qiáng)功能。 盡管PHREAK是RETE算法的改進(jìn),但它不再被歸類為RETE實(shí)現(xiàn)。 就像動物進(jìn)化超過特定點(diǎn)并改變關(guān)鍵特征一樣,該動物也被歸類為新物種。 無論優(yōu)化如何,有兩個(gè)關(guān)鍵的RETE特征可強(qiáng)烈識別任何衍生菌株。 這是一個(gè)渴望的,面向數(shù)據(jù)的算法。 在插入,更新或刪除操作期間完成所有工作的位置; 急于產(chǎn)生所有規(guī)則的所有部分匹配。 相比之下,PHREAK被描述為一種懶惰的,面向目標(biāo)的算法。 其中部分匹配會被嚴(yán)重延遲。
RETE的這種渴望會導(dǎo)致大型系統(tǒng)中的大量用戶流失,并浪費(fèi)大量工作。 浪費(fèi)的工作歸類為不會導(dǎo)致解雇的匹配工作。
PHREAK受到許多算法的啟發(fā)。 包括(但不限于)LEAPS,RETE / UL和面向集合的匹配。 PHREAK具有ReteOO部分中列出的所有增強(qiáng)功能。 此外,它還添加了以下增強(qiáng)功能集,將在以下各段中進(jìn)行詳細(xì)說明。
- 三層上下文記憶; 節(jié)點(diǎn),段和規(guī)則存儲器。
- 基于規(guī)則,分段和節(jié)點(diǎn)的鏈接。
- 懶惰(延遲)規(guī)則評估。
- 孤立的規(guī)則評估。
- 面向集合的傳播。
- 基于堆棧的評估,包括暫停和繼續(xù)。
當(dāng)PHREAK引擎啟動時(shí),所有規(guī)則都被認(rèn)為是未鏈接的,因此,當(dāng)規(guī)則未鏈接時(shí),將不會進(jìn)行任何規(guī)則評估。 進(jìn)入Beta網(wǎng)絡(luò)之前,插入,更新和刪除操作已排隊(duì)。 根據(jù)最有可能導(dǎo)致解雇的規(guī)則,使用一種簡單的啟發(fā)式方法來選擇下一個(gè)評估規(guī)則; 這會延遲評估和觸發(fā)其他規(guī)則。 盡管尚未完成任何工作,但只有在規(guī)則中填充了所有正確輸入后,該規(guī)則才被視為已鏈接。 而是創(chuàng)建一個(gè)代表規(guī)則的目標(biāo),并將其放入優(yōu)先級隊(duì)列中。 這是由顯著性命令的。 每個(gè)隊(duì)列本身都與AngendaGroup相關(guān)聯(lián)。 只有活動的AgendaGroup會檢查其隊(duì)列,以最高顯著性彈出規(guī)則的目標(biāo),并將其提交評估。 因此,完成的工作從插入,更新,刪除階段轉(zhuǎn)移到fireAllRules階段。 僅評估為其創(chuàng)建目標(biāo)的規(guī)則,而根據(jù)這些事實(shí)進(jìn)行的其他潛在規(guī)則評估將被延遲。 在評估各個(gè)規(guī)則時(shí),仍然可以通過分段過程來實(shí)現(xiàn)節(jié)點(diǎn)共享,這將在后面說明。
RETE中每次成功的加入嘗試都會生成一個(gè)元組(或令牌,或部分匹配),該元組將傳播到子節(jié)點(diǎn)。 因此,它被描述為面向元組的算法。 對于到達(dá)的每個(gè)子節(jié)點(diǎn),它將嘗試與該節(jié)點(diǎn)的另一側(cè)進(jìn)行聯(lián)接,再次,每次成功的聯(lián)接嘗試都將立即傳播。 這將產(chǎn)生下降遞歸效果。 當(dāng)節(jié)點(diǎn)網(wǎng)絡(luò)從進(jìn)入beta網(wǎng)絡(luò)的點(diǎn)到所有可到達(dá)的葉節(jié)點(diǎn)上下左右波動時(shí),對節(jié)點(diǎn)網(wǎng)絡(luò)進(jìn)行處理。
PHREAK傳播是面向集合(或面向集合)的,而不是面向元組的。 對于正在評估的規(guī)則,它將訪問第一個(gè)節(jié)點(diǎn)并處理所有排隊(duì)的插入,更新和刪除。 將結(jié)果添加到集合中,并將該集合傳播到子節(jié)點(diǎn)。 在子節(jié)點(diǎn)中,所有排隊(duì)的插入,更新和刪除都將被處理,并將結(jié)果添加到同一集合中。 完成后,該集合將傳播到下一個(gè)子節(jié)點(diǎn),依此類推,直到到達(dá)終端節(jié)點(diǎn)。 這將創(chuàng)建一個(gè)單一的管道類型效果,該效果與當(dāng)前正在評估的規(guī)則隔離。 這將創(chuàng)建批處理效果,可以為某些規(guī)則構(gòu)造提供性能優(yōu)勢。 例如具有累積作用的子網(wǎng)。 將來,它將依靠多種方式來利用多核計(jì)算機(jī)。
鏈接和取消鏈接使用基于網(wǎng)絡(luò)分段的分層位掩碼系統(tǒng)。 構(gòu)建規(guī)則網(wǎng)絡(luò)后,將為由同一組規(guī)則共享的節(jié)點(diǎn)創(chuàng)建分段。 規(guī)則本身是由段的路徑組成的,盡管如果沒有共享,則將是一個(gè)段。 將位掩碼偏移量分配給段中的每個(gè)節(jié)點(diǎn)。 另外,將另一個(gè)位掩碼(分層)分配給規(guī)則路徑中的每個(gè)段。 當(dāng)至少有一個(gè)輸入(數(shù)據(jù)傳播)時(shí),節(jié)點(diǎn)的位設(shè)置為on。 每個(gè)節(jié)點(diǎn)的位設(shè)置為on時(shí),段的位也設(shè)置為on。 相反,如果任何節(jié)點(diǎn)的位設(shè)置為關(guān)閉,則該段也將設(shè)置為關(guān)閉。 如果將規(guī)則路徑中的每個(gè)細(xì)分均設(shè)置為啟用,則將規(guī)則鏈接到該規(guī)則中,并創(chuàng)建一個(gè)目標(biāo)來計(jì)劃該規(guī)則以進(jìn)行評估。 相同的位掩碼技術(shù)還用于跟蹤臟節(jié)點(diǎn),段和規(guī)則。 如果自上次評估以來認(rèn)為已變臟的規(guī)則,則可以安排已鏈接的規(guī)則進(jìn)行評估。
這樣可以確保沒有規(guī)則會評估部分匹配,如果由于其中一個(gè)聯(lián)接沒有數(shù)據(jù)而導(dǎo)致它無法導(dǎo)致規(guī)則實(shí)例的情況,則不會評估。 這在RETE中是可能的,并且即使最后一個(gè)連接為空,也會為所有節(jié)點(diǎn)產(chǎn)生混亂的匹配嘗試。
雖然增量規(guī)則評估始終從根節(jié)點(diǎn)開始,但臟位掩碼用于允許跳過不臟的節(jié)點(diǎn)和段。
使用每個(gè)節(jié)點(diǎn)至少存在一項(xiàng)數(shù)據(jù)是一種相當(dāng)基本的啟發(fā)式方法。 未來的工作將試圖進(jìn)一步延遲鏈接; 使用諸如弧一致性的技術(shù)來確定匹配是否會導(dǎo)致規(guī)則實(shí)例觸發(fā)。
由于RETE僅具有一個(gè)單一的存儲器單元(節(jié)點(diǎn)存儲器),因此PHREAK具有3個(gè)級別的存儲器。 這樣可以在評估規(guī)則期間獲得更多的上下文理解。
PHREAK 3分層存儲系統(tǒng)
示例1顯示了具有三種模式的一條規(guī)則; A,B和C。它形成單個(gè)段,節(jié)點(diǎn)的位1、2和4。
示例1:單一規(guī)則,不共享
示例2演示了添加另一個(gè)共享模式A的規(guī)則時(shí)會發(fā)生的情況。A放置在其自己的細(xì)分中,每個(gè)規(guī)則導(dǎo)致兩個(gè)細(xì)分。 這兩段構(gòu)成了各自規(guī)則的路徑。 第一條路段由兩條路徑共享。 當(dāng)鏈接A時(shí),該段將被鏈接,然后迭代該段共享的每個(gè)路徑,將位1設(shè)置為on。 如果稍后打開B和C,則鏈接到路徑R1的第二段; 這將導(dǎo)致R1的位2被打開。 將R1的位1和位2設(shè)置為打開后,現(xiàn)在將鏈接該規(guī)則,并創(chuàng)建一個(gè)目標(biāo)以計(jì)劃該規(guī)則以供以后評估和觸發(fā)。
評估規(guī)則時(shí),正是可以共享匹配結(jié)果的細(xì)分。 每個(gè)段都有一個(gè)臨時(shí)存儲器,用于將該段的所有插入,更新和刪除排隊(duì)。 如果要評估R1,它將處理A并得到一組元組。 該算法檢測到有分段分割,并將為集合中的每個(gè)插入,更新和刪除創(chuàng)建對等元組,并將它們添加到R2的暫存中。 這些元組將與任何現(xiàn)有的暫存元組合并,并等待R2最終被評估。
示例2:共享的兩個(gè)規(guī)則
示例3添加了第三條規(guī)則,并演示了共享A和B時(shí)發(fā)生的情況。 這次僅顯示段的位。 證明R4具有3個(gè)段,R3具有3個(gè)段,R1具有2個(gè)段。 A和B由R1,R3和R4共享。 而D由R3和R4共享。
示例3:共享的三個(gè)規(guī)則
當(dāng)“不存在,存在或累積”節(jié)點(diǎn)包含多個(gè)元素時(shí),形成子網(wǎng)。 在示例4中,“ B not(C)”形成子網(wǎng),請注意,“ not(C)”是單個(gè)元素,不需要子網(wǎng),并且在Not節(jié)點(diǎn)內(nèi)部合并。
子網(wǎng)擁有自己的網(wǎng)段。 R1仍具有兩個(gè)段的路徑。 子網(wǎng)形成了另一個(gè)“內(nèi)部”路徑。 鏈接子網(wǎng)時(shí),它將鏈接到外部網(wǎng)段。
示例4:單規(guī)則,具有子網(wǎng)且不共享
示例5顯示了可以通過不具有子網(wǎng)的規(guī)則對子網(wǎng)節(jié)點(diǎn)進(jìn)行分片。 這導(dǎo)致子網(wǎng)段被分成兩個(gè)部分。
示例5:兩條規(guī)則,一條與子網(wǎng)共享
并非具有約束的節(jié)點(diǎn)和累積節(jié)點(diǎn)都具有特殊的行為,并且永遠(yuǎn)無法取消鏈接段,并且始終將其視為打開狀態(tài)。
所有規(guī)則評估都是遞增的,不會浪費(fèi)已經(jīng)重新產(chǎn)生的工作重新計(jì)算匹配項(xiàng)。
評估算法基于堆棧,而不是方法遞歸。 通過使用StackEntry表示要評估的當(dāng)前節(jié)點(diǎn),可以隨時(shí)暫停和恢復(fù)評估。
當(dāng)規(guī)則評估到達(dá)子網(wǎng)時(shí),將為外部路徑段和子網(wǎng)段創(chuàng)建StackEntry。 首先評估子網(wǎng)段,當(dāng)集合到達(dá)子網(wǎng)路徑的末尾時(shí),將其合并到其饋入的外部節(jié)點(diǎn)的暫存列表中。 然后恢復(fù)先前的StackEntry,在其中可以處理子網(wǎng)的結(jié)果。 這樣做的另一個(gè)好處是,所有工作在傳播到子節(jié)點(diǎn)之前都將被成批處理; 這對于累積節(jié)點(diǎn)效率更高。
相同的堆棧系統(tǒng)可用于有效的反向鏈接。 當(dāng)規(guī)則評估到達(dá)查詢節(jié)點(diǎn)時(shí),它會通過將其放在堆棧上來再次暫停當(dāng)前評估。 然后對查詢進(jìn)行評估,生成結(jié)果集,該結(jié)果集保存在內(nèi)存位置中,以供恢復(fù)的StackEntry拾取并傳播到子節(jié)點(diǎn)。 如果查詢本身調(diào)用了其他查詢,則該過程將重復(fù),暫停當(dāng)前查詢,并為當(dāng)前查詢節(jié)點(diǎn)設(shè)置新的評估。
關(guān)于性能的最后一點(diǎn)。 通常,使用PHREAK的單個(gè)規(guī)則不會比使用RETE更快。 對于使用根上下文對象啟用和禁用匹配的給定規(guī)則和相同數(shù)據(jù)集,它們都嘗試相同數(shù)量的匹配并產(chǎn)生相同數(shù)量的規(guī)則實(shí)例,并且花費(fèi)的時(shí)間大致相同。 除了帶有子網(wǎng)的用例和積累。
但是,對于規(guī)則編寫得不好的規(guī)則庫,PHREAK可以認(rèn)為比RETE更寬容,并且隨著規(guī)則數(shù)量和復(fù)雜性的增加,性能會更適度地下降。
RETE還將為不包含所有聯(lián)接的數(shù)據(jù)的規(guī)則生產(chǎn)部分機(jī)器。 PHREAK會避免這種情況。
因此,并不是說PHREAK比RETE快,它不會隨系統(tǒng)的增長而變慢。
AgendaGroups對RETE的性能沒有幫助,因?yàn)樗幸?guī)則都在任何時(shí)候進(jìn)行評估,而與組別無關(guān)。 顯著性也是如此。 這就是為什么經(jīng)常使用根上下文對象來限制匹配嘗試的原因。 PHREAK僅評估活動議程組的規(guī)則,并且在該組內(nèi)將嘗試避免評估(通過顯著性)不會導(dǎo)致規(guī)則實(shí)例觸發(fā)的規(guī)則。
通過PHREAK AgendaGroups和顯著性現(xiàn)在已成為有用的績效工具。 根上下文對象不再需要,并且有可能對性能產(chǎn)生反作用,因?yàn)樗鼈儠?qiáng)制刷新和重新生成規(guī)則的匹配項(xiàng)。
翻譯自: https://www.javacodegeeks.com/2013/11/r-i-p-rete-time-to-get-phreaky.html
總結(jié)
以上是生活随笔為你收集整理的RIP RETE时间获得PHREAKY的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 路由器不用了怎么关闭如何才能把路由器关闭
- 下一篇: ThreadLocal如何实现?