轉自:http://www.blogjava.net/diggbag/articles/359347.html
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對象就是普通的具有若干個屬性及其對應的getter與setter方法的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();
}
}
接下來定義一個定義積分規則接口,里面包含了初始化RuleBase、workingMemory以及執行規則的方法。
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(匹配模式):在一個規則當中when與then 中間的部分就是LHS 部分。在LHS 當中,可以包含0~n 個條件,如果LHS 部分沒空的話,那么引擎會自動添加一個eval(true)的條件,由於該條件總是返回true,所以LHS 為空的規則總是返回true,在Drools
當中在pattern 中沒有連接符號,那么就用and 來作為默認連接,所以在該規則的LHS 部分中兩個pattern 只有都滿足了才會返回true。默認情況下,每行可以用“;”來作為結束符(和Java 的結束一樣),當然行尾也可以不加“;”結尾。
約束連接:對於對象內部的多個約束的連接,可以采用“&&”(and)、“||”(or)和“,”(and)來實現,表面上看“,”與“&&”具有相同的含義,但是有一點需要注意,“,”與“&&”和“||”不能混合使用,也就是說在有“&&”或“||”出現的LHS 當中,是不可以有“,”連接符出現的,反之亦然。
1. 比較操作符:共計12種:
>、>=、<、<=、= =、!=、
contains、not contains、memberof、not memberof、matches、not 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-group、agenda-group、auto-focus、date-effective、date-expires、dialect、duration、enabled、lock-on-active、no-loop、ruleflow-group、salience、when
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對象就是普通的具有若干個屬性及其對應的getter與setter方法的JavaBean對象。Drools除了可以接受用戶在外部向WorkingMemory當中插入現成的Fact對象,還允許用戶在規則文件當中定義一個新的Fact 對象, 在規則文件當中定義Fact 對象要以declare 關鍵字開頭,以end 關鍵字結尾,中間部分就是該Fact 對象的屬性名及其類型等信息的聲明。
示例:
declare Address
city : String
addressName : String
end
7.5.2元數據定義
為Fact對象的屬性或者是規則來定義元數據,元數據定義采用的是“@”符號開頭,后面是元數據的屬性名(屬性名可以是任意的),然后是括號,括號當中是該元數據屬性對應的具體值
示例:
@author(jacob)