3. CEP 概念精讲:事件、模式、模式序列、模式组、循环模式、条件模式
在深入 Flink CEP 风控巡检案例之前,必须牢固掌握 CEP(Complex Event Processing,复杂事件处理)的核心概念。这些概念是构建风控规则引擎的“语法”和“词汇”。本章将逐一拆解事件、模式、模式序列、模式组、循环模式与条件模式,并通过内联 SVG 图展示它们之间的逻辑关系。
3.1 事件(Event)
事件是 CEP 处理的基本单元。在风控场景中,一个事件通常对应一条交易记录、一次登录尝试或一次账户操作。Flink CEP 将事件建模为 Java/Pojo 或 Scala case class 对象,其字段包含时间戳、交易金额、设备指纹等风控特征。
| 属性 | 说明 | 风控示例 |
|---|---|---|
| 事件类型 | 标识事件所属的类别 | TransactionEvent, LoginEvent |
| 时间戳 | 事件发生或到达的时间 | 2025-03-21 14:30:00.123 |
| 关键字段 | 用于匹配和计算的特征 | userId, amount, deviceId, ip |
| 事件ID | 全局唯一标识 | txn_20250321_001234 |
equals() 和 hashCode() 方法,因为模式匹配引擎会基于事件对象进行状态比较和去重。
3.2 模式(Pattern)
模式是定义“我们想要寻找什么”的规则。一个模式由 事件约束 和 量词 组成。在 Flink CEP 中,每个模式通过 .where() 方法指定过滤条件,通过 .times()、.oneOrMore() 等指定出现次数。
// 定义一个简单模式:单笔交易金额超过 10000
Pattern<TransactionEvent, ?> highAmount =
Pattern.<TransactionEvent>begin("high_amount")
.where(new SimpleCondition<TransactionEvent>() {
@Override
public boolean filter(TransactionEvent event) {
return event.getAmount() > 10000;
}
});
3.3 模式序列(Pattern Sequence)
模式序列是将多个模式按时间顺序串联起来,形成“先 A 后 B 再 C”的匹配逻辑。这是风控中检测“行为链条”的核心手段,例如:先登录失败 → 再修改密码 → 最后大额转账。
// 模式序列:连续三次登录失败后,在 5 分钟内发生转账
Pattern<LoginEvent, ?> loginFailThenTransfer =
Pattern.<LoginEvent>begin("fail1")
.where(new SimpleCondition<LoginEvent>() {
@Override
public boolean filter(LoginEvent event) {
return event.getStatus().equals("FAIL");
}
})
.next("fail2")
.where(...)
.next("fail3")
.where(...)
.followedBy("transfer")
.where(new SimpleCondition<LoginEvent>() {
@Override
public boolean filter(LoginEvent event) {
return event.getType().equals("TRANSFER");
}
})
.within(Time.minutes(5));
.next() 表示严格连续(事件必须紧挨着出现),.followedBy() 表示非严格连续(允许中间有其他事件)。风控场景中,.followedBy() 更常用,因为攻击者可能穿插正常操作。
3.4 模式组(Pattern Group)
模式组允许将多个模式组合成一个逻辑单元,用于构建更复杂的嵌套规则。例如,检测“短时间内高频交易”时,可以将“交易金额 > 5000”和“交易金额 < 20000”两个模式组合成一个组,再与“设备更换”模式串联。
// 模式组示例:将两个金额条件组合为一个组
Pattern<TransactionEvent, ?> amountGroup =
Pattern.<TransactionEvent>begin("medium_amount")
.where(event -> event.getAmount() > 5000 && event.getAmount() < 20000)
.times(3)
.consecutive();
// 将组与另一个模式串联
Pattern<TransactionEvent, ?> finalPattern =
Pattern.<TransactionEvent>begin(amountGroup)
.next("device_change")
.where(event -> event.isDeviceChanged());
| 概念 | 作用 | 风控场景 |
|---|---|---|
| 模式组 | 将多个模式封装为可复用的子规则 | “可疑金额范围” + “高频次数” |
| 嵌套组 | 组内可以包含序列或循环 | “连续失败”组 + “异地登录”组 |
3.5 循环模式(Looping Pattern)
循环模式用于匹配同一事件类型的多次出现。在风控中,循环模式是检测“高频”、“批量”、“重复”行为的核心工具。Flink CEP 提供 .times(n)、.times(n, m)、.oneOrMore()、.timesOrMore(n) 等量词。
// 循环模式:同一用户 1 分钟内发生 5 次以上交易
Pattern<TransactionEvent, ?> highFreq =
Pattern.<TransactionEvent>begin("freq_txns")
.where(new SimpleCondition<TransactionEvent>() {
@Override
public boolean filter(TransactionEvent event) {
return event.getAmount() > 0;
}
})
.times(5)
.within(Time.minutes(1));
.within(Time) 时间窗口,避免状态无限增长。同时,使用 .consecutive() 可以要求匹配的事件在时间上连续,减少无效匹配。
3.6 条件模式(Conditional Pattern)
条件模式通过 .where()、.or()、.until() 等方法定义事件必须满足的谓词逻辑。条件可以是简单的字段比较,也可以是复杂的跨事件关联(通过 IterativeCondition 访问之前匹配的事件)。
// 条件模式:使用 IterativeCondition 关联之前的事件
Pattern.<TransactionEvent>begin("first")
.where(event -> event.getAmount() > 1000)
.next("second")
.where(new IterativeCondition<TransactionEvent>() {
@Override
public boolean filter(TransactionEvent second,
Context<TransactionEvent> ctx) throws Exception {
// 获取第一个事件
TransactionEvent first = ctx.getEventsForPattern("first")
.iterator().next();
// 条件:第二个事件的金额是第一个的 2 倍以上
return second.getAmount() > first.getAmount() * 2;
}
});
- 简单条件(SimpleCondition): 只依赖当前事件字段,无状态。
- 迭代条件(IterativeCondition): 可访问之前匹配的事件,用于跨事件关联。
- 组合条件: 通过
.or()连接多个条件,满足任一即可。 - 终止条件(.until()): 用于循环模式,指定何时停止匹配。
3.7 概念关系总览
下图展示了 CEP 核心概念之间的层次关系与组合方式,帮助理解从“事件”到“复杂规则”的构建路径。
3.8 概念对比速查表
下表总结了六个核心概念的定义、量词/操作符和典型风控场景,方便快速查阅。
| 概念 | 定义 | 关键操作符/量词 | 风控场景示例 |
|---|---|---|---|
| 事件 | CEP 处理的基本数据单元 | — | 交易事件、登录事件 |
| 模式 | 定义事件匹配条件的规则单元 | .where(), .or() |
金额 > 10000 |
| 模式序列 | 多个模式按时间顺序串联 | .next(), .followedBy() |
登录失败 → 修改密码 → 转账 |
| 模式组 | 将多个模式封装为逻辑单元 | Pattern.begin(group) |
“可疑金额范围”组 + “设备更换” |
| 循环模式 | 匹配同一事件类型的多次出现 | .times(n), .oneOrMore() |
1 分钟内 5 次交易 |
| 条件模式 | 通过谓词逻辑过滤事件 | IterativeCondition, .until() |
第二次金额是第一次的 2 倍 |
3.9 风控场景中的模式组合示例
下面通过一个完整的风控规则,展示如何将上述概念组合起来,检测“盗刷”行为。
// 规则:同一设备在 10 分钟内,先有 3 次小额试探交易(金额 < 100),
// 然后发生 1 笔大额交易(金额 > 50000)
Pattern<TransactionEvent, ?> fraudPattern =
Pattern.<TransactionEvent>begin("probe")
.where(event -> event.getAmount() < 100)
.times(3)
.consecutive()
.next("large")
.where(event -> event.getAmount() > 50000)
.within(Time.minutes(10));
- “probe” 是一个 循环模式,匹配 3 次小额交易。
- “large” 是一个 条件模式,匹配大额交易。
- .next() 将两者组成 模式序列,要求大额交易紧接在 3 次试探之后。
- .within(10 分钟) 为整个序列设置时间窗口。