此處介紹一下drools
中then
部分的寫法,以及一些內建的方法,比如insert/delete/modify
等等。同時也介紹一下rule
的繼承,和在when
中實現if else if
等操作。
drools提供了一些內建的方法,這些方法會修改drools的工作記憶體
中Fact
物件的值。從而會導致重新進行模式匹配。
insert
是向工作記憶體中插入物件,同時會導致重新進行規則的模式匹配。同時當規則不滿足時,不會自動刪除。
當發生火災Fire
時,向工作記憶體中插入一個Alarm
物件,告警發生後,刪除工作記憶體中的Fire
物件,然後檢測Alarm
物件是否還存在。
package rules
import com.huan.drools.insertmethod.Fire
import com.huan.drools.insertmethod.Alarm
rule "insert_發生火災時,往工作記憶體中插入告警物件"
when
$fire: Fire()
then
System.out.println("1、發生火災時,往工作記憶體中插入告警物件");
insert(new Alarm($fire));
end
rule "insert_當規則記憶體中存在告警物件,進行告警,然後刪除火災物件"
when
$fire: Fire()
$alarm: Alarm( fire == $fire )
then
System.out.println("2、進行告警,然後刪除對應的火災物件");
end
rule "insert_檢測告警物件是否還是存在-01"
when
Alarm()
then
System.out.println("3、insert 插入的告警物件還存在");
// 刪除工作記憶體中的Fire物件
delete($fire);
end
rule "insert_檢測告警物件不存在"
when
not Alarm()
then
System.out.println("3、insert 插入的告警物件不存在");
end
此處使用的是 insert
進行插入
// 將火災物件插入到工作記憶體中
kieSession.insert(new Fire());
// 只觸發規則名稱以 insert_ 開頭的規則
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("insert_"));
1、發生火災時,往工作記憶體中插入告警物件
2、進行告警,然後刪除對應的火災物件
3、insert 插入的告警物件還存在
insert
可以向工作記憶體中插入Fact
物件。insert
方法呼叫後,會導致模式的重新匹配,導致之前不會執行的規則,重新執行。insert
方法插入到工作記憶體的物件,在規則不成立時,不會自動刪除,需要手動刪除,注意和insertLogical
的區別insert
是向工作記憶體中插入物件,同時會導致重新進行規則的模式匹配。同時當規則不滿足時,會自動刪除。
當發生火災Fire
時,向工作記憶體中插入一個Alarm
物件,告警發生後,刪除工作記憶體中的Fire
物件,然後檢測Alarm
物件是否還存在。
package rules
import com.huan.drools.Fire
import com.huan.drools.Alarm
rule "insertLogical_發生火災時,往工作記憶體中插入告警物件"
when
$fire: Fire()
then
System.out.println("1、發生火災時,往工作記憶體中插入告警物件");
insertLogical(new Alarm($fire));
end
rule "insertLogical_當規則記憶體中存在告警物件,進行告警,然後刪除火災物件"
when
$fire: Fire()
$alarm: Alarm( fire == $fire )
then
System.out.println("2、進行告警,然後刪除對應的火災物件");
delete($fire);
end
rule "insertLogical_檢測告警物件是否還是存在-01"
when
Alarm()
then
System.out.println("3、insertLogical 插入的告警物件還存在");
end
rule "insertLogical_檢測告警物件不存在"
when
not Alarm()
then
System.out.println("3、insertLogical 插入的告警物件不存在");
end
此處使用的是insertLogical
插入
kieSession.insert(new Fire());
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("insertLogical_"));
1、發生火災時,往工作記憶體中插入告警物件
2、進行告警,然後刪除對應的火災物件
3、insertLogical 插入的告警物件不存在
insertLogical
可以向工作記憶體中插入Fact
物件。insertLogical
方法呼叫後,會導致模式的重新匹配,導致之前不會執行的規則,重新執行。insertLogical
方法插入到工作記憶體的物件,在規則不成立時,會自動刪除注意和insert
的區別update:
使用它來指定要更新的欄位和整個相關Fact,並將更改通知 Drools 引擎。 Fact發生更改後,您必須在更改可能受更新值影響的另一個事實之前呼叫 update。 為避免此新增步驟,請改用 modify 方法。
規則一: 當工作記憶體中存在火災物件Fire
,並且名字name為空時觸發規則,同時在設定火災的名字為大火災
。
規則二: 當火災存在名字時,輸出火災名字
package rules
import com.huan.drools.Fire
import com.huan.drools.Alarm
rule "update_當存在火災物件時,設定一個火災的名字"
when
$fire: Fire(name == null)
then
System.out.println("1、設定火災名字");
$fire.setName("大火災");
update($fire)
end
rule "update_當火災物件存在名字時觸發"
when
$fire: Fire(name != null)
then
System.out.println("2、火災物件的名字為: " + $fire.getName());
end
kieSession.insert(new Fire());
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("update_"));
1、設定火災名字
2、火災物件的名字為: 大火災
update
會導致模式的重新匹配。update
會修改工作物件記憶體中的值。modify:
使用它來指定要為Fact物件修改的欄位並將更改通知 Drools 引擎。 此方法提供了一種結構化的事實更新方法。 它將更新操作與 setter 呼叫相結合以更改物件欄位。
規則一: 當工作記憶體中存在火災物件Fire
,並且名字name為空時觸發規則,同時在設定火災的名字為大火災
。
規則二: 當火災存在名字時,輸出火災名字
package rules
import com.huan.drools.Fire
import com.huan.drools.Alarm
rule "modify_當存在火災物件時,設定一個火災的名字"
when
$fire: Fire(name == null)
then
System.out.println("1、設定火災名字");
modify($fire){
setName("大火災")
}
end
rule "modify_當火災物件存在名字時觸發"
when
$fire: Fire(name != null)
then
System.out.println("2、火災物件的名字為: " + $fire.getName());
end
kieSession.insert(new Fire());
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("modify_"));
1、設定火災名字
2、火災物件的名字為: 大火災
modify
會導致模式的重新匹配。modify
會修改工作物件記憶體中的值。modify
,不要使用update
。用法:delete(<object>)
retract
也是和delete
一樣的效果,但是推薦使用delete
。
package rules
rule "drools_變數的使用"
when
eval(true)
then
System.out.println("Match啟用的當前觸發規則: " + drools.getMatch());
System.out.println("當前觸發規則的名字: " + drools.getRule().getName());
// System.out.println("終止規則執行fireUntilHalt(): " + drools.getKieRuntime().halt());
// System.out.println("啟用AgendaGroup組: " + drools.getKieRuntime().getAgenda().getAgendaGroup( "CleanUp" ).setFocus());
System.out.println("獲取所有全域性變數: " + drools.getKieRuntime().getGlobals());
// System.out.println("設定全域性變數:" + drools.getKieRuntime().setGlobal("username","huan"); );
// System.out.println("獲取查詢結果:" + drools.getKieRuntime().getQueryResults());
end
規則一: 如果使用者(customer
)的年齡(age
)大於60歲,則打0.9
折。
規則二: 在規則一的基礎上,如果使用者有車(car
),則可以免費停車(freeParking
)。
package rules
import com.huan.drools.Customer
import com.huan.drools.Car
rule "rule_extends_規則一"
when
$c: Customer(age > 60)
then
modify($c){
setDiscount(0.9)
}
System.out.println("觸發規則一:使用者年齡>60歲,打0.9折");
end
// 規則二繼承規則一的條件
rule "rule_extends_規則二" extends "rule_extends_規則一"
when
$car: Car()
then
modify($car){
setFreeParking(true)
}
System.out.println("觸發規則二:使用者有車,免費停車");
end
此處rule_extends_規則二
繼承了rule_extends_規則一
,所以規則一的條件也繼承了。
Car car = new Car();
Customer customer = new Customer();
customer.setAge(65);
kieSession.insert(customer);
kieSession.insert(car);
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("rule_extends_"));
客戶有車,並且年齡是65歲,滿足上方的規則一和規則二
觸發規則一:使用者年齡>60歲,打0.9折
觸發規則二:使用者有車,免費停車
可以看到在rule
上使用extends
關鍵字,可以實現規則的繼承。
只要使用者大於60歲,直接打0.9折,如果還有車,則可以免費停車。
package rules
import com.huan.drools.Customer
import com.huan.drools.Car
rule "命名結果_rule"
when
$c: Customer(age > 60)
do[giveDiscount] // 當上方的條件成立時執行 then [giveDiscount]
$car: Car() // 此條件成立時,執行預設的 then
then
modify($car){
setFreeParking(true)
};
System.out.println("使用者有車,免費停車");
then [giveDiscount]
modify($c){
setDiscount(0.9)
};
System.out.println("使用者年齡>60歲,打0.9折");
end
解釋:
見上方的規則檔案裡的注視
Car car = new Car();
Customer customer = new Customer();
customer.setAge(65);
kieSession.insert(customer);
kieSession.insert(car);
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("命名結果_"));
使用者年齡>60歲,打0.9折
使用者有車,免費停車
也實現了需求
通過when
中使用 do[名字]
然後 then
then 名字
也可以實現。
完成類似 if else if else
效果。見下方的各種執行結果。
rule "if else-if"
when
$customer: Customer(age > 60) // 規則記憶體中存在Customer物件,並且age>60
if($customer.getLevel() == 1) do[level1] // 使用者的級別是1,執行then[level1],然後繼續執行下方的條件
else if ($customer.getLevel() == 2) break[level2] // 使用者的級別是2,執行then[level2],不在執行下方的條件
else do[levelOther] // 其他的level級別,執行then[levelOther],然後在執行下方的條件
Car()
then
System.out.println("我執行了");
then[level1]
System.out.println("level1");
then[level2]
System.out.println("level2");
then[levelOther]
System.out.println("levelOther");
end
1、Customer
的age
小於60
。
輸出:
沒有輸出。
2、Customer
的age
大於60
並且level=1
,沒有Car
。
輸出:
level1
3、Customer
的age
大於60
並且level=1
,有Car
。
輸出:
level1 我執行了
4、Customer
的age
大於60
並且level=2
,沒有Car
。
輸出:
level2
5、Customer
的age
大於60
並且level=2
,有Car
。
輸出:
level2
6、Customer
的age
大於60
並且level=3
,沒有Car
。
輸出:
levelOther
7、Customer
的age
大於60
並且level=3
,有Car
。
輸出:
levelOther 我執行了
do
:執行完之後,還會繼續判斷後面的執行條件。 (即還會執行後面的Car判斷,根據是否有Car獲取不同的結果
)
break
:執行完之後,不會在判斷後面的執行條件。(即忽略了後面的Car判斷,rule執行完了
)
https://gitee.com/huan1993/spring-cloud-parent/tree/master/drools/drools-drl-then
1、https://docs.drools.org/7.69.0.Final/drools-docs/html_single/index.html