一.什麼是CEP
複雜事件處理(Complex Event Processing,CEP)
Flink CEP是在Flink中實現的複雜事件處理(CEP)庫
CEP允許在無休止的事件流中檢測事件模式,讓我們有機會掌握數據中重要的部分
一個或多個由簡單事件構成的事件流通過一定的規則匹配,然後輸出用戶想得到的數據——滿足規則的複雜事件
二.CEP特點
目標:從有序的簡單事件流中發現一些高階特徵
輸入:一個或多個由簡單事件構成的事件流
處理:識別簡單事件之間的內在聯繫,多個符合一定規則的簡單事件構成複雜事件
輸出:滿足規則的複雜事件
三. Pattern API
處理事件的規則,被叫做"模式"(Pattern)
Flink CEP提供了Pattern API,用於對輸入流數據進行復雜事件規則定義,用來提取符合規則的時間序列
DataStream<Event> input = ...
// 定義一個Pattern
Pattern<Event, Event> pattern = Pattern.<Event>begin("start").where(...)
.next("middle").subtype(SubEvent.class).where(...)
.followedBy("end").where(...);
// 將創建好的Pattern應用到輸入事件流上
PatternStream<Event> patternStream = CEP.pattern(input,pattern);
// 檢出匹配事件序列,處理得到結果
DataStream<Alert> result = patternStream.select(...);
3.1 個體模式(Individual Patterns)
組成複雜規則的每一個單獨的模式定義,就是"個體模式"
start.times(3).where(new SimpleCondition<Event>() {...})
個體模式可以包括"單例(singleton)模式"和"循環(looping)模式"
單例模式只接收一個事件,而循環模式可以接收多個
量詞(Quantifier)
可以在一個個體模式後追加量詞,也就是指定循環次數
//匹配出現4次
start.times(4)
//匹配出現2/3/4次
start.time(2,4).greedy
//匹配出現0或者4次
start.times(4).optional
//匹配出現1次或者多次
start.oneOrMore
//匹配出現2,3,4次
start.times(2,4)
//匹配出現0次,2次或者多次,並且儘可能多的重複匹配
start.timesOrMore(2),optional.greedy
條件(Condition)
- 每個模式都需要指定觸發條件,作爲模式是否接受事件進入的判斷依據
- CEP中的個體模式主要通過調用.where(),.or()和.until()來指定條件
- 按不同的調用方式,可以分成以下幾類
1)簡單條件(Simple Condition)
通過.where()方法對事件中的字段進行判斷篩選,決定是否接受該事件
start.where(new SimpleCondition<Event>){
@Override
public boolean filter(Event value) throws Exception{
return value.getName.startsWith("foo");
}
}
2)組合條件(Combining Condition)
將簡單條件進行合併;.or()方法表示或邏輯相連,where的直接組合就是AND
pattern.where(event => ... /* some condition */).or(event => ... /* or condition */)
3)終止條件(Stop Condition)
如果使用了oneOrMore或者oneOrMore.optional,建議使用.until()作爲終止條件,以便清理狀態
4)迭代條件(Iterative Condition)
能夠對模式之前所有接收的事件進行處理
可以調用ctx.getEventsForPattern("name")
.where(new IterativeCondition<Event>(){...})
3.2 組合模式(Combining Patterns)
組合模式(Combining Patterns)也叫模式序列。
1)很多個體模式組合起來,就形成了整個的模式序列
2)模式序列必須以一個"初始模式"開始
Pattern<Event, Event> start = Pattern.<Event>begin("start")
嚴格近鄰(Strict Contiguity)
1)所有事件按照嚴格的順序出現,中間沒有任何不匹配的事件,由.next()指定
2)例如對於模式"a next b",事件序列[a,c,b1,b2]沒有匹配寬鬆近鄰(Relaxed Contiguity)
1)允許中間出現不匹配的事件,由.followedBy()指定
2)例如對於模式"a followedBy b",事件序列[a,c,b1,b2]匹配爲[a,b1]非確定性寬鬆近鄰(Non-Deterministic Relaxed Contiguity)
1)進一步放寬條件,之前已經匹配過的事件也可以再次使用,由.followByAny()指定
2)例如對於模式"a followedAny b",事件序列[a,c,b1,b2]匹配爲{a,b1},{a,b2}除了以上模式序列外,還可以定義"不希望出現某種近鄰關係":
1).notNext() 不嚴格近鄰
2).notFollowedBy()不在兩個事件之間發生
(eg,a not FollowedBy c,a Followed By b,a希望之後出現b,且不希望ab之間出現c)需要注意:
1)所有模式序列必須以.begin()開始
2)模式序列不能以.notFollowedBy()結束
3)"not "類型的模式不能被optional 所修飾
4)此外,還可以爲模式指定事件約束,用來要求在多長時間內匹配有效:
next.within(Time.seconds(10))
3.3 模式組
3.3.1 模式的檢測
指定要查找的模式序列後,就可以將其應用於輸入流以檢測潛在匹配
調用CEP.pattern(),給定輸入流和模式,就能得到一個PatternStream
DataStream<Event> input = ...
Pattern<Event, Event> pattern = Pattern.<Event>begin("start").where(...)...
PatternStream<Event> patternStream = CEP.pattern(input, pattern);
3.3.2 匹配事件提取
- 創建PatternStrean之後,就可以應用select或者flatselect方法,從檢測到的事件序列中提取事件了
- select()方法需要輸入一個select function作爲參數,每個成功匹配的事件序列都會調用它
- select() 以一個Map<String,List<IN]>> 來接收匹配到的事件序列,其中Key就是每個模式的名稱,而value就是所有接收到的事件的List類型
public OUT select(Map<String, List<IN>> pattern) throws Exception {
IN startEvent = pattern.get("start").get(0);
IN endEvent = pattern.get("end").get(0);
return new OUT(startEvent, endEvent);
}
3.3.3 超時事件提取
當一個模式通過within關鍵字定義了檢測窗口時間時,部分事件序列可能因爲超過窗口長度而被丟棄;爲了能夠處理這些超時的部分匹配,select和flatSelect API調用允許指定超時處理程序
超時處理程序會接收到目前爲止由模式匹配到的所有事件,由一個OutputTag定義接收到的超時事件序列
PatternStream<Event> patternStream = CEP.pattern(input, pattern);
OutputTag<String> outputTag = new OutputTag<String>("side-output"){};
SingleOutputStreamOperator<ComplexEvent> flatResult =
patternStream.flatSelect(
outputTag,
new PatternFlatTimeoutFunction<Event, TimeoutEvent>() {...},
new PatternFlatSelectFunction<Event, ComplexEvent>() {...}
);
DataStream<TimeoutEvent> timeoutFlatResult =
flatResult.getSideOutput(outputTag);