Flink 分流

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

 

 

处理函数本身可以认为是一个转换算子,它的输出类型是单一的,处理之后得到的仍然是一个DataStream;而侧输出流则不受限制,可以任意自定义输出数据,它们就像从“主流”上分叉出的“支流”。尽管看起来主流和支流有所区别,不过实际上它们都是某种类型的DataStream,所以本质上还是平等的。利用侧输出流就可以很方便地实现分流操作,而且得到的多条DataStream类型可以不同,这就给我们的应用带来了极大的便利。关于处理函数中侧输出流的用法,我们已经在7.5节做了详细介绍。简单来说,只需要调用上下文ctx的.output()方法,就可以输出任意类型的数据了。而侧输出流的标记和提取,都离不开一个“输出标签”(OutputTag),它就相当于split()分流时的“戳”,指定了侧输出流的id和类型。

侧输出流实现分流

复制代码
/**
 * 侧输出流实现分流
 */
public class SplitSDtreamTest {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        SingleOutputStreamOperator<Event> eventStream = env.addSource(new ClickSource())
                .assignTimestampsAndWatermarks(WatermarkStrategy.
                        <Event>forBoundedOutOfOrderness(Duration.ofSeconds(2))
                        .withTimestampAssigner(new SerializableTimestampAssigner<Event>() {
                            @Override
                            public long extractTimestamp(Event element, long recordTimestamp) {
                                return element.timestamp * 10000;
                            }
                        }));

        //定义侧输出流标签
        OutputTag<Tuple3<String, String, Long>> yilin = new OutputTag<Tuple3<String, String, Long>>("依琳"){};
        OutputTag<Tuple3<String, String, Long>> linghc = new OutputTag<Tuple3<String, String, Long>>("令狐冲"){};

        SingleOutputStreamOperator<Event> processStream = eventStream.process(new ProcessFunction<Event, Event>() {

            @Override
            public void processElement(Event value, Context ctx, Collector<Event> out) throws Exception {
                if (value.user.equals("依琳")) {
                    ctx.output(yilin, Tuple3.of(value.user, value.url, value.timestamp));
                } else if (value.user.equals("令狐冲")) {
                    ctx.output(linghc, Tuple3.of(value.user, value.url, value.timestamp));
                } else {
                    out.collect(value);
                }
            }
        });
        //获取主流
        processStream.print("  else  ");
        //获取侧输出流
        processStream.getSideOutput(yilin).print();
        processStream.getSideOutput(linghc).print();
        env.execute();
    }
}
复制代码

这里定义了两个侧输出流,分别拣选Mary的浏览事件和Bob的浏览事件;由于类型已经确定,可以只保留(用户id, url, 时间戳)这样一个三元组。而剩余的事件则直接输出到主流,类型依然保留Event,就相当于之前的elseStream。这样的实现方式显然更简洁,也更加灵活。

posted @   晓枫的春天  阅读(505)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示
点击右上角即可分享
微信分享提示