Flink(四)--DataStream的窗口计算

flink根据上游数据集是否为KeyedStream类型(将数据集按照Key分区),对应的Windows Assigner也会有所不同。上游数据集如果是KeyedStream类型,则调用DataStream API的windows()方法来指定Windows Assigner,数据会根据Key在不同的Task实例中并行分别计算,最后得出针对每个Key的统计结果。如果是Non-Keyed类型,则调用WindowsAll()方法来指定Windows Assigner,所有的数据都会在窗口算子中路由到一个Task中计算,并得到全局统计结果。

flink支持两种类型的窗口,一种是基于时间的窗口,一种是基于数量的窗口。

基于时间的窗口可分为四大类:滚动窗口(Tumbling Windows)、滑动窗口(Sliding Windows)、会话窗口(Session Windows)、全局窗口(Global Windows)。

(1)滚动窗口:根据固定时间或大小进行切分,且窗口和窗口之间的元素互不重叠。

        final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        Properties props = new Properties();
        props.put("bootstrap.servers", "kafka:9092");
        props.put("group.id", "test_flink");

        DataStream input = env.addSource(new FlinkKafkaConsumer010
                ("test", new SimpleStringSchema(), props));
        SingleOutputStreamOperator> map = input.map(new MapFunction>() {
            @Override
            public Tuple2 map(String value) throws Exception {
                String[] strs = value.split(",");
                return new Tuple2<>(strs[0], strs[1]);
            }
        });

        WindowedStream, Tuple, TimeWindow> window = map.keyBy(0).window(TumblingProcessingTimeWindows.of(Time.seconds(10)));
        SingleOutputStreamOperator> process = window.process(new ProcessWindowFunction, Tuple2, Tuple, TimeWindow>() {
            @Override
            public void process(Tuple tuple, Context context, Iterable> elements, Collector> out) throws Exception {
                Iterator> iterator = elements.iterator();
                StringBuffer sb = new StringBuffer();
                String key = null;
                while (iterator.hasNext()){
                    Tuple2 ele = iterator.next();
                    if (key == null){
                        key = ele.f0;
                    }
                    sb.append(ele.f1);
                }
                out.collect(new Tuple2(key,sb.toString()));
            }
        });
        process.print();

kafka输入:

程序输出:

上面是用的TumblingProcessTimeWindows类,也可以

env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime);
WindowedStream, Tuple, TimeWindow> window = map.keyBy(0).timeWindow(Time.seconds(10));

效果是一样的。

如果想使用事件时间,需要指定watermark和timestamp。这篇文章解释的非常清楚。感谢这位作者。

https://blog.csdn.net/xu470438000/article/details/83271123

除了指定watermark和timestamp之外,其他逻辑和上面的代码基本相同。

(2)滑动窗口:允许窗口数据发横重叠。滚动窗口可以看做是窗口大小与滑动步长相等的特殊滑动窗口。

WindowedStream, Tuple, TimeWindow> window = map.keyBy(0).window(SlidingProcessingTimeWindows.of(Time.seconds(10),Time.seconds(5)));

(3)会话窗口:主要用于将某段时间内活跃度较高的数据聚合成一个窗口进行计算。窗口的触发条件是Session Gap,是指在规定的时间内如果没有数据进入窗口,那么就认为窗口结束,触发窗口进行计算。

WindowedStream, Tuple, TimeWindow> window = map.keyBy(0).window(ProcessingTimeSessionWindows.withGap(Time.seconds(10)));

(4)全局窗口:窗口没有起始时间与结束时间,需要借助Triger来触发计算。

基于数量的窗口包括滚动窗口和滑动窗口。

滚动窗口:

WindowedStream, Tuple, GlobalWindow> window = map.keyBy(0).countWindow(5);

滑动窗口:

WindowedStream, Tuple, GlobalWindow> window = map.keyBy(0).countWindow(5,2);

基于数量的窗口本质上是一种全局窗口,触发条件就是窗口中的元素数量是否等于用户传入的参数。

你可能感兴趣的:(flink)