flink窗口

本文探讨了如何在Flink流处理中使用TumblingEventTimeWindows进行WordCount,窗口机制如何改变结果输出模式,使得每个窗口关闭时得到一次计数结果,从而避免了无限流中的重复计数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们知道flink是一个流计算框架,流计算就意味着程序是不知道自己什么时候该结束,所以一般的流程序都是:来了一个元素,得到一个相应的结果。这个特性在做WordCount的时候感受非常清晰,比方说,使用spark或者flink batch模型进行WordCount时,对某个文档的统计结果输出:

(hello, 2)
(flink, 3)

那么如果我们使用flink streaming模型进行处理时,输出的结果很有可能长下面这个样子:

1> (hello, 1)
2> (flink, 1)
1> (hello, 2)
2> (flink, 2)
2> (flink, 3)

为啥会这样呢,因为flink流程需并不直到这个输入的文本流什么时候结束,因此来一个word,就得到一个count结果,将结果写入结果流一次,所以来了多少个word,结果流里面就有多少个count结果。
给出一下flink流进行WordCount的代码:

public class WindowWordCount {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<Tuple2<String, Long>> source = env.fromElements(
                Tuple2.of("hello", 1L),
                Tuple2.of("flink", 1L),
                Tuple2.of("hello", 2L),
                Tuple2.of("spark", 3L),
                Tuple2.of("hello", 4L),
                Tuple2.of("flink", 5L),
                Tuple2.of("spark", 7L));

        DataStream<Tuple2<String, Long>> words = source
                .assignTimestampsAndWatermarks(new TimestampsAndWatermarks())
                .map(new MapFunction<Tuple2<String, Long>, Tuple2<String, Long>>() {
                    @Override
                    public Tuple2<String, Long> map(Tuple2<String, Long> value) throws Exception {
                        return Tuple2.of(value.f0, 1L);
                    }
                });

        words.keyBy(x->x.f0)
                .reduce((ReduceFunction<Tuple2<String, Long>>) (value1,value2)-> Tuple2.of(value1.f0,
                        value1.f1 + value2.f1))
                .print();

        env.execute();
    }

    static class TimestampsAndWatermarks implements WatermarkStrategy<Tuple2<String, Long>> {
        @Override
        public WatermarkGenerator<Tuple2<String, Long>> createWatermarkGenerator(
                WatermarkGeneratorSupplier.Context context) {
            return new WatermarkGenerator<Tuple2<String, Long>>() {
                @Override
                public void onEvent(
                        Tuple2<String, Long> event,
                        long eventTimestamp,
                        WatermarkOutput output) {
                    output.emitWatermark(new Watermark(event.f1-1));
                }

                @Override
                public void onPeriodicEmit(WatermarkOutput output) {
                    return;
                }
            };
        }

        @Override
        public TimestampAssigner<Tuple2<String, Long>> createTimestampAssigner(
                TimestampAssignerSupplier.Context context) {
            return (element, recordTimestamp) -> element.f1;
        }
    }
}

上面的代码产生的结果是:

1> (spark,1)
1> (spark,2)
10> (flink,1)
10> (flink,2)
4> (hello,1)
4> (hello,2)
4> (hello,3)

所以实际上,我决定更贴切的说法是:因为流是没有边界的,流中来个一个事件event,就触发一次相应的计算,得到一个结果。那么我理解的窗口就是:其改变了flink得到结果的方式,为流明确地规定了界限,从来一个元素得到一次相应的结果,变为一个窗口关闭得到一次结果。

我们依然从WordCount举例子,不同的是,我们在这里使用窗口:

words.keyBy(x->x.f0)
        .window(TumblingEventTimeWindows.of(Time.milliseconds(5))) // 窗口跟在keyby后面
        .reduce((ReduceFunction<Tuple2<String, Long>>) (value1,value2)-> Tuple2.of(value1.f0,
                value1.f1 + value2.f1))
        .print();

因为我设置了5ms的滚动窗口,产生了[0,5), [5,10)这两个窗口(窗口的产生规则),那么此时产生的结果就是:

10> (flink,1) // 0~5 ms
10> (flink,1) // 5~10 ms
1> (spark,1) // 0~5 ms
1> (spark,1) // 5~10 ms
4> (hello,3) // 0~5ms

可以看到,flink 变为一个窗口关闭得到一个结果(窗口的关闭由watermark触发,一旦窗口的结束时间小于watermark,窗口就关闭)。

但是需要注意的是,即便我们使用了窗口,reduce方法的计算也是来一个事件计算一次,只是在窗口关闭的时候输出一个结果罢了。也就是说reduce在窗口内也是增量聚合,这很合理,因为这样处理利用流处理的优点,将压力分给了各个时间段,而避免了窗口结束时刻统一计算的热点问题。所以说,窗口仅仅改变了读出结果的方式,而没有改变产生结果的方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

canaryW

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值