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 @ 2022-07-28 14:41  晓枫的春天  阅读(489)  评论(2编辑  收藏  举报