Flink批处理中 Operator / Transformation 方法作用总结
说明:
本文总结的是 Flink 经典 DataSet 批处理 API 中常见的 Operator/Transformation 方法。
按 Apache Flink 1.17 官方文档说明,DataSet API 自 1.12 起已进入 soft deprecated 状态;新项目更推荐使用 Table API / SQL,或使用 DataStream API 的 BATCH 执行模式。
1. 基础转换方法
| 方法 | 作用 | 常见场景 | 说明 |
|---|---|---|---|
map() |
对每个元素做一对一转换 | 字段加工、类型转换、格式标准化 | 每个输入元素必须返回且只返回 1 个输出元素 |
flatMap() |
对每个元素做一对零/一/多转换 | 分词、拆分记录、过滤并展开 | 一个输入元素可以输出多个结果,也可以不输出 |
mapPartition() |
以"分区"为单位处理数据 | 分区内批量处理、分区级聚合、减少外部连接次数 | 一次拿到一个并行分区的全部数据,适合批量逻辑 |
filter() |
按条件保留元素 | 条件筛选、脏数据过滤 | 返回 true 保留,返回 false 丢弃 |
project(int...) |
选择并重排 Tuple 字段 |
只保留部分列、调整字段顺序 | 仅适用于 Tuple DataSet |
2. 分组与分组后方法
| 方法 | 作用 | 常见场景 | 说明 |
|---|---|---|---|
groupBy(...) |
按 key 分组,得到 GroupedDataSet |
统计、聚合、去重前分组 | 是后续 reduce、reduceGroup、aggregate 等的基础 |
sortGroup(...) |
对每个分组内部排序 | 组内 TopN、组内按时间或分数排序 | 通常与 first(n) 连用 |
reduce() |
把每个分组逐步归约为 1 条记录 | 按 key 求和、累加计数 | 返回值中的分组 key 应与输入 key 保持一致 |
reduceGroup() |
对每个分组整体处理,可输出任意条结果 | 复杂组内统计、组内去重、组内重组 | 与 reduce() 的区别是它能拿到整组数据 |
combineGroup() |
先在本地分区内做预聚合,再进入下一阶段 | 先做局部压缩,减少网络传输 | 属于"局部 combine",可能产生部分结果 |
aggregate(SUM/MIN/MAX, field) |
对分组后的 Tuple 执行内置聚合 |
分组求和、最大值、最小值 | 仅适用于 Tuple DataSet,且分组 key 只支持字段位置 |
.and(...) |
在同一次聚合链中继续添加聚合字段 | 同时求和、求最小值等 | .aggregate(...).and(...) 是对原始分组继续聚合,不是再次聚合前一次结果 |
minBy() / maxBy() |
在每个分组中选出指定字段最小/最大的整条元组 | 按组取最优记录、最高分记录 | 返回的是"整条元组",不是单个字段值 |
first(n) |
取每个分组前 n 条记录 | 组内抽样、组内 TopN 的基础步骤 | 若先 sortGroup(),则能实现"按序取前 n 条" |
3. 作用于整个 DataSet 的方法
| 方法 | 作用 | 常见场景 | 说明 |
|---|---|---|---|
reduce() |
将整个 DataSet 归约成 1 条结果 |
全局求和、全局累加 | 最终归约阶段不能完全并行,但函数可自动 combine |
reduceGroup() |
对整个 DataSet 做整体处理,可输出任意条结果 |
全局复杂统计、整体重组 | 若函数不可 combine,则可能计算开销较大 |
combineGroup() |
在各节点本地先进行全量局部 combine | 预聚合、压缩数据量 | 属于全量数据的局部预处理 |
aggregate(SUM/MIN/MAX, field) |
对整个 Tuple DataSet 做内置聚合 |
全局求和、全局最值 | 只适用于 Tuple DataSet |
.and(...) |
追加多个全局聚合字段 | 同时求多个字段统计值 | 与分组聚合中的 .and(...) 作用相同 |
minBy() / maxBy() |
从整个数据集中选出某字段最小/最大的整条记录 | 找最小值对应记录、最大值对应记录 | 若有多条并列,返回其中任意一条 |
distinct() |
去重 | 全量去重、按字段去重 | 可按整条记录去重,也可按字段位置、KeySelector、key expression 去重 |
first(n) |
取整个数据集前 n 条记录 | 样例查看、抽样查看 | 返回的是任意前 n 条,不保证全局排序语义 |
4. 双输入与关联类方法
| 方法 | 作用 | 常见场景 | 说明 |
|---|---|---|---|
join() |
内连接,只保留两边 key 匹配的数据 | 用户表与订单表关联 | 默认是等值连接 |
where(...).equalTo(...) |
指定两侧连接 key | join、outerJoin、coGroup 等 |
是连接类方法中最常见的 key 指定方式 |
with(JoinFunction) |
自定义连接结果输出 | 连接后拼装新结构 | 1 对 1 输出 |
projectFirst() / projectSecond() |
从连接结果中选字段并重排 | 只保留所需连接列 | 常用于 join 和 cross 后做投影 |
joinWithTiny() |
提示优化器:第二个数据集很小 | 小表广播连接 | 是性能优化提示,不改变语义 |
joinWithHuge() |
提示优化器:第二个数据集很大 | 大表连接优化 | 也是优化器 hint |
leftOuterJoin() |
左外连接 | 保留左表全部记录 | 右侧无匹配时右值可能为 null |
rightOuterJoin() |
右外连接 | 保留右表全部记录 | 左侧无匹配时左值可能为 null |
fullOuterJoin() |
全外连接 | 保留两边全部记录 | 任一侧无匹配时另一侧可能为 null |
cross() |
笛卡尔积,两边所有元素两两组合 | 组合枚举、距离矩阵等 | 计算量很大,实际使用要谨慎 |
crossWithTiny() |
提示优化器:第二个数据集很小的 cross |
小规模笛卡尔组合 | 仅是 hint |
crossWithHuge() |
提示优化器:第二个数据集很大的 cross |
大规模交叉场景优化 | 仅是 hint |
coGroup() |
对两个按同一 key 分组后的数据集做联合分组处理 | 双表分组比较、差异分析、非标准连接 | 某个 key 若只出现在一边,另一边会给空组 |
union() |
合并两个或多个同类型 DataSet |
多批次结果合并、分支结果汇总 | 只是拼接,不会自动去重 |
5. 分区、排序与数据重分布方法
| 方法 | 作用 | 常见场景 | 说明 |
|---|---|---|---|
rebalance() |
把数据均匀重新分配到各并行分区 | 解决数据倾斜 | 属于"均匀重平衡" |
partitionByHash() |
按 key 做哈希分区 | 保证同 key 落到同分区 | 常用于后续分区级处理 |
partitionByRange() |
按 key 范围分区 | 范围统计、分区排序前准备 | 适合有序或区间型数据 |
sortPartition() |
对每个分区内部排序 | 分区内顺序处理、局部 TopN | 是"局部排序",不是全局排序 |
6. 方法之间的常见关系
| 组合方式 | 作用 |
|---|---|
groupBy(...).reduce(...) |
按 key 做简单聚合,适合求和、计数等 |
groupBy(...).sortGroup(...).first(n) |
实现"每组按顺序取前 n 条" |
groupBy(...).reduceGroup(...) |
处理整组数据,适合复杂组内逻辑 |
partitionByHash(...).mapPartition(...) |
先按 key 分区,再做分区级批处理 |
join(...).where(...).equalTo(...).with(...) |
两表等值连接后生成新结果 |
distinct(...) |
去重;若只想保留唯一 key,可与 groupBy 思路对照理解 |
7. 学习时最容易混淆的点
-
map()和flatMap()的区别:map()必须 1 条进 1 条出;flatMap()可以 1 条进、多条出。 -
reduce()和reduceGroup()的区别:reduce()是逐步两两合并,最终每组只剩 1 条;reduceGroup()是把整组交给函数,输出条数不受限制。 -
combineGroup()和reduceGroup()的区别:combineGroup()更像"本地预聚合",主要为了减少后续传输量;reduceGroup()是真正的分组整体处理。 -
sortPartition()和全局排序的区别:sortPartition()只保证"每个分区内部有序",不保证整个DataSet全局有序。 -
union()和distinct()的区别:union()只是合并;distinct()才是去重。
8. 一句话记忆
- 单条变换:
map、flatMap、filter - 分区处理:
mapPartition - 分组聚合:
groupBy+reduce/reduceGroup/aggregate - 连接关联:
join、outerJoin、coGroup - 集合关系:
union、distinct - 分布控制:
rebalance、partitionByHash、partitionByRange - 排序截取:
sortGroup、sortPartition、first