Drools 學習筆記

1.Drools簡單例子

首先是搭建一個可供進行Drools開發的框架。Jboss官方推薦使用Drools Eclipse IDE進行開發,但是我發現其插件的安裝相當繁瑣,對其他的組件依賴嚴重,而且裏面新手能用到的東東不多,下面就偷懶來搭建一個demo

demo基於Maven3進行開發,沒有用過Maven的同學還是希望先看看Maven的東西。當然,不用maven也是沒有問題的,你需要用到的包如下圖:





當然最好還是用maven。首先使用ecplise新建一個maven的工程:TestDrools,在其中Pom.xml中添加如下依賴:

<dependencies>

        <dependency>

            <groupId>org.drools</groupId>

            <artifactId>drools-core</artifactId>

            <version>5.2.0.M2</version>

        </dependency>

        <dependency> 

            <groupId>org.drools</groupId>

            <artifactId>drools-compiler</artifactId>

            <version>5.2.0.M2</version>

        </dependency>

        <dependency>

            <groupId>com.thoughtworks.xstream</groupId>

            <artifactId>xstream</artifactId>

            <version>1.3.1</version>

        </dependency>

</dependencies>

我們假定如下情景:網站伴隨業務產生而進行的積分發放操作。比如支付寶信用卡還款獎勵積分等。

我們定義一下發放規則:

積分的發放參考因素有:交易筆數、交易金額數目、信用卡還款次數、生日特別優惠等。

定義規則:

// 過生日,則加10分,並且將當月交易比數翻倍後再計算積分

// 2011-01-08 - 2011-08-08每月信用卡還款3次以上,每滿3筆贈送30

// 當月購物總金額100以上,每100元贈送10

// 當月購物次數5次以上,每五次贈送50

// 特別的,如果全部滿足了要求,則額外獎勵100

// 發生退貨,扣減10

// 退貨金額大於100,扣減100

首先我們進入的Drools規則的編制階段。這裏採用drl文件定義規則,我們分別建立兩個drl文件。

addpoint.drl

package com.drools.demo.point

import com.jd.drools.test.PointDomain;

rule birthdayPoint

// 過生日,則加10分,並且將當月交易比數翻倍後再計算積分

salience 100

lock-on-active true

when

$pointDomain : PointDomain(birthDay == true)

then

$pointDomain.setPoint($pointDomain.getPoint()+10);

$pointDomain.setBuyNums($pointDomain.getBuyNums()*2);

$pointDomain.setBuyMoney($pointDomain.getBuyMoney()*2);

$pointDomain.setBillThisMonth($pointDomain.getBillThisMonth()*2);

$pointDomain.recordPointLog($pointDomain.getUserName(),"birthdayPoint");

end

rule billThisMonthPoint

// 2011-01-08 - 2011-08-08每月信用卡還款3次以上,每滿3筆贈送30分

salience 99

lock-on-active true

date-effective "2011-01-08 23:59:59"

date-expires "2011-08-08 23:59:59"

when

$pointDomain : PointDomain(billThisMonth >= 3)

then

$pointDomain.setPoint($pointDomain.getPoint()+$pointDomain.getBillThisMonth()/3*30);

$pointDomain.recordPointLog($pointDomain.getUserName(),"billThisMonthPoint");

end

rule buyMoneyPoint

// 當月購物總金額100以上,每100元贈送10分

salience 98

lock-on-active true

when

$pointDomain : PointDomain(buyMoney >= 100)

then

$pointDomain.setPoint($pointDomain.getPoint()+ (int)$pointDomain.getBuyMoney()/100 * 10);

$pointDomain.recordPointLog($pointDomain.getUserName(),"buyMoneyPoint");

end

rule buyNumsPoint

// 當月購物次數5次以上,每五次贈送50分

salience 97

lock-on-active true

when

$pointDomain : PointDomain(buyNums >= 5)

then

$pointDomain.setPoint($pointDomain.getPoint()+$pointDomain.getBuyNums()/5 * 50);

$pointDomain.recordPointLog($pointDomain.getUserName(),"buyNumsPoint");

end

rule allFitPoint

// 特別的,如果全部滿足了要求,則額外獎勵100分

salience 96

lock-on-active true

when

$pointDomain:PointDomain(buyNums >= 5 && billThisMonth >= 3 && buyMoney >= 100)

then

$pointDomain.setPoint($pointDomain.getPoint()+ 100);

$pointDomain.recordPointLog($pointDomain.getUserName(),"allFitPoint");

End

subpoint.drl:

package com.drools.demo.point

import com.jd.drools.test.PointDomain;

rule subBackNumsPoint

// 發生退貨,扣減10分

salience 10

lock-on-active true

when

$pointDomain : PointDomain(backNums >= 1)

then

$pointDomain.setPoint($pointDomain.getPoint()-10);

$pointDomain.recordPointLog($pointDomain.getUserName(),"subBackNumsPoint");

end

rule subBackMondyPoint

// 退貨金額大於100,扣減100分

salience 9

lock-on-active true

when

$pointDomain : PointDomain(backMondy >= 100)

then

$pointDomain.setPoint($pointDomain.getPoint()-10);

$pointDomain.recordPointLog($pointDomain.getUserName(),"subBackMondyPoint");

End

這樣我們就把開頭所述的規則濃縮到這兩個文件當中,Drools中可以使用PackageBuilder類來編譯這兩個文件。(具體用法在下面有體現)

接下來進入Drools的運行階段。首先需要說明Drools中一個比較重要的概念:fact對象。

Drools 當中是通過向WorkingMemory中插入Fact對象的方式來實現規則引擎與業務數據的交互,對於Fact對象就是普通的具有若干個屬性及其對應的gettersetter方法的JavaBean對象。Drools除了可以接受用戶在外部向WorkingMemory當中插入現成的Fact對象,還允許用戶在規則文件當中定義一個新的Fact 對象在規則文件當中定義Fact 對象要以declare 關鍵字開頭,以end 關鍵字結尾,中間部分就是該Fact 對象的屬性名及其類型等信息的聲明。

我們定義此例中的fact對象:PointDomain.java

/**

 * 積分計算對象

 * @author quzishen

 */

public class PointDomain {

// 用戶名

private String userName;

public String getUserName() {

return userName;

}

public void setUserName(String userName) {

this.userName = userName;

}

public boolean isBirthDay() {

return birthDay;

}

public void setBirthDay(boolean birthDay) {

this.birthDay = birthDay;

}

public long getPoint() {

return point;

}

public void setPoint(long point) {

this.point = point;

}

public int getBuyNums() {

return buyNums;

}

public void setBuyNums(int buyNums) {

this.buyNums = buyNums;

}

public int getBackNums() {

return backNums;

}

public void setBackNums(int backNums) {

this.backNums = backNums;

}

public double getBuyMoney() {

return buyMoney;

}

public void setBuyMoney(double buyMoney) {

this.buyMoney = buyMoney;

}

public double getBackMondy() {

return backMondy;

}

public void setBackMondy(double backMondy) {

this.backMondy = backMondy;

}

public int getBillThisMonth() {

return billThisMonth;

}

public void setBillThisMonth(int billThisMonth) {

this.billThisMonth = billThisMonth;

}

// 是否當日生日

private boolean birthDay;

// 增加積分數目

private long point;

// 當月購物次數

private int buyNums;

// 當月退貨次數

private int backNums;

// 當月購物總金額

private double buyMoney;

// 當月退貨總金額

private double backMondy;

// 當月信用卡還款次數

private int billThisMonth;

/**

 * 記錄積分發送流水,防止重複發放

 * @param userName 用戶名

 * @param type 積分發放類型

 */

public void recordPointLog(String userName, String type){

System.out.println("增加對"+userName+"的類型爲"+type+"的積分操作記錄.");

}

}

規則有了,交互的對象也有了,我們需要實現一個workingMemory來裝載這些對象進行運算。在Drools5 當中提供了兩個對象與規則引擎進行交互:StatefulKnowledgeSession

和StatelessKnowledgeSession。本例中使用了StatefulKnowledgeSession進行交互。

前面說過一個RuleBase可以同時初始化多個Working Memory,而RuleBase是通過Drools中的

RuleBaseFactory產生的。我們定義一個工廠類用於獲取單例的RuleBase

RuleBaseFacatory.java

/**

 * RuleBaseFacatory 單實例RuleBase生成工具

 * @author quzishen

 */

public class RuleBaseFacatory {

private static RuleBase ruleBase;

public static RuleBase getRuleBase(){

return null != ruleBase ? ruleBase : RuleBaseFactory.newRuleBase();

}

}

接下來定義一個定義積分規則接口,裏面包含了初始化RuleBaseworkingMemory以及執行規則的方法。

PointRuleEngine.java

/**

 * 規則接口

 * @author quzishen

 */

public interface PointRuleEngine {

/**

 * 初始化規則引擎

 */

public void initEngine();

/**

 * 刷新規則引擎中的規則

 */

public void refreshEnginRule();

/**

 * 執行規則引擎

 * @param pointDomain 積分Fact

 */

public void executeRuleEngine(final PointDomain pointDomain);

}

定義它的實現類,並封裝main方法用於測試規則是否有效。

PointRuleEngineImpl.java

import java.io.BufferedReader;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.Reader;

import java.util.ArrayList;

import java.util.List;

import org.drools.RuleBase;

import org.drools.StatefulSession;

import org.drools.compiler.DroolsParserException;

import org.drools.compiler.PackageBuilder;

import org.drools.spi.Activation;

import com.jd.drools.test.PointDomain;

/**

 * 規則接口實現類

 * @author quzishen

 */

public class PointRuleEngineImpl implements PointRuleEngine {

private RuleBase ruleBase;

/* (non-Javadoc)

 * @see com.drools.demo.point.PointRuleEngine#initEngine()

 */

public void initEngine() {

// 設置時間格式

System.setProperty("drools.dateformat""yyyy-MM-dd HH:mm:ss");

ruleBase = RuleBaseFacatory.getRuleBase();

try {

PackageBuilder backageBuilder = getPackageBuilderFromDrlFile();

ruleBase.addPackages(backageBuilder.getPackages());

catch (DroolsParserException e) {

e.printStackTrace();

catch (IOException e) {

e.printStackTrace();

catch (Exception e) {

e.printStackTrace();

}

}

/* (non-Javadoc)

 * @see com.drools.demo.point.PointRuleEngine#refreshEnginRule()

 */

public void refreshEnginRule() {

ruleBase = RuleBaseFacatory.getRuleBase();

org.drools.rule.Package[] packages = ruleBase.getPackages();

for(org.drools.rule.Package pg : packages) {

ruleBase.removePackage(pg.getName());

}

initEngine();

}

/* (non-Javadoc)

 * @see com.drools.demo.point.PointRuleEngine#executeRuleEngine(com.drools.demo.point.PointDomain)

 */

public void executeRuleEngine(final PointDomain pointDomain) {

if(null == ruleBase.getPackages() || 0 == ruleBase.getPackages().length) {

return;

}

StatefulSession statefulSession = ruleBase.newStatefulSession();

statefulSession.insert(pointDomain);

// fire

statefulSession.fireAllRules(new org.drools.spi.AgendaFilter() {

public boolean accept(Activation activation) {

return !activation.getRule().getName().contains("_test");

}

});

statefulSession.dispose();

}

/**

 * 從Drl規則文件中讀取規則

 * @return

 * @throws Exception

 */

private PackageBuilder getPackageBuilderFromDrlFile() throws Exception {

// 獲取測試腳本文件

List<String> drlFilePath = getTestDrlFile();

// 裝載測試腳本文件

List<Reader> readers = readRuleFromDrlFile(drlFilePath);

PackageBuilder backageBuilder = new PackageBuilder();

for (Reader r : readers) {

backageBuilder.addPackageFromDrl(r);

}

// 檢查腳本是否有問題

if(backageBuilder.hasErrors()) {

throw new Exception(backageBuilder.getErrors().toString());

}

return backageBuilder;

}

/**

 * @param drlFilePath 腳本文件路徑

 * @return

 * @throws FileNotFoundException

 */

private List<Reader> readRuleFromDrlFile(List<String> drlFilePath) throws FileNotFoundException {

if (null == drlFilePath || 0 == drlFilePath.size()) {

return null;

}

List<Reader> readers = new ArrayList<Reader>();

for (String ruleFilePath : drlFilePath) {

readers.add(new FileReader(new File(ruleFilePath)));

}

return readers;

}

/**

 * 獲取測試規則文件

 * 

 * @return

 */

private List<String> getTestDrlFile() {

List<String> drlFilePath = new ArrayList<String>();

drlFilePath

.add("D:\\myworkspace\\TestDrools\\target\\classes\\addpoint.drl");

drlFilePath

.add("D:\\myworkspace\\TestDrools\\target\\classes\\subpoint.drl");

return drlFilePath;

}

public static void main(String[] args) throws IOException {

PointRuleEngine pointRuleEngine = new PointRuleEngineImpl();

while(true){

InputStream is = System.in;

BufferedReader br = new BufferedReader(new InputStreamReader(is));

String input = br.readLine();

System.out.println("請輸入命令:");

if(null != input && "s".equals(input)){

System.out.println("初始化規則引擎...");

pointRuleEngine.initEngine();

System.out.println("初始化規則引擎結束.");

}else if("e".equals(input)){

final PointDomain pointDomain = new PointDomain();

System.out.println("初始化規則引擎...");

pointRuleEngine.initEngine();

System.out.println("初始化規則引擎結束.");

pointDomain.setUserName("hello kity");

pointDomain.setBackMondy(100d);

pointDomain.setBuyMoney(500d);

pointDomain.setBackNums(1);

pointDomain.setBuyNums(5);

pointDomain.setBillThisMonth(5);

pointDomain.setBirthDay(true);

pointDomain.setPoint(0l);

pointRuleEngine.executeRuleEngine(pointDomain);

System.out.println("執行完畢BillThisMonth:"+pointDomain.getBillThisMonth());

System.out.println("執行完畢BuyMoney:"+pointDomain.getBuyMoney());

System.out.println("執行完畢BuyNums:"+pointDomain.getBuyNums());

System.out.println("執行完畢規則引擎決定發送積分:"+pointDomain.getPoint());

else if("r".equals(input)){

System.out.println("刷新規則文件...");

pointRuleEngine.refreshEnginRule();

System.out.println("刷新規則文件結束.");

}

}

}

}

執行main方法,輸入'e',得到:

初始化規則引擎...

初始化規則引擎結束.

增加對hello kity的類型爲birthdayPoint的積分操作記錄.

增加對hello kity的類型爲buyMoneyPoint的積分操作記錄.

增加對hello kity的類型爲buyNumsPoint的積分操作記錄.

增加對hello kity的類型爲allFitPoint的積分操作記錄.

增加對hello kity的類型爲subBackNumsPoint的積分操作記錄.

增加對hello kity的類型爲subBackMondyPoint的積分操作記錄.

執行完畢BillThisMonth:10

執行完畢BuyMoney:1000.0

執行完畢BuyNums:10

執行完畢規則引擎決定發送積分:290

2.Droolsv API解釋

Drools API可以分爲三類:規則編譯、規則收集和規則的執行

API: 

1. KnowledgeBuilder規則編譯:規則文件進行編譯, 最終產生一批編譯好的規則包(KnowledgePackage)供其它的應用程序使用

2. KnowledgeBase:提供的用來收集應用當中知識(knowledge)定義的知識庫對象,在一個KnowledgeBase 當中可以包含普通的規則(rule)、規則流(rule flow)、函數定義(function)、用戶自定義對象(type model)等

3. StatefulKnowledgeSession:是一種最常用的與規則引擎進行交互的方式,它可以與規則引擎建立一個持續的交互通道,在推理計算的過程當中可能會多次觸發同一數據集。在用戶的代碼當中,最後使用完StatefulKnowledgeSession 對象之後,一定要調用其dispose()方法以釋放相關內存資源。有狀態的

4. StatelessKnowledgeSession:使用StatelessKnowledgeSession 對象時不需要再調用dispose()方法釋放內存資源不能進行重複插入fact 的操作、也不能重複的調用fireAllRules()方法來執行所有的規則,對應這些要完成的工作在StatelessKnowledgeSession當中只有execute()方法,通過這個方法可以實現插入所有的fact 並且可以同時執行所有的規則或規則流,事實上也就是在執行execute()方法的時候就在StatelessKnowledgeSession內部執行了insert()方法、fireAllRules()方法和dispose()方法

5. Fact :是指在Drools 規則應用當中,將一個普通的JavaBean 插入到規則的WorkingMemory當中後的對象規則可以對Fact 對象進行任意的讀寫操作,當一個JavaBean 插入到WorkingMemory 當中變成Fact 之後,Fact 對象不是對原來的JavaBean 對象進行Clone,而是原來JavaBean 對象的引用

6. 

7.Drools規則

7.1規則文件

 Drools 當中,一個標準的規則文件就是一個以“.drl”結尾的文本文件,標準的規則文件格式:

package package-name //包名是必須的,並放在第一行,包名對於規則文件中規則的管理只限於邏輯上的

imports

globals

functions

queries

rules

7.2規則語言

一個標準規則的結構

rule "name" //規則名稱

attributes //屬性部分

when

LHS //left hand sid條件部分

then

RHS //right hand sid結果部分

End

7.2.1條件部分

條件部分又被稱之爲Left Hand Side,簡稱爲LHS,條件又稱之爲pattern(匹配模式):在一個規則當中whenthen 中間的部分就是LHS 部分。在LHS 當中,可以包含0~n 個條件,如果LHS 部分沒空的話,那麼引擎會自動添加一個eval(true)的條件,由於該條件總是返回true,所以LHS 爲空的規則總是返回true,在Drools

當中在pattern 中沒有連接符號,那麼就用and 來作爲默認連接,所以在該規則的LHS 部分中兩個pattern 只有都滿足了纔會返回true。默認情況下,每行可以用“;”來作爲結束符(和Java 的結束一樣),當然行尾也可以不加“;”結尾。

約束連接:對於對象內部的多個約束的連接,可以採用“&&”(and)、“||(or)和“,(and)來實現,表面上看“,”與“&&”具有相同的含義,但是有一點需要注意,“,”與“&&”和“||”不能混合使用,也就是說在有“&&”或“||”出現的LHS 當中,是不可以有“,”連接符出現的,反之亦然。

1. 比較操作符:共計12種:

>>=<<== =!=

containsnot containsmemberofnot memberofmatchesnot matches

1) Contains:比較操作符contains 是用來檢查一個Fact 對象的某個字段(該字段要是一個Collection或是一個Array 類型的對象)是否包含一個指定的對象

contains 只能用於對象的某個Collection/Array 類型的字段與另外一個值進行比較,作爲比較的值可以是一個靜態的值,也可以是一個變量(綁定變量或者是一個global 對象)

示例:

package test

rule "rule1"

when

$order:Order();

$customer:Customer(age >20, orders contains $order);

then

System.out.println($customer.getName());

end

2) Not Contains:與contains作用相反

3) Member Of :是用來判斷某個Fact 對象的某個字段是否在一個集合(Collection/Array)當中,用法與contains 有些類似,但也有不同,member of 前邊是某個數據對象且一定要是一個變量(綁定變量或者是一個global 對象),後邊是數據對象集合:

示例:

package test

global String[] orderNames;

rule "rule1"

when

$order:Order(name memberOf orderNames);

then

System.out.println($order.getName());

End

4) Not member of:與member of作用相反

5) Matches: matches 是用來對某個Fact 的字段與標準的Java 正則表達式進行相似匹配,被比較的字符串可以是一個標準的Java 正則表達式,但有一點需要注意,那就是正則表達式字符串當中不用考慮“\”的轉義問題

示例:

package test

import java.util.List;

rule "rule1"

when

$customer:Customer(name matches ".*");

then

System.out.println($customer.getName());

end

6) not matches:matches相反

結果部分:結果部分又被稱之爲Right Hand Side,簡稱爲RHS,在一個規則當中then 後面部分就是RHS,只有在LHS 的所有條件都滿足時RHS 部分纔會執行, salience該屬性的作用是通過一個數字來確認規則執行的優先級,數字越大,執行越靠前。

函數介紹:

ü Insert:作用與我們在Java類當中調用StatefulKnowledgeSession對象的insert 方法的作用相同,都是用來將一個Fact 對象插入到當前的Working Memory 當中。一旦調用insert宏函數,那麼Drools會重新與所有的規則再重新匹配一次

ü insertLogical:作用與insert 類似,它的作用也是將一個Fact 對象插入到當前的WorkingMemroy 當中

ü update:用來實現對當前Working Memory 當中的Fact 進行更新。如果希望規則只執行一次,那麼可以通過設置規則的no-loop屬性爲true 來實現

示例:

package test

import java.util.List;

query "query fact count"

Customer();

end

rule "rule1"

salience 2

when

eval(true);

then

Customer cus=new Customer();

cus.setName("張三");

cus.setAge(1);

insert(cus);

end

rule "rule2"

salience 1

when

$customer:Customer(name=="張三",age<10);

then

$customer.setAge($customer.getAge()+1);

update($customer);

System.out.println("----------"+$customer.getName());

End

示例說明:

調用update 宏函數更新Customer 對象後Working Memory 當中還只存在一個Customer 對象

ü retract:宏函數retract也是用來將Working Memory當中某個Fact對象從Working Memory當中刪除

ü drools:宏對象可以實現在規則文件裏直接訪問Working Memory

常用方法說明:

方法名稱

含義說明

getWorkingMemory()

獲取當前的WorkingMemory 對象

halt()

在當前規則執行完成後,不再執行

其它未執行的規則。

getRule()

得到當前的規則對象

insert(new Object)

向當前的WorkingMemory 當中插入

指定的對象,功能與宏函數insert

相同

update(new Object)

更新當前的WorkingMemory 中指定

的對象,功能與宏函數update 相同

update(FactHandle

Object)

更新當前的WorkingMemory 中指定

的對象,功能與宏函數update 相同。

retract(new Object)

從當前的WorkingMemory 中刪除指

定的對象,功能與宏函數retract 

同。

kcontext

作用主要是用來得到當前的

KnowledgeRuntime 對象,KnowledgeRuntime 對象可以實現與引擎的各種交互

ü Modify:是一個表達式塊,它可以快速實現對Fact 對象多個屬性進行修改,修改完成後會自動更新到當前的Working Memory 當中

7.2.2屬性部分

規則的屬性共有13 個分別是:activation-groupagenda-groupauto-focusdate-effectivedate-expiresdialectdurationenabledlock-on-activeno-loopruleflow-groupsaliencewhen

1. Salience: 屬性的值是一個數字,數字越大執行優先級越高,同時它的值可以是一個負數。默認情況下,規則的salience默認值爲0,所以如果我們不手動設置規則的salience屬性,那麼它的執行順序是隨機的。

2. no-loop: 屬性的值是一個布爾型,默認情況下規則的no-loop屬性的值爲false,如果no-loop 屬性值爲true,那麼就表示該規則只會被引擎檢查一次,如果滿足條件就執行規則的RHS 部分

3. date-effective:在規則運行時,引擎會自動拿當前操作系統的時間與date-effective設置的時間值進行比對,只有當系統時間>=date-effective設置的時間值時,規則纔會觸發執行,否則執行將不執行。日期格式:dd-MM-yyyy

4. date-expires該屬性的作用與date-effective屬性恰恰相反,如果大於系統時間,那麼規則就執行,否則就不執行。日期格式:dd-MM-yyyy

5. enabled: true執行該規則,false不執行該規則

6. dialect:該屬性用來定義規則當中要使用的語言類型:mvel java,如果沒有手工設置規則的dialect,默認使用的java 語言

7. duration該屬性對應的值爲一個長整型,單位是毫秒。如果設置了該屬性,那麼規則將在該屬性值之後時間,在另外一個線程裏觸發

8. lock-on-active:該屬性爲boolean,當在規則上使用ruleflow-group屬性或agenda-group屬性的時候,將lock-on-action屬性的值設置爲true,可能避免因某些Fact 對象被修改而使已經執行過的規則再次被激活執行

9. activation-group該屬性的作用是將若干個規則劃分成一個組,用一個字符串來給這個組命名,這樣在執 行的時候,具有相同 activation-group 屬性的規則中只要有一個會被執行,其它的規則都將 不再執行。

10. agenda-group: agenda-group規則的調用與執行是通過StatelessSession StatefulSession 來實現的,一般的順序是創建一個StatelessSession StatefulSession,將各種經過編譯的規則的package添加到session當中,接下來將規則當中可能用到的Global 對象和Fact對象插入到Session 當中,最後調用fireAllRules 方法來觸發、執行規則。在沒有調用最後一步fireAllRules 方法之前,所有的規則及插入的Fact對象都存放在一個名叫Agenda 表的對象當中,這個Agenda表中每一個規則及與其匹配相關業務數據叫做Activation,在調用fireAllRules方法後,這些Activation會依次執行,這些位於Agenda表中的Activation的執行順序在沒有設置相關用來控制順序的屬性時(比如salience 屬性),它的執行順序是隨機的,不確定的。Agenda Group是用來在Agenda的基礎之上,對現在的規則進行再次分組,具體的分組方法可以採用爲規則添加agenda-group屬性來實現

11. auto-focus:它的作用是用來在已設置了agenda-group的規則上設置該規則是否可以自動獨取Focus,如果該屬性設置爲true,那麼在引擎執行時,就不需要顯示的爲某個Agenda Group設置Focus否則需要。

12. ruleflow-group在使用規則流的時候要用到ruleflow-group屬性,該屬性的值爲一個字符串,作用是用來將規則劃分爲一個個的組,然後在規則流當中通過使用ruleflow-group 屬性的值,從而使用對應的規則

7.2.3註釋

1. 單行註釋:採用“#”或者“//”來進行標記

2. 多行註釋:以“/*”開始,以“*/”結束

7.3函數

函數的編寫位置可以是規則文件當中package 聲明後的任何地方

function void/Object functionName(Type arg...) {

/*函數體的業務代碼*/

}

函數以function標記開頭,可以有或無返回類型,然後定義方法名和參數,語法基本同java一致,不同規則文件的函數相互之間是不可見的。

示例:

package test

import java.util.List;

import java.util.ArrayList;

/*

一個測試函數

用來向Customer對象當中添加指定數量的Order對象的函數

*/

function void setOrder(Customer customer,int orderSize) {

List ls=new ArrayList();

for(int i=0;i<orderSize;i++){

Order order=new Order();

ls.add(order);

}

customer.setOrders(ls);

}

/*

測試規則

*/

rule "rule1"

when

$customer :Customer();

then

setOrder($customer,5);

System.out.println("rule 1 customer has order

size:"+$customer.getOrders().size());

end

/*

測試規則

*/

rule "rule2"

when

$customer :Customer();

then

setOrder($customer,10);

System.out.println("rule 2 customer has order

size:"+$customer.getOrders().size());

end

7.4查詢

查詢是Drools 當中提供的一種根據條件在當前的WorkingMemory當中查找Fact 的方法,在Drools當中查詢可分爲兩種:一種是不需要外部傳入參數;一種是需要外部傳入參數

7.4.1無參數查詢

Drools當中查詢以query 關鍵字開始,以end 關鍵字結束,在package 當中一個查詢要有唯一的名稱,查詢的內容就是查詢的條件部分,條件部分內容的寫法與規則的LHS 部分寫法完全相同

示例:

query "testQuery"

customer:Customer(age>30,orders.size >10)

end

查詢的調用是由StatefulSession完成的,通過調用StatefulSession對象的getQueryResults(String queryName)方法實現對查詢的調用,該方法的調用會返回一個QueryResults對象,QueryResults是一個類似於Collection接口的集合對象,在它當中存放在若干個QueryResultsRow對象,通過QueryResultsRow可以得到對應的Fact對象,從而實現根據條件對當前WorkingMemory當中Fact 對象的查詢

7.4.2參數查詢

和函數一樣,查詢也可以接收外部傳入參數

代碼示例:

query "testQuery"(int $age,String $gender)

customer:Customer(age>$age,gender==$gender)

end

7.5對象定義

 Drools當中,可以定義兩種類型的對象:一種是普通的類型Java Fact 的對象;另一種是用來描述Fact 對象或其屬性的元數據對象。

7.5.1 java Fact 對象

Drools 當中是通過向WorkingMemory中插入Fact對象的方式來實現規則引擎與業務數據的交互,對於Fact對象就是普通的具有若干個屬性及其對應的gettersetter方法的JavaBean對象。Drools除了可以接受用戶在外部向WorkingMemory當中插入現成的Fact對象,還允許用戶在規則文件當中定義一個新的Fact 對象在規則文件當中定義Fact 對象要以declare 關鍵字開頭,以end 關鍵字結尾,中間部分就是該Fact 對象的屬性名及其類型等信息的聲明。

示例:

declare Address

city : String

addressName : String

end

7.5.2元數據定義

Fact對象的屬性或者是規則來定義元數據,元數據定義採用的是“@”符號開頭,後面是元數據的屬性名(屬性名可以是任意的),然後是括號,括號當中是該元數據屬性對應的具體值

示例:

@author(jacob)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章