複雜事件處理(CEP)
CEP方案具有以下關鍵特徵:
- 場景通常處理大量事件,但是隻有一小部分事件是相關的。
- 事件通常是不可變的,代表狀態變化的記錄。
- 規則和查詢針對事件運行,並且必須對檢測到的事件模式做出反應。
- 相關事件通常具有很強的時間關係。
- 個別事件沒有優先級。CEP系統對相關事件的模式及其之間的關係進行優先排序。
- 通常需要對事件進行組合和彙總。
Drools CEP支持:
- 具有適當語義的事件處理
- 事件檢測,關聯,聚合和組合
- 事件流處理
- 時間約束,用於建模事件之間的時間關係
- 重要事件的滑動窗口
- 會話範圍的統一時鐘
- CEP用例所需的事件量
- 反應式規則
- 事件輸入到Drools引擎的適配器(管道)
CEP event
Eent的特性:
- 不可更改
- 有很強的時間限制
- 管理生命週期
- 可以使用滑動窗口
可以在Java類或者DRL規則文件中將fact聲明爲event.
event的兩種時間類型:
- 時間間隔:基於間隔的事件有一個持續時間,並持續存在於Drools引擎的工作內存中,直到其持續時間失效。
- 時間點:沒有持續時間,本質上是基於間隔的事件,持續時間爲0。
event配置元數據:
meta | 描述 | 實例 |
---|---|---|
@role | 參數值:fact,event。 默認爲fact | declare VoiceCall @role( event ) end |
@timestamp | 默認情況下,drools給每個event創建一個時間戳。可以通過timestamp指定時間戳的屬性。 | declare VoiceCall @role( event ) @timestamp( callDateTime ) end |
@duration( ) | 該標籤確定Drools引擎中事件的持續時間。事件可以是基於時間間隔的事件或時間點事件。基於間隔的事件具有持續時間,並且持續到Drools引擎的工作內存中,直到其持續時間過去。時間點事件沒有持續時間,本質上是持續時間爲零的基於間隔的事件。默認情況下,Drools引擎中的每個事件的持續時間爲零。 | declare VoiceCall @role( event ) @timestamp( callDateTime ) @duration( callDuration ) end |
@expires | 該標籤確定事件在Drools引擎的工作內存中到期之前的持續時間。默認情況下,當事件不再匹配並激活任何當前規則時,事件就會過期。 | declare VoiceCall @role( event ) @timestamp( callDateTime ) @duration( callDuration ) @expires( 1h35m ) end |
Drools引擎中的事件處理模式
Drools引擎以雲模式或流模式運行。
在雲模式下,Drools引擎將事實作爲事實進行處理,沒有時間限制,與時間無關,並且沒有特定的順序。在流模式下,Drools引擎實時或接近實時地將事實作爲具有強大時間約束的事件進行處理。
雲模式是Drools引擎的默認操作模式。在雲模式下,Drools引擎將事件視爲無序雲。事件仍然具有時間戳,但是以雲模式運行的Drools引擎無法從時間戳中獲取相關性,因爲雲模式會忽略當前時間。此模式使用規則約束來查找匹配的元組以激活和執行規則。
雲模式不對事實施加任何其他要求。但是,由於在此模式下的Drools引擎沒有時間概念,因此它無法使用諸如滑動窗口或自動生命週期管理之類的臨時功能。在雲模式下,不再需要事件時,必須顯式撤消事件。
在雲模式下不強加以下要求:
- 沒有時鐘同步,因爲Drools引擎沒有時間概念
- 沒有事件的排序,因爲Drools引擎將事件作爲無序的雲處理,Drools引擎根據該雲對規則進行匹配
設置方式:
import org.kie.api.conf.EventProcessingOption;
import org.kie.api.KieBaseConfiguration;
import org.kie.api.KieServices.Factory;
KieBaseConfiguration config = KieServices.Factory.get().newKieBaseConfiguration();
config.setOption(EventProcessingOption.CLOUD);
在流模式下,Drools引擎同步事件流(以便可以按時間順序處理不同流中的事件),實現時間或長度的滑動窗口,並實現自動生命週期管理。
以下要求適用於流模式:
- 每個流中的事件必須按時間順序排序。
- 必須存在會話時鐘才能同步事件流。
設置方式:
import org.kie.api.conf.EventProcessingOption;
import org.kie.api.KieBaseConfiguration;
import org.kie.api.KieServices.Factory;
KieBaseConfiguration config = KieServices.Factory.get().newKieBaseConfiguration();
config.setOption(EventProcessingOption.STREAM);
event臨時運算符
在流模式下,Drools引擎支持以下臨時運算符,用於將事件插入Drools引擎的工作存儲器中。雲模式不支持時間運算符。
after
該運算符指定當前事件是否在相關事件之後發生。
例子:
#如果$eventA在$eventB完成後3分鐘30秒至4分鐘之間開始,則以下模式匹配。
$eventA : EventA(this after[3m30s, 4m] $eventB)
參數:
- 如果定義了兩個值,則間隔從第一個值(示例中爲3分鐘30秒)開始,以第二個值(示例中爲4分鐘)結束。
- 如果僅定義一個值,則間隔從提供的值開始,並無限期地運行,沒有結束時間。
- 如果未定義任何值,則間隔從1毫秒開始,並無限期地運行,沒有結束時間。
before
該運算符指定當前事件是否在相關事件之前發生。
和after相似。
coincides
此運算符指定兩個事件是否同時發生。
判斷條件:eventA的開始時間和veventB的開始時間差在指定範圍內,且結束時間差也在指定範圍內。
coincides的參數制定時間差:
- 如果僅給出一個參數,則該參數用於設置兩個事件的開始時間和結束時間的閾值。
- 如果給出了兩個參數,則第一個用作開始時間的閾值,第二個用作結束時間的閾值。
例子:
$eventA : EventA(this coincides[15s, 10s] $eventB)
則判定條件爲:
abs($eventA.startTimestamp - $eventB.startTimestamp) <= 15s
&&
abs($eventA.endTimestamp - $eventB.endTimestamp) <= 10s
during
該運算符指定當前事件是否在相關事件開始和結束的時間範圍內發生。
例子:
$eventA : EventA(this during $eventB)
則計算方式爲:
$eventB.startTimestamp < $eventA.startTimestamp <= $eventA.endTimestamp < $eventB.endTimestamp
includes
該運算符指定相關事件是否在當前事件發生的時間範圍內發生。
例子:
$eventA : EventA(this includes $eventB)
則計算方法:
$eventA.startTimestamp < $eventB.startTimestamp <= $eventB.endTimestamp < $eventA.endTimestamp
finishes
該運算符指定當前事件是否在相關事件之後開始,但是兩個事件同時結束。
例子:
$eventA : EventA(this finishes $eventB)
計算方法:
$eventB.startTimestamp < $eventA.startTimestamp
&&
$eventA.endTimestamp == $eventB.endTimestamp
$eventA : EventA(this finishes[5s] $eventB)
計算方法:
$eventB.startTimestamp < $eventA.startTimestamp
&&
abs($eventA.endTimestamp - $eventB.endTimestamp) <= 5s
finished by
該運算符指定相關事件是否在當前事件之後開始,但是兩個事件同時結束。(此運算finishes符的行爲與運算符的行爲相反。)
例子:
$eventA : EventA(this finishedby $eventB)
計算方法:
$eventA.startTimestamp < $eventB.startTimestamp
&&
$eventA.endTimestamp == $eventB.endTimestamp
$eventA : EventA(this finishedby[5s] $eventB)
計算方法:
$eventA.startTimestamp < $eventB.startTimestamp
&&
abs($eventA.endTimestamp - $eventB.endTimestamp) <= 5s
meets
該運算符指定當前事件是否在相關事件開始的同時結束。
例子:
$eventA : EventA(this meets $eventB)
算法:
abs($eventB.startTimestamp - $eventA.endTimestamp) == 0
$eventA : EventA(this meets[5s] $eventB)
算法:
abs($eventB.startTimestamp - $eventA.endTimestamp) <= 5s
met by
該運算符指定相關事件是否在當前事件開始的同時結束。(此運算meets符的行爲與運算符的行爲相反。)
overlaps
該運算符指定當前事件是否在關聯事件開始之前開始,是否在關聯事件發生的時間段內結束。當前事件必須在相關事件的開始時間和結束時間之間結束。
overlapped by
此運算符指定相關事件是否在當前事件開始之前開始,是否在當前事件發生的時間段內結束。相關事件必須在當前事件的開始時間和結束時間之間結束。(此運算overlaps符的行爲與運算符的行爲相反。)
starts
該運算符指定兩個事件是否同時開始,但是當前事件在相關事件結束之前結束。
例子:
$eventA : EventA(this starts $eventB)
算法:
$eventA.startTimestamp == $eventB.startTimestamp
&&
$eventA.endTimestamp < $eventB.endTimestamp
$eventA : EventA(this starts[5s] $eventB)
算法:
abs($eventA.startTimestamp - $eventB.startTimestamp) <= 5s
&&
$eventA.endTimestamp < $eventB.endTimestamp
started by
該運算符指定兩個事件是否同時開始,但是相關事件在當前事件結束之前結束。(此運算starts符的行爲與運算符的行爲相反。)
Drools引擎中的會話時鐘實現
Drools引擎支持實時時鐘和僞時鐘。
實時時鐘
實時時鐘是Drools引擎中的默認時鐘實現,並使用系統時鐘來確定時間戳的當前時間。
僞時鐘
Drools引擎中的僞時鐘實現有助於測試時間規則,並且可以由應用程序控制。要將Drools引擎配置爲使用僞時鐘,請將KIE會話配置參數設置爲pseudo:
import org.kie.api.runtime.conf.ClockTypeOption;
import org.kie.api.runtime.KieSessionConfiguration;
import org.kie.api.KieServices.Factory;
KieSessionConfiguration config = KieServices.Factory.get().newKieSessionConfiguration();
config.setOption(ClockTypeOption.get("pseudo"));
當插入fact時,手動更改時鐘:
import java.util.concurrent.TimeUnit;
import org.kie.api.runtime.KieSessionConfiguration;
import org.kie.api.KieServices.Factory;
import org.kie.api.runtime.KieSession;
import org.drools.core.time.SessionPseudoClock;
import org.kie.api.runtime.rule.FactHandle;
import org.kie.api.runtime.conf.ClockTypeOption;
KieSessionConfiguration conf = KieServices.Factory.get().newKieSessionConfiguration();
conf.setOption( ClockTypeOption.get("pseudo"));
KieSession session = kbase.newKieSession(conf, null);
SessionPseudoClock clock = session.getSessionClock();
// 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);
滑動時間或長度的窗口
在流模式下,Drools引擎可以從時間或長度的指定滑動窗口中處理事件。
實例:
# 從最近2分鐘開始處理庫存點(滑動時間窗口)
StockPoint() over window:time(2m)
# 處理最後10個存貨點(滑動長度窗口)
StockPoint() over window:length(10)
# 滑動時間範圍內的平均溫度
rule "Sound the alarm if 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
# 滑動長度窗口上的平均溫度
rule "Sound the alarm if 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