什么是Flink CEP
FlinkCEP(Complex event processing for Flink) 是在Flink实现的复杂事件处理库. 它可以让你在无界流中检测出特定的数据,有机会掌握数据中重要的那部分。
是一种基于动态环境中事件流的分析技术,事件在这里通常是有意义的状态变化,通过分析事件间的关系,利用过滤、关联、聚合等技术,根据事件间的时序关系和聚合关系制定检测规则,持续地从事件流中查询出符合要求的事件序列,最终分析得到更复杂的复合事件。
1.目标:从有序的简单事件流中发现一些高阶特征
2.输入:一个或多个由简单事件构成的事件流
3.处理:识别简单事件之间的内在联系,多个符合一定规则的简单事件构成复杂事件
4.输出:满足规则的复杂事件
Flink CEP应用场景
风险控制
对用户异常行为模式进行实时检测,当一个用户发生了不该发生的行为,判定这个用户是不是有违规操作的嫌疑。
策略营销
用预先定义好的规则对用户的行为轨迹进行实时跟踪,对行为轨迹匹配预定义规则的用户实时发送相应策略的推广。
运维监控
灵活配置多指标、多依赖来实现更复杂的监控模式。
CEP开发基本步骤
导入CEP相关依赖
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-cep_2.11</artifactId>
<version>1.12.0</version>
</dependency>
基本使用
//1.定义模式(获取严格连续出现两次sensor_1的数据)
Pattern<WaterSensor, WaterSensor> pattern = Pattern
.<WaterSensor>begin("start")
.where(new SimpleCondition<WaterSensor>() {
@Override
public boolean filter(WaterSensor waterSensor) throws Exception {
return waterSensor.getId().equalsIgnoreCase("sensor_1");
}
}).times(2).consecutive();
//2.把模式运用在流上
PatternStream<WaterSensor> patternDS = CEP.pattern(waterSensorDS, pattern);
//3.获取匹配得到的结果
SingleOutputStreamOperator<String> resultDS = patternDS.select(new PatternSelectFunction<WaterSensor, String>() {
@Override
public String select(Map<String, List<WaterSensor>> map) throws Exception {
return map.get("start").toString();
}
});
原始数据
计算结果
模式API
模式API可以让你定义想从输入流中抽取的复杂模式序列
模式
比如找拥有相同属性事件序列的模式(前面案例中的拥有相同的id), 我们一般把简单模式称之为模式
注意:
1.每个模式必须有一个独一无二的名字,你可以在后面使用它来识别匹配到的事件。(比如前面的start模式)
2.模式的名字不能包含字符":"
模式序列
每个复杂的模式序列包括多个简单的模式,也叫模式序列. 你可以把模式序列看作是这样的模式构成的图, 这些模式基于用户指定的条件从一个转换到另外一个
匹配
输入事件的一个序列,这些事件通过一系列有效的模式转换,能够访问到复杂模式图中的所有模式
单个模式
where(condition):为当前模式定义一个条件。为了匹配这个模式,一个事件必须满足某些条件。 多个连续的where()语句组成判断条件。
Pattern<WaterSensor, WaterSensor> pattern = Pattern
.<WaterSensor>begin("start")
.where(new SimpleCondition<WaterSensor>() {
@Override
public boolean filter(WaterSensor waterSensor) throws Exception {
return waterSensor.getId().equalsIgnoreCase("sensor_1");
}
});
or(condition):增加一个新的判断,和当前的判断取或。一个事件只要满足至少一个判断条件就匹配到模式。
Pattern<WaterSensor, WaterSensor> pattern = Pattern
.<WaterSensor>begin("start")
.where(new SimpleCondition<WaterSensor>() {
@Override
public boolean filter(WaterSensor waterSensor) throws Exception {
return waterSensor.getId().equalsIgnoreCase("sensor_2");
}
}).or(new SimpleCondition<WaterSensor>() {
@Override
public boolean filter(WaterSensor waterSensor) throws Exception {
return waterSensor.getVc().equals(60);
}
});
until(condition):为循环模式指定一个停止条件。意思是满足了给定的条件的事件出现后,就不会再有事件被接受进入模式了。只适用于和 oneOrMore()同时使用。注意: 在基于事件的条件中,它可用于清理对应模式的状态。
Pattern<WaterSensor, WaterSensor> pattern = Pattern
.<WaterSensor>begin("start")
.where(new SimpleCondition<WaterSensor>() {
@Override
public boolean filter(WaterSensor waterSensor) throws Exception {
return waterSensor.getId().equalsIgnoreCase("sensor_2");
}
}).oneOrMore().until(new SimpleCondition<WaterSensor>() {
@Override
public boolean filter(WaterSensor waterSensor) throws Exception {
return waterSensor.getVc().equals(100);
}
});
VC等于100的就不会匹配上,until通常和oneOrMore(),timesOrMore(#times),times(#ofTimes)多个匹配条件同时使用
oneOrMore():指定模式期望匹配到的事件至少出现一次。注意: 推荐使用until()或者within()来清理状态。
}).oneOrMore()
timesOrMore(#times):指定模式期望匹配到的事件至少出现#times次。.
times(#ofTimes):指定模式期望匹配到的事件正好出现的次数。
times(#fromTimes, #toTimes):指定模式期望匹配到的事件出现次数在#fromTimes和#toTimes之间。
optional():指定这个模式是可选的,也就是说,它可能根本不出现。这对所有之前提到的量词都适用。
greedy():指定这个模式是贪心的,也就是说,它会重复尽可能多的次数。这只对量词适用,现在还不支持模式组。
subtype(subClass):为当前模式定义一个子类型条件。一个事件只有是这个子类型的时候才能匹配到模式。
组合模式
严格连续: 期望所有匹配的事件严格的一个接一个出现,中间没有任何不匹配的事件。
松散连续: 忽略匹配的事件之间的不匹配的事件。
不确定的松散连续: 更进一步的松散连续,允许忽略掉一些匹配事件的附加匹配。
next(),指定严格连续
followedBy(),指定松散连续
followedByAny(),指定不确定的松散连续
notNext(),如果不想后面直接连着一个特定事件
notFollowedBy(),如果不想一个特定事件发生在两个事件之间的任何地方
within(),松散连续中可以指定一个模式应该在10秒内发生
consecutive(),循环模式的连续指定严格连续
allowCombinations(),不确定松散连续
模式组
在前面的代码中次数只能用在某个模式上, 比如: .begin(…).where(…).next(…).where(…).times(2) 这里的次数只会用在next这个模式上, 而不会用在begin模式上.
如果需要用在多个模式上,可以使用模式组
Pattern<WaterSensor, WaterSensor> pattern = Pattern
.begin(
Pattern
.<WaterSensor>begin("start")
.where(new SimpleCondition<WaterSensor>() {
@Override
public boolean filter(WaterSensor value) throws Exception {
return "sensor_1".equalsIgnoreCase(value.getId());
}
})
.next("next")
.where(new SimpleCondition<WaterSensor>() {
@Override
public boolean filter(WaterSensor value) throws Exception {
return "sensor_2".equalsIgnoreCase(value.getId());
}
})
)
.times(2);