Flink 核心算子详解:map / flatMap / filter / process

文章目录

在学习 Flink 的过程中,mapflatMapfilterprocess 是最常用、也是最容易让人迷糊的几个算子。

很多初学者都会有这些疑问:

  • 为什么 flatMap 里一定要写 Collector
  • 为什么 map 不能返回多个元素?
  • process 到底强在哪里?什么时候该用?

本文将 从接口设计出发 ,结合 可运行 Demo + 实际运行结果,带你真正理解 Flink 算子的设计思想。


一、算子能力对照表

算子 输入 → 输出 是否可丢数据 是否可多输出 是否可用时间/状态
map 1 → 1
filter 1 → 0/1
flatMap 1 → 0/N
process 1 → 0/N

一句话总结:

越简单的算子,约束越多,Flink 能优化得越好;
越底层的算子,能力越强,但责任全在你。


二、测试数据

text 复制代码
hello flink
hello world

三、map:一进一出

1. 接口定义

java 复制代码
public interface MapFunction<T, R> {
    R map(T value) throws Exception;
}

特点:

  • 一个输入
  • 必须返回一个输出
  • 不能多、不能少

2. Demo:字符串转大写

java 复制代码
  StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStream<String> source = env.fromElements(
                "hello flink",
                "hello world"
        );

        source.map(value -> value.toUpperCase()).print();
        try {
            env.execute("Simple Map Example");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

DataStream 程序是惰性执行的,必须调用 execute() 才会触发作业执行

3. 运行结果

text 复制代码
8> HELLO WORLD
7> HELLO FLINK

四、filter:只负责"要不要"

1. 接口定义

java 复制代码
public interface FilterFunction<T> {
    boolean filter(T value) throws Exception;
}

注意:

  • 不能修改数据
  • 只能决定保留 or 丢弃

2. Demo:只保留包含 flink 的行

java 复制代码
source
    .filter(line -> line.contains("flink"))
    .print();

3. 运行结果

text 复制代码
6> hello flink

五、flatMap:一进多出

1. 接口定义

java 复制代码
public interface FlatMapFunction<T, O> {
    void flatMap(T value, Collector<O> out) throws Exception;
}

2. 为什么要 Collector

因为:

flatMap 允许一条输入,输出 0 条、1 条或多条数据

返回值已经不够用,所以 Flink 把"输出控制权"交给你。


3. Demo:拆分单词

java 复制代码
        source.flatMap((String line, Collector<String> out) -> {
                    for (String word : line.split(" ")) {
                        out.collect(word);
                    }
                })
                .returns(Types.STRING)   // ⭐ 关键:补全类型信息
                .print();

4. 运行结果

text 复制代码
4> hello
4> world
3> hello
3> flink

六、process:最底层、最强大的算子

map / filter / flatMap 能做的,process 全都能做

并且还能:

  • 获取时间
  • 使用状态
  • 注册定时器

1. 接口结构

java 复制代码
public abstract class ProcessFunction<I, O> {
    public abstract void processElement(
        I value,
        Context ctx,
        Collector<O> out
    ) throws Exception;
}

2. Demo:手写 WordCount(不使用 keyBy.sum)

java 复制代码
      source
                .keyBy(value -> value)
                .process(new ProcessFunction<String, Tuple2<String, Integer>>() {

                    private int count = 0;

                    @Override
                    public void processElement(
                            String value,
                            Context ctx,
                            Collector<Tuple2<String, Integer>> out) {

                        count++;
                        out.collect(Tuple2.of(value, count));
                    }
                })
                .print();

3. 运行结果

text 复制代码
3> (hello flink,1)
6> (hello world,1)

⚠️ 注意:这里只是演示 process 能力

实际生产应使用 Keyed State 而不是普通成员变量


七、如何选择算子?

官方推荐原则:

能用 map,就别用 flatMap
能用 flatMap,就别用 process

原因是:

  • 简单算子 → Flink 能做更多优化
  • process → 灵活但难维护、难调优

八、总结

  • map:最简单,1 → 1
  • filter:只做判断
  • flatMap:拆分、多输出
  • process:终极武器,慎用

理解算子 ≠ 记 API
理解算子 = 理解接口设计 + 数据流模型

相关推荐
天若有情6732 小时前
省市聚力:软件产业的“中国土壤”与“创新脊梁”
大数据·人工智能·microsoft
FJW0208142 小时前
Python推导式与生成器
开发语言·python
roman_日积跬步-终至千里2 小时前
【大数据框架】Calcite 基础概念:从 SQL 到执行计划的思维路径
java·大数据·sql
深蓝电商API2 小时前
Scrapy杜绝重复请求:Rfpdupfilter源码分析与优化
爬虫·python·scrapy
ID_180079054732 小时前
乐天(Letian)商品详情API接口的调用示例与代码实现
开发语言·python
中科天工2 小时前
智装升级:工业4.0时代的高效包装革命
大数据·人工智能·智能
南 阳2 小时前
Python从入门到精通day10
linux·windows·python
mftang2 小时前
Python 获取当前目录的多种方法
python
晨非辰2 小时前
C++波澜壮阔40年|类和对象篇:拷贝构造与赋值重载的演进与实现
运维·开发语言·c++·人工智能·后端·python·深度学习