FlinkAPI开发之数据分流

13 篇文章 0 订阅

案例用到的测试数据请参考文章:
Flink自定义Source模拟数据流
原文链接:https://blog.csdn.net/m0_52606060/article/details/135436048

概述

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

在这里插入图片描述

简单实现

其实根据条件筛选数据的需求,本身非常容易实现:只要针对同一条流多次独立调用.filter()方法进行筛选,就可以得到拆分之后的流了。
案例需求:将订单数据按交易额大于50和小于等于50的条件分成两条流。

package com.zxl.flink;

import com.zxl.bean.Orders;
import com.zxl.datas.OrdersData;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;

public class DemoTest {
    public static void main(String[] args) throws Exception {
        //创建Flink流处理执行环境
        StreamExecutionEnvironment environment = StreamExecutionEnvironment.getExecutionEnvironment();
        //设置并行度为1
        environment.setParallelism(1);
        //调用Flink自定义Source
        // TODO: 2024/1/6 订单数据
        DataStreamSource<Orders> ordersDataStreamSource = environment.addSource(new OrdersData());
        // TODO: 2024/1/7 订单金额大于50的
        DataStream<Orders> filter1 = ordersDataStreamSource.filter(orders -> orders.getOrder_amount() > 50);
        // TODO: 2024/1/7 订单金额小于等于50的
        DataStream<Orders> filter2 = ordersDataStreamSource.filter(orders -> orders.getOrder_amount() <= 50);
        filter1.print("订单金额大于50的");
        filter2.print("订单金额小于等于50的");
        environment.execute();
    }
}

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

使用侧输出流

绝大多数转换算子,输出的都是单一流,流里的数据类型只能有一种。而侧输出流可以认为是“主流”上分叉出的“支流”,所以可以由一条流产生出多条流,而且这些流中的数据类型还可以不一样。利用这个功能可以很容易地实现“分流”操作。

简单来说,只需要调用上下文ctx的.output()方法,就可以输出任意类型的数据了。而侧输出流的标记和提取,都离不开一个“输出标签”(OutputTag),指定了侧输出流的id和类型。

案例:根据支付类型来分割支付数据

package com.zxl.flink;

import com.zxl.bean.Payments;
import com.zxl.datas.PaymentData;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SideOutputDataStream;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.ProcessFunction;
import org.apache.flink.util.Collector;
import org.apache.flink.util.OutputTag;

public class DemoTest {
    public static void main(String[] args) throws Exception {
        //创建Flink流处理执行环境
        StreamExecutionEnvironment environment = StreamExecutionEnvironment.getExecutionEnvironment();
        //设置并行度为1
        environment.setParallelism(1);
        //调用Flink自定义Source
        // TODO: 2024/1/6 支付数据
        DataStreamSource<Payments> paymentsDataStreamSource = environment.addSource(new PaymentData());
        // TODO: 2024/1/7 根据支付类型进行打标,对象后面的{}一定不要忘记写否则会报错
        //六种支付类型{"银行卡", "支付宝", "微信", "美团", "抖音", "现金"};现金作为主流
        OutputTag<Payments> yhk_tag = new OutputTag<Payments>("银行卡", Types.POJO(Payments.class)){};
        OutputTag<Payments> zfb_tag = new OutputTag<Payments>("支付宝", Types.POJO(Payments.class)){};
        OutputTag<Payments> wx_tag = new OutputTag<Payments>("微信", Types.POJO(Payments.class)){};
        OutputTag<Payments> mt_tag = new OutputTag<Payments>("美团", Types.POJO(Payments.class)){};
        OutputTag<Payments> dy_tag = new OutputTag<Payments>("抖音", Types.POJO(Payments.class)){};

        // TODO: 2024/1/7 根据标签进行打标(传入值1为传入类型,传入值2为传出类型)
        // TODO: 2024/1/7  侧输出流的返回值一定要用SingleOutputStreamOperator,不能用DataStream,DataStream里面没有根据标签获取数据的方法
        SingleOutputStreamOperator<Payments> paymentsOutputStream = paymentsDataStreamSource.process(new ProcessFunction<Payments, Payments>() {

            // TODO: 2024/1/7  传入值1为传入类型,传入值2为打标输出的集合,传入值3为主流输出的集合
            @Override
            public void processElement(Payments payments, ProcessFunction<Payments, Payments>.Context context, Collector<Payments> collector) throws Exception {
                if ("银行卡".equals(payments.getPayment_type())) {
                    context.output(yhk_tag, payments);
                } else if ("支付宝".equals(payments.getPayment_type())) {
                    context.output(zfb_tag, payments);
                } else if ("微信".equals(payments.getPayment_type())) {
                    context.output(wx_tag, payments);
                } else if ("美团".equals(payments.getPayment_type())) {
                    context.output(mt_tag, payments);
                } else if ("抖音".equals(payments.getPayment_type())) {
                    context.output(dy_tag, payments);
                } else {
                    //没有符合标签的作为主流输出
                    collector.collect(payments);
                }
            }
        });
        //主流打印
        paymentsOutputStream.print("主流");
        // TODO: 2024/1/7 根据标签获取测流 
        SideOutputDataStream<Payments> yhk_out = paymentsOutputStream.getSideOutput(yhk_tag);
        SideOutputDataStream<Payments> zfb_out = paymentsOutputStream.getSideOutput(zfb_tag);
        SideOutputDataStream<Payments> wx_out = paymentsOutputStream.getSideOutput(wx_tag);
        SideOutputDataStream<Payments> mt_out = paymentsOutputStream.getSideOutput(mt_tag);
        SideOutputDataStream<Payments> dy_out = paymentsOutputStream.getSideOutput(dy_tag);
        // TODO: 2024/1/7 打印测输出流 
        yhk_out.print("银行卡");
        zfb_out.print("支付宝");
        wx_out.print("微信");
        mt_out.print("美团");
        dy_out.print("抖音");
        environment.execute();
    }
}

在这里插入图片描述

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值