4、Flink CEP核心API:Pattern API详解——个体模式、组合模式、循环模式
Flink CEP 的 Pattern API 是定义事件匹配规则的核心编程接口。它采用链式调用的方式,允许开发者像搭建积木一样,从最简单的单一事件条件开始,逐步组合出复杂的时序逻辑。本章将深入剖析 Pattern API 的三大核心构件:个体模式(Individual Pattern)、组合模式(Combining Pattern) 和 循环模式(Looping Pattern),并结合实时交易风控场景进行讲解。
核心认知: 在 Flink CEP 中,一个完整的规则(Pattern)是由多个“个体模式”通过“组合模式”连接,并配合“循环模式”定义重复次数而构成的。理解这三者的关系是掌握 CEP 的关键。
4.1 个体模式(Individual Pattern)
个体模式是 Pattern API 中最基本的单元,它定义了对单个事件的匹配条件。每个个体模式都包含一个事件类型和一个过滤条件。在风控场景中,一个个体模式可以对应“一笔交易金额大于 10000 元”或“一个登录 IP 来自高风险地区”等单一规则。
4.1.1 核心方法
| 方法 | 描述 | 风控示例 |
|---|---|---|
.where(condition) |
定义事件必须满足的条件,可多次调用形成 AND 逻辑。 | .where(tx -> tx.getAmount() > 10000) |
.or(condition) |
添加一个可选条件,与已有条件形成 OR 逻辑。 | .where(tx -> tx.getAmount() > 10000).or(tx -> tx.getRiskLevel() > 8) |
.until(condition) |
指定模式匹配的终止条件(通常用于循环模式)。 | 连续失败登录直到登录成功为止。 |
.subtype(subClass) |
限制匹配的事件为指定类型的子类型。 | .subtype(CreditCardTx.class) |
4.1.2 个体模式分类
- 单例模式(Singleton Pattern):默认类型,只匹配单个事件。例如:“检测到一笔单笔转账超过 5 万元”。
- 循环模式(Looping Pattern):通过
.times()、.oneOrMore()等方法定义,匹配多个同类事件。将在 4.3 节详细展开。
避坑指南: 在个体模式中使用
.where() 时,条件函数必须是可序列化的(Serializable),且应避免使用外部可变状态,以保证算子的容错性和一致性。
4.2 组合模式(Combining Pattern)
组合模式用于将多个个体模式按照时间顺序连接起来,形成事件序列。它定义了事件之间的时序关系和连续性策略。在风控中,组合模式用于描述“先登录,后交易”或“先下单,后支付,再发货”等业务流程。
4.2.1 组合方式
| 方法 | 语义 | 风控场景示例 |
|---|---|---|
.next() |
严格连续:下一个事件必须紧接着上一个事件发生,中间不能有其他事件。 | 连续两次输错密码(中间不能有其他操作)。 |
.followedBy() |
宽松连续:后续事件可以在任意时间点出现,不要求紧邻。 | 登录后,在 10 分钟内发生交易。 |
.followedByAny() |
非确定性宽松连续:允许后续事件与前面的事件重叠匹配。 | 检测“A 事件后出现 B 事件”,允许 B 事件同时作为多个匹配的起点。 |
.notNext() |
否定模式(严格):下一个事件不能是指定事件。 | 支付后,下一个事件不能是退款。 |
.notFollowedBy() |
否定模式(宽松):在指定时间范围内,不能出现指定事件。 | 登录后 5 分钟内,不能有密码修改事件。 |
性能注意:
.followedByAny() 由于会产生多个重叠匹配,其状态开销和计算复杂度远高于 .next() 和 .followedBy()。在风控高并发场景下,应优先使用 .next() 或 .followedBy(),仅在必要时(如检测“首次”与“后续”关系)才使用 .followedByAny()。
4.2.2 组合模式示例(风控:盗刷检测)
Pattern<Transaction, ?> fraudPattern = Pattern
.<Transaction>begin("login")
.where(evt -> evt.getType().equals("LOGIN"))
.where(evt -> evt.getGeo().equals("abnormal"))
.followedBy("txn")
.where(evt -> evt.getAmount() > 5000)
.within(Time.minutes(5));
上述规则表示:在 5 分钟内,先发生一次异常地理位置的登录,随后发生一笔超过 5000 元的交易,即触发告警。
4.3 循环模式(Looping Pattern)
循环模式是对个体模式的扩展,用于匹配多个相同类型的事件。它通过指定重复次数来定义“连续发生多次”的行为。在风控中,循环模式常用于检测“短时间内多次尝试”、“批量操作”等场景。
4.3.1 循环量词
| 量词方法 | 含义 | 风控示例 |
|---|---|---|
.times(n) |
精确匹配 n 次。 | 连续 3 次输错密码。 |
.times(n, m) |
匹配 n 到 m 次(包含边界)。 | 连续 2~5 次小额试探交易。 |
.oneOrMore() |
匹配一次或多次(至少一次)。 | 连续多次异地登录。 |
.timesOrMore(n) |
匹配 n 次或更多次。 | 连续 3 次及以上的失败支付。 |
.optional() |
使当前模式可选(可匹配 0 次或 1 次)。 | 登录后,可能发生交易(也可能不发生)。 |
.greedy() |
贪婪匹配:尽可能多地匹配事件(需配合循环量词使用)。 | 在满足条件的情况下,匹配尽可能多的失败尝试。 |
.consecutive() |
要求匹配的事件在时间上是严格连续的(中间不能有不符合条件的事件)。 | 连续 3 次失败,中间不能有成功登录。 |
4.3.2 循环模式示例(风控:暴力破解检测)
Pattern<LoginEvent, ?> bruteForcePattern = Pattern
.<LoginEvent>begin("failures")
.where(evt -> evt.getStatus().equals("FAILED"))
.times(3)
.consecutive()
.next("success")
.where(evt -> evt.getStatus().equals("SUCCESS"))
.within(Time.minutes(2));
该规则匹配:在 2 分钟内,连续 3 次登录失败(中间不能有成功登录),紧接着发生一次登录成功,这通常意味着攻击者已破解密码。
4.4 三种模式的关系与组合
下图展示了一个完整的 Flink CEP 规则是如何由个体模式、组合模式和循环模式构建而成的:
4.5 实战对比:三种模式在风控中的典型应用
| 模式类型 | 典型风控场景 | 关键 API | 匹配结果 |
|---|---|---|---|
| 个体模式 | 单笔大额交易告警 | .where(amount > 100000) |
单个事件 |
| 组合模式 | 登录后立即修改密码 | .begin("login").next("changePwd") |
事件序列(2个事件) |
| 循环模式 | 5分钟内连续3次失败支付 | .times(3).consecutive() |
多个同类事件 |
| 组合+循环 | 连续失败后成功登录(暴力破解) | .times(3).next("success") |
混合事件序列 |
设计建议: 在编写风控规则时,建议先画出事件流的时序图,明确哪些事件是“必须连续”的(使用
.next()),哪些是“可以间隔”的(使用 .followedBy()),以及哪些事件需要“重复出现”(使用循环量词)。这能有效避免因连续性策略选择不当导致的误报或漏报。