一、Flink 专栏
Flink 专栏系统介绍某一知识点,并辅以具体的示例进行说明。
1、Flink 部署系列
本部分介绍Flink的部署、配置相关基础内容。
2、Flink基础系列
本部分介绍Flink 的基础部分,比如术语、架构、编程模型、编程指南、基本的datastream api用法、四大基石等内容。
3、Flik Table API和SQL基础系列
本部分介绍Flink Table Api和SQL的基本用法,比如Table API和SQL创建库、表用法、查询、窗口函数、catalog等等内容。
4、Flik Table API和SQL提高与应用系列
本部分是table api 和sql的应用部分,和实际的生产应用联系更为密切,以及有一定开发难度的内容。
5、Flink 监控系列
本部分和实际的运维、监控工作相关。
二、Flink 示例专栏
Flink 示例专栏是 Flink 专栏的辅助说明,一般不会介绍知识点的信息,更多的是提供一个一个可以具体使用的示例。本专栏不再分目录,通过链接即可看出介绍的内容。
两专栏的所有文章入口点击:Flink 系列文章汇总索引
本文介绍了Flink 的类库CEP的单个模式中条件部分、组合模式、模式组和匹配后的跳过策略。
如果需要了解更多内容,可以在本人Flink 专栏中了解更新系统的内容。
本文除了maven依赖外,没有其他依赖。
本专题分为以下几篇介绍:
59、Flink CEP - Flink的复杂事件处理介绍及示例(1)-入门
59、Flink CEP - Flink的复杂事件处理介绍及示例(2)- 模式API
59、Flink CEP - Flink的复杂事件处理介绍及示例(3)- 模式选取及超时处理
59、Flink CEP - Flink的复杂事件处理介绍及示例(4)- 延迟数据处理和三个实际应用示例
59、Flink CEP - Flink的复杂事件处理介绍及示例(完整版)
对每个模式你可以指定一个条件来决定一个进来的事件是否被接受进入这个模式,例如,它的value字段应该大于5,或者大于前面接受的事件的平均值。 指定判断事件属性的条件可以通过pattern.where()、pattern.or()或者pattern.until()方法。 这些可以是IterativeCondition或者SimpleCondition。
这是最普遍的条件类型。使用它可以指定一个基于前面已经被接受的事件的属性或者它们的一个子集的统计数据来决定是否接受时间序列的条件。
在 Flink CEP 中,提供了 IterativeCondition 抽象类。这其实是更加通用的条件表达,查看源码可以发现, .where()方法本身要求的参数类型就是 IterativeCondition;而之前 的SimpleCondition 是它的一个子类。
在 IterativeCondition 中同样需要实现一个 filter()方法,不过与 SimpleCondition 中不同的是,这个方法有两个参数:除了当前事件之外,还有一个上下文 Context。调用这个上下文的.getEventsForPattern()方法,传入一个模式名称,就可以拿到这个模式中已匹配到的所有数据了。
下面是一个迭代条件的代码,它接受"first"模式下一个事件的userid开头是"1001", 并且前面已经匹配到的事件登录状态改为S。 迭代条件非常强大,尤其是跟循环模式结合使用时。
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.cep.CEP;
import org.apache.flink.cep.PatternSelectFunction;
import org.apache.flink.cep.PatternStream;
import org.apache.flink.cep.pattern.Pattern;
import org.apache.flink.cep.pattern.conditions.IterativeCondition;
import org.apache.flink.cep.pattern.conditions.SimpleCondition;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/*
* @Author: alanchan
* @LastEditors: alanchan
* @Description:
*/
public class TestCEPDemo {
@Data
@NoArgsConstructor
@AllArgsConstructor
static class LoginEvent {
private Integer userId;
private String ip;
private String status;
private Long timestamp;
@Override
public boolean equals(Object obj) {
if (obj instanceof LoginEvent) {
LoginEvent loginEvent = (LoginEvent) obj;
return this.userId == loginEvent.getUserId() && this.ip.equals(loginEvent.ip)
&& this.status.equals(loginEvent.getStatus()) && this.timestamp == loginEvent.getTimestamp();
} else {
return false;
}
}
@Override
public int hashCode() {
return super.hashCode() + Long.hashCode(timestamp);
}
}
final static List<LoginEvent> loginEventList = Arrays.asList(
new LoginEvent(1001, "192.168.10.1", "F", 2L),
new LoginEvent(1001, "192.168.10.2", "F", 3L),
new LoginEvent(1002, "192.168.10.8", "F", 4L),
new LoginEvent(1001, "192.168.10.6", "F", 5L),
new LoginEvent(1002, "192.168.10.8", "F", 7L),
new LoginEvent(1002, "192.168.10.8", "F", 8L),
new LoginEvent(1002, "192.168.10.8", "S", 6L),
new LoginEvent(1003, "192.168.10.8", "F", 6L),
new LoginEvent(1004, "192.168.10.3", "S", 4L));
static void test2() throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 按用户id分组
DataStream<LoginEvent> loginEventDS = env.fromCollection(loginEventList).assignTimestampsAndWatermarks(
WatermarkStrategy.<LoginEvent>forBoundedOutOfOrderness(Duration.ofSeconds(10))
.withTimestampAssigner((loginEvent, rs) -> loginEvent.getTimestamp()))
.keyBy(loginEvent -> loginEvent.getUserId());
// 定义模式
Pattern<LoginEvent, ?> loginEventPattern = Pattern.<LoginEvent>begin("first")
.where(new SimpleCondition<LoginEvent>() {
@Override
public boolean filter(LoginEvent value) throws Exception {
return value.getStatus().equals("F");
}
})
.next("second")
.where(new IterativeCondition<TestCEPDemo.LoginEvent>() {
@Override
public boolean filter(LoginEvent value, Context<LoginEvent> ctx) throws Exception {
Iterable<LoginEvent> loginEventIterable = ctx.getEventsForPattern("first");
for (LoginEvent loginEvent : loginEventIterable) {
if (loginEvent.getUserId() == 1001) {
loginEvent.setStatus("S");
}
}
return value.getStatus().equals("F");
}
});
// 将Pattern应用到流上,检测匹配的复杂事件,得到一个PatternStream
PatternStream<LoginEvent> patternStream = CEP.pattern(loginEventDS, loginEventPattern);
// 将匹配到的流选择出来输出
patternStream
.select(new PatternSelectFunction<LoginEvent, String>() {
@Override
public String select(Map<String, List<LoginEvent>> map) throws Exception {
return map.get("first").toString()+" \n"+map.get("second").toString();
}
})
.print("输出信息:\n");
// 控制台输出:
env.execute();
}
public static void main(String[] args) throws Exception {
test2();
}
}
调用ctx.getEventsForPattern(…)可以获得所有前面已经接受作为可能匹配的事件。调用这个操作的代价可能很小也可能很大,所以在实现你的条件时,尽量少使用它。
这种类型的条件扩展了前面提到的IterativeCondition类,它决定是否接受一个事件只取决于事件自身的属性。
start.where(SimpleCondition.of(value -> value.getName().startsWith("foo")));
你可以通过pattern.subtype(subClass)方法限制接受的事件类型是初始事件的子类型。
start.subtype(SubEvent.class)
.where(SimpleCondition.of(value -> ... /*一些判断条件*/));
你可以把subtype条件和其他的条件结合起来使用。这适用于任何条件,你可以通过依次调用where()来组合条件。 最终的结果是每个单一条件的结果的逻辑AND。
如果想使用OR来组合条件,你可以像下面这样使用or()方法。
pattern
.where(SimpleCondition.of(value -> ... /*一些判断条件*/))
.or(SimpleCondition.of(value -> ... /*一些判断条件*/));
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.cep.CEP;
import org.apache.flink.cep.PatternSelectFunction;
import org.apache.flink.cep.PatternStream;
import org.apache.flink.cep.pattern.Pattern;
import org.apache.flink.cep.pattern.conditions.IterativeCondition;
import org.apache.flink.cep.pattern.conditions.SimpleCondition;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/*
* @Author: alanchan
* @LastEditors: alanchan
* @Description:
*/
public class TestCEPDemo {
@Data
@NoArgsConstructor
@AllArgsConstructor
static class LoginEvent {
private Integer userId;
private String ip;
private String status;
private Long timestamp;
@Override
public boolean equals(Object obj) {
if (obj instanceof LoginEvent) {
LoginEvent loginEvent = (LoginEvent) obj;
return this.userId == loginEvent.getUserId() && this.ip.equals(loginEvent.ip)
&& this.status.equals(loginEvent.getStatus()) && this.timestamp == loginEvent.getTimestamp();
} else {
return false;
}
}
@Override
public int hashCode() {
return super.hashCode() + Long.hashCode(timestamp);
}
}
final static List<LoginEvent> loginEventList = Arrays.asList(
new LoginEvent(1001, "192.168.10.1", "F", 2L),
new LoginEvent(1001, "192.168.10.2", "F", 3L),
new LoginEvent(1002, "192.168.10.8", "F", 4L),
new LoginEvent(1001, "192.168.10.6", "F", 5L),
new LoginEvent(1002, "192.168.10.8", "F", 7L),
new LoginEvent(1002, "192.168.10.8", "F", 8L),
new LoginEvent(1002, "192.168.10.8", "S", 6L),
new LoginEvent(1003, "192.168.10.8", "F", 6L),
new LoginEvent(1004, "192.168.10.3", "S", 4L));
static void test3() throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 按用户id分组
DataStream<LoginEvent> loginEventDS = env.fromCollection(loginEventList).assignTimestampsAndWatermarks(
WatermarkStrategy.<LoginEvent>forBoundedOutOfOrderness(Duration.ofSeconds(10))
.withTimestampAssigner((loginEvent, rs) -> loginEvent.getTimestamp()))
.keyBy(loginEvent -> loginEvent.getUserId());
// 定义模式
Pattern<LoginEvent, ?> loginEventPattern = Pattern.<LoginEvent>begin("first")
.where(new SimpleCondition<LoginEvent>() {
@Override
public boolean filter(LoginEvent value) throws Exception {
return value.getStatus().equals("F");
}
})
.or(new IterativeCondition<TestCEPDemo.LoginEvent>() {
@Override
public boolean filter(LoginEvent value, Context<LoginEvent> ctx) throws Exception {
return value.getIp().equals("192.168.10.3");
}
});
// 将Pattern应用到流上,检测匹配的复杂事件,得到一个PatternStream
PatternStream<LoginEvent> patternStream = CEP.pattern(loginEventDS, loginEventPattern);
// 将匹配到的流选择出来输出
patternStream
.select(new PatternSelectFunction<LoginEvent, String>() {
@Override
public String select(Map<String, List<LoginEvent>> map) throws Exception {
return map.get("first").toString();
}
})
.print("输出信息:\n");
// 控制台输出:
env.execute();
}
public static void main(String[] args) throws Exception {
test3();
}
}
如果使用循环模式(oneOrMore()和oneOrMore().optional()),你可以指定一个停止条件,例如,接受事件的值大于5直到值的和小于50。
为了更好的理解它,看下面的例子。给定
你可以看到{a1 a2 a3}和{a2 a3}由于停止条件没有被输出。
为当前模式定义一个条件。为了匹配这个模式,一个事件必须满足某些条件。 多个连续的 where() 语句取与组成判断条件。
pattern.where(new IterativeCondition<Event>() {
@Override
public boolean filter(Event value, Context ctx) throws Exception {
return ... // 一些判断条件
}
});
增加一个新的判断,和当前的判断取或。一个事件只要满足至少一个判断条件就匹配到模式。
pattern.where(new IterativeCondition<Event>() {
@Override
public boolean filter(Event value, Context ctx) throws Exception {
return ...; // 一些判断条件
}
}).or(new IterativeCondition<Event>() {
@Override
public boolean filter(Event value, Context ctx) throws Exception {
return ...; // 替代条件
}
});
为循环模式指定一个停止条件。意思是满足了给定的条件的事件出现后,就不会再有事件被接受进入模式了。 只适用于和oneOrMore()同时使用。
在基于事件的条件中,它可用于清理对应模式的状态。
pattern.oneOrMore().until(new IterativeCondition<Event>() {
@Override
public boolean filter(Event value, Context ctx) throws Exception {
return ...; // 替代条件
}
});
static void test4() throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 按用户id分组
DataStream<LoginEvent> loginEventDS = env.fromCollection(loginEventList).assignTimestampsAndWatermarks(
WatermarkStrategy.<LoginEvent>forBoundedOutOfOrderness(Duration.ofSeconds(10))
.withTimestampAssigner((loginEvent, rs) -> loginEvent.getTimestamp()))
.keyBy(loginEvent -> loginEvent.getUserId());
// 定义模式
Pattern<LoginEvent, ?> loginEventPattern = Pattern.<LoginEvent>begin("first")
// .where(new SimpleCondition<LoginEvent>() {
// @Override
// public boolean filter(LoginEvent value) throws Exception {
// return value.getStatus().equals("F");
// }
// })
.oneOrMore()
.until(new IterativeCondition<TestCEPDemo.LoginEvent>() {
@Override
public boolean filter(LoginEvent value, Context<LoginEvent> ctx) throws Exception {
return value.getIp().equals("192.168.10.3");
}
});
// 将Pattern应用到流上,检测匹配的复杂事件,得到一个PatternStream
PatternStream<LoginEvent> patternStream = CEP.pattern(loginEventDS, loginEventPattern);
// 将匹配到的流选择出来输出
patternStream
.select(new PatternSelectFunction<LoginEvent, String>() {
@Override
public String select(Map<String, List<LoginEvent>> map) throws Exception {
return map.get("first").toString();
}
})
.print("输出信息:\n");
// 控制台输出:
env.execute();
}
为当前模式定义一个子类型条件。一个事件只有是这个子类型的时候才能匹配到模式。
pattern.subtype(SubEvent.class);
指定模式期望匹配到的事件至少出现一次。 默认(在子事件间)使用松散的内部连续性。 推荐使用 until()或者 within()来清理状态。
pattern.oneOrMore();
指定模式期望匹配到的事件至少出现 #times 次。 默认(在子事件间)使用松散的内部连续性。
pattern.timesOrMore(2);
指定模式期望匹配到的事件正好出现的次数。 默认(在子事件间)使用松散的内部连续性。
pattern.times(2);
指定模式期望匹配到的事件出现次数在#fromTimes和#toTimes之间。 默认(在子事件间)使用松散的内部连续性。
pattern.times(2, 4);
指定这个模式是可选的,也就是说,它可能根本不出现。这对所有之前提到的量词都适用。
pattern.oneOrMore().optional();
指定这个模式是贪心的,也就是说,它会重复尽可能多的次数。这只对量词适用,现在还不支持模式组。
pattern.oneOrMore().greedy();
模式序列由一个初始模式作为开头,如下所示:
Pattern<Event, ?> start = Pattern.<Event>begin("start");
接下来,你可以增加更多的模式到模式序列中并指定它们之间所需的连续条件。
FlinkCEP支持事件之间如下形式的连续策略:
可以使用下面的方法来指定模式之间的连续策略:
或者
如果模式序列没有定义时间约束,则不能以 notFollowedBy() 结尾。
一个 NOT 模式前面不能是可选的模式。
// 严格连续
Pattern<Event, ?> strict = start.next("middle").where(...);
// 松散连续
Pattern<Event, ?> relaxed = start.followedBy("middle").where(...);
// 不确定的松散连续
Pattern<Event, ?> nonDetermin = start.followedByAny("middle").where(...);
// 严格连续的NOT模式
Pattern<Event, ?> strictNot = start.notNext("not").where(...);
// 松散连续的NOT模式
Pattern<Event, ?> relaxedNot = start.notFollowedBy("not").where(...);
松散连续意味着跟着的事件中,只有第一个可匹配的事件会被匹配上,而不确定的松散连接情况下,有着同样起始的多个匹配会被输出。 举例来说,模式"a b",给定事件序列"a",“c”,“b1”,“b2”,会产生如下的结果:
也可以为模式定义一个有效时间约束。
例如,你可以通过pattern.within()方法指定一个模式应该在10秒内发生。 这种时间模式支持处理时间和事件时间.
一个模式序列只能有一个时间限制。如果限制了多个时间在不同的单个模式上,会使用最小的那个时间限制。
next.within(Time.seconds(10));
注意定义过时间约束的模式允许以 notFollowedBy() 结尾。
例如,可以定义如下的模式:
Pattern.<Event>begin("start")
.next("middle")
.where(SimpleCondition.of(value -> value.getName().equals("a")))
.notFollowedBy("end")
.where(SimpleCondition.of(value -> value.getName().equals("b")))
.within(Time.seconds(10));
连续性会被运用在被接受进入模式的事件之间。 用这个例子来说明上面所说的连续性,
一个模式序列"a b+ c"(“a"后面跟着一个或者多个(不确定连续的)“b”,然后跟着一个"c”)
输入为"a",“b1”,“d1”,“b2”,“d2”,“b3”,“c”,
输出结果如下:
对于循环模式(例如oneOrMore()和times())),默认是松散连续。
如果想使用严格连续,你需要使用consecutive()方法明确指定
如果想使用不确定松散连续,你可以使用allowCombinations()方法。
Pattern.<Event>begin("start")
.where(SimpleCondition.of(value -> value.getName().equals("c")))
.followedBy("middle")
.where(SimpleCondition.of(value -> value.getName().equals("a")))
.oneOrMore()
.consecutive()
.followedBy("end1")
.where(SimpleCondition.of(value -> value.getName().equals("b")));
// 输入:C D A1 A2 A3 D A4 B
// 会产生下面的输出:
// 如果施加严格连续性: {C A1 B},{C A1 A2 B},{C A1 A2 A3 B}
// 不施加严格连续性: {C A1 B},{C A1 A2 B},{C A1 A2 A3 B},{C A1 A2 A3 A4 B}
Pattern.<Event>begin("start")
.where(SimpleCondition.of(value -> value.getName().equals("c")))
.followedBy("middle")
.where(SimpleCondition.of(value -> value.getName().equals("a")))
.oneOrMore()
.allowCombinations()
.followedBy("end1")
.where(SimpleCondition.of(value -> value.getName().equals("b")));
// 输入:C D A1 A2 A3 D A4 B
// 会产生如下的输出:
// 如果使用不确定松散连续: {C A1 B},{C A1 A2 B},{C A1 A3 B},{C A1 A4 B},{C A1 A2 A3 B},{C A1 A2 A4 B},{C A1 A3 A4 B},{C A1 A2 A3 A4 B}
// 如果不使用:{C A1 B},{C A1 A2 B},{C A1 A2 A3 B},{C A1 A2 A3 A4 B}
也可以定义一个模式序列作为begin,followedBy,followedByAny和next的条件。
这个模式序列在逻辑上会被当作匹配的条件, 并且返回一个GroupPattern,可以在GroupPattern上使用oneOrMore(),times(#ofTimes), times(#fromTimes, #toTimes),optional(),consecutive(),allowCombinations()。
此处官方的示例好像是不能编译过的,需要将其“?”变为具体的输出类型方可。
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.cep.CEP;
import org.apache.flink.cep.PatternSelectFunction;
import org.apache.flink.cep.PatternStream;
import org.apache.flink.cep.pattern.GroupPattern;
import org.apache.flink.cep.pattern.Pattern;
import org.apache.flink.cep.pattern.conditions.IterativeCondition;
import org.apache.flink.cep.pattern.conditions.SimpleCondition;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/*
* @Author: alanchan
* @LastEditors: alanchan
* @Description:
*/
public class TestCEPDemo {
@Data
@NoArgsConstructor
@AllArgsConstructor
static class LoginEvent {
private Integer userId;
private String ip;
private String status;
private Long timestamp;
@Override
public boolean equals(Object obj) {
if (obj instanceof LoginEvent) {
LoginEvent loginEvent = (LoginEvent) obj;
return this.userId == loginEvent.getUserId() && this.ip.equals(loginEvent.ip)
&& this.status.equals(loginEvent.getStatus()) && this.timestamp == loginEvent.getTimestamp();
} else {
return false;
}
}
@Override
public int hashCode() {
return super.hashCode() + Long.hashCode(timestamp);
}
}
final static List<LoginEvent> loginEventList = Arrays.asList(
new LoginEvent(1001, "192.168.10.1", "F", 2L),
new LoginEvent(1001, "192.168.10.2", "F", 3L),
new LoginEvent(1002, "192.168.10.8", "F", 4L),
new LoginEvent(1001, "192.168.10.6", "F", 5L),
new LoginEvent(1002, "192.168.10.8", "F", 7L),
new LoginEvent(1002, "192.168.10.8", "F", 8L),
new LoginEvent(1002, "192.168.10.8", "S", 6L),
new LoginEvent(1003, "192.168.10.8", "F", 6L),
new LoginEvent(1004, "192.168.10.3", "S", 4L));
static void test5() throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 按用户id分组
DataStream<LoginEvent> loginEventDS = env.fromCollection(loginEventList).assignTimestampsAndWatermarks(
WatermarkStrategy.<LoginEvent>forBoundedOutOfOrderness(Duration.ofSeconds(10))
.withTimestampAssigner((loginEvent, rs) -> loginEvent.getTimestamp()))
.keyBy(loginEvent -> loginEvent.getUserId());
// 定义模式
Pattern<LoginEvent, LoginEvent> loginEventPattern = Pattern.begin(
Pattern.<LoginEvent>begin("first")
.where(new SimpleCondition<LoginEvent>() {
@Override
public boolean filter(LoginEvent value) throws Exception {
return value.getStatus().equals("F");
}
})
);
// 严格连续
Pattern<LoginEvent, ?> strictLoginEventPattern = loginEventPattern.next(
Pattern.<LoginEvent>begin("test").where(new SimpleCondition<LoginEvent>() {
@Override
public boolean filter(LoginEvent value) throws Exception {
return false;
}
})).times(3);
// 松散连续
Pattern<LoginEvent, ?> relaxedLoginEventPattern = Pattern.begin(
Pattern.<LoginEvent>begin("r_first")
.where(new SimpleCondition<LoginEvent>() {
@Override
public boolean filter(LoginEvent value) throws Exception {
return value.getStatus().equals("F");
}
})
).oneOrMore();
// 不确定松散连续
Pattern<LoginEvent, ?> nonDeterminLoginEventPattern = Pattern.begin(
Pattern.<LoginEvent>begin("n_first")
.where(new SimpleCondition<LoginEvent>() {
@Override
public boolean filter(LoginEvent value) throws Exception {
return value.getStatus().equals("F");
}
})
).optional();
// 将Pattern应用到流上,检测匹配的复杂事件,得到一个PatternStream
PatternStream<LoginEvent> patternStream = CEP.pattern(loginEventDS, nonDeterminLoginEventPattern);
// 将匹配到的流选择出来输出
patternStream
.select(new PatternSelectFunction<LoginEvent, String>() {
@Override
public String select(Map<String, List<LoginEvent>> map) throws Exception {
return map.get("n_first").toString();
}
})
.print("输出信息:\n");
// 控制台输出:
env.execute();
}
public static void main(String[] args) throws Exception {
test5();
}
}
具体方法说明详见下图
对于一个给定的模式,同一个事件可能会分配到多个成功的匹配上。
为了控制一个事件会分配到多少个匹配上,你需要指定跳过策略AfterMatchSkipStrategy。
有五种跳过策略,如下:
当使用SKIP_TO_FIRST和SKIP_TO_LAST策略时,需要指定一个合法的PatternName。
AfterMatchSkipStrategy skipStrategy = ...;
Pattern.begin("patternName", skipStrategy);
使用SKIP_TO_FIRST/LAST时,有两个选项可以用来处理没有事件可以映射到对应模式名上的情况。 默认情况下会使用NO_SKIP策略,另外一个选项是抛出异常。 可以使用如下的选项:
AfterMatchSkipStrategy.skipToFirst(patternName).throwExceptionOnMiss();
以上,本文介绍了Flink 的类库CEP的单个模式中条件部分、组合模式、模式组和匹配后的跳过策略。
本专题分为以下几篇介绍:
59、Flink CEP - Flink的复杂事件处理介绍及示例(1)-入门
59、Flink CEP - Flink的复杂事件处理介绍及示例(2)- 模式API
59、Flink CEP - Flink的复杂事件处理介绍及示例(3)- 模式选取及超时处理
59、Flink CEP - Flink的复杂事件处理介绍及示例(4)- 延迟数据处理和三个实际应用示例
59、Flink CEP - Flink的复杂事件处理介绍及示例(完整版)