Drools介紹與使用

Drools 是用 Java 語言編寫的開放源碼規(guī)則引擎,使用 Rete 算法對所編寫的規(guī)則求值。Drools 允許使用聲明方式表達(dá)業(yè)務(wù)邏輯。可以使用非 XML 的本地語言編寫規(guī)則,從而便于學(xué)習(xí)和理解。并且,還可以將 Java 代碼直接嵌入到規(guī)則文件中,這令 Drools 的學(xué)習(xí)更加吸引人。

Drools 還具有其他優(yōu)點(diǎn):
  • 非常活躍的社區(qū)支持
  • 易用
  • 快速的執(zhí)行速度
  • 在 Java 開發(fā)人員中流行
  • 與 Java Rule Engine API(JSR 94)兼容
Drools 是業(yè)務(wù)邏輯集成平臺(tái),被分為4個(gè)項(xiàng)目:
  • Drools Guvnor (BRMS/BPMS):業(yè)務(wù)規(guī)則管理系統(tǒng)
  • Drools Expert (rule engine):規(guī)則引擎,drools的核心部分
  • Drools Flow (process/workflow):工作流引擎
  • Drools Fusion (cep/temporal reasoning):事件處理

官網(wǎng):http://www.drools.org/#
官方文檔:http://www.drools.org/learn/documentation.html

Drools語法

規(guī)則文件

規(guī)則文件可以使用 .drl文件,也可以是xml文件,這里我們使用drl文件

規(guī)則文件

package:對一個(gè)規(guī)則文件而言,package是必須定義的,必須放在規(guī)則文件第一行,package的名字是隨意的,不必必須對應(yīng)物理路徑,跟java的package的概念不同,這里只是邏輯上的一種區(qū)分

如:
package com.sankuai.meituan.waimai.drools.demo

import:導(dǎo)入規(guī)則文件需要使用到的外部規(guī)則文件或者變量,這里的使用方法跟java相同,但是不同于java的是,這里的import導(dǎo)入的不僅僅可以是一個(gè)類,也可以是這個(gè)類中的某一個(gè)可訪問的靜態(tài)方法

import com.drools.demo.point.PointDomain;

rule:定義一個(gè)具體規(guī)則。rule "ruleName"。一個(gè)規(guī)則可以包含三個(gè)部分:

  • 屬性部分: 定義當(dāng)前規(guī)則執(zhí)行的一些屬性等,比如是否可被重復(fù)執(zhí)行、過期時(shí)間、生效時(shí)間等。

  • 條件部分(LHS): 定義當(dāng)前規(guī)則的條件,如 when Message(); 判斷當(dāng)前workingMemory中是否存在Message對象。

  • 結(jié)果部分(RHS): 即當(dāng)前規(guī)則條件滿足后執(zhí)行的操作,可以直接調(diào)用Fact對象的方法來操作應(yīng)用。這里可以寫普通java代碼

rule部分
rule "ruleName"
     no-loop true

     when
         $message:Message(status == 0)

     then
         System.out.println("fit");
         $message.setStatus(1);
         update($message);
end
規(guī)則詳情
屬性詳情
  • no-loop: 定義當(dāng)前的規(guī)則是否不允許多次循環(huán)執(zhí)行,默認(rèn)是false;當(dāng)前的規(guī)則只要滿足條件,可以無限次執(zhí)行。什么情況下會(huì)出現(xiàn)一條規(guī)則執(zhí)行過一次又被多次重復(fù)執(zhí)行呢?drools提供了一些api,可以對當(dāng)前傳入workingMemory中的Fact對象進(jìn)行修改或者個(gè)數(shù)的增減,比如上述的update方法,就是將當(dāng)前的workingMemory中的Message類型的Fact對象進(jìn)行屬性更新,這種操作會(huì)觸發(fā)規(guī)則的重新匹配執(zhí)行,可以理解為Fact對象更新了,所以規(guī)則需要重新匹配一遍,那么疑問是之前規(guī)則執(zhí)行過并且修改過的那些Fact對象的屬性的數(shù)據(jù)會(huì)不會(huì)被重置?結(jié)果是不會(huì),已經(jīng)修改過了就不會(huì)被重置,update之后,之前的修改都會(huì)生效。當(dāng)然對Fact對象數(shù)據(jù)的修改并不是一定需要調(diào)用update才可以生效,簡單的使用set方法設(shè)置就可以完成,這里類似于java的引用調(diào)用,所以何時(shí)使用update是一個(gè)需要仔細(xì)考慮的問題,一旦不慎,極有可能會(huì)造成規(guī)則的死循環(huán)。上述的no-loop true,即設(shè)置當(dāng)前的規(guī)則,只執(zhí)行一次,如果本身的RHS部分有update等觸發(fā)規(guī)則重新執(zhí)行的操作,也不要再次執(zhí)行當(dāng)前規(guī)則。
    但是其他的規(guī)則會(huì)被重新執(zhí)行,豈不是也會(huì)有可能造成多次重復(fù)執(zhí)行,數(shù)據(jù)紊亂甚至死循環(huán)?答案是使用其他的標(biāo)簽限制,也是可以控制的:lock-on-active true

  • lock-on-active:lock-on-active true 通過這個(gè)標(biāo)簽,可以控制當(dāng)前的規(guī)則只會(huì)被執(zhí)行一次,因?yàn)橐粋€(gè)規(guī)則的重復(fù)執(zhí)行不一定是本身觸發(fā)的,也可能是其他規(guī)則觸發(fā)的,所以這個(gè)是no-loop的加強(qiáng)版

  • date-expires:設(shè)置規(guī)則的過期時(shí)間,默認(rèn)的時(shí)間格式:“日-月-年”

  • date-effective:設(shè)置規(guī)則的生效時(shí)間,時(shí)間格式同上。

  • duration:規(guī)則定時(shí),duration 3000,3秒后執(zhí)行規(guī)則

  • salience:優(yōu)先級(jí),數(shù)值越大越先執(zhí)行,這個(gè)可以控制規(guī)則的執(zhí)行順序。

**rule attributes**
條件部分- LHS
  • when:規(guī)則條件開始。條件可以單個(gè),也可以多個(gè),多個(gè)條件一次排列
    如:當(dāng)前規(guī)則只有在這三個(gè)條件都匹配的時(shí)候才會(huì)執(zhí)行RHS部分
when
      eval(true)
      $customer:Customer()
      $message:Message(status==0)
  • eval(true):是一個(gè)默認(rèn)的api,true 無條件執(zhí)行,類似于 while(true)

  • 操作符>>=<<===!=containsnot containsmemberOfnot memberOfmatchesnot matches

操作符
  • contains: 對比是否包含操作,操作的被包含目標(biāo)可以是一個(gè)復(fù)雜對象也可以是一個(gè)簡單的值
    Person( fullName not contains "Jr" )
  • not contains:與contains相反。
  • memberOf:判斷某個(gè)Fact屬性值是否在某個(gè)集合中,與contains不同的是他被比較的對象是一個(gè)集合,而contains被比較的對象是單個(gè)值或者對象
    CheeseCounter( cheese memberOf $matureCheeses )
  • not memberOf:與memberOf正好相反
  • matches:正則表達(dá)式匹配
    Cheese( type matches "(Buffalo)?\\S*Mozarella" )
    注意: 就像在Java中,寫為字符串的正則表達(dá)式需要轉(zhuǎn)義“\”
  • not matches:與matches正好相反
結(jié)果部分- RHS

當(dāng)規(guī)則條件滿足,則進(jìn)入規(guī)則結(jié)果部分執(zhí)行,結(jié)果部分可以是純java代碼

  • then:
then
     System.out.println("OK"); //會(huì)在控制臺(tái)打印出ok
end
  • insert:往當(dāng)前workingMemory中插入一個(gè)新的Fact對象,會(huì)觸發(fā)規(guī)則的再次執(zhí)行,除非使用no-loop限定
  • update:更新
  • modify:修改,與update語法不同,結(jié)果都是更新操作
  • retract:刪除
rule "Rule 03" 
      when 
          $number : Number( ) 
          not Number( intValue < $number.intValue ) 
      then 
          System.out.println("Number found with value: " + $number.intValue() ); 
          retract( $number );
end
Drools關(guān)鍵詞
關(guān)鍵詞 描述 詳情
lock-on-active
date-effective
date-expires
no-loop
auto-focus
activation-group
agenda-group
ruleflow-group
entry-point
duration
package
import
dialect
salience
enabled
attributes
rule
extend
when
then
template
query
declare
function
global
eval
not
in
or
and
exists
forall
accumulate
collect
from
action
reverse
result
end
over
init -
Drools方法定義
  • function
function String hello(String name) { 
      return "Hello "+name+"!";
}
Drools聲明類型
  • declare:聲明類型
  • 聲明Class、Enum etc類型
  • 聲明元數(shù)據(jù)
聲明類類型
declare  Address 
    number : int 
    streetName : String 
    city : String
end
聲明枚舉類型
declare enum DaysOfWeek
    SUN("Sunday"),MON("Monday"),TUE("Tuesday"),WED("Wednesday"),THU("Thursday"),FRI("Friday"),SAT("Saturday"); 
    fullName : String
end
聲明元數(shù)據(jù)類型

元數(shù)據(jù)可以被分配給在Drools中幾個(gè)不同的結(jié)構(gòu):

  • fact types
  • fact attributes
  • rules
定義格式:
@metadata_key(metadata_value)
例子:
@author( Bob )

import java.util.Date
    declare Person 
    @author( Bob ) 
    @dateOfCreation*( 01-Feb-2009 ) 
    name : String @key @maxLength*( 30 ) 
    dateOfBirth : Date address : Address
end

聲明元數(shù)據(jù)類級(jí)別 關(guān)鍵詞

  • @role( <fact | event> )
import some.package.StockTick
declare StockTick 
    @role ( event )
end
  • @typesafe( <boolean> )
  • @timestamp( <attribute name> )
declare VoiceCall 
    @role( event ) 
    @timestamp( callDateTime )
end
  • @duration( <attribute name> )

  • @expires( <time interval> )

  • @propertyChangeSupport

  • @propertyReactive

聲明元數(shù)據(jù)屬性級(jí)別 關(guān)鍵詞

  • @key

兩個(gè)方面影響:

  • 根據(jù)@key作為類標(biāo)識(shí)符,類比較以 @key 的字段為準(zhǔn)
  • 根據(jù)@key字段生成構(gòu)造函數(shù)
declare Person 
    firstName : String @key 
    lastName : String @key 
    age : int
end
  • @position
declare Cheese 
    name : String @position(1) 
    shop : String @position(2) 
    price : int @position(0)
end

設(shè)計(jì)

Drools vs ILog vs Jess vs Mandarax

優(yōu)點(diǎn)
Drools 開源、社區(qū)非常活躍、易使用、免費(fèi)、JSR94兼容(JSR94是Java Rule Engine API)、支持Java、強(qiáng)大的工具集 只支持一種推理方式、安全性不夠
ILog 性能高(電信領(lǐng)域使用)、易使用 商業(yè)產(chǎn)品、不開源
Jess 支持2種推理方式(正向鏈和反向鏈)、很強(qiáng)的表示、推理能力、支持AOP 不開源、無規(guī)則管理工具、不易使用
Mandarax 開源、免費(fèi)、支持Java JSR94不兼容(JSR94是Java Rule Engine API)、已經(jīng)不更新、社區(qū)不活躍、并且文檔不全
推理方式
  • 正向鏈推理:一條由問題開始搜索,并得到其解答的鏈稱為正向鏈推理。
  • 反向鏈推理:一條由假設(shè)回推到支持該假設(shè)的事實(shí)的鏈稱為反向鏈推理。

作者 @九都散人
2016 年 5月 6日


參考:
Jess 反向鏈推理機(jī)理及診斷專家系統(tǒng)開發(fā)模式研究
http://www.docin.org/p-86340503.html
Drools 6.4 Final 文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,763評論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,238評論 3 428
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,823評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,604評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,339評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,713評論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,712評論 3 445
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,893評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,448評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,201評論 3 357
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,397評論 1 372
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,944評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,631評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,033評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,321評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,128評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,347評論 2 377

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,818評論 18 139
  • 一. 簡介 Drools是一個(gè)基于java的規(guī)則引擎,開源的,可以將復(fù)雜多變的規(guī)則從硬編碼中解放出來,以規(guī)則腳本的...
    碼農(nóng)夢醒閱讀 2,228評論 1 6
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,733評論 18 399
  • 概述(Overview) 以.drl為擴(kuò)展名的文件,是Drools中的規(guī)則文件,規(guī)則文件的編寫,遵循Drools規(guī)...
    老羊_肖恩閱讀 41,863評論 4 31
  • 家里不慎進(jìn)入了老鼠 一個(gè)老頭說,他的 粘板粘到老鼠就跑不脫 老鼠粘板順理成章躺在我家地板上 粘板粘完了我的拖鞋 再...
    閩洞秋沙閱讀 270評論 4 2