原文:http://blog.csdn.net/it_man/article/details/7348277
事件處理&時空推理(event processing/temporal reasoning)
概念:
下面來看看jboss的Drools Fusion
Fusion 是業務邏輯集成平臺(Business Logic Integration Platform)一部分,是一個CEP/ESP引擎。
事件,是指在應用程序域中有意義狀態改變的記錄
一個複雜事件是簡單事件的集合。CEP(Complex Event Processing) 處理複雜事件-從事件雲中檢測並選擇事件,根據選擇的事件和他們建立的關係發現他們的關係推理出新的數據。
比如,一系列的鉅額提款激發可疑交易事件的發生。一個複雜事件的發生是由一系列簡單事件的引導形成的。
ESP(Event Stream Processing) 是更實時(real-time)的大量事件處理。例如,根據時間計算實時平均交易量。
一、事件(Events).
從drools視圖來看,事件就是一個特殊的事實(fact)。我們說,所有的事件都是事實,但是所有的事實並不都是事件。
1.事件和事實不同特徵:
(1)通常不可變:事件是在應用程序域中狀態改變的記錄,記錄已經發生的事情,可變的事件是沒有意義的。
應用程序允許給沒有賦值的事件屬性賦值,但是已經賦值的屬性是不應該被改變的。
(2)強時間約束:規則涉及的事件通常需要多個事件的相互關係,尤其某個事件相對其他事件發生的時間點的時間關係。
(3)可管理的生命週期:由於上兩個事件特徵的原因,事件通常在一個有限的時間窗(Time Window)匹配事件和事實,
這就讓引擎管理事件的生命週期成爲可能。一個事件插入working memory,引擎有能力發現一個不在匹配
其他事實的事件,然後自動回收它,釋放相關的資源。
(4)滑動窗( sliding windows)的使用:由於所有的事件都有關聯的時間戳,可以定義並使用滑動窗,讓事件在特定的一段時間有效。
2.事件聲明:
import some.package.StockTick
declare StockTick
@role( event )
end
將一個已有的StockTick(類)事實生命爲事件類型
@role 元數據接受2個值:
fact:默認值,聲明爲常規的事實
event:聲明爲事件
由於Drools支持在DRL中聲明一個事實,可以去掉StockTick(類),還可以這樣:
declare StockTick
@role( event )
datetime : java.util.Date
symbol : String
price : double
end
3.事件元數據
所有的事件都有一個事件元數據集合。當事件插入working memory,事件元數據會自動賦予默認值,我們可以用元數據標籤改變他們的默認值。
假設我們有這樣的一個實體類:
/**
* A class that represents a voice call in
* a Telecom domain model
*/
public class VoiceCall {
private String originNumber;
private String destinationNumber;
private Date callDateTime;
private long callDuration; // in milliseconds
// constructors, getters and setters
}
(1) @timestamp
默認的,當事件插入working memory,會讀取(會話時鐘)Session Clock的timestamp賦值給事件的startTimestamp。
@timestamp( <attributeName> ) //以毫秒計算
表示把事件的attributeName屬性值賦給事件元數據startTimestamp
declare VoiceCall
@role( event )
@timestamp( callDateTime )
end
(2) @duration
Drools支持時間點(point-in-time)事件和時間間隔(interval-based)事件,一個時間點事件可以理解爲時間間隔爲0。默認,所有的事件的持續時間(duration)爲0.我們可以通過@duration標籤來修改事件的duration屬性值。
@duration( <attributeName> )// 以毫秒計算。
表示把事件的attributeName屬性值賦給事件元數據duration
declare VoiceCall
@role( event )
@timestamp( callDateTime )
end
(3)@expires
這個標籤在引擎爲Stream模式下才有效。默認的,當一個事件不在匹配(match)事實,激活規則(有活化的規則),事件自動失效(回收).
@expires( <timeOffset> )
顯示的定義事件的失效時間。
timeOffset可以是下列形式:
[#d][#h][#m][#s][#[ms]]
[]表示是可選參數
declare VoiceCall
@role( event )
@timestamp( callDateTime )
@duration( callDuration )
@expires( 1h35m )
end
VoiceCall事件在1小時35分鐘後過期。
二、會話時鐘(Session Clock)
Drools 5提供2種時鐘。默認的是基於系統時間的即時時鐘(real time clock)。另一個是虛擬(pseudo clock)時鐘,可以手動控制。
1. 即時時鐘(Real Time Clock)
雖然Drools默認使用即時時鐘,我們仍然可以顯示的配置:
KnowledgeSessionConfiguration config = KnowledgeBaseFactory.newKnowledgeSessionConfiguration();
config.setOption( ClockTypeOption.get("realtime") );
2. 配置虛擬時鐘(Pseudo Clock)
KnowledgeSessionConfiguration config = KnowledgeBaseFactory.newKnowledgeSessionConfiguration();
config.setOption( ClockTypeOption.get("pseudo") );
怎樣控制虛擬時鐘的例子:
KnowledgeSessionConfiguration conf = KnowledgeBaseFactory.newKnowledgeSessionConfiguration();
conf.setOption( ClockTypeOption.get( "pseudo" ) );
StatefulKnowledgeSession session = kbase.newStatefulKnowledgeSession( conf, null );
SessionPseudoClock clock = session.getSessionClock();
// then, while inserting facts, advance the clock as necessary:
FactHandle handle1 = session.insert( tick1 );
clock.advanceTime( 10, TimeUnit.SECONDS );
FactHandle handle2 = session.insert( tick2 );
clock.advanceTime( 30, TimeUnit.SECONDS );
FactHandle handle3 = session.insert( tick3 );
新的SessionPseudoClock時間值爲0毫秒,new Date(0) 爲GMT 1970 年 1 月 1 日 00:00:00 ,
clock.advanceTime( 10, TimeUnit.SECONDS ); SessionPseudoClock時間值+10秒。
三、Entry Points
一個entry point是事實(facts)或者事件(events)進入引擎的入口點。
1.聲明Entry Points
rule "authorize withdraw"
when
WithdrawRequest( $ai : accountId, $am : amount ) from entry-point "ATM Stream"
CheckingAccount( accountId == $ai, balance > $am )
then
// authorize withdraw
end
只有賬戶的餘額大於提款請求的金額,規則才被激活
2.使用Entry Points
// create your rulebase and your session as usual
StatefulKnowledgeSession session = ...
// get a reference to the entry point
WorkingMemoryEntryPoint atmStream = session.getWorkingMemoryEntryPoint( "ATM Stream" );
// and start inserting your facts into the entry point
atmStream.insert( aWithdrawRequest );
通常情況下,我們不需要硬編碼把事實插入到WorkingMemory中,通過Drools pipeline,
將從JMS或者 其他非java對象的數據源 中獲得信息(對象)插入到WorkingMemory。
默認的entry point是"DEFAULT",是事實進入WorkingMemory的入口點。
session.insert(fact)實際上是session.getWorkingMemoryEntryPoint("DEFAULT").insert(fact)。
四、時間推理(Temporal Reasoning)
Drools 實現了由Allen定義的13種時間操作運算
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
Temporal Operators ┃ Illustration ┃ Interpretation
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___x___ ┃
x before y ┃ ___y___ ┃ X發生在y之前
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___y___ ┃
x after y ┃ ___x___ ┃ X發生在y之後
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___x___ ┃
x meets y ┃ ___y___ ┃ x結束時y開始
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___y___ ┃
x metby y ┃ ___x___ ┃ y結束時x開始
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ______x______ ┃
x overlaps y ┃ ______y______ ┃ x開始在y之前,結束在y之後
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ______x______ ┃
x overlappedby y ┃ ______y______ ┃ x開始在y之後,結束在y之前
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___x___ ┃
x starts y ┃ ______y______ ┃ x和y同時開始,結束在y之前
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ______x______ ┃
x startedby y ┃ ___y___ ┃ x和y同時開始,結束在y之後
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___x___ ┃
x during y ┃ ______y______ ┃ x發生在y期間
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ______x______ ┃
x includes y ┃ ___y___ ┃ y發生在x期間
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ___x___ ┃
x finishes y ┃ ______y______ ┃X開始在y之後,同y一起結束
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ______x______ ┃
x finishedby y ┃ ___y___ ┃X開始在y之前,同y一起結束
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
┃ ______x______ ┃
x coincides y ┃ y ┃ X和y同時發生
━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━
1.before
$eventA : EventA( this before[ 3m30s, 4m ] $eventB )
也就是:
3m30s <= $eventB.startTimestamp - $eventA.endTimeStamp <= 4m
before操作符的時間間隔距離是可選的:
如果2個值都被定義了,間隔開始於第1個值,結束於第2個值。
如果只有1個值被定義,間隔開始於該值,結束於正無窮大。
如果沒有值定義,間隔開始於1毫秒,結束於正無窮大。
時間間隔距離也可以是負數的,例:
$eventA : EventA( this before[ -3m30s, -2m ] $eventB )
注意:當時間間隔第1個值大於第2個值時,引擎會自動的調換他們。
2.After
$eventA : EventA( this after[ 3m30s, 4m ] $eventB )
也就是:
3m30s <= $eventA.startTimestamp - $eventB.endTimeStamp <= 4m
after操作符的時間間隔距離是可選的:
如果2個值都被定義了,間隔開始於第1個值,結束於第2個值。
如果只有1個值被定義,間隔開始於該值,結束於正無窮大。
如果沒有值定義,間隔開始於1毫秒,結束於正無窮大。
時間間隔距離也可以是負數的,例:
$eventA : EventA( this after[ -3m30s, -2m ] $eventB )
注意:當時間間隔第1個值大於第2個值時,引擎會自動的調換他們。
3.meets
$eventA : EventA( this meets $eventB )
也就是:
abs( $eventB.startTimestamp - $eventA.endTimestamp ) == 0
meets操作符有1個可選參數
$eventA : EventA( this meets[ 5s ] $eventB )
也就是:
abs( $eventB.startTimestamp - $eventA.endTimestamp) <= 5s
注意:時間間隔不能爲負
4.metby
$eventA : EventA( this metby $eventB )
也就是:
abs( $eventA.startTimestamp - $eventB.endTimestamp ) == 0
metby操作符有1個可選參數
$eventA : EventA( this metby[ 5s ] $eventB )
也就是:
abs( $eventA.startTimestamp - $eventB.endTimestamp) <= 5s
注意:時間間隔不能爲負
5.overlaps
$eventA : EventA( this overlaps $eventB )
也就是:
$eventA.startTimestamp < $eventB.startTimestamp < $eventA.endTimestamp < $eventB.endTimestamp
overlaps操作符有1個/2個可選參數
$eventA : EventA( this overlaps[ 5s ] $eventB )
也就是:
$eventA.startTimestamp < $eventB.startTimestamp < $eventA.endTimestamp < $eventB.endTimestamp &&
0 <= $eventA.endTimestamp - $eventB.startTimestamp <= 5s
$eventA : EventA( this overlaps[ 5s, 10s ] $eventB )
也就是:
$eventA.startTimestamp < $eventB.startTimestamp < $eventA.endTimestamp < $eventB.endTimestamp &&
5s <= $eventA.endTimestamp - $eventB.startTimestamp <= 10s
6.overlappedby
eventA : EventA( this overlappedby $eventB )
也就是:
$eventB.startTimestamp < $eventA.startTimestamp < $eventB.endTimestamp < $eventA.endTimestamp
overlappedby操作符有1個/2個可選參數
$eventA : EventA( this overlappedby[ 5s ] $eventB )
也就是:
$eventB.startTimestamp < $eventA.startTimestamp < $eventB.endTimestamp < $eventA.endTimestamp &&
0 <= $eventB.endTimestamp - $eventA.startTimestamp <= 5s
$eventA : EventA( this overlappedby[ 5s, 10s ] $eventB )
也就是:
$eventB.startTimestamp < $eventA.startTimestamp < $eventB.endTimestamp < $eventA.endTimestamp &&
5s <= $eventB.endTimestamp - $eventA.startTimestamp <= 10s
7.starts
$eventA : EventA( this starts $eventB )
也就是:
$eventA.startTimestamp == $eventB.startTimestamp &&
$eventA.endTimestamp < $eventB.endTimestamp
starts操作符有1個可選參數
$eventA : EventA( this starts[ 5s ] $eventB )
也就是:
abs( $eventA.startTimestamp - $eventB.startTimestamp ) <= 5s &&
$eventA.endTimestamp < $eventB.endTimestamp
注意:時間間隔不能爲負
8.startedby
$eventA : EventA( this startedby $eventB )
也就是:
$eventA.startTimestamp == $eventB.startTimestamp &&
$eventA.endTimestamp > $eventB.endTimestamp
starts操作符有1個可選參數
$eventA : EventA( this starts[ 5s ] $eventB )
也就是:
abs( $eventA.startTimestamp - $eventB.startTimestamp ) <= 5s &&
$eventA.endTimestamp > $eventB.endTimestamp
注意:時間間隔不能爲負
9.during
$eventA : EventA( this during $eventB )
也就是:
$eventB.startTimestamp < $eventA.startTimestamp <= $eventA.endTimestamp < $eventB.endTimestamp
during操作符有1個/2個/4個可選參數
$eventA : EventA( this during[ 5s ] $eventB )
也就是:
0 < $eventA.startTimestamp - $eventB.startTimestamp <= 5s &&
0 < $eventB.endTimestamp - $eventA.endTimestamp <= 5s
$eventA : EventA( this during[ 5s, 10s ] $eventB )
也就是:
5s <= $eventA.startTimestamp - $eventB.startTimestamp <= 10s &&
5s <= $eventB.endTimestamp - $eventA.endTimestamp <= 10s
$eventA : EventA( this during[ 2s, 6s, 4s, 10s ] $eventB )
也就是:
2s <= $eventA.startTimestamp - $eventB.startTimestamp <= 6s &&
4s <= $eventB.endTimestamp - $eventA.endTimestamp <= 10s
10.includes
$eventA : EventA( this includes $eventB )
也就是:
$eventA.startTimestamp < $eventB.startTimestamp <= $eventB.endTimestamp < $eventA.endTimestamp
includes操作符有1個/2個/4個可選參數
$eventA : EventA( this includes[ 5s ] $eventB )
也就是:
0 < $eventB.startTimestamp - $eventA.startTimestamp <= 5s &&
0 < $eventA.endTimestamp - $eventB.endTimestamp <= 5s
$eventA : EventA( this includes[ 5s, 10s ] $eventB )
也就是:
5s <= $eventB.startTimestamp - $eventA.startTimestamp <= 10s &&
5s <= $eventA.endTimestamp - $eventB.endTimestamp <= 10s
$eventA : EventA( this includes[ 2s, 6s, 4s, 10s ] $eventB )
也就是:
2s <= $eventB.startTimestamp - $eventA.startTimestamp <= 6s &&
4s <= $eventA.endTimestamp - $eventB.endTimestamp <= 10s
11.finishes
$eventA : EventA( this finishes $eventB )
也就是:
$eventB.startTimestamp < $eventA.startTimestamp &&
$eventA.endTimestamp == $eventB.endTimestamp
finishes操作符有1個可選參數
$eventA : EventA( this finishes[ 5s ] $eventB )
也就是:
$eventB.startTimestamp < $eventA.startTimestamp &&
abs( $eventA.endTimestamp - $eventB.endTimestamp ) <= 5s
注意:時間間隔不能爲負
12.finishedby
$eventA : EventA( this finishedby $eventB )
也就是:
$eventA.startTimestamp < $eventB.startTimestamp &&
$eventA.endTimestamp == $eventB.endTimestamp
finishedby操作符有1個可選參數
$eventA : EventA( this finishedby[ 5s ] $eventB )
也就是:
$eventA.startTimestamp < $eventB.startTimestamp &&
abs( $eventA.endTimestamp - $eventB.endTimestamp ) <= 5s
注意:時間間隔不能爲負
13.coincides
$eventA : EventA( this coincides $eventB )
也就是:
$eventA.startTimestamp ==$eventB.startTimestamp &&
$eventA.endTimestamp == $eventB.endTimestamp
finishedby操作符有1個/2個可選參數
$eventA : EventA( this coincides[15s] $eventB )
也就是:
abs( $eventA.startTimestamp - $eventB.startTimestamp ) <= 15s &&
abs( $eventA.endTimestamp - $eventB.endTimestamp ) <= 15s
$eventA : EventA( this coincides[15s, 10s] $eventB )
也就是:
abs( $eventA.startTimestamp - $eventB.startTimestamp ) <= 15s &&
abs( $eventA.endTimestamp - $eventB.endTimestamp ) <= 10s
注意:時間間隔不能爲負 .
五、事件處理模式(Event Processing Modes)
Drools支持2種事件處理模式:雲模式(Cloud Mode)和流模式(Stream Mode)
1.雲模式(Cloud Mode)
雲(Cloud)處理模式是默認的處理方式。
在雲模式下,不會區分事實和事件,都看成是事實。
(1)沒有時間的概念。儘管事件在插入引擎被賦予了時間戳,也不能判斷該事件“多大了”,因爲沒有“現在”的概念。滑動窗(sliding windows)基於“現在”的概念,所以在雲模式下無法使用。
(2)無序的事件雲。由於事件無序,沒有自動的生命週期管理,需要像正常的事實一樣顯示的刪除事件。
雲模式雖然是默認的執行模式,我們也可以配置它:
KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( EventProcessingOption.CLOUD );
等同系統屬性配置:
drools.eventProcessingMode = cloud
2.流模式(Stream Mode)
當處理事件流的時候需要選擇流處理模式。
在流模式下:
(1) 插入到引擎裏的事件必須是時間順序的。
(2) 引擎強制性的和使用的會話時鐘session clock同步。
配置流模式:
KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( EventProcessingOption.STREAM );
等同配置系統屬性:
drools.eventProcessingMode = stream
使用流(STREAM)模式,引擎有時間流和"現在"的概念(通過讀取Session Clock的時間戳),
提供了以下3種支持:
(1) 滑動窗的支持
(2) 自動的時間生命週期管理
(3) 使用消極模式(Negative Patterns)自動的規則延遲
3.會話時鐘(Session Clock)在流模式(Stream mode)中的作用
在雲模式下,會話時鐘只有一個作用,就是給插入到working momery 的事件賦予時間戳的值(如果規則沒有定義時間戳屬性)
在流模式下,會話時鐘負責維護當前時間戳,基於當前的時間戳,引擎根據事件的年齡計算所有時間運算,從多種源同步流,安排未來任務等等。
4.流模式(in Stream Mode)中的消極模式(Negative Patterns)
消極模式在流模式和雲模式意義是不同的。
在雲模式下,所有的事實和事件都是預先知道的,消極模式立即計算執行
//a rule that activates immediately upon matching
rule "Sound the alarm"
when
$f : FireDetected( )
not( SprinklerActivated( ) )
then
// sound the alarm
end
在流模式下,帶有時間約束的消極模式可以要求引擎等待一段時間後激活規則。
//a rule that automatically delays activation due to temporal constraints
rule "Sound the alarm"
when
$f : FireDetected( )
not( SprinklerActivated( this after[0s,10s] $f ) )
then
// sound the alarm
end
六. 滑動窗(Sliding Windows)
滑動窗是一種選擇事件範圍的方式。
滑動窗有2種實現方式:滑動時間窗(Sliding Time Windows),滑動長度窗(Sliding Length Windows)。
注意:滑動窗只有在引擎爲(STREAM)流模式下才是可用的
1.滑動時間窗(Sliding Time Windows)
滑動時間窗(允許我們的規則)僅僅匹配發生在最近X時間單元的事件。
例如,如果只關心最近2分鐘的股票行情,模式(pattern)可以這樣寫:
StockTick() over window:time( 2m )
更復雜的例子:
如果最近10分鐘從傳感器讀來的溫度高於最大的臨界值,發出警報。
rule "Sound the alarm in case temperature rises above threshold"
when
TemperatureThreshold( $max : max )
Number( doubleValue > $max ) from accumulate(
SensorReading( $temp : temperature ) over window:time( 10m ),
average( $temp ) )
then
// sound the alarm
end
2.滑動長度窗(Sliding Length Windows)
滑動長度窗(允許我們的規則)僅僅匹配發生在最近X個的事件。
例如,如果只關心最近10個IBM股票的行情,模式(pattern)可以這樣寫:
StockTick( company == "IBM" ) over window:length( 10 )
更復雜的例子:
如果最近100次從傳感器讀來的溫度高於最大的臨界值,發出警報。
rule "Sound the alarm in case temperature rises above threshold"
when
TemperatureThreshold( $max : max )
Number( doubleValue > $max ) from accumulate(
SensorReading( $temp : temperature ) over window:length( 100 ),
average( $temp ) )
then
// sound the alarm
end
七.Knowledgebase分割(Partitioning)
(注意:這是個實驗性的特徵,將來可能會發生變化)
傳統的Rete算法通常一個線程在執行,也是Drools默認的。但是,該算法本身是可平行(化)的。Drools執行的ReteOO算法通過Knowledgebase分割支持粗粒度的平行執行。
當這個選項可用,Knowledgebase分割成若干個獨立的區域,然後用線程池通過這些區域傳播事實。該實現保證最多有一個線程在給定的一個區域執行。
要點:這個特徵只在LHS平行執行可用,不會改變規則激活行爲。
1.平行執行在什麼時候有益:
(1)多處理器
(2)knowledge session處理大量的事實
(3)規則的LHS計算量大
(4)knowledge base包含數百或者更多的規則
如果以上條件都符合,這個特徵可能會提高knowledgebase計算總性能。
2.配置Knowledgebase分割
//enabling multithread evaluation (partitioning)
KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( MultithreadEvaluationOption.YES );
等同系統屬性配置:
drools.multithreadEvaluation = <true|false>
3.多線程管理
配置線程池:
//setting the maximum number of threads for rule evaluation to 5
KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( MaxThreadsOption.get(5) );
等同系統屬性配置:
drools.maxThreads = <-1|1..n>
配置默認值是3,負數值表示在Knowledgebase中有多少分區,引擎就會產生多少線程,使用負數值是很危險的。
八.事件的內存管理
要點:自動的事件內存管理只有在引擎爲Stream模式下才有效。
引擎在Steam模式下的好處之一是引擎能夠根據時間約束檢測出不再匹配任何規則的事件,然後引擎可以沒有負作用的安全地回收事件並釋放其相關的資源。
引擎有2種基本方式計算一個事件有效期:
(1)顯式,使用過期(expiration)策略
(2)隱式,分析事件的時間約束
1.顯式的過期偏移量(有效期)
//explicitly defining an expiration offset of 30 minutes for StockTick events
declare StockTick
@expires( 30m )
end
當StockTick事件持續30分鐘後,如果沒有規則需要該事件,引擎將自動的回收該事件。
2.推知的過期偏移量
//example rule with temporal constraints
rule "correlate orders"
when
$bo : BuyOrderEvent( $id : id )
$ae : AckEvent( id == $id, this after[0,10s] $bo )
then
// do something
end
引擎需要保存BuyOrderEvent 10秒以匹配AckEvent。
BuyOrderEvent隱式的過期偏移量是10秒,AckEvent隱式的過期偏移量是0。
引擎會分析整個Knowledgebase,找出每個事件類型的過期偏移量。當隱式過期偏移量和顯式過期偏移量衝突時,引擎會選擇2個值中最大的1個
Drools and jBPM consist out of several projects: Drools
Guvnor (Business Rules Manager) |