目錄
- 4. Drools基礎語法
- 4.1 規則檔案構成
- 4.2 規則體語法結構
- 4.3 注釋
- 4.4 Pattern模式匹配
- 4.5 比較運算子
- 4.5.1 語法
- 4.5.2 操作步驟
- 4.6 執行指定規則
- 4.7 關鍵字
- 4.8 Drools內置方法
- 4.8.1 update方法
- 4.8.2 insert方法
- 4.8.3 retract方法
4. Drools基礎語法
全套代碼及資料全部完整提供,點此處下載
4.1 規則檔案構成
在使用Drools時非常重要的一個作業就是撰寫規則檔案,通常規則檔案的后綴為.drl,
drl是Drools Rule Language的縮寫,在規則檔案中撰寫具體的規則內容,
一套完整的規則檔案內容構成如下:
| 關鍵字 | 描述 |
|---|---|
| package | 包名,只限于邏輯上的管理,同一個包名下的查詢或者函式可以直接呼叫 |
| import | 用于匯入類或者靜態方法 |
| global | 全域變數 |
| function | 自定義函式 |
| query | 查詢 |
| rule end | 規則體 |
Drools支持的規則檔案,除了drl形式,還有Excel檔案型別的,
4.2 規則體語法結構
規則體是規則檔案內容中的重要組成部分,是進行業務規則判斷、處理業務結果的部分,
規則體語法結構如下:
rule "ruleName"
attributes
when
LHS
then
RHS
end
rule:關鍵字,表示規則開始,引數為規則的唯一名稱,
attributes:規則屬性,是rule與when之間的引數,為可選項,
when:關鍵字,后面跟規則的條件部分,
LHS(Left Hand Side):是規則的條件部分的通用名稱,它由零個或多個條件元素組成,如果LHS為空,則它將被視為始終為true的條件元素,
then:關鍵字,后面跟規則的結果部分,
RHS(Right Hand Side):是規則的后果或行動部分的通用名稱,
end:關鍵字,表示一個規則結束,
4.3 注釋
在drl形式的規則檔案中使用注釋和Java類中使用注釋一致,分為單行注釋和多行注釋,
單行注釋用"//"進行標記,多行注釋以"/*"開始,以"*/"結束,如下示例:
//規則rule1的注釋,這是一個單行注釋
rule "rule1"
when
then
System.out.println("rule1觸發");
end
/*
規則rule2的注釋,
這是一個多行注釋
*/
rule "rule2"
when
then
System.out.println("rule2觸發");
end
4.4 Pattern模式匹配
前面我們已經知道了Drools中的匹配器可以將Rule Base中的所有規則與Working Memory中的Fact物件進行模式匹配,那么我們就需要在規則體的LHS部分定義規則并進行模式匹配,LHS部分由一個或者多個條件組成,條件又稱為pattern,
pattern的語法結構為:系結變數名:Object(Field約束)
其中系結變數名可以省略,通常系結變數名的命名一般建議以$開始,如果定義了系結變數名,就可以在規則體的RHS部分使用此系結變數名來操作相應的Fact物件,Field約束部分是需要回傳true或者false的0個或多個運算式,
例如我們的入門案例中:
//規則二:所購圖書總價在100到200元的優惠20元
rule "book_discount_2"
when
//Order為型別約束,originalPrice為屬性約束
$order:Order(originalPrice < 200 && originalPrice >= 100)
then
$order.setRealPrice($order.getOriginalPrice() - 20);
System.out.println("成功匹配到規則二:所購圖書總價在100到200元的優惠20元");
end
通過上面的例子我們可以知道,匹配的條件為:
1、作業記憶體中必須存在Order這種型別的Fact物件-----型別約束
2、Fact物件的originalPrice屬性值必須小于200------屬性約束
3、Fact物件的originalPrice屬性值必須大于等于100------屬性約束
以上條件必須同時滿足當前規則才有可能被激活,
系結變數既可以用在物件上,也可以用在物件的屬性上,例如上面的例子可以改為:
//規則二:所購圖書總價在100到200元的優惠20元
rule "book_discount_2"
when
$order:Order($op:originalPrice < 200 && originalPrice >= 100)
then
System.out.println("$op=" + $op);
$order.setRealPrice($order.getOriginalPrice() - 20);
System.out.println("成功匹配到規則二:所購圖書總價在100到200元的優惠20元");
end
LHS部分還可以定義多個pattern,多個pattern之間可以使用and或者or進行連接,也可以不寫,默認連接為and,
//規則二:所購圖書總價在100到200元的優惠20元
rule "book_discount_2"
when
$order:Order($op:originalPrice < 200 && originalPrice >= 100) and
$customer:Customer(age > 20 && gender=='male')
then
System.out.println("$op=" + $op);
$order.setRealPrice($order.getOriginalPrice() - 20);
System.out.println("成功匹配到規則二:所購圖書總價在100到200元的優惠20元");
end
4.5 比較運算子
Drools提供的比較運算子,如下表:
| 符號 | 說明 |
|---|---|
| > | 大于 |
| < | 小于 |
| >= | 大于等于 |
| <= | 小于等于 |
| == | 等于 |
| != | 不等于 |
| contains | 檢查一個Fact物件的某個屬性值是否包含一個指定的物件值 |
| not contains | 檢查一個Fact物件的某個屬性值是否不包含一個指定的物件值 |
| memberOf | 判斷一個Fact物件的某個屬性是否在一個或多個集合中 |
| not memberOf | 判斷一個Fact物件的某個屬性是否不在一個或多個集合中 |
| matches | 判斷一個Fact物件的屬性是否與提供的標準的Java正則運算式進行匹配 |
| not matches | 判斷一個Fact物件的屬性是否不與提供的標準的Java正則運算式進行匹配 |
前6個比較運算子和Java中的完全相同,下面我們重點學習后6個比較運算子,
4.5.1 語法
-
contains | not contains語法結構
Object(Field[Collection/Array] contains value)
Object(Field[Collection/Array] not contains value)
-
memberOf | not memberOf語法結構
Object(field memberOf value[Collection/Array])
Object(field not memberOf value[Collection/Array])
-
matches | not matches語法結構
Object(field matches "正則運算式")
Object(field not matches "正則運算式")
4.5.2 操作步驟
第一步:創建物體類,用于測驗比較運算子
package com.itheima.drools.entity;
import java.util.List;
/**
* 物體類
* 用于測驗比較運算子
*/
public class ComparisonOperatorEntity {
private String names;
private List<String> list;
public String getNames() {
return names;
}
public void setNames(String names) {
this.names = names;
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
}
第二步:在/resources/rules下創建規則檔案comparisonOperator.drl
package comparisonOperator
import com.itheima.drools.entity.ComparisonOperatorEntity
/*
當前規則檔案用于測驗Drools提供的比較運算子
*/
//測驗比較運算子contains
rule "rule_comparison_contains"
when
ComparisonOperatorEntity(names contains "張三")
ComparisonOperatorEntity(list contains names)
then
System.out.println("規則rule_comparison_contains觸發");
end
//測驗比較運算子not contains
rule "rule_comparison_notContains"
when
ComparisonOperatorEntity(names not contains "張三")
ComparisonOperatorEntity(list not contains names)
then
System.out.println("規則rule_comparison_notContains觸發");
end
//測驗比較運算子memberOf
rule "rule_comparison_memberOf"
when
ComparisonOperatorEntity(names memberOf list)
then
System.out.println("規則rule_comparison_memberOf觸發");
end
//測驗比較運算子not memberOf
rule "rule_comparison_notMemberOf"
when
ComparisonOperatorEntity(names not memberOf list)
then
System.out.println("規則rule_comparison_notMemberOf觸發");
end
//測驗比較運算子matches
rule "rule_comparison_matches"
when
ComparisonOperatorEntity(names matches "張.*")
then
System.out.println("規則rule_comparison_matches觸發");
end
//測驗比較運算子not matches
rule "rule_comparison_notMatches"
when
ComparisonOperatorEntity(names not matches "張.*")
then
System.out.println("規則rule_comparison_notMatches觸發");
end
第三步:撰寫單元測驗
//測驗比較運算子
@Test
public void test2(){
KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();
ComparisonOperatorEntity comparisonOperatorEntity = new ComparisonOperatorEntity();
comparisonOperatorEntity.setNames("張三");
List<String> list = new ArrayList<String>();
list.add("張三");
list.add("李四");
comparisonOperatorEntity.setList(list);
//將資料提供給規則引擎,規則引擎會根據提供的資料進行規則匹配,如果規則匹配成功則執行規則
kieSession.insert(comparisonOperatorEntity);
kieSession.fireAllRules();
kieSession.dispose();
}
4.6 執行指定規則
通過前面的案例可以看到,我們在呼叫規則代碼時,滿足條件的規則都會被執行,那么如果我們只想執行其中的某個規則如何實作呢?
Drools給我們提供的方式是通過規則過濾器來實作執行指定規則,對于規則檔案不用做任何修改,只需要修改Java代碼即可,如下:
//測驗執行指定規則
@Test
public void test3(){
KieServices kieServices = KieServices.Factory.get();
//獲得Kie容器物件
KieContainer kieContainer = kieServices.newKieClasspathContainer();
//從Kie容器物件中獲取會話物件
KieSession session = kieContainer.newKieSession();
//Fact物件,事實物件
ComparisonOperatorEntity fact = new ComparisonOperatorEntity();
fact.setNames("李四");
List<String> list = new ArrayList<String>();
list.add("張三2");
//list.add("李四");
fact.setList(list);
session.insert(fact);
//激活規則,由Drools框架自動進行規則匹配,如果規則匹配成功,則執行當前規則
//使用框架提供的規則過濾器執行指定規則
session.fireAllRules(new RuleNameEqualsAgendaFilter("rule_comparison_notcontains"));
//session.fireAllRules(new RuleNameStartsWithAgendaFilter("rule_"));
//關倍訓話
session.dispose();
}
4.7 關鍵字
Drools的關鍵字分為:硬關鍵字(Hard keywords)和軟關鍵字(Soft keywords),
硬關鍵字是我們在規則檔案中定義包名或者規則名時明確不能使用的,否則程式會報錯,軟關鍵字雖然可以使用,但是不建議使用,
硬關鍵字包括:true false null
軟關鍵字包括: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
4.8 Drools內置方法
規則檔案的RHS部分的主要作用是通過插入,洗掉或修改作業記憶體中的Fact資料,來達到控制規則引擎執行的目的,Drools提供了一些方法可以用來操作作業記憶體中的資料,操作完成后規則引擎會重新進行相關規則的匹配,原來沒有匹配成功的規則在我們修改資料完成后有可能就會匹配成功了,
創建如下物體類:
package com.itheima.drools.entity;
import java.util.List;
/**
* 學生
*/
public class Student {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
4.8.1 update方法
update方法的作用是更新作業記憶體中的資料,并讓相關的規則重新匹配,
第一步:撰寫規則檔案/resources/rules/student.drl,檔案內容如下
package student
import com.itheima.drools.entity.Student
/*
當前規則檔案用于測驗Drools提供的內置方法
*/
rule "rule_student_age小于10歲"
when
$s:Student(age < 10)
then
$s.setAge(15);
update($s);//更新資料,導致相關的規則會重新匹配
System.out.println("規則rule_student_age小于10歲觸發");
end
rule "rule_student_age小于20歲同時大于10歲"
when
$s:Student(age < 20 && age > 10)
then
$s.setAge(25);
update($s);//更新資料,導致相關的規則會重新匹配
System.out.println("規則rule_student_age小于20歲同時大于10歲觸發");
end
rule "rule_student_age大于20歲"
when
$s:Student(age > 20)
then
System.out.println("規則rule_student_age大于20歲觸發");
end
第二步:撰寫單元測驗
KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();
Student student = new Student();
student.setAge(5);
//將資料提供給規則引擎,規則引擎會根據提供的資料進行規則匹配,如果規則匹配成功則執行規則
kieSession.insert(student);
kieSession.fireAllRules();
kieSession.dispose();
通過控制臺的輸出可以看到規則檔案中定義的三個規則都觸發了,
在更新資料時需要注意防止發生死回圈,
4.8.2 insert方法
insert方法的作用是向作業記憶體中插入資料,并讓相關的規則重新匹配,
第一步:修改student.drl檔案內容如下
package student
import com.itheima.drools.entity.Student
/*
當前規則檔案用于測驗Drools提供的內置方法
*/
rule "rule_student_age等于10歲"
when
$s:Student(age == 10)
then
Student student = new Student();
student.setAge(5);
insert(student);//插入資料,導致相關的規則會重新匹配
System.out.println("規則rule_student_age等于10歲觸發");
end
rule "rule_student_age小于10歲"
when
$s:Student(age < 10)
then
$s.setAge(15);
update($s);
System.out.println("規則rule_student_age小于10歲觸發");
end
rule "rule_student_age小于20歲同時大于10歲"
when
$s:Student(age < 20 && age > 10)
then
$s.setAge(25);
update($s);
System.out.println("規則rule_student_age小于20歲同時大于10歲觸發");
end
rule "rule_student_age大于20歲"
when
$s:Student(age > 20)
then
System.out.println("規則rule_student_age大于20歲觸發");
end
第二步:撰寫單元測驗
KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();
Student student = new Student();
student.setAge(10);
//將資料提供給規則引擎,規則引擎會根據提供的資料進行規則匹配,如果規則匹配成功則執行規則
kieSession.insert(student);
kieSession.fireAllRules();
kieSession.dispose();
通過控制臺輸出可以發現,四個規則都觸發了,這是因為首先進行規則匹配時只有第一個規則可以匹配成功,但是在第一個規則中向作業記憶體中插入了一個資料導致重新進行規則匹配,此時第二個規則可以匹配成功,在第二個規則中進行了資料修改導致第三個規則也可以匹配成功,以此類推最終四個規則都匹配成功并執行了,
4.8.3 retract方法
retract方法的作用是洗掉作業記憶體中的資料,并讓相關的規則重新匹配,
第一步:修改student.drl檔案內容如下
package student
import com.itheima.drools.entity.Student
/*
當前規則檔案用于測驗Drools提供的內置方法
*/
rule "rule_student_age等于10歲時洗掉資料"
/*
salience:設定當前規則的執行優先級,數值越大越優先執行,默認值為0.
因為當前規則的匹配條件和下面規則的匹配條件相同,為了保證先執行當前規則,需要設定優先級
*/
salience 100
when
$s:Student(age == 10)
then
retract($s);//retract方法的作用是洗掉作業記憶體中的資料,并讓相關的規則重新匹配,
System.out.println("規則rule_student_age等于10歲時洗掉資料觸發");
end
rule "rule_student_age等于10歲"
when
$s:Student(age == 10)
then
Student student = new Student();
student.setAge(5);
insert(student);
System.out.println("規則rule_student_age等于10歲觸發");
end
rule "rule_student_age小于10歲"
when
$s:Student(age < 10)
then
$s.setAge(15);
update($s);
System.out.println("規則rule_student_age小于10歲觸發");
end
rule "rule_student_age小于20歲同時大于10歲"
when
$s:Student(age < 20 && age > 10)
then
$s.setAge(25);
update($s);
System.out.println("規則rule_student_age小于20歲同時大于10歲觸發");
end
rule "rule_student_age大于20歲"
when
$s:Student(age > 20)
then
System.out.println("規則rule_student_age大于20歲觸發");
end
第二步:撰寫單元測驗
KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();
Student student = new Student();
student.setAge(10);
//將資料提供給規則引擎,規則引擎會根據提供的資料進行規則匹配,如果規則匹配成功則執行規則
kieSession.insert(student);
kieSession.fireAllRules();
kieSession.dispose();
通過控制臺輸出可以發現,只有第一個規則觸發了,因為在第一個規則中將作業記憶體中的資料洗掉了導致第二個規則并沒有匹配成功,
全套代碼及資料全部完整提供,點此處下載
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/538294.html
標籤:Java
