CEP——Complex Event Processing,复制事件处理,Flink CEP是在Flink中复杂事件处理库。处理事件的规则叫做Pattern,Flink CEP 提供了API,用于对输入流数据进行复制事件规则定义,用来提取符合规则的事件序列。Pattern API 大致分为三种:个体模式,组合模式,模式组。
Flink CEP的应用场景:
组成复杂规则的每一个单独的模式定义。个体模式包括单例模式和循环模式,单例模式只接收一个事件,循环模式可以接收多个事件。
可以在一个个体模式后追加两次,也就是指定循环次数。
start.time(4) // 匹配出现4次
start.time(4).optional // 匹配出现0次或4次
start.time(2,4) // 匹配出现2,3,4次
start.time(2,4).greedy //匹配出现2,3,4次,尽可能多地重复匹配
start.oneOrMore // 匹配出现1或多次
start.timeOrMore(2).optional.greedy // 匹配出现0,2或多次,尽可能多地重复匹配
每个模式都需要指定触发条件,作为模式是否接受事件进入的判断依据。
start.where(event=>event.getName.startsWith("foo"))
start.where(event=>.../*some condition */).or(event=> /*or condition*/)
很多个体模式组合起来,就形成了整个组合模式,又叫模式序列。
.next() // 严格近邻 (a,b,c,d) -> a next b
.followedBy() // 宽松近邻 (a,b,c,d) -> a followedBy c
.followedByAny() // 非确定新宽松近邻(之前已经匹配过的事件可以再次使用) (a,b,c,d) -> a followedByAny c, a followedByAny d
.notNext()
.notFollowedBy()
将一个组合模式作为条件嵌套在个体模式里,成为一组模式。
指定要查找的迷失序列后,就可以将其应用于输入流以检测潜在的匹配。调用CEP.pattern(),给定输入流和迷失,就能得到一个Pattern Stream。
创建PatternStream后,可以用于select或者flatSelect方法,从检测到的事件序列中提取事件了。
当一个模式通过within关键字定义了检测窗口时间时,部分事件序列可能因为超过窗口长度而被丢弃,select和faltSelect API调用允许指定超时处理程序。
Flink CEP 开发流程:
<dependency>
<groupId>org.apache.flinkgroupId>
<artifactId>flink-cep_2.12artifactId>
<version>1.11.1version>
dependency>
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
env.setParallelism(1);
// 数据源
DataStreamSource<RawLogGroupList> ds = env.addSource(../* TrackLog 类型数据源 */..);
KeyedStream<TrackLog, String> keyedStream = ds
.filter(value -> value.getPorjectId().equals("2") && !value.getLib().equals("JS"))
.assignTimestampsAndWatermarks(new WatermarkStrategy<TrackLog>() {
@Override
public WatermarkGenerator<TrackLog> createWatermarkGenerator(WatermarkGeneratorSupplier.Context context) {
return new WatermarkGenerator<TrackLog>() {
long maxTimeStamp = Long.MIN_VALUE;
@Override
public void onEvent(TrackLog event, long eventTimestamp, WatermarkOutput output) {
maxTimeStamp = Math.max(maxTimeStamp, event.getServerTime());
}
long maxOutOfOrderness = 5000L;
@Override
public void onPeriodicEmit(WatermarkOutput output) {
output.emitWatermark(new Watermark(maxTimeStamp - maxOutOfOrderness));
}
};
}
}.withTimestampAssigner((value, recordTimestamp) -> value.getServerTime())) // 在数据源上做出watermark
.keyBy(value -> value.getId()); // 在watermark上分组
// 创建模式pattern
Pattern<TrackLog, TrackLog> pattern = Pattern.<TrackLog>begin("start").where(new IterativeCondition<TrackLog>() {
@Override
public boolean filter(TrackLog value, Context<TrackLog> ctx) throws Exception {
return value.getEvent().equals("AppLeaveScreen");
}
}).next("next").where(new IterativeCondition<TrackLog>() {
@Override
public boolean filter(TrackLog value, Context<TrackLog> ctx) throws Exception {
return value.getEvent().equals("AppViewScreen");
}
}).within(Time.seconds(10));
// 在数据流上进行模式匹配
PatternStream<TrackLog> patternStream = CEP.pattern(keyedStream, pattern);
// 提取匹配成功的数据
patternStream.process(new PatternProcessFunction<TrackLog, String>() {
@Override
public void processMatch(Map<String, List<TrackLog>> map, Context context, Collector<String> out) throws Exception {
out.collect("lib: " +map.get("next").get(0).getLib()+" id: " +map.get("next").get(0).getId());
}
})
.print();
env.execute("add candidate demo");
}