Drools介紹與使用


Drools 是用 Java 語言編寫的開放源碼規則引擎,使用 Rete 算法對所編寫的規則求值。Drools 允許使用聲明方式表達業務邏輯。可以使用非 XML 的本地語言編寫規則,從而便於學習和理解。並且,還可以將 Java 代碼直接嵌入到規則文件中,這令 Drools 的學習更加吸引人。

Drools 還具有其他優點:
  • 非常活躍的社區支持
  • 易用
  • 快速的執行速度
  • 在 Java 開發人員中流行
  • 與 Java Rule Engine API(JSR 94)兼容
Drools 是業務邏輯集成平台,被分為4個項目:
  • Drools Guvnor (BRMS/BPMS):業務規則管理系統
  • Drools Expert (rule engine):規則引擎,drools的核心部分
  • Drools Flow (process/workflow):工作流引擎
  • Drools Fusion (cep/temporal reasoning):事件處理

官網:http://www.drools.org/#
官方文檔:http://www.drools.org/learn/documentation.html

Drools語法

規則文件

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

規則文件

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

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

import:導入規則文件需要使用到的外部規則文件或者變量,這里的使用方法跟java相同,但是不同於java的是,這里的import導入的不僅僅可以是一個類,也可以是這個類中的某一個可訪問的靜態方法

import com.drools.demo.point.PointDomain;

rule:定義一個具體規則。rule "ruleName"。一個規則可以包含三個部分:

  • 屬性部分: 定義當前規則執行的一些屬性等,比如是否可被重復執行、過期時間、生效時間等。

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

  • 結果部分(RHS): 即當前規則條件滿足后執行的操作,可以直接調用Fact對象的方法來操作應用。這里可以寫普通java代碼

rule部分
rule "ruleName"
     no-loop true
 <span class="hljs-keyword">when</span>
     $message<span class="hljs-symbol">:Message</span>(status == <span class="hljs-number">0</span>)

 <span class="hljs-keyword">then</span>
     System.out.println(<span class="hljs-string">"fit"</span>);
     $message.setStatus(<span class="hljs-number">1</span>);
     update($message);

end

規則詳情
屬性詳情
  • 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:lock-on-active true 通過這個標簽,可以控制當前的規則只會被執行一次,因為一個規則的重復執行不一定是本身觸發的,也可能是其他規則觸發的,所以這個是no-loop的加強版

  • date-expires:設置規則的過期時間,默認的時間格式:“日-月-年”

  • date-effective:設置規則的生效時間,時間格式同上。

  • duration:規則定時,duration 3000,3秒后執行規則

  • salience:優先級,數值越大越先執行,這個可以控制規則的執行順序。

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

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

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

當規則條件滿足,則進入規則結果部分執行,結果部分可以是純java代碼

  • then:
then
     System.out.println("OK"); //會在控制台打印出ok
end
  • insert:往當前workingMemory中插入一個新的Fact對象,會觸發規則的再次執行,除非使用no-loop限定
  • update:更新
  • modify:修改,與update語法不同,結果都是更新操作
  • 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關鍵詞
關鍵詞 描述 詳情
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類型
  • 聲明元數據
聲明類類型
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
聲明元數據類型

元數據可以被分配給在Drools中幾個不同的結構:

  • 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

聲明元數據類級別 關鍵詞

  • @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

聲明元數據屬性級別 關鍵詞

  • @key

兩個方面影響:

  • 根據@key作為類標識符,類比較以 @key 的字段為准
  • 根據@key字段生成構造函數
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

設計

Drools vs ILog vs Jess vs Mandarax

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

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


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

      </div>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM