Drools入門


文章轉載自:http://cwqcwq.iteye.com/blog/397869

一、背景知識: 
1、什么是規則引擎 
Java規則引擎起源於基於規則的專家系統,而基於規則的專家系統又是專家系統的其中一個分支。專家系統屬於人工智能的范疇,它模仿人類的推理方式,使用試探性的方法進行推理,並使用人類能理解的術語解釋和證明它的推理結論。 
推理引擎包括三部分:模式匹配器(Pattern Matcher)、議程(Agenda)和執行引擎(Execution Engine)。推理引擎通過決定哪些規則滿足事實或目標,並授予規則優先級,滿足事實或目標的規則被加入議程。模式匹配器決定選擇執行哪個規則,何時執行規則;議程管理模式匹配器挑選出來的規則的執行次序;執行引擎負責執行規則和其他動作。 
和人類的思維相對應,推理引擎存在兩者推理方式:演繹法(Forward-Chaining)和歸納法(Backward-Chaining)。演繹法從一個初始的事實出發,不斷地應用規則得出結論(或執行指定的動作)。而歸納法則是根據假設,不斷地尋找符合假設的事實。Rete算法是目前效率最高的一個 Forward-Chaining推理算法,許多Java規則引擎都是基於Rete算法來進行推理計算的。 
推理引擎的推理步驟如下: 
(1)將初始數據(fact)輸入Working Memory。 
(2)使用Pattern Matcher比較規則庫(rule base)中的規則(rule)和數據(fact)。 
(3)如果執行規則存在沖突(conflict),即同時激活了多個規則,將沖突的規則放入沖突集合。 
(4)解決沖突,將激活的規則按順序放入Agenda。 
(5)使用執行引擎執行Agenda中的規則。重復步驟2至5,直到執行完畢所有Agenda中的規則。 
上述即是規則引擎的原始架構,Java規則引擎就是從這一原始架構演變而來的。 
Drools是基於正向推理的規則引擎。正向推理是數據驅動的,facts事實被傳遞到工作空間中,在那里有一個或多個規則與這些事實匹配,並由Agenda安排執行—我們從一個事實開始,傳遞事實,最后得到一個結論。 
產生式規則是一個用一階邏輯進行知識呈現的二元結構。 
when 
    
then 
    
Drools中的Rete算法被稱為ReteOO,表示Drools為面向對象系統(Object Oriented systems)增強並優化了Rete算法。 

2、規則引擎的優點 
聲明式編程:使用規則更加容易對復雜的問題進行表述,並得到驗證 
邏輯與數據分離:數據保存在系統對象中,邏輯保存在規則中。這根本性的打破了面向對象系統中將數據和邏輯耦合起來的局面 
速度及可測量性:Drools的Rete、Leaps算法,提供了對系統數據對象非常有效率的匹配,這些算法經過了大量實際考驗的證明 
3、何時使用 
業務邏輯經常發生改變 
代碼中有很多”if””else””switch”和其它凌亂的邏輯,且總是易變的 

二、開始 

目前drools的最新版本是5.0(2009年5月19日發布),本文使用4.0.7。 

1、導入jar包: 

drools-core-4.0.7.jar 
drools-compiler-4.0.7.jar 
antlr3-runtime-3.0 
mvel-1.3.1-java1.4 
core-3.2.3.v_686_R32x :在eclipse中編譯.drl文件時需要 

2、從HelloWorld開始: 

一個通用的規則引擎類: 

Java代碼   復制代碼  收藏代碼

  1. import java.io.InputStreamReader;   
  2. import java.io.Reader;   
  3.   
  4. import org.drools.RuleBase;   
  5. import org.drools.RuleBaseFactory;   
  6. import org.drools.WorkingMemory;   
  7. import org.drools.compiler.DroolsParserException;   
  8. import org.drools.compiler.PackageBuilder;   
  9. import org.drools.event.DebugWorkingMemoryEventListener;   
  10. import org.drools.rule.Package;   
  11.   
  12. public class RuleEngine {   
  13.   
  14.  private RuleBase rules;   
  15.   
  16.  private boolean debug = false;   
  17.   
  18.  public RuleEngine(String rulesFile) throws DroolsParserException {   
  19.   super();   
  20.   try {   
  21.    //讀取規則文件,*.drl   
  22.    Reader source = new InputStreamReader(RuleEngine.class.getResourceAsStream("/" + rulesFile));   
  23.       
  24.    //PackageBuilder用來構建Package   
  25.    PackageBuilder builder = new PackageBuilder();   
  26.   
  27.    //解析和編譯規則文件   
  28.    builder.addPackageFromDrl(source);   
  29.   
  30.    //獲取包中的規則集合   
  31.    Package pkg = builder.getPackage();   
  32.   
  33.    //RuleBase是運行時組件,包含一個或多個Package   
  34.    rules = RuleBaseFactory.newRuleBase();   
  35.   
  36.    rules.addPackage(pkg);   
  37.   } catch (Exception e) {   
  38.    throw new DroolsParserException("Could not load/compile rules file: " + rulesFile, e);   
  39.   }   
  40.  }   
  41.   
  42.  public void executeRules(WorkingEnvironmentCallback callback) {   
  43.   WorkingMemory workingMemory = rules.newStatefulSession();   
  44.   if (debug) {   
  45.    workingMemory.addEventListener(new DebugWorkingMemoryEventListener());   
  46.   }   
  47.   callback.initEnvironment(workingMemory);//用來向Working Memory中設置Facts對象   
  48.   workingMemory.fireAllRules();//觸發規則引擎   
  49.  }   
  50.   
  51. }  
Java代碼    收藏代碼

  1. import java.io.InputStreamReader;  
  2. import java.io.Reader;  
  3.   
  4. import org.drools.RuleBase;  
  5. import org.drools.RuleBaseFactory;  
  6. import org.drools.WorkingMemory;  
  7. import org.drools.compiler.DroolsParserException;  
  8. import org.drools.compiler.PackageBuilder;  
  9. import org.drools.event.DebugWorkingMemoryEventListener;  
  10. import org.drools.rule.Package;  
  11.   
  12. public class RuleEngine {  
  13.   
  14.  private RuleBase rules;  
  15.   
  16.  private boolean debug = false;  
  17.   
  18.  public RuleEngine(String rulesFile) throws DroolsParserException {  
  19.   super();  
  20.   try {  
  21.    //讀取規則文件,*.drl  
  22.    Reader source = new InputStreamReader(RuleEngine.class.getResourceAsStream("/" + rulesFile));  
  23.      
  24.    //PackageBuilder用來構建Package  
  25.    PackageBuilder builder = new PackageBuilder();  
  26.   
  27.    //解析和編譯規則文件  
  28.    builder.addPackageFromDrl(source);  
  29.   
  30.    //獲取包中的規則集合  
  31.    Package pkg = builder.getPackage();  
  32.   
  33.    //RuleBase是運行時組件,包含一個或多個Package  
  34.    rules = RuleBaseFactory.newRuleBase();  
  35.   
  36.    rules.addPackage(pkg);  
  37.   } catch (Exception e) {  
  38.    throw new DroolsParserException("Could not load/compile rules file: " + rulesFile, e);  
  39.   }  
  40.  }  
  41.   
  42.  public void executeRules(WorkingEnvironmentCallback callback) {  
  43.   WorkingMemory workingMemory = rules.newStatefulSession();  
  44.   if (debug) {  
  45.    workingMemory.addEventListener(new DebugWorkingMemoryEventListener());  
  46.   }  
  47.   callback.initEnvironment(workingMemory);//用來向Working Memory中設置Facts對象  
  48.   workingMemory.fireAllRules();//觸發規則引擎  
  49.  }  
  50.   
  51. }  

3、編寫drl文件:test.drl

Java代碼   復制代碼  收藏代碼

  1.   
  2. package org.drools.tutorials.banking   
  3.   
  4. rule "Rule 01"      
  5.     when   
  6.         String (toString=="jack") //含義:如果插入的Facts對象是String類型,且調用其toString()方法后的值等於"jack",則為true   
  7.     then   
  8.         System.out.println("HelloWorld!");   
  9. end  
Java代碼    收藏代碼

  1. package org.drools.tutorials.banking  
  2.   
  3. rule "Rule 01"     
  4.     when  
  5.         String (toString=="jack") //含義:如果插入的Facts對象是String類型,且調用其toString()方法后的值等於"jack",則為true  
  6.     then  
  7.         System.out.println("HelloWorld!");  
  8. end  

4、測試:

Java代碼   復制代碼  收藏代碼

  1. public class Test {   
  2.   
  3.  public static void main(String[] args) {    
  4.   RuleEngine engine = null;   
  5.   try {   
  6.    engine = new RuleEngine("test.drl");   
  7.   } catch (DroolsParserException e) {   
  8.    // process Exception   
  9.   }   
  10.   engine.executeRules(new WorkingEnvironmentCallback(){   
  11.    public void initEnvironment(WorkingMemory workingMemory) throws FactException {       
  12.     workingMemory.insert("jack"); //向Working Memory中設置Facts對象      
  13.    }      
  14.   });     
  15.  }   
  16. }  
Java代碼    收藏代碼

  1. public class Test {  
  2.   
  3.  public static void main(String[] args) {   
  4.   RuleEngine engine = null;  
  5.   try {  
  6.    engine = new RuleEngine("test.drl");  
  7.   } catch (DroolsParserException e) {  
  8.    // process Exception  
  9.   }  
  10.   engine.executeRules(new WorkingEnvironmentCallback(){  
  11.    public void initEnvironment(WorkingMemory workingMemory) throws FactException {      
  12.     workingMemory.insert("jack"); //向Working Memory中設置Facts對象     
  13.    }     
  14.   });    
  15.  }  
  16. }  

三、簡單介紹 

1、術語解釋 

Rule:一條規則可以看作是IF…THEN…語句塊,或者一個簡單的IPO(即輸入、處理和輸出),描述了一組輸入,一組判斷和一組輸出; 
RuleBase: RuleBase包含一個或多個規則包,它們已經被校驗和編譯完成,是可以序列化的 
Package: 規則包,是規則以及其它相關結構的一個集合,包必須有一個名稱空間,並且使用標准的java約定進行命名 
WorkingMemory: 用戶工作區,包含用戶的數據和相關Rule的引用 
Facts: Facts就是規則中用到的輸入,Facts可以是任何規則可以存取的Java對象,規則引擎完全不會克隆對象,它僅僅是保存對對象的一個引用/指針 

2、規則文件詳解 
規則文件通常是以drl擴展名結尾。在一個drl文件中可以包含多個規則,函數等等,DRL是簡單的text文件格式。 

規則文件的構成: 

package package-name //定義包名 
imports   //導入java包 
globals   //定義全局變量,如 global java.util.List myGlobalList; 
functions  //定義函數 
rules   //一系列的規則 

規則的構成: 

rule "name" 
    attributes 
    when 
        LHS 
    then 
        RHS 
end 

說明: 
LHS是規則的條件部分,可以定義變量 
RHS是允許Java語義代碼,RHS中的多條語句實質上是一個規則,只有滿足全部語句才符合規則 
任何在LHS中綁定的變量可以在RHS中使用 

3、規則文件示例解讀 

rule “Rule 01”   
    when 
//$date定義一個變量,其值為Cashflow對象getDate()的值 
//$cashflow定義一個指向Cashflow對象的引用 
        $cashflow : Cashflow( $date : date, $amount : amount ) 
        not Cashflow( date < “27-Oct-2007”) //not 意為不存在,只有不存在date < “27-Oct-2007″的Cashflow對象才為true 
    then 
        System.out.println(“Cashflow: “+$date+” :: “+$amount); 
$cashflow.setAmount($cashflow.getAmount()+$amount); //設置Cashflow對象的amount值 
        retract($cashflow);//當retract一個fact,WorkingMemory將不再跟蹤該fact 
end 

public class Cashflow { 
    private Date   date; 
    private double amount; 
    //省略getter.. setter.. 
} 

重要:規則引擎完全不會克隆對象,它僅僅是保存對對象的一個引用/指針 
即,在規則定義中對fact的修改,就是對代碼中fact對象的修改。 
也即,規則的根本目的是產生一個供使用的輸出結果,即修改后的JavaBean


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM