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,上线切换成 FlinkRunnerDataflowRunner,完全解耦业务逻辑与底层执行引擎。✅


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。例如 MapElementsFilterCount.perElement() 都是典型的 PTransform。
  • Pipeline:整个数据处理流程的有向无环图(DAG),由 PCollection 和 PTransform 构成。它是所有操作的容器。
  • PipelineRunner:负责将 Pipeline 提交到具体执行引擎的“翻译官”。比如 DirectRunner 用于本地测试,SparkRunner 提交到 Spark 集群。

简单总结:
👉 你构建 Pipeline,里面包含数据(PCollection)和操作(PTransform),最后交给 PipelineRunner 去跑。


5. 词频统计示例

接下来我们通过一个经典的 Word Count 示例,把上面的概念串起来。

5.1. 流水线设计思路

目标:统计一段文本中每个单词出现的次数。

步骤分解:

  1. 读取文本文件
  2. 按空格拆分成单词
  3. 转为小写
  4. 去除标点符号
  5. 过滤停用词(如 "the", "a", "is")
  6. 统计每个词的频次

这些步骤将被转化为一个由 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 不依赖任何集群环境,适合本地调试。生产环境应替换为 FlinkRunnerDataflowRunner

5.3. 编码实现

Beam 的编程风格类似 Java 8 Stream,如果你熟悉 mapflatMapfilterreduce,那上手会非常快。🧠

创建 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)。内容就是上面那样的词频对。

💡 提示:生产环境建议配合 WindowTrigger 处理乱序事件流,本文暂不展开。


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


原始标题:Introduction to Apache Beam