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
理解算子 = 理解接口设计 + 数据流模型

相关推荐
hfywmsj3 小时前
广州餐饮铺位招租决策模型:多因子选址系统设计
开发语言·人工智能·python·广州餐饮铺位招租
IT研究室4 小时前
最新大数据毕业设计选题推荐-基于大数据的城市交通流量数据可视化分析-大数据-Spark-Hadoop-Bigdata
大数据·信息可视化·课程设计
面向Google编程5 小时前
Apache Iceberg Variant 类型:v3 半结构化数据不再「二选一」
大数据·后端
大大大大晴天6 小时前
从数仓建模到 AI 数据底座:重新理解数据治理的位置
大数据
泡海椒6 小时前
内置SPI函数库详解:JQuick-Java Builtin工具类实战用法
java·开发语言·python
hqyjzsb6 小时前
零 AI 项目经验,学 Python 转型 AI 的正确顺序是什么?
开发语言·人工智能·python·算法·职场和发展·数据挖掘·数据分析
不会写代码的女程序猿6 小时前
中小康养门店选型参考|明理 AI 四诊仪场景适配与投入回报分析
大数据·人工智能·科技·ai·健康医疗
云泽8087 小时前
Git 版本控制系统(下):从 .git 目录结构到冲突解决机制详解
大数据·git·elasticsearch
Elastic 中国社区官方博客7 小时前
教程:使用 ES|QL 进行威胁狩猎
大数据·运维·数据库·elasticsearch·搜索引擎·全文检索·安全威胁分析
weixin_505061457 小时前
原厂技术协同|世强硬创携手星坤连接解锁 IOTE 高可靠互连解决方案
大数据