Drools规则引擎的基本使用
Drools規則引擎的基本使用
1、概述
規則引擎是一種嵌入在應用程序中的組件,實現了將業務決策從應用程序代碼中分離出來,并使用預定義的語義模塊編寫業務決策。接受數據輸入,解釋業務規則,并根據業務規則做出業務決策。
Drools是一個基于java的規則引擎,開源的,可以將復雜多變的規則從硬編碼中解放出來,以規則腳本的形式存放在文件中,使得規則的變更不需要修正代碼重啟機器就可以立即在線上環境生效。
其前身是 Codehaus 的一個開源項目叫 Drools,最近被納入 JBoss 門下,更名為 JBoss Rules,成為了 JBoss 應用服務器的規則引擎。
常見規則引擎:
?IBM的iLog,商業產品
?Drools,開源
?最近比較火的FLink CEP,開源
?Easy Rule,開源
?阿里的qlexpress,開源
2、工作機制
左邊是規則,右邊是事實(數據),中間就是執行器(決策引擎)
在 Drools 中,規則被存放在 Production Memory(規則庫)中,要匹配的facts(事實)被存在 Working Memory(工作內存)中。當時facts被插入到工作內存中后,規則引擎會把事實和規則庫里的模式進行匹配;
對于匹配成功的規則再由 Agenda 負責具體執行推理算法中被激發規則的結論部分,同時 Agenda 通過沖突決策策略管理這些沖突規則的執行順序,Drools 中規則沖突決策策略有:(1) 優先級策略 (2) 復雜度優先策略 (3) 簡單性優先策略 (4) 廣度策略 (5) 深度策略 (6) 裝載序號策略 (7) 隨機策略
3、基本使用
Kmodule配置
Fact類:
@Data public class Applicant {private String name;private int age;private boolean valid; ?public Applicant(String name, int age) {this.name = name;this.age = age;this.valid = true;} } ? public class Action {private String msg; ?public Action(String msg) {this.msg = msg;} ?public void doSomeThing() {System.out.println(msg);} }規則模板DRL文件
package cn.yyds.demo.droolsdemo.rules ? // 導包 import cn.yyds.demo.droolsdemo.Applicant import cn.yyds.demo.droolsdemo.Action; ? rule "age if valid" // rule名稱 when // 觸發判斷條件$a: Applicant(age < 18) then // 滿足條件后要執行的邏輯$a.setValid(false); // 可以執行任何java代碼(對輸入的對象調用方法)new Action("執行動作").doSomeThing(); //可以執行任何java代碼(創建對象調方法)insert(new Action("不合法")); //可以繼續給容器插入對象,以觸發其他規則 end測試代碼:
public class TestApp {public static void main(String[] args) {KieServices kieServices = KieServices.Factory.get();//默認自動加載 META-INF/kmodule.xmlKieContainer kieContainer = kieServices.getKieClasspathContainer();//kmodule.xml 中定義的 ksession nameKieSession kieSession = kieContainer.newKieSession("all-rules");Applicant applicant = new Applicant("Mr John Smith", 17);kieSession.insert(applicant);kieSession.fireAllRules();kieSession.dispose();} }依賴:
<dependency><groupId>org.drools</groupId><artifactId>drools-compiler</artifactId><version>7.23.0.Final</version> </dependency>4、語法
規則文件可以使用 .drl文件,也可以是 .xml 文件,這里我們使用drl文件。
package cn.yyds.drools.rules; import java.util.List; rule "name"no-loop true ?when$message:Message(status == 0)thenSystem.out.println("fit");$message.setStatus(1);update($message);1、基本定義語法
package: 對一個規則文件而言,package是必須定義的,必須放在規則文件第一行。特別的是,package的名字是隨意的,不必必須對應物理路徑,跟java的package的概念不同,這里只是邏輯上的一種區分。同樣的package下定義的function和query等可以直接使用。
比如:package com.drools.demo.point
import: 導入規則文件需要使用到的外部變量,這里的使用方法跟java相同,但是不同于java的是,這里的import導入的不僅僅可以是一個類,也可以是這個類中的某一個可訪問的靜態方法。
比如:
import com.drools.demo.point.PointDomain; import com.drools.demo.point.PointDomain.getById;rule: 定義一個規則。rule “ruleName”。一個規則可以包含三個部分:
?屬性部分:定義當前規則執行的一些屬性等,比如是否可被重復執行、過期時間、生效時間等。
?條件部分,即LHS,定義當前規則的條件,如 when Message(); 判斷當前workingMemory中是否存在Message對象。
?結果部分,即RHS,這里可以寫普通java代碼,即當前規則條件滿足后執行的操作,可以直接調用Fact對象的方法來操作應用。
2、屬性定義ATTRIBUTE
no-loop : 定義當前的規則是否不允許多次循環執行,默認是false,也就是當前的規則只要滿足條件,可以無限次執行。什么情況下會出現一條規則執行過一次又被多次重復執行呢?drools提供了一些api,可以對當前傳入workingMemory中的Fact對象進行修改或者個數的增減,比如上述的update方法,就是將當前的workingMemory中的Message類型的Fact對象進行屬性更新,這種操作會觸發規則的重新匹配執行,可以理解為Fact對象更新了,所以規則需要重新匹配一遍,那么疑問是之前規則執行過并且修改過的那些Fact對象的屬性的數據會不會被重置?結果是不會,已經修改過了就不會被重置,update之后,之前的修改都會生效。當然對Fact對象數據的修改并不是一定需要調用update才可以生效,簡單的使用set方法設置就可以完成,這里類似于java的引用調用,所以何時使用update是一個需要仔細考慮的問題,一旦不慎,極有可能會造成規則的死循環。上述的no-loop true,即設置當前的規則,只執行一次,如果本身的RHS部分有update等觸發規則重新執行的操作,也不要再次執行當前規則。
但是其他的規則會被重新執行,豈不是也會有可能造成多次重復執行,數據紊亂甚至死循環?答案是使用其他的標簽限制,也是可以控制的:lock-on-active true
lock-on-active true:通過這個標簽,可以控制當前的規則只會被執行一次,因為一個規則的重復執行不一定是本身觸發的,也可能是其他規則觸發的,所以這個是no-loop的加強版。當然該標簽正規的用法會有其他的標簽的配合,后續提及。
date-expires:設置規則的過期時間,默認的時間格式:“日-月-年”,中英文格式相同,但是寫法要用各自對應的語言,比如中文:“29-七月-2010”,但是還是推薦使用更為精確和習慣的格式,這需要手動在java代碼中設置當前系統的時間格式,后續提及。屬性用法舉例:date-expires “2011-01-31 23:59:59” // 這里我們使用了更為習慣的時間格式
date-effective:設置規則的生效時間,時間格式同上。
duration:規則定時,duration 3000 ,3秒后執行規則
salience:優先級,數值越大越先執行,這個可以控制規則的執行順序。
其他的屬性可以參照相關的api文檔查看具體用法,此處略。
3、條件部分LHS
when:規則條件開始。條件可以單個,也可以多個,多個條件一次排列,比如
wheneval(true)$customer:Customer()$message:Message(status==0)上述羅列了三個條件,當前規則只有在這三個條件都匹配的時候才會執行RHS部分,三個條件中第一個
eval(true):是一個默認的api,true 無條件執行,類似于 while(true)
$message:Message(status==0) 這句話標示的:當前的workingMemory存在Message類型并且status屬性的值為0的Fact對象,這個對象通常是通過外部java代碼插入或者自己在前面已經執行的規則的RHS部分中insert進去的。
前面的$message代表著當前條件的引用變量,在后續的條件部分和RHS部分中,可以使用當前的變量去引用符合條件的FACT對象,修改屬性或者調用方法等。可選,如果不需要使用,則可以不寫。
條件可以有組合,比如:
Message(status==0 || (status > 1 && status <=100))RHS中對Fact對象private屬性的操作必須使用getter和setter方法,而LHS中則必須要直接用.的方法去使用,比如
$order:Order(name=="qu") $message:Message(status==0 && orders contains $order && $order.name=="qu")特別的是,如果條件全部是 &&關系,可以使用“,”來替代,但是兩者不能混用
如果現在Fact對象中有一個List,需要判斷條件,如何判斷呢?
看一個例子,有如下Message類fact對象
Message {
int status;
List names;
}
判斷條件:
$message:Message(status==0 && names contains “網易” && names.size >= 1)
上述的條件中,status必須是0,并且names列表中含有“網易”并且列表長度大于等于1
contains:對比是否包含操作,操作的被包含目標可以是一個復雜對象也可以是一個簡單的值。
Drools提供了十二中類型比較操作符:
= < <= == != contains / not contains / memberOf / not memberOf /matches/ not matches
?not contains:與contains相反。
?memberOf:判斷某個Fact屬性值是否在某個集合中,與contains不同的是他被比較的對象是一個集合,而contains被比較的對象是單個值或者對象。
?not memberOf:正好相反。
?matches:正則表達式匹配,與java不同的是,不用考慮’/'的轉義問題
?not matches:正好相反。
4、結果部分RHS
當規則條件滿足,則進入規則結果部分執行,結果部分可以是純java代碼,比如:
thenSystem.out.println("OK"); //會在控制臺打印出ok end當然也可以調用Fact的方法,比如 $message.execute();操作數據庫等等一切操作。
結果部分也有drools提供的方法:
insert:往當前workingMemory中插入一個新的Fact對象,會觸發規則的再次執行,除非使用no-loop限定;
update: 更新
modify: 修改,與update語法不同,結果都是更新操作
retract: 刪除
RHS部分除了調用Drools提供的api和Fact對象的方法,也可以調用規則文件中定義的方法,方法的定義使用 function 關鍵字
function void console {System.out.println();StringUtils.getId();// 調用外部靜態方法,StringUtils必須使用import導入,getId()必須是靜態方法 }5、類聲明declare
Drools還有一個可以定義類的關鍵字:
declare 可以再規則文件中定義一個class,使用起來跟普通java對象相似,你可以在RHS部分中new一個并且使用getter和setter方法去操作其屬性。
上述的’@'是什么呢?是元數據定義,用于描述數據的數據~,沒什么執行含義
可以在RHS部分中使用Address address = new Address()的方法來定義一個對象。
總結
以上是生活随笔為你收集整理的Drools规则引擎的基本使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [Android] Android学习手
- 下一篇: STL 中map的用法详解