【Flink-1.17-教程】-【四】Flink DataStream API(5)转换算子(Transformation)【分流】

所谓"分流",就是将一条数据流拆分成完全独立的两条、甚至多条流。也就是基于一个 DataStream,定义一些筛选条件,将符合条件的数据拣选出来放到对应的流里。

1)使用 filter 简单实现

其实根据条件筛选数据的需求,本身非常容易实现:只要针对同一条流多次独立调用 .filter() 方法进行筛选,就可以得到拆分之后的流了。

案例需求:读取一个整数数字流,将数据流划分为奇数流和偶数流。

java 复制代码
public class SplitByFilterDemo {
    public static void main(String[] args) throws Exception {
//        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        StreamExecutionEnvironment env = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(new Configuration());

        env.setParallelism(1);

        DataStreamSource<String> socketDS = env.socketTextStream("hadoop102", 7777);

        /**
         * TODO 使用filter来实现分流效果
         * 缺点: 同一个数据,要被处理两遍(调用两次filter)
          */

        SingleOutputStreamOperator<String> even = socketDS.filter(value -> Integer.parseInt(value) % 2 == 0);
        SingleOutputStreamOperator<String> odd = socketDS.filter(value -> Integer.parseInt(value) % 2 == 1);


        even.print("偶数流");
        odd.print("奇数流");


        env.execute();
    }
}

这种实现非常简单,但代码显得有些冗余------我们的处理逻辑对拆分出的三条流其实是一样的,却重复写了三次。而且这段代码背后的含义,是将原始数据流 stream 复制三份,然后对每一份分别做筛选;这明显是不够高效的。我们自然想到,能不能不用复制流,直接用一个算子就把它们都拆分开呢?

2)使用侧输出流实现

关于处理函数中侧输出流的用法,我们已经在 flatmap 课节做了详细介绍。简单来说,只需要调用上下文 ctx.output() 方法,就可以输出任意类型的数据了。而侧输出流的标记和提取,都离不开一个"输出标签"OutputTag ),指定了侧输出流的 id 和类型。

代码实现:将 WaterSensor 按照 id 类型进行分流。

准备好自定义的 MapFunction:

java 复制代码
public class WaterSensorMapFunction implements MapFunction<String,WaterSensor> {
    @Override
    public WaterSensor map(String value) throws Exception {
        String[] datas = value.split(",");
        return new WaterSensor(datas[0], Long.valueOf(datas[1]), Integer.valueOf(datas[2]));
    }
}

实现:

java 复制代码
public class SideOutputDemo {
    public static void main(String[] args) throws Exception {
//        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        StreamExecutionEnvironment env = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(new Configuration());

        env.setParallelism(1);

        SingleOutputStreamOperator<WaterSensor> sensorDS = env
                .socketTextStream("hadoop102", 7777)
                .map(new WaterSensorMapFunction());


        /**
         * TODO 使用侧输出流 实现分流
         * 需求: watersensor的数据,s1、s2的数据分别分开
         *
         * TODO 总结步骤:
         *    1、使用 process算子
         *    2、定义 OutputTag对象
         *    3、调用 ctx.output
         *    4、通过主流 获取 测流
         */

        /**
         * 创建OutputTag对象
         * 第一个参数: 标签名
         * 第二个参数: 放入侧输出流中的 数据的 类型,Typeinformation
         */
        OutputTag<WaterSensor> s1Tag = new OutputTag<>("s1", Types.POJO(WaterSensor.class));
        OutputTag<WaterSensor> s2Tag = new OutputTag<>("s2", Types.POJO(WaterSensor.class));

        SingleOutputStreamOperator<WaterSensor> process = sensorDS
                .process(
                        new ProcessFunction<WaterSensor, WaterSensor>() {
                            @Override
                            public void processElement(WaterSensor value, Context ctx, Collector<WaterSensor> out) throws Exception {
                                String id = value.getId();
                                if ("s1".equals(id)) {
                                    // 如果是 s1,放到侧输出流s1中
                                    /**
                                     * 上下文ctx 调用ouput,将数据放入侧输出流
                                     * 第一个参数: Tag对象
                                     * 第二个参数: 放入侧输出流中的 数据
                                     */
                                    ctx.output(s1Tag, value);
                                } else if ("s2".equals(id)) {
                                    // 如果是 s2,放到侧输出流s2中

                                    ctx.output(s2Tag, value);
                                } else {
                                    // 非s1、s2的数据,放到主流中
                                    out.collect(value);
                                }

                            }
                        }
                );
        // 从主流中,根据标签 获取 侧输出流
        SideOutputDataStream<WaterSensor> s1 = process.getSideOutput(s1Tag);
        SideOutputDataStream<WaterSensor> s2 = process.getSideOutput(s2Tag);

        // 打印主流
        process.print("主流-非s1、s2");

        //打印 侧输出流
        s1.printToErr("s1");
        s2.printToErr("s2");

        env.execute();
    }
}

要点:

1、使用 process();(是最底层 API)。

2、process 每次处理一条数据

3、定义 OutputTag 对象:

(1)第一个参数:标签名

(2)第二个参数:放入侧输出流中的数据的类型,Typeinformation

4、调用 ctx.output();

5、通过主流获取测流

相关推荐
拂拉氏2 小时前
【知识讲解】 AVL树从基本成员的介绍到核心接口的实现(插入、判断、删除等等)
数据结构·算法·avl树
卓怡学长2 小时前
w266基于spring boot + vue 圣地延安美食乐享系统
java·数据库·vue.js·spring boot·spring·intellij-idea
GEO_ai_zhijian2 小时前
饮料生产线质量检测系统供应商哪家强
大数据·python
C++、Java和Python的菜鸟2 小时前
第7章 Java高级技术
java·开发语言
程序员佳佳2 小时前
模型网关灰度不是调百分比:把放量、观测和回滚做成账本
java·数据库·人工智能·redis·gpt·aigc·embedding
CryptoPP2 小时前
BSE股票K线数据接入实战:从接口调用到前端图表展示
大数据·前端·网络·人工智能·websocket·网络协议
可靠的仙人掌2 小时前
SAC(Soft Actor-Critic)算法底座
开发语言·算法·php
得闲喝茶2 小时前
跨表数据匹配——VLOOKUP、XLOOKUP
大数据·数据库·笔记·信息可视化·数据分析·excel
码农阿强3 小时前
GPT-5.6 Sol/Terra/Luna 三模型全量上架StartAPI|分层选型+可运行调用代码实战
大数据·人工智能·gpt·ai·aigc
zandy10113 小时前
体验家 XMPlus 批量操作与自动化工作流引擎:让大规模运营从手动执行走向规则驱动
大数据·运维·自动化