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

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

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

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

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

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

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

  • package 包充當(dāng)每組規(guī)則的唯一名稱空間。一個(gè)規(guī)則庫可以包含多個(gè)程序包。
    通常,將包的所有規(guī)則與包聲明存儲(chǔ)在同一文件中,以便包是獨(dú)立的。但是,
    也可以在規(guī)則中使用從其他的包中導(dǎo)入的對象
  • imports 與Java中的import語句類似,用來標(biāo)識(shí)在規(guī)則中使用的任何對象的標(biāo)準(zhǔn)路徑和類型名稱
  • factions 函數(shù)代碼塊如:
function String hello(String applicantName) {
    return "Hello " + applicantName + "!";
}
  • queries 在Drools引擎的工作內(nèi)存中搜索與DRL文件中的規(guī)則相關(guān)的事實(shí)
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é)中詳細(xì)描述 帶我飛過去

1.2 glable 全局變量

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

1.3 querys 查詢

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

1.4 declare 自定義fact對象

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

2.rules 規(guī)則

2.1 drl屬性

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

2.2 匹配模式

2.2.1 沒有約束的匹配模式

實(shí)事不需要滿足任何條件,若類型相同,則觸發(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 有條件約束的匹配模式

實(shí)事類型相同,且滿足條件,則觸發(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 匹配并綁定屬性以及實(shí)事

實(shí)事類型相同,且滿足條件,則觸發(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ī)則條件的多個(gè)模式,沒有定義關(guān)鍵字連詞,默認(rè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 約束

??標(biāo)準(zhǔn)Java運(yùn)算符優(yōu)先級(jí)適用于DRL中的約束運(yùn)算符,而drl運(yùn)算符除==和!=運(yùn)算符外均遵循標(biāo)準(zhǔn)Java語義。

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

約束 描述
!. 使用此運(yùn)算符可以以空安全的方式取消引用屬性。!.運(yùn)算符左側(cè)的值不能為null(解釋為!= null)
[] 按List索引訪問值或Map按鍵訪問值
<,<=,>,>= 在具有自然順序的屬性上使用這些運(yùn)算符
==, != 在約束中使用這些運(yùn)算符作為equals()和!equals()方法
&&,|| 組合關(guān)系條件
matches,not matches 使用這些運(yùn)算符可以指示字段與指定的Java正則表達(dá)式匹配或不匹配
contains,not contains 使用這些運(yùn)算符可以驗(yàn)證Array或字段是否包含或不包含指定值
memberOf,not memberOf 使用這些運(yùn)算符可以驗(yàn)證字段是否為定義為變量Array的成員
soundslike 使用英語發(fā)音來驗(yàn)證單詞是否具有與給定值幾乎相同的聲音(類似于該matches運(yùn)算符)
in,notin 使用這些運(yùn)算符可以指定一個(gè)以上的可能值來匹配約束(復(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,"達(dá)","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個(gè)people滿足條件,執(zhí)行兩次
People(sex=0, name=秋, drlType=from)
People(sex=1, name=達(dá), 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, "達(dá)","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í)行測試,正確打印出匹配的實(shí)事,其中 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=達(dá), drlType=collect)]

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

2.5.3 accumulate 迭代器

??用于遍歷數(shù)據(jù)集對數(shù)據(jù)項(xiàng)執(zhí)行自定義或預(yù)設(shè)動(dòng)作并返回結(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("達(dá)", 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í)行的動(dòng)作
  • reverse (可選)反轉(zhuǎn)動(dòng)作,用于優(yōu)化
  • result 返回的執(zhí)行結(jié)果
@Test
public void diyaccumulate() {
    session.insert(new People(1, "達(dá)",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動(dòng)作 & header詳解





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

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


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容