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
实践要点: 在 Flink CEP 中,事件必须实现 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;
            }
        });
关键理解: 模式是 CEP 规则的“原子单元”。一个模式可以独立匹配,也可以与其他模式组合成更复杂的序列。

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));
严格连续 vs 非严格连续: .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 核心概念之间的层次关系与组合方式,帮助理解从“事件”到“复杂规则”的构建路径。

CEP 核心概念关系图 CEP 核心概念关系图 事件 (Event) 模式 (Pattern) 条件模式 循环模式 模式序列 模式组 (Group) 复杂规则 (Complex Rule) 说明:事件是原子单元,模式定义匹配逻辑,模式序列/循环/条件组合成模式组,最终构成复杂规则

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 分钟) 为整个序列设置时间窗口。