rule的salience(突出性)屬性,定義rule的執行順序
屬性值越高,執行的優先級越高。
RuleB雖然定義在RuleA的後邊,但salience值比較高,所以總優先執行。
rule "RuleA"
salience 95
when
$fact : MyFact( field1 == true )
then
System.out.println("Rule2 : " + $fact);
update($fact);
end
rule "RuleB"
salience 100
when
$fact : MyFact( field1 == false )
then
System.out.println("Rule1 : " + $fact);
$fact.setField1(true);
update($fact);
end
rule group的agenda屬性,定義一組rule和其他組的執行順序
通過設置agenda-group的屬性,將一組rule綁定到一個組中。
在同一時刻,只有一個組被focus,其中的rule將會被執行。
可以爲rule設置auto-focus屬性,那麼rule所在的組會自動被focus。
默認情況下,所有沒有設置group的rule都會放到"MAIN"組中。如果其他組也沒有設置focus,那麼"MAIN"中的將會在所有的組之前執行。
例子:
rule "Increase balance for credits"
agenda-group "calculation"
when
ap : AccountPeriod()
acc : Account( $accountNo : accountNo )
CashFlow( type == CREDIT,
accountNo == $accountNo,
date >= ap.start && <= ap.end,
$amount : amount )
then
acc.balance += $amount;
end
rule "Print balance for AccountPeriod"
agenda-group "report"
when
ap : AccountPeriod()
acc : Account()
then
System.out.println( acc.accountNo +
" : " + acc.balance );
end
report必須在calculation之前執行,且這兩個分組在所有的rule之前執行,則需要在java中如下設置。
Agenda agenda = ksession.getAgenda();
agenda.getAgendaGroup( "report" ).setFocus();
agenda.getAgendaGroup( "calculation" ).setFocus();
ksession.fireAllRules();
也可以取消一個組內所有rule的執行。
ksession.getAgenda().getAgendaGroup( "Group A" ).clear();
activation-group控制一組rule的排他性
activation-group下只有一個符合條件的rule執行。
rule "Print balance for AccountPeriod1"
activation-group "report"
when
ap : AccountPeriod1()
acc : Account()
then
System.out.println( acc.accountNo +
" : " + acc.balance );
end
rule "Print balance for AccountPeriod2"
activation-group "report"
when
ap : AccountPeriod2()
acc : Account()
then
System.out.println( acc.accountNo +
" : " + acc.balance );
end
只會執行一個。
rule執行模式以及drools引擎的線程安全
被動模式
默認模式。
明確調用fireAllRules()觸發rule。
Drools引擎中的被動模式最適合於需要直接控制規則評估和執行的應用程序,或者適合於在Drools引擎中使用僞時鐘實現的複雜事件處理(CEP)應用程序。
KieSessionConfiguration config = KieServices.Factory.get().newKieSessionConfiguration();
config.setOption( ClockTypeOption.get("pseudo") );
KieSession session = kbase.newKieSession( conf, null );
SessionPseudoClock clock = session.getSessionClock();
session.insert( tick1 );
session.fireAllRules();
clock.advanceTime(1, TimeUnit.SECONDS);
session.insert( tick2 );
session.fireAllRules();
clock.advanceTime(1, TimeUnit.SECONDS);
session.insert( tick3 );
session.fireAllRules();
session.dispose();
主動模式
用戶調用fireUntilHalt()將會開啓主動模式。程序會不斷處理,直到調用了halt()。
Drools引擎中的Active模式最適合將規則評估和執行的控制權委託給Drools引擎的應用程序,或者適合使用Drools引擎中的實時時鐘實現的複雜事件處理(CEP)應用程序。
KieSessionConfiguration config = KieServices.Factory.get().newKieSessionConfiguration();
config.setOption( ClockTypeOption.get("realtime") );
KieSession session = kbase.newKieSession( conf, null );
new Thread( new Runnable() {
@Override
public void run() {
session.fireUntilHalt();
}
} ).start();
session.insert( tick1 );
... Thread.sleep( 1000L ); ...
session.insert( tick2 );
... Thread.sleep( 1000L ); ...
session.insert( tick3 );
session.halt();
session.dispose();
儘管應該避免同時使用fireAllRules()和fireUntilHalt()調用,特別是來自不同線程的調用,但是Drools引擎可以使用線程安全邏輯和內部狀態機安全地處理這種情況。如果正在調用一個fireAllRules(),並且您調用了fireUntilHalt(),那麼Drools引擎將繼續以被動模式運行,直到fireAllRules()操作完成,然後以主動模式啓動以響應fireUntilHalt()調用。
Fact在Drools引擎中的傳播模式
- Lazy模式:
默認模式。批處理方式。
fact的處理順序不能保證和輸入順序相同。 - Immediate:
fact在輸入的時候,立即傳播出去。可以保證順序性。 - Eager:
在rule執行之前,批量傳播。
可以通過@Propagation()改變單個rule的傳播模式。type可以是LAZY, IMMEDIATE, 或者 EAGER。
query Q (Integer i)
String( this == i.toString() )
end
rule "Rule" @Propagation(IMMEDIATE)
when
$i : Integer()
?Q( $i; )
then
System.out.println( $i );
end
議程估算過濾器
調用fireAllRules()的時候,可以指定過濾器,過濾哪些rule執行。
ksession.fireAllRules( new RuleNameEndsWithAgendaFilter( "Test" ) );
默認過濾器包括名稱匹配,名稱前綴匹配,名稱後綴匹配等。
DRL rule集合中的rule unit
rule unit 是數據源,全局變量,DRL rule的組,爲了特定的目的組織起來。
rule unit是對agenda group以及activation group的加強。
定義rule unit:
package org.mypackage.myunit;
public static class AdultUnit implements RuleUnit {
private int adultAge;
private DataSource<Person> persons;
public AdultUnit( ) { }
public AdultUnit( DataSource<Person> persons, int age ) {
this.persons = persons;
this.age = age;
}
// A data source of `Persons` in this rule unit:
public DataSource<Person> getPersons() {
return persons;
}
// A global variable in this rule unit:
public int getAdultAge() {
return adultAge;
}
// Life-cycle methods:
@Override
public void onStart() {
System.out.println("AdultUnit started.");
}
@Override
public void onEnd() {
System.out.println("AdultUnit ended.");
}
}
persons是Person類型fact的集合。整個rule unit的數據源。
adultAge是一個全局變量,所有的rule都可以引用。
onStart() onEnd()是rule unit的生命週期接口。
Method | Invoked when |
---|---|
onStart() | Rule unit execution starts |
onEnd() | Rule unit execution ends |
onSuspend() | Rule unit execution is suspended (used only with runUntilHalt()) |
onResume() | Rule unit execution is resumed (used only with runUntilHalt()) |
onYield(RuleUnit other) | The consequence of a rule in the rule unit triggers the execution of a different rule unit |
默認,所有的rule都在DRL文件同名的rule unit下。如果DRL文件的包路徑和名字,和一個實現了Rulenit接口的類相同,那麼DRL下所有的rule都會加入這個unit。
可以通過unit關鍵字更改unit的名字。
package org.mypackage.myunit
unit AdultUnit
rule Adult
when
$p : Person(age >= adultAge) from persons
then
System.out.println($p.getName() + " is adult and greater than " + adultAge);
end
可以通過更簡單的方式OOPath訪問數據源。
package org.mypackage.myunit
unit AdultUnit
rule Adult
when
$p : /persons[age >= adultAge]
then
System.out.println($p.getName() + " is adult and greater than " + adultAge);
end
Unit執行方法。
// Create a `RuleUnitExecutor` class and bind it to the KIE base:
KieBase kbase = kieContainer.getKieBase();
RuleUnitExecutor executor = RuleUnitExecutor.create().bind( kbase );
// Create the `AdultUnit` rule unit using the `persons` data source and run the executor:
RuleUnit adultUnit = new AdultUnit(persons, 18);
executor.run( adultUnit );
除了創建一個Rule Unit的實例,也可以通過綁定的方式傳入數據。
executor.bindVariable( "persons", persons );
.bindVariable( "adultAge", 18 );
executor.run( AdultUnit.class );
可以通過註解@UnitVar來更改綁定接口中的key。
package org.mypackage.myunit;
public static class AdultUnit implements RuleUnit {
@UnitVar("minAge")
private int adultAge = 18;
@UnitVar("data")
private DataSource<Person> persons;
}
executor.bindVariable( "data", persons );
.bindVariable( "minAge", 18 );
executor.run( AdultUnit.class );