規則引擎由推理引擎發展而來,是一種嵌入在應用程序中的組件,實現了將業務決策從應用程序代碼中分離出來,並使用預約義的語義模塊編寫業務決策。接受數據輸入,解釋業務規則,並根據規則作出業務決策。git
概念解析:github
Fact: 業務數據對象,在規則中至關於變量對象數組
Rule:規則,至關於一個if then的邏輯體,同事自己包含屬性bash
Module:模式,至關於一個判斷,A>10網絡
WorkingMemory:工做區,至關於一個內存的執行空間,一批規則都在一個執行空間中執行,全部的fact也存儲於該內存空間數據結構
Session:會話,一個工做區對應於一個會話,包含參數和執行流程的規則函數
Rete:規則網絡,rule的lhs部分的執行網絡ui
Agenda:議程,決定執行哪些rhs的Actionthis
rule是規則管理系統中每個子規則對應的實體,起主要包含lhs,rhs,other,分別對應 if-then-else 的邏輯表達 Urule-Rule.png lua
原圖:www.processon.com/view/link/5…
lhs存儲的是一顆規則樹,樹中的每個節點用Criterion接口來標示
public interface Criterion{
Junction getParent();
void setParent(Junction parent);
}
複製代碼
Criterion 的主要實現Criteria和Junction,分別表明一個條件明細(left op value,如age > 10) 和一個聯合條件(and/or)
rule是最原子的規則,只包含單層的if-else-then,沒有嵌套的if-else,因此rhs/other對應的都是一系列的動做,即Action
public class Rhs {
private List<Action> actions;
public List<Action> getActions() {
return actions;
}
public void setActions(List<Action> actions) {
this.actions = actions;
Collections.sort(actions);
}
public void addAction(Action action) {
if(actions==null){
actions=new ArrayList<Action>();
}
actions.add(action);
Collections.sort(actions);
}
}
複製代碼
各類Context是規則執行時候須要用到的上下文
ReteInstance用於執行全部規則的LHS,Agenda用於執行全部規則的RHS
KnowledgeSession是規則引擎對客戶端暴露的接口,使用KnowlegeSessionFactory進行生成,須要傳入KnowledgePackage,KnowledgePackage對應的是規則配置系統中的知識包
KnowledgeSession繼承了WorkingMemory接口,擁有了維護變量對象的功能,能夠經過insert()方法插入一個業務變量實體,fileRule是的時候能夠經過paramters參數設置參數數據
經過調用KnowledgeSession 的fireRule()方法開始進行規則計算,其最後會調用execute()方法進行執行,execute()方法首先對變量庫和參數庫進行歸一,造成fact數組,而後調用ReteInstance的enter()方法執行規則的LHS,最後調用Agenda的execute方法執行規則的RHS
private RuleExecutionResponse execute(AgendaFilter filter, Map<String, Object> params,int max){
this.parameterMap.clear();
this.clearInitParameters();
this.parameterMap.putAll(initParameters);
// 變量是map
for(Map<?,?> map:factMaps){
for(Object key:map.keySet()){
this.parameterMap.put(key.toString(), map.get(key));
}
}
// 參數
if(params!=null){
this.parameterMap.putAll(params);
}
if(!facts.contains(parameterMap)){
facts.add(parameterMap);
}
long start=System.currentTimeMillis();
for(Object fact:facts){
evaluationRete(fact);
}
evaluationContext.clean();
buildElseRules(true);
ExecutionResponseImpl resp=(ExecutionResponseImpl)agenda.execute(filter,max);
resp.setDuration(System.currentTimeMillis()-start);
reset();
return resp;
}
private void evaluationRete(Object fact) {
for(ReteInstance reteInstance:reteInstanceList){
Collection<FactTracker> trackers=reteInstance.enter(evaluationContext, fact);
if(trackers!=null){
agenda.addTrackers(trackers);
}
}
}
複製代碼
rete是對執行LHS(規則)的流程封裝,多個Rule的LHS交織在一塊兒,組成一張有向無環圖(DAG),起點是各個實體數據的輸入(Object),通過每個具體條件(Criteria)和聯合添加(And/Or),最終若是符合某一個LHS的全部規則,則會到達終點(規則的定義-Terminal)
rete是經過DAG的形式保存在規則管理系統中,當規則引擎請求到一個規則的時候拿到的是一張Node圖,Node圖只表示了規則的定義但不能執行,而後其中的每一個Node會調用toActivity方法進而生成一張Activity圖,Activity用於執行
ObjectType對應的是規則使用的變量庫/參數庫的類型,該類節點是DAG的起點
Junction有兩個子類And和Or,分別對應的是聯合調解
Criteria對應的是UI中的每個條件明細,好比[用戶.年齡>18]
Line和Path標示的是DAG中的邊的關係,其做爲from節點實例的屬性,保存了to節點的實例
valueCompute用於全部子表達式的計算,如變量賦值,函數執行,方法執行,控制檯輸出等
FactTracker用於追蹤每個須要計算的數據實體,若是一個數據實體經過DAG的全部規則判斷,到達了一個終點,會將終點內保存的規則(Rule)以及改對象保存在FactTracker中,該數據結構做爲Rete模塊的輸出和Agenda模塊的輸入
ReteInstance封裝了全部的ObjectTypeActivity(即DAG的起點),對KnowledgeSession提供統一的接口調用
經過調用ReteInstance.enter()方法,進而以此調用全部Activity的enter()方法來完成整個LHS的判斷,並返回Collection
一個DAG的示例以下:
agenda是對執行RHS(動做)的流程封裝,規則引擎能夠將多個規則換分紅不一樣的組,屬於相同組的規則的RHS會按照組的定義來執行,目前有三種組
1. 互斥組(activation-group):系統會自動將此屬性相同的規則劃爲一組,且這個組中只有一個規則會執行,待執行的規則如設置了優先級,則優先級最高的規則執行,不然隨機;
2. 執行組(agenda-group):系統會自動將此屬性相同的規則劃爲一組,默認狀況下,引擎不會執行這個組裏的規則,須要咱們在定義規則動做時利用系統內置的函數顯示的指定要激活執行的執行組名,這樣系統纔會嘗試匹配並執行組裏的規則。
3. 默認組:不屬於互斥組和執行組的規則都會被劃分在默認組,默認組的規則會被順序執行
複製代碼
須要注意的是,一個規則只會被劃分到一個組,若是一個規則定義了多個組的屬性,會按照執行組>互斥組>默認組的順序依次判斷該規則須要被添加到哪一個組
下面看下agenda模塊的UML類圖
Activation是用來具體執行RHS的接口,裏面封裝了rule和rule做用的對象(objectCriteriaMap的key),具體執行代碼在 com.bstek.urule.action.Action#execute 106 行
Rhs rhs=rule.getRhs();
if(rhs!=null){
List<Action> actions=rhs.getActions();
if(actions!=null){
for(Action action:actions){
if(rule.getDebug()!=null){
action.setDebug(rule.getDebug());
}
ActionValue actionValue=action.execute(context,objectCriteriaMap.keySet(),matchedObjects,varia bleMap);
if(actionValue!=null){
actionValues.add(actionValue);
}
}
}
}
複製代碼
RuleGroup對應的是上面提到的組的概念
ActivationGroup 是互斥組,即該組內的Activation只會執行一個,因此執行完後會清楚該組全部Activation,對應代碼爲com.bstek.urule.runtime.agenda.ActivationGroup#execute:40
AgendaGroup 是執行組,該組內獲取焦點的規則都會執行,獲取焦點有兩種方式,一是在UI上配置自動獲取焦點的屬性,二是直接調用com.bstek.urule.runtime.agenda.AgendaGroup#setFocus使得整個組獲取焦點
默認組實際上就是順序執行不在互斥組和執行組裏的規則,因此沒有對應的RuleGroup
RuleBox 將相同的RuleGroup放在一塊兒,執行的時候順序執行,不一樣類型的RuleBox封裝了對應的RuleGroup
ActivationRuleBox(默認組) 沒有 group 的概念,執行的時候直接順序執行Activation,因此也沒有RuleGroup類
ActivationGroupRuleBox(互斥組)和AgendaGroupRuleBox(執行組) 都有 group 的概念,在UI上定義的group名同樣的劃分爲一組,執行的時候是分組執行,因此都有對應RuleGroup類
但ActivationGroupRuleBox和AgendaGroupRuleBox這兩個類的group按順序執行的邏輯是如出一轍的,區別在於RuleGroup類的實現
Agenda封裝了全部的 RuleBox,對KnowledgeSession提供統一的接口調用
經過調用Agenda.execute()方法會依次調用全部組的規則,並將結果封裝成RuleExecutionResponse
經過調用Agenda.addTrackers()方法接受Rete模塊執行的結果,並取出其中的Activation放進對應的RuleBox