Drools規則引擎的使用總結

前一段時間在開發了一個做文本分析的項目。在項目技術選型的過程中,嘗試使用了Drools規則引擎。讓它來作爲項目中有關模式分析和關鍵詞匹配的任務。但後來,因爲某種原因,還是撇開了Drools。現將這個過程中使用Drools的一些經驗和心得記錄下來。 
(一)什麼時候應該使用規則引擎
    這實際是一個技術選型的問題。但這個問題又似乎是一個很關鍵的問題(一旦返工的話,你就知道這個問題是多麼重要了)。不知大家有沒有過這樣的經驗和體會。往往在項目開始的時候,總會遇到應該選用什麼技術?是不是應該使用最新的技術?或者應該選用什麼技術呢(PS:現在計算機軟件中的各種技術層出不窮,具有類似功能的技術很多)?
    不管怎麼樣,這些問題總會困擾着我。比如,這次的這個項目。項目要求是要在一些log文件中(這些log文件都是很大的應用系統所產生的,但由於legacy的原因,log本身的維護和規範工作一直沒有得到改善,所以想藉助於一些外部應用對這些log做以分析和清洗)抽取出有用的信息。
    於是,第一個想到的就是,這是一個文本挖掘類的項目。但又想,要抽取有用信息,必須得建立一些規則或pattern(模式)。所以,我第一個想到了規則引擎。因爲這裏面要建立好多規則,而這些規則可以獨立於代碼級別(放到一個單獨的drl文件裏)並可以用規則引擎去解析和執行。另一個重要的原因是,我原來用過,比較熟悉。這樣,也可以節省開發時間吧。於是,好不猶豫的就開始做了Demo....
    但事實上,在經歷了一個多星期的編碼、測試後,我發現運用規則引擎實在是太笨拙了。
    (1)首先必須建立一些數據模型。通過這些模型來refer規則文件中的LHS和Action。
    (2)還要考慮規則的conflict。如果有一些規則同時被觸發,就要考慮設定規則的優先級或者是設定activiation-group來保證在一個group中的規則只有一個規則可以被觸發。
    (3)對於‘流’規則group ruleflow-group的使用。如果要控制在workingmemory中的規則被觸發的順序,則可以將這些規則分組。然後,通過規則建模的方式來實現。但這也添加了一定的effort。修改或者更新不大方便。
    所以,基於上述體會,我更認爲規則引擎更適用於那些對非流程性規則匹配的應用。當然,Drools也支持對流程性規則的建模過程。但,這也許不是最好的方式。
(二)Drools規則引擎的使用雜記
    (1)Fact 的變更監聽。在Drools裏,如果一個Fact通過規則而改變,則需將這種改變通知給規則引擎。這裏,一般有兩種方式:顯式和隱式。
         顯式---在drl文件中通過 update、modify來通知;在程序中,通過Fact的引用調用modifyObject等方法來實現。
         隱式---通過在java bean實現property Listener Interface來讓引擎自動監聽到屬性值的變化。我更習慣於這種方式。因爲,一般看來凡是在規則引擎中添加到fact都是希望引擎來幫你進行管理的。 所以,那它自己看到fact的變化是種很省事的辦法。也很簡單,就是用java bean property 監聽的方式。
   通過StatefulSession來註冊。
   調用StatefulSession的某個instance 的insert(Object,true)實現。而這個object是一個java bean。其中,要實現 
       
         
private final PropertyChangeSupport changes = new PropertyChangeSupport( this );
   public void addPropertyChangeListener(final PropertyChangeListener l) {
        this.changes.addPropertyChangeListener( l );
   }

   public void removePropertyChangeListener(final PropertyChangeListener l) {
        this.changes.removePropertyChangeListener( l );
   }
   
        然後在set方法中調用
    this.changes.firePropertyChange( "temp",null,this.temp );
     (2)規則觸發的優先級、組設置
    往往,在設計我們自己的規則時,要考慮規則的觸發條件。這不僅限於LHS的條件部分,還有規則本身被觸發的有些設置等等。這裏,列出一些比較常用和有效的規則優先級設置方式,以及需要注意的地方。
         A.通過Salience方式。此值可正可負。越大優先級越高,也會被引擎首先執行。
         B.通過ruleflow-group 方式。實際上,使用這種方式也就是在使用建立規則流的方式。在Eclipse 3.3 中,Drools提供了建立規則流的插件。要在drl的同級目錄中建立rf和rfm兩個文件(當然,插件會幫助你建立這些)。
         
選擇RuleFlow File。
      這裏,需要注意的一點是要在啓動規則引擎的時候,加入啓動rule flow的代碼。

     InputStreamReader source = new InputStreamReader(RuleManager.class
                   .getResourceAsStream(rule_path));
           PackageBuilder builder = new PackageBuilder();
           builder.addPackageFromDrl(source);
           builder.addRuleFlow(new InputStreamReader(RuleManager.class
                   .getResourceAsStream(rule_flow_path)));
           Package pkg = builder.getPackage();
            RuleBase ruleBase = RuleBaseFactory.newRuleBase();
           ruleBase.addPackage(pkg);
      然後,在每次啓動規則引擎的時候,調用如下方法:

            StatefulSession ss;
            ss.startProcess(flowProgress);
            ss.fireAllRules();

            flowProgress 是一個string類型。這個flow的名字。

這個rule flow圖中,顯示了一個簡單的規則流。如RSA就是一個rule-flow的名字。在這個rule set中可以設定一組rules。這樣,就可以分開規則執行的順序。在於rf和rfm同名的另一個 drl文件中定義這些組的名字。通過關鍵字 ruleflow-group 來表明。
    C.通過activation-group的方式。通過這種方式,可以exclude一組rule中一旦有一個rule被invoke,而其它rule不 會被execute。同時,可以搭配使用salience關鍵字來標明每個rule的優先級,這樣就能夠使得你想要的一般性概念的rule先被匹配執行。
    D.在使用ruleflow-group 的時候要注意使用lock-on-active true 關鍵字在每個rule。這樣可以避免一旦有rule被觸發,不會造成循環匹配執行。
    E.如果在LHS部分,需要調用某個方法來返回真、假值作爲判斷的一個條件,那麼可以用eval函數。
    如,eval(pattern.matched(5,$line.getCurrLine()))
    其中,pattern是某個加入到workingmemory中的一個實例。matched是這個實例所代表類的一個方法。它返回boolean類型。
    
(3)Drools規則引擎的使用感受
    
總之,Drools還是一個很不錯的開源規則引擎。 現在v4.0以上的版本已經比以前的版本在速度上有了很大的提升。可以作爲我們一般應用程序系統的中間件產品(那些規則不是很經常改變的系統,已經非流程 類規則)。但是,這其中還是需要一些額外的effort來學習它的使用文檔以及整體架構,有一定的學習曲線。
   
    最後,我想一個較好的對於技術使用的practice就是:首先知道它能爲你做什麼,它最好的應用領域,然後再去深入。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章