Flink学习笔记-窗口计算之WindowsAssigner

本文深入探讨Flink中的窗口计算机制,包括KeyedWindows与Non-KeyedWindows的区别,详细解析WindowsAssigner的功能,以及基于时间与数量类型的窗口划分策略。通过实例演示滚动窗口、滑动窗口、会话窗口及全局窗口的应用,同时介绍了自定义窗口类型的方法。

Windows在Flink中作为独立的Operator存在,其可以将无限的数据集按照时间或者长度进行切分,从而完成当前所关心数据的统计计算,满足流计算中相关业务场景。每个窗口算子中,包含了Windows Assigner、Windows Trigger、Evictor、Lateness。OutPutTag以及Windows Function等。其中Windows Assigner和Windows Function是所有窗口算子必须指定的的。

Keyed Windows&Non-Keyed Windows

keyed windows会将数据分区,最后计算出每个key(同一分区)的结果数据,例如:同一用户在某一段时间内的访问频次。而non-keyed则需要调用windowsAll来制定window assigner,所有数据都会在窗口算子中路由到一个Task中进行计算,并得到全局统计结果。
在这里插入图片描述

WindowsAssigner

Windows Assigner的作用是指定窗口的类型,定义如何将数据流分配到一个或者多个窗口,api中通过window (WindowsAssigner assigner)指定。在Flink中支持两种类型的窗口,一种是基于时间的窗口(timeWindow),另一种是基于数量的窗口(countWindow)。窗口所表现出的类型特性取决于window assigner的定义。

Assigner家族
在这里插入图片描述
Flink底层Window模型仅有TimeWindow以及GlobalWindow。
在这里插入图片描述

基于时间类型窗口

基于时间类型的窗口,Flink内置了常用的四种,其中包含:滑动窗口,滚动窗口,会话窗口,全局窗口;其中前三种最终的窗口还是TimeWindow模型,而全局窗口则是GlobalWindow模型。

  • 滚动窗口(Tumbling Windows):根据固定时间或大小进行切分,窗口与窗口之间元素互不重叠。DataStream Api中提供了基于Event Time和process Time两种时间类型的滚动窗口,对应的Assigner分别为TumblingEventTimeWindows,TumblingProcessingTimeWindows。例子如下:
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<Tuple3<String, Integer, Long>> dataStreamSource = env.addSource(new MySourceFunction());
        DataStream<Tuple3<String, Integer, Long>> result = dataStreamSource.keyBy(0).
                window(TumblingEventTimeWindows.of(Time.seconds(10L))).sum(1);

该例中,窗口的时间按照10S进行切分,TumblingProcessingTimeWindows类似。我们还可以通过timeWindow()的方式定义Window Assigner,timeWindow是Flink对时间窗口做的一层封装,如下:
在这里插入图片描述
所以我们只需要指定构建Assigner所需的时间即可,因为时间类型,timeWindow会根据事先设定的时间概念来推断。例子如下:

       StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
        DataStreamSource<Tuple3<String, Integer, Long>> dataStreamSource = env.addSource(new MySourceFunction());
        DataStream<Tuple3<String, Integer, Long>> result = dataStreamSource.keyBy(0).
                timeWindow(Time.seconds(10L)).sum(1);

该例与上述常规window方法指定assigner的效果一样,均为按照事件时间10S切分。

  • 滑动窗口(Sliding Windows):滑动窗口只是在滚动窗口的基础上增加了窗口滑动时间(Slide Time),允许窗口数据发生重叠。简言之,当窗口的size固定之后,窗口会根据给定的Slide Time向前滑动,即窗口之间的数据重叠大小是根据window size和 Slide size来决定的。也就是说有可能会出现窗口不连续,数据可能不在任何一个窗口内,当slide size和windows size相等时,滑动窗口就降级为滚动窗口了。同样的,DataStream Api中也提供了基于Event Time和process Time两种时间类型的滑动窗口,例子如下:
   StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<Tuple3<String, Integer, Long>> dataStreamSource = env.addSource(new MySourceFunction());
        DataStream<Tuple3<String, Integer, Long>> result = dataStreamSource.keyBy(0).
                window(SlidingEventTimeWindows.of(Time.minutes(5),Time.seconds(10))).sum(1);
        result.print();
        env.execute("qingh Demo");

想要使用process Time只需要将例子中SlidingEventTimeWindows改为SlidingProcessingTimeWindows即可。同样滴,例子Flink包装的方式(timeWindow)例子如下:

 StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
        DataStreamSource<Tuple3<String, Integer, Long>> dataStreamSource = env.addSource(new MySourceFunction());
        DataStream<Tuple3<String, Integer, Long>> result = dataStreamSource.keyBy(0).
                timeWindow(Time.minutes(5),Time.seconds(10)).sum(1);
        result.print();
        env.execute("qingh Demo");

通过阅读timeWindow的实现,不难发现,本质上还是调用相应的window,无非就是简化一些操作。
在这里插入图片描述

  • 会话窗口(Session Windows):本质还是TimeWindow,将某段时间内活跃度比较高的数据聚合成一个窗口进行计算,窗口触发的条件是Session Gap,Session Gap规定了不活跃数据的时间上限。会话窗口适用于非连续型数据处理或者周期性产生数据的场景。同样滴,会话窗口也有基于Event Time和process Time两种时间类型的不同实现。 例子如下:
   StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<Tuple3<String, Integer, Long>> dataStreamSource = env.addSource(new MySourceFunction());
        DataStream<Tuple3<String, Integer, Long>> result = dataStreamSource.keyBy(0).
                window(EventTimeSessionWindows.withGap(Time.minutes(10))).sum(1);
        result.print();
        env.execute("qingh Demo");

通过withGap来指定不活跃数据的时间周期(本例10m),想要使用process time只需将EventTimeSessionWindows替换为ProcessingTimeSessionWindows,会话窗口没有类似timeWindow的快捷构造方式

Flink还支持动态调整Session Gap,例子如下:

 StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<Tuple3<String, Integer, Long>> dataStreamSource = env.addSource(new MySourceFunction());
        DataStream<Tuple3<String, Integer, Long>> result = dataStreamSource.keyBy(0).
                window(ProcessingTimeSessionWindows.withDynamicGap(new SessionWindowTimeGapExtractor<Tuple3<String, Integer, Long>>() {
                    @Override
                    public long extract(Tuple3<String, Integer, Long> element) {
                    // 完成动态调整session grap的具体逻辑
                        return element.f2;
                    }
                })).sum(1);
        result.print();
        env.execute("qingh Demo");

实现Flink的SessionWindowTimeGapExtractor动态抽取器,然后复写抽取方法,将抽取器作为参数传入*TimeSessionWindows的withDynamicGap方法中即可完成动态调整Session Gap,具体逻辑在extract中完成。

由于Session Window本质上没有固定的起止时间,因此其底层计算逻辑和滑动、滚动窗口有一定的区别。Session Windows会为每一个进入的数据都创建一个窗口,最后将距离Session Gap最近的窗口进行合并计算窗口结果。因此对于Session Windows来说,需要能够合并的Trigger和Windows Function,比如ReduceFunction,AggregateFunction,ProcessWindowFunction等。

  • 全局窗口(Global Windows):将所有相同key的数据分配到单个窗口中计算结果,窗口没有起始和结束时间,需要借助Triger来触发计算,也就是说如果指定为全局窗口而不指定Triger则窗口是不会触发计算的,同时还需要指定数据清理机制,不然数据将一直存在于内存中。栗子:
	 StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<Tuple3<String, Integer, Long>> dataStreamSource = env.addSource(new MySourceFunction());
        DataStream<Tuple3<String, Integer, Long>> result = dataStreamSource.keyBy(0).
                window(GlobalWindows.create()).sum(1);
        result.print();
        env.execute("qingh Demo");

GlobalWindows负责维护GlobalWindow,通过create构造GlobalWindows,然后在调用assignWindows时,调用assignWindow的get方法获取唯一实例。
在这里插入图片描述
在这里插入图片描述

基于数量类型窗口

基于数量类型的窗口,flink通过GlobalWindows来支持countWindow,通过给GlobalWindows设置CountTrigger来实现滚动的count Window,通过设置CountEvictor,以及CountTrigger来实现滑动的count Windows。

  • 滚动数量类型窗口
    计数触发,栗子:
  StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<Tuple3<String, Integer, Long>> dataStreamSource = env.addSource(new MySourceFunction());
        DataStream<Tuple3<String, Integer, Long>> result = dataStreamSource.keyBy(0).
                countWindow(10).sum(1);
        result.print();
        env.execute("qingh Demo");

其底层实现如图
在这里插入图片描述

  • 滑动数量类型窗口
   StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<Tuple3<String, Integer, Long>> dataStreamSource = env.addSource(new MySourceFunction());
        DataStream<Tuple3<String, Integer, Long>> result = dataStreamSource.keyBy(0).
                countWindow(10,2).sum(1);
        result.print();
        env.execute("qingh Demo");

实现方式
在这里插入图片描述

自定义窗口类型

实现WindowAssigner,复写assignWindows设定窗口类型,复写getDefaultTrigger设定默认触发器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值