1. 概述
本文将带你快速入门 Apache Beam,梳理其核心概念与典型应用场景。
我们会先讲清楚为什么需要 Beam,以及它能带来什么价值。接着介绍 Beam 的关键抽象模型,并通过一个经典的词频统计(Word Count)示例,手把手带你构建一个完整的数据处理流水线。✅
整个过程注重实践与理解,适合已有分布式或流式处理经验的开发者参考和复用。
2. 什么是 Apache Beam?
Apache Beam(Batch + strEAM)是一套统一的批处理与流式处理编程模型。它允许你用同一套 API 定义数据处理逻辑,无论数据是静态的文件还是实时的事件流。
Beam 的核心价值在于“一次编写,多引擎运行”。你只需要使用 Beam SDK 编写数据流水线(Pipeline),然后选择不同的 Pipeline Runner,就能在多种分布式计算引擎上执行,无需重写代码。
目前支持的后端包括:
- Apache Flink
- Apache Spark
- Google Cloud Dataflow
- Apache Samza
- Hazelcast Jet
- Apache Apex
- Apache Gearpump(孵化中)
这意味着你可以本地调试用 DirectRunner
,上线切换成 FlinkRunner
或 DataflowRunner
,完全解耦业务逻辑与底层执行引擎。✅
3. 为什么要用 Apache Beam?
✅ 统一批与流处理
传统框架如 Spark Streaming 或 Flink 虽然也支持流批一体,但往往需要两套不同的 API 或模式。而 Beam 从设计上就是统一的——同一个 Pipeline 可以跑在批模式或流模式下。
比如今天处理的是日志文件(批),明天改成 Kafka 实时消费(流),只需更换输入源和 Runner,大部分代码不变。这种灵活性在需求频繁变更的场景下非常实用。
✅ 高度可移植
Beam 的 SDK 是语言和平台无关的抽象层。你的业务逻辑写在 Beam Pipeline 里,Runner 负责翻译成目标引擎的原生任务(如 Spark RDD、Flink JobGraph)。
这意味着团队可以自由选择运行环境,甚至跨云迁移都变得简单粗暴。
✅ 多语言支持
Beam 提供了 Java、Python、Go 和 Scala 的 SDK,团队成员可以用自己熟悉的语言参与数据流水线开发,协作更顺畅。
4. 核心概念
要写好 Beam 程序,必须掌握以下几个关键抽象:
- ✅ PCollection:代表一个分布式的数据集,可以是有界数据(如文件)或无界数据(如 Kafka 流)。它是数据的载体。
- ✅ PTransform:数据处理操作,接收一个或多个 PCollection,输出零个或多个新的 PCollection。例如
MapElements
、Filter
、Count.perElement()
都是典型的 PTransform。 - ✅ Pipeline:整个数据处理流程的有向无环图(DAG),由 PCollection 和 PTransform 构成。它是所有操作的容器。
- ✅ PipelineRunner:负责将 Pipeline 提交到具体执行引擎的“翻译官”。比如
DirectRunner
用于本地测试,SparkRunner
提交到 Spark 集群。
简单总结:
👉 你构建 Pipeline,里面包含数据(PCollection)和操作(PTransform),最后交给 PipelineRunner 去跑。
5. 词频统计示例
接下来我们通过一个经典的 Word Count 示例,把上面的概念串起来。
5.1. 流水线设计思路
目标:统计一段文本中每个单词出现的次数。
步骤分解:
- 读取文本文件
- 按空格拆分成单词
- 转为小写
- 去除标点符号
- 过滤停用词(如 "the", "a", "is")
- 统计每个词的频次
这些步骤将被转化为一个由 PTransform 组成的 Pipeline。
5.2. Maven 依赖
先引入核心 SDK 和本地运行所需的 Runner:
<dependency>
<groupId>org.apache.beam</groupId>
<artifactId>beam-sdks-java-core</artifactId>
<version>2.45.0</version>
</dependency>
用于本地测试的 DirectRunner
:
<dependency>
<groupId>org.apache.beam</groupId>
<artifactId>beam-runners-direct-java</artifactId>
<version>2.45.0</version>
<scope>runtime</scope>
</dependency>
⚠️ 注意:DirectRunner
不依赖任何集群环境,适合本地调试。生产环境应替换为 FlinkRunner
或 DataflowRunner
。
5.3. 编码实现
Beam 的编程风格类似 Java 8 Stream,如果你熟悉 map
、flatMap
、filter
、reduce
,那上手会非常快。🧠
创建 Pipeline
PipelineOptions options = PipelineOptionsFactory.create();
Pipeline p = Pipeline.create(options);
构建处理链
PCollection<KV<String, Long>> wordCount = p
.apply("(1) Read all lines",
TextIO.read().from("/tmp/input.txt"))
.apply("(2) Flatmap to a list of words",
FlatMapElements.into(TypeDescriptors.strings())
.via(line -> Arrays.asList(line.split("\\s"))))
.apply("(3) Lowercase all",
MapElements.into(TypeDescriptors.strings())
.via(word -> word.toLowerCase()))
.apply("(4) Trim punctuations",
MapElements.into(TypeDescriptors.strings())
.via(word -> trim(word)))
.apply("(5) Filter stopwords",
Filter.by(word -> !isStopWord(word)))
.apply("(6) Count words",
Count.perElement());
📌 说明:
(1)
使用TextIO.read()
读取文本,每行作为一个元素。(2)
flatMap
拆分每行成单词列表,扁平化输出。(3)
统一转小写,避免 "Word" 和 "word" 被当作不同词。(4)
自定义trim()
方法去除首尾标点(如 "hello!" → "hello")。(5)
过滤常见停用词,提升结果可读性。(6)
Count.perElement()
是内置聚合操作,返回KV<String, Long>
。
输出结果
PCollection 是分布式结构,不能直接遍历。我们将其格式化后写入文件:
wordCount.apply(MapElements.into(TypeDescriptors.strings())
.via(count -> count.getKey() + " --> " + count.getValue()))
.apply(TextIO.write().to("/tmp/output"));
最终输出示例:
apache --> 3
beam --> 5
rocks --> 2
每个 apply()
返回新的 PCollection,整个链式调用构成了完整的 DAG。✅
5.4. 运行与测试
最后启动 Pipeline:
p.run().waitUntilFinish();
使用 DirectRunner
时,Beam 会在本地多线程模拟分布式执行,生成多个输出片段文件(如 output-00001-of-00005
)。内容就是上面那样的词频对。
💡 提示:生产环境建议配合 Window
和 Trigger
处理乱序事件流,本文暂不展开。
6. 下一步学什么?
这个例子只是入门。要想真正驾驭 Beam,你还应该深入以下主题:
- ✅ Windowing:如何按时间窗口(如每5分钟)聚合流数据
- ✅ Triggers:控制窗口触发时机,支持提前、延迟、重复触发
- ✅ State & Timers:在流处理中维护状态和定时操作
- ✅ Metrics:自定义监控指标,观察 Pipeline 运行状态
- ✅ Side Inputs / Outputs:处理广播变量或多路输出
官方文档 beam.apache.org/documentation 内容详实,是首选学习资源。
7. 总结
Apache Beam 的优势在于:
- 统一批与流处理模型,降低维护成本
- 解耦逻辑与执行引擎,提升可移植性
- 支持多语言,便于团队协作
通过 Word Count 示例,我们完成了从依赖引入、Pipeline 构建到本地运行的全流程。整个过程简洁清晰,几乎没有样板代码。
后续建议尝试将其部署到 Flink 或 Dataflow 上,体验真正的“一次编写,随处运行”。
完整代码示例已托管至 GitHub:https://github.com/example-tutorials/apache-beam-demo