流式关联的两种做法
流处理里的关联分两类:流与流之间按时间区间匹配(interval join),流与外部维表之间按主键点查(lookup join)。前者把两侧数据都放在状态里,按事件时间窗口对齐;后者不保留维表数据,每条流记录到达时去外部系统查一次。选错类型不仅影响结果正确性,也直接决定状态大小与下游数据库的压力。
基本信息
| Interval Join | 两条流按事件时间区间匹配,如订单与支付 15 分钟内关联 |
|---|---|
| Lookup Join | 流去外部维表点查,适合缓慢变化维 |
| 状态成本 | interval join 需保存区间内两侧数据 |
| 前提条件 | 两侧都要声明事件时间属性与水位线 |
| 常见引擎 | Flink SQL、Spark Structured Streaming 均提供对应能力 |
Flink SQL 区间关联
Flink SQL 区间关联
SELECT o.order_id, pay.pay_id
FROM orders o JOIN payments pay
ON o.order_id = pay.order_id
AND pay.pay_time BETWEEN o.order_time AND o.order_time + INTERVAL '15' MINUTE;
-- 关联的字段必须带时间属性:建表时用 WATERMARK 声明
-- WATERMARK FOR order_time AS order_time - INTERVAL '5' SECONDFlink SQL 维表关联
Flink SQL 维表关联
SELECT o.order_id, u.city
FROM orders AS o
JOIN user_dim FOR SYSTEM_TIME AS OF o.proc_time AS u
ON o.user_id = u.user_id;
-- 维表通常加缓存参数控压:
-- 'lookup.cache' = 'PARTIAL', 'lookup.cache.max-rows' = '10000',
-- 'lookup.cache.ttl' = '10min'两种方式对比
| 维度 | Interval Join | Lookup Join |
|---|---|---|
| 关联对象 | 两条流之间 | 流与外部维表之间 |
| 状态占用 | 保存区间内两侧数据,随窗口与流量增长 | 不保存维表数据,仅本地缓存 |
| 时效性 | 受水位线推进速度影响 | 受缓存过期时间影响 |
| 下游压力 | 无额外查询 | 每次未命中缓存都会点查一次 |
| 典型用途 | 订单与支付、曝光与点击 | 订单打宽用户与商品属性 |
典型使用场景
- 订单与支付对账:用区间关联关联上下单后一段时间内的支付记录
- 曝光与点击归因:把点击与一段时间窗口内的曝光匹配
- 流数据打宽:订单流按 user_id 点查用户维表补上地域、等级
- 缓慢变化维:维表更新不频繁,用缓存换取更低的下游查询压力
- 多流合并:先按业务键分区,再在算子内做区间匹配减少跨分区状态
lookup join 的维表缓存过期时间决定数据新鲜度,调大缓存能减压力但会命中旧维度值。
区间关联的状态会随窗口与流量增长:区间越长、水位线推进越慢,状态越大,checkpoint 耗时也越长,需要按业务真正需要的匹配范围来设区间。