【原創】Drools規則引擎初窺---drl和決策表實現[實例]

因項目須要,看了下drools規則引擎。寫了一個比較簡單的drools的drl規則和決策表實現的例子。java

規則說明:api

  網絡商城要舉辦活動(獎勵額外積分),網絡

  訂單原價金額在session

  100如下, 不加分 maven

  100-500 加100分 函數

  500-1000 加500分 oop

  1000 以上 加1000分單元測試

1.創建最基本的Drools項目結構並引入必須的類庫。(這裏採用junit來執行單元測試)。建立一個Java Project,創建maven形式的源碼包。測試

 

2.定義實體類Order.javaui

 1 import java.util.Date;
 2 
 3 public class Order {
 4     private Date bookingDate;// 下單日期
 5 
 6     private int amout;// 訂單原價金額
 7 
 8     private User user;// 下單人
 9 
10     private int score;//積分
11     
12     public  Order(Date bookingDate,int amout, User user, int score){
13             this.bookingDate = bookingDate;
14             this.amout = amout;
15             this.user = user;
16             this.score = score;
17     }
18     
19     public Order(){
20     }
21     
22    //省略get、set方法53 
54 }

3.定義實體User.java

public class User {
    private String name;// 姓名

    private int level;// 用戶級別

    public User(){
        
    }
    
    public User(String name, int level){
        this.name = name;
        this.level = level;
    } 
    
      //省略get、set方法
}

4.編寫規則文件point-rules.drl

package  drools

import com.wang.drools.point.Order
import com.wang.drools.point.User

rule "zero"
no-loop true            //只檢查一次
lock-on-active true   
salience 9    //值越大 ,優先級越高
when 
    //購物金額100如下不加分
    $s  : Order(amout <= 100);
then 
     $s.setScore(0);
     update($s);
end

rule "add100"
no-loop true            //只檢查一次
lock-on-active true   
salience 8    //值越大 ,優先級越高
when 
    //購物金額100以上500如下加100積分
    $s  : Order(amout > 100 && amout <= 500);
then 
     $s.setScore(100);
     update($s);
end

rule "add500"
no-loop true            //只檢查一次
lock-on-active true  
salience 6    //值越大 ,優先級越高
when 
    //購物金額500以上1000如下加500積分
    $s  : Order(amout > 500 && amout <= 1000);
then 
     $s.setScore(500);
     update($s);
end

rule "add1000"
no-loop true            //只檢查一次
lock-on-active true   
salience 5    //值越大 ,優先級越高
when 
    //購物金額1000以上加1000積分
    $s  : Order(amout > 1000);
then 
     $s.setScore(1000);
     update($s);
end

說明:rule表示規則的開始,salience表示規則的優先級,當有多條規則同時存在是,優先級越高的越先被匹配執行。lock-on-active表示執行過一次以後就再也不執行,防止後續的條件執行過程當中改變變量的值致使從新知足該規則以後再次執行對應的操做。When表示匹配的規則,then表示匹配規則以後執行的動做。

5.測試drl規則TestPoint.java

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.kie.api.io.ResourceType;
import org.kie.internal.KnowledgeBase;
import org.kie.internal.KnowledgeBaseFactory;
import org.kie.internal.builder.KnowledgeBuilder;
import org.kie.internal.builder.KnowledgeBuilderErrors;
import org.kie.internal.builder.KnowledgeBuilderFactory;
import org.kie.internal.definition.KnowledgePackage;
import org.kie.internal.io.ResourceFactory;
import org.kie.internal.runtime.StatefulKnowledgeSession;

@SuppressWarnings("deprecation")
public class TestPoint {
     /** 
     * 計算額外積分金額 規則以下: 訂單原價金額  
     * 100如下, 不加分  
     * 100-500 加100分  
     * 500-1000 加500分  
     * 1000 以上 加1000分 
     *  
     * @param args 
     * @throws Exception 
     */  
    public static void main(String[] args) throws Exception {  
        KnowledgeBuilder builder = KnowledgeBuilderFactory.newKnowledgeBuilder();  
        builder.add(ResourceFactory.newClassPathResource("point/point-rules.drl"), ResourceType.DRL);  
  
        if (builder.hasErrors()) {  
            System.out.println("規則中存在錯誤,錯誤消息以下:");  
            KnowledgeBuilderErrors kbuidlerErrors = builder.getErrors();  
            for (Iterator<?> iter = kbuidlerErrors.iterator(); iter.hasNext();) {  
                System.out.println(iter.next());  
            }  
            return;  
        }  
  
        Collection<KnowledgePackage> packages = builder.getKnowledgePackages();  
        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();  
        kbase.addKnowledgePackages(packages);  
  
        StatefulKnowledgeSession session = kbase.newStatefulKnowledgeSession();  
  
        List<Order> orderList = getInitData();  
  
        for (int i = 0; i < orderList.size(); i++) {  
            Order o = orderList.get(i);  
            session.insert(o);  
            session.fireAllRules();  
            // 執行完規則後, 執行相關的邏輯  
            addScore(o);  
        }  
  
        session.dispose();  
    }  
  
    private static void addScore(Order o){  
        System.out.println("用戶" + o.getUser().getName() + "享受額外增長積分: " + o.getScore());  
    }  
      
    private static List<Order> getInitData() throws Exception {  
        List<Order> orderList = new ArrayList<Order>();  
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");  
        {  
            Order order = new Order();  
            order.setAmout(80);  
            order.setBookingDate(df.parse("2015-07-01"));  
            User user = new User();  
            user.setLevel(1);  
            user.setName("Name1");  
            order.setUser(user);  
            orderList.add(order);  
        }  
        {  
            Order order = new Order();  
            order.setAmout(200);  
            order.setBookingDate(df.parse("2015-07-02"));  
            User user = new User();  
            user.setLevel(2);  
            user.setName("Name2");  
            order.setUser(user);  
            orderList.add(order);  
        }  
        {  
            Order order = new Order();  
            order.setAmout(800);  
            order.setBookingDate(df.parse("2015-07-03"));  
            User user = new User();  
            user.setLevel(3);  
            user.setName("Name3");  
            order.setUser(user);  
            orderList.add(order);  
        }  
        {  
            Order order = new Order();  
            order.setAmout(1500);  
            order.setBookingDate(df.parse("2015-07-04"));  
            User user = new User();  
            user.setLevel(4);  
            user.setName("Name4");  
            order.setUser(user);  
            orderList.add(order);  
        }  
        return orderList;  
    }  
}

6.創建等同於drl規則文件的xsl文件 point.xsl

說明:

  1. RuleSet關鍵字是必須的,名字是可選的
  2. Import語句很是像java的import,若是有多個import,用逗號隔開
  3. RuleTable關鍵字也是必須的,它指示了後面將會有一批rule,ruletable的名稱將會做爲之後生成rule的前綴
  4. 條件若是不寫的話默認就是==, 好比上面的contract.get("productLine"),其實就是contract.get("productLine") == $param, 若是有多個參數能夠使用$1,$2,好比咱們常常用到的一個區間數據,這個佔位符就派上用場了

7.在META-INF文件夾下的kmodule.xml文件中配置ksession信息。

說明:1.packages = 「xxxx」 配置xsl所在包的名稱

   2.<ksession name="ksession-calXSL"/> 配置ksession的名稱(方便在項目中調用)

8.測試xsl決策表文件正確性 TestPointXML.java

import java.util.Date;

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

/***
 * 使用決策表實現規則引擎
 * 
 * @author wyx
 *
 */
public class TestPointXSL {
    public static void main(String[] args) {
        KieServices ks = KieServices.Factory.get();
        KieContainer kc = ks.getKieClasspathContainer();
        
        KieSession kSession = kc.newKieSession("ksession-pointXML");
        
        User user = new User();
        user.setName("張學友");
        user.setLevel(1);
        Order order = new Order(new Date(),100,user,0);
        
        kSession.insert(order);
        kSession.fireAllRules();
        kSession.dispose();
        System.out.println(order.getScore());
    }
}

9.有個很方便的文件解析能夠幫助咱們很快知道xsl文件是否書寫正確  GenerationRules.java

 直接能將xsl文件解析成drl規則打印在控制檯,方便查看、修改

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;

import org.drools.decisiontable.InputType;
import org.drools.decisiontable.SpreadsheetCompiler;
import org.junit.Test;

/***
 * 
 * 解析決策樹文件
 * 
 * @author wyx
 *
 */
public class GenerationRules {
    @Test
    public void compile() throws FileNotFoundException {
        File file = new File(
                "F:\\icore\\drools\\src\\main\\resources\\pointXML\\point.xls");
        InputStream is = new FileInputStream(file);
        SpreadsheetCompiler converter = new SpreadsheetCompiler();
        String drl = converter.compile(is, InputType.XLS);
        System.out.println("\n\n" + drl);
    }
}

 

 

項目結構圖

 

 

關鍵字

說明

是否必須

RuleSet

在這個單元的右邊單元中包含ruleset的名稱

必須,只能有一個(若是爲空則使用默認值)

Sequential

右邊的單元能夠是true或false,若是是true則確保規則按照從表格的上面到下面的順序執行(規則觸發是從上朝下,若是是false就是亂序)

可選

Import

要導入規則庫中的類的列表(逗號隔開)

可選

Variables

緊跟在右邊的單元格包含global聲明。格式是類型跟着變量名(全局變量定義,多個用逗號隔開

可選

Functions

緊跟在右邊的單元格包含能夠用在規則代碼段中的函數聲明。Drools支持在DRL中定義函數,容許邏輯在規則中嵌入

可選

RuleTable

一個以RuleTable開頭的單元格表明一個規則 表定義的開始。實際的規則表從下一行開始。規則表的讀取遵循從左到右,從上到下的順序,知道出現空行

至少一個,若是有多個,所有加入到同一個RuleSet中

CONDITION

說明該列用於規則的條件表達式

每一個規則表至少一個

ACTION

說明該列用於規則表的推論部分

每一個規則表至少一個

PRIORITY

說明該列值將用來設定改行規則的salience值,覆蓋‘Sequential’標記

可選

NAME

說明該列規則的名字將使用該列所指定名字

可選

UNLOOP

若是單元格這一列上有值,則no-loop屬性被設置

可選

Worksheet

默認只有第一個工做表被認爲是決策表

N/A

相關文章
相關標籤/搜索