Drools規(guī)則引擎 系列教程(二)Drools規(guī)則語法 & LHS 條件

Drools規(guī)則引擎 系列教程(一)SpringBoot整合 & 快速集成上手

Drools規(guī)則引擎 系列教程(三)Drools規(guī)則語法 & RHS動作 & header詳解

Drools規(guī)則引擎 系列教程(四)Drools 主要API & 決策表

教程代碼已提交到ytooo-drools,歡迎star

文中代碼方法均基于上一篇教程

1. .drl文件結(jié)構(gòu)

  • package 包充當(dāng)每組規(guī)則的唯一名稱空間压鉴。一個規(guī)則庫可以包含多個程序包暇矫。
    通常秦驯,將包的所有規(guī)則與包聲明存儲在同一文件中犁罩,以便包是獨立的庄拇。但是呈础,
    也可以在規(guī)則中使用從其他的包中導(dǎo)入的對象
  • imports 與Java中的import語句類似毡惜,用來標識在規(guī)則中使用的任何對象的標準路徑和類型名稱
  • factions 函數(shù)代碼塊如:
function String hello(String applicantName) {
    return "Hello " + applicantName + "!";
}
  • queries 在Drools引擎的工作內(nèi)存中搜索與DRL文件中的規(guī)則相關(guān)的事實
query "people under the age of 21"
    $person : Person( age < 21 )
end
  • global 為規(guī)則提供數(shù)據(jù)或服務(wù)
  • rules 規(guī)則

1.1 import引入java方法 以及 function

?? import & function 在下一節(jié)中詳細描述 帶我飛過去

1.2 glable 全局變量

?? 全局變量在下一節(jié)中詳細描述 帶我飛過去

1.3 querys 查詢

?? querys查詢在下一節(jié)中詳細描述 帶我飛過去

1.4 declare 自定義fact對象

?? declare在下一節(jié)中詳細描述 帶我飛過去

2.rules 規(guī)則

2.1 drl屬性

屬性 描述
salience 定義規(guī)則優(yōu)先級的整數(shù),數(shù)值越大,優(yōu)先級越高
enabled 規(guī)則啟用開關(guān)
date-effective 包含日期和時間定義的字符串批幌。僅當(dāng)當(dāng)前日期和時間在date-effective屬性之后時础锐,才能激活該規(guī)則。
date-expires 如果當(dāng)前日期和時間在date-expires屬性之后荧缘,則無法激活該規(guī)則皆警。
no-loop 選擇該選項后,如果規(guī)則的結(jié)果重新觸發(fā)了先前滿足的條件截粗,則無法重新激活(循環(huán))規(guī)則耀怜。如果未選擇條件,則在這些情況下可以循環(huán)規(guī)則桐愉。
agenda-group 標識要向其分配規(guī)則的議程組
activation-group 激活組财破,在激活組中,只能激活一個規(guī)則从诲。觸發(fā)的第一個規(guī)則將取消激活組中所有規(guī)則的所有未決激活左痢。
duration 定義了如果仍滿足規(guī)則條件,則可以激活規(guī)則的持續(xù)時間(以毫秒為單位)系洛。
timer cron定時表達式
calendar 時鐘
auto-focus 僅適用于議程組中的規(guī)則俊性。選擇該選項后,下次激活該規(guī)則時描扯,將自動將焦點分配給分配了該規(guī)則的議程組定页。
lock-on-active no-loop屬性的更強版
ruleflow-group 標識規(guī)則流組的字符串
dialect 用于標識規(guī)則中的代碼表達式JAVA或MVEL將其用作語言

2.2 匹配模式

2.2.1 沒有約束的匹配模式

實事不需要滿足任何條件,若類型相同绽诚,則觸發(fā)該規(guī)則典徊,如:

package com.ytooo.bean
import com.ytooo.bean.People
dialect  "java"

rule "girl"
    when
        People()
    then
        System.out.println("girl規(guī)則執(zhí)行");
end
2.2.2 有條件約束的匹配模式

實事類型相同,且滿足條件恩够,則觸發(fā)該規(guī)則卒落,如:

package com.ytooo.bean
import com.ytooo.bean.People
dialect  "java"

rule "girl"
    when
        People(sex == 0 && drlType == "people")
    then
        System.out.println("girl規(guī)則執(zhí)行");
end
2.2.3 匹配并綁定屬性以及實事

實事類型相同,且滿足條件蜂桶,則觸發(fā)該規(guī)則儡毕,并綁定數(shù)據(jù),如:

package com.ytooo.bean
import com.ytooo.bean.People
dialect  "java"

rule "girl"
    when
         $p:People(sex == 0,$sex : sex && drlType == "people")
    then
        System.out.println("girl規(guī)則執(zhí)行");
        System.out.println($p);
        System.out.println($sex);
end

2.3 條件

and扑媚,or 等結(jié)合規(guī)則條件的多個模式腰湾,沒有定義關(guān)鍵字連詞,默認是and:

package com.ytooo.bean
import com.ytooo.bean.People
import com.ytooo.bean.Cat
dialect  "java"

rule "girl"
    when
        People(sex == 0) and
        Cat(sex == 0)
    then
        System.out.println("girl規(guī)則執(zhí)行");
end

2.4 約束

??標準Java運算符優(yōu)先級適用于DRL中的約束運算符疆股,而drl運算符除==和!=運算符外均遵循標準Java語義费坊。

??在drl中 Person( firstName != "John" )類似于 !java.util.Objects.equals(person.getFirstName(), "John")

約束 描述
!. 使用此運算符可以以空安全的方式取消引用屬性。!.運算符左側(cè)的值不能為null(解釋為!= null)
[] 按List索引訪問值或Map按鍵訪問值
<押桃,<=葵萎,>,>= 在具有自然順序的屬性上使用這些運算符
==, != 在約束中使用這些運算符作為equals()和!equals()方法
&&唱凯,|| 組合關(guān)系條件
matches羡忘,not matches 使用這些運算符可以指示字段與指定的Java正則表達式匹配或不匹配
contains,not contains 使用這些運算符可以驗證Array或字段是否包含或不包含指定值
memberOf磕昼,not memberOf 使用這些運算符可以驗證字段是否為定義為變量Array的成員
soundslike 使用英語發(fā)音來驗證單詞是否具有與給定值幾乎相同的聲音(類似于該matches運算符)
in卷雕,notin 使用這些運算符可以指定一個以上的可能值來匹配約束(復(fù)合值限制)
2.4.1 約束demo

??來自官方文檔

  • matches, not matches
Person( country matches "(USA)?\\S*UK" )
Person( country not matches "(USA)?\\S*UK" )
  • contains, not contains
FamilyTree(countries contains "UK" )
Person( fullName not contains "Jr" )
FamilyTree(countries contains $var)
Person( fullName not contains $var )
  • memberOf, not memberOf
FamilyTree( person memberOf $europeanDescendants )
FamilyTree( person not memberOf $europeanDescendants )

2.5 集合

2.5.1 from 取集合中的元素
新建bean Animal
package com.ytooo.bean;
import lombok.Data;
import java.util.List;

/**
 * Created by Youdmeng on 2020/1/7 0007.
 */
@Data
public class Animal {

    private Integer level;

    private List<People> peoples;

}
新建 from.drl
package com.ytooo.frm
dialect "java"
import com.ytooo.bean.People
import com.ytooo.bean.Animal

rule "from"
when
    $an : Animal()
    $p : People(sex != 3 && drlType == "from") from $an.peoples
    then
        System.out.println($p);
    end
新建測試方法
@Test
public void from() {
    People p1 = new People(1,"達","from");
    People p2 = new People(0,"秋","from");
    People p3 = new People(3,"金","from");
    Animal animal = new Animal();
    animal.setPeoples(new ArrayList<>());
    animal.getPeoples().add(p1);
    animal.getPeoples().add(p2);
    animal.getPeoples().add(p3);
    session.insert(animal);//插入
    session.fireAllRules();//執(zhí)行規(guī)則
}
執(zhí)行測試,在三組數(shù)據(jù)中票从,2個people滿足條件漫雕,執(zhí)行兩次
People(sex=0, name=秋, drlType=from)
People(sex=1, name=達, drlType=from)
2.5.2 collect

??從指定來源或從Drools引擎的工作內(nèi)存中獲取集合,可以使用Java集合(例如List,LinkedList和HashSet)

新建 collect.drl
package com.ytooo.collt
dialect "java"
import com.ytooo.bean.People
import java.util.List

rule "collect"
 when
    $alarms : List( size >= 3 ) from collect(People(sex != 3 && drlType == "collect"))
    then
        System.out.println("collect執(zhí)行成功峰鄙,匹配結(jié)果為:"+$alarms);
    end
新建測試方法
@Test
public void collect() {
   session.insert(new People(1, "達","collect"));
   session.insert(new People(0, "秋","collect"));
   session.insert(new People(0, "春","collect"));
   session.insert(new People(1, "夏","collect"));
   session.insert(new People(0, "冬","collect"));
   session.insert(new People(3, "金","collect"));

    session.fireAllRules();//執(zhí)行規(guī)則
}
執(zhí)行測試浸间,正確打印出匹配的實事,其中 sex=3的“金” 沒有匹配到結(jié)果中
collect執(zhí)行成功吟榴,匹配結(jié)果為:
[People(sex=0, name=冬, drlType=collect),
 People(sex=1, name=夏, drlType=collect), 
 People(sex=0, name=春, drlType=collect), 
 People(sex=0, name=秋, drlType=collect), 
 People(sex=1, name=達, drlType=collect)]

??當(dāng)改變參數(shù)魁蒜,入?yún)⒅涣粝聝蓚€ sex != 3 的數(shù)據(jù),則沒有任何打印結(jié)果

2.5.3 accumulate 迭代器

??用于遍歷數(shù)據(jù)集對數(shù)據(jù)項執(zhí)行自定義或預(yù)設(shè)動作并返回結(jié)果吩翻。

2.5.3.1 accumulate 函數(shù)
  • average
  • min
  • max
  • count
  • sum
  • collectList 獲取列表
  • collectSet 獲取集合
average樣例 新建 accumulate.drl
package com.ytooo.collt
dialect "java"
import com.ytooo.bean.Sensor
import java.util.List

rule "accumulate"
  when
   $avg : Number() from accumulate(Sensor(temp >= 5 && $temp : temp),average($temp))
  then
    System.out.println("accumulate成功執(zhí)行兜看,平均溫度為:" + $avg);
end
新建測試方法
 @Test
public void accumulate() {
    session.insert(new Sensor("達", 8.26));
    session.insert(new Sensor("秋", 7.12));
    session.insert(new Sensor("春", 3.24));
    session.insert(new Sensor("夏", 6.32));
    session.insert(new Sensor("冬", 12.23));
    session.insert(new Sensor("金", 10.8));

    session.fireAllRules();//執(zhí)行規(guī)則
}
執(zhí)行測試,觸發(fā)規(guī)則并打印平均值
accumulate成功執(zhí)行,平均溫度為:8.946
2.5.4 自定義 accunmulate
  • init 初始化變量
  • action 每次遍歷執(zhí)行的動作
  • reverse (可選)反轉(zhuǎn)動作狭瞎,用于優(yōu)化
  • result 返回的執(zhí)行結(jié)果
@Test
public void diyaccumulate() {
    session.insert(new People(1, "達",26,"diyaccumulate"));
    session.insert(new People(0, "秋",18,"diyaccumulate"));
    session.insert(new People(0, "春",38,"diyaccumulate"));
    session.insert(new People(1, "夏",90,"diyaccumulate"));
    session.insert(new People(0, "冬",55,"diyaccumulate"));
    session.insert(new People(3, "金",12,"diyaccumulate"));

    session.fireAllRules();//執(zhí)行規(guī)則
}
rule "diyaccumulate"
    when
        People(drlType == "diyaccumulate")
        $avg: Number() from accumulate(People($age: age,drlType == "diyaccumulate"),
        init(int $total = 0, $count = 0;),
        action($total += $age; $count++;),
        result($total/$count))

    then
        System.out.println("Avg: " + $avg);
end
輸出結(jié)果
Avg: 39




教程代碼已提交到ytooo-drools细移,歡迎star

Drools規(guī)則引擎 系列教程(一)SpringBoot整合 & 快速集成上手

Drools規(guī)則引擎 系列教程(三)Drools規(guī)則語法 & RHS動作 & header詳解





更多好玩好看的內(nèi)容,歡迎到我的博客交流熊锭,共同進步????????WaterMin

喜歡聽相聲的朋友弧轧,也可以來我的 YouTube,來聽郭老師的相聲????秋釀


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末碗殷,一起剝皮案震驚了整個濱河市劣针,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌亿扁,老刑警劉巖捺典,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異从祝,居然都是意外死亡襟己,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門牍陌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來擎浴,“玉大人,你說我怎么就攤上這事毒涧≈ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長仿吞。 經(jīng)常有香客問我滑频,道長,這世上最難降的妖魔是什么唤冈? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任峡迷,我火速辦了婚禮,結(jié)果婚禮上你虹,老公的妹妹穿的比我還像新娘绘搞。我一直安慰自己,他們只是感情好傅物,可當(dāng)我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布夯辖。 她就那樣靜靜地躺著,像睡著了一般董饰。 火紅的嫁衣襯著肌膚如雪楼雹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天尖阔,我揣著相機與錄音贮缅,去河邊找鬼。 笑死介却,一個胖子當(dāng)著我的面吹牛谴供,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播齿坷,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼桂肌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了永淌?” 一聲冷哼從身側(cè)響起崎场,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎遂蛀,沒想到半個月后谭跨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡李滴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年螃宙,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片所坯。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡谆扎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出芹助,到底是詐尸還是另有隱情堂湖,我是刑警寧澤闲先,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站无蜂,受9級特大地震影響伺糠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜酱讶,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一退盯、第九天 我趴在偏房一處隱蔽的房頂上張望彼乌。 院中可真熱鬧泻肯,春花似錦、人聲如沸慰照。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽毒租。三九已至稚铣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間墅垮,已是汗流浹背惕医。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留算色,地道東北人抬伺。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像灾梦,于是被迫代替她去往敵國和親峡钓。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,512評論 2 359