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,來聽郭老師的相聲????秋釀