36、Flink 的窗口分配器(Assigner)详解

Window Assigners
a)概述

Window assigner 定义了 stream 中的元素如何被分发到各个窗口,可以在 window(...)(用于 keyed streams)或 windowAll(...) (用于 non-keyed streams)中指定一个 WindowAssigner

WindowAssigner 负责将 stream 中的每个数据分发到一个或多个窗口中,Flink 提供了默认的 window assigner,即 tumbling windowssliding windowssession windowsglobal windows ;也可以继承 WindowAssigner 类来实现自定义的 window assigner。

所有内置的 window assigner(除了 global window)都是基于时间分发数据的,processing time 或 event time 均可。

基于时间的窗口用 start timestamp (包含)和 end timestamp (不包含)描述窗口的大小;在代码中,Flink 处理基于时间的窗口使用的是 TimeWindow, 它有查询开始和结束的 timestamp 以及返回窗口所能储存的最大 timestamp 的方法 maxTimestamp()

下图展示了每种 assigner 如何工作,紫色的圆圈代表 stream 中按 key 划分的元素(本例中是按 user 1user 2user 3 划分),x 轴表示时间的进展。

b)滚动窗口(Tumbling Windows)

滚动窗口的 assigner 分发元素到指定大小的窗口,滚动窗口的大小是固定的,且各自范围之间不重叠;如果指定了滚动窗口的大小为 5 分钟,那么每 5 分钟就会有一个窗口被计算,且一个新的窗口被创建。

复制代码
DataStream<T> input = ...;

// 滚动 event-time 窗口
input
    .keyBy(<key selector>)
    .window(TumblingEventTimeWindows.of(Time.seconds(5)))
    .<windowed transformation>(<window function>);

// 滚动 processing-time 窗口
input
    .keyBy(<key selector>)
    .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
    .<windowed transformation>(<window function>);

// 长度为一天的滚动 event-time 窗口, 偏移量为 -8 小时。
input
    .keyBy(<key selector>)
    .window(TumblingEventTimeWindows.of(Time.days(1), Time.hours(-8)))
    .<windowed transformation>(<window function>);

时间间隔可以用 Time.milliseconds(x)Time.seconds(x)Time.minutes(x) 等来指定。

如上一个例子所示,滚动窗口的 assigners 也可以传入可选的 offset 参数 ,这个参数可以用来对齐窗口。 比如说,不设置 offset 时,长度为一小时的滚动窗口会与 linux 的 epoch 对齐,会得到如 1:00:00.000 - 1:59:59.9992:00:00.000 - 2:59:59.999 等。

如果想改变对齐方式,可以设置一个 offset,如果设置了 15 分钟的 offset, 会得到 1:15:00.000 - 2:14:59.9992:15:00.000 - 3:14:59.999 等,一个重要的 offset 用例是根据 UTC-0 调整窗口的时差,在中国可能会设置 offset 为 Time.hours(-8)

c)滑动窗口(Sliding Windows)

与滚动窗口类似,滑动窗口的 assigner 分发元素到指定大小的窗口,窗口大小通过 window size 参数设置,滑动窗口需要一个额外的滑动距离(window slide)参数来控制生成新窗口的频率;如果 slide 小于窗口大小,滑动窗口可以允许窗口重叠,此时一个元素可能会被分发到多个窗口。

举例设置了大小为 10 分钟,滑动距离 5 分钟的窗口,会在每 5 分钟得到一个新的窗口,里面包含之前 10 分钟到达的数据。

复制代码
DataStream<T> input = ...;

// 滑动 event-time 窗口
input
    .keyBy(<key selector>)
    .window(SlidingEventTimeWindows.of(Time.seconds(10), Time.seconds(5)))
    .<windowed transformation>(<window function>);

// 滑动 processing-time 窗口
input
    .keyBy(<key selector>)
    .window(SlidingProcessingTimeWindows.of(Time.seconds(10), Time.seconds(5)))
    .<windowed transformation>(<window function>);

// 滑动 processing-time 窗口,偏移量为 -8 小时
input
    .keyBy(<key selector>)
    .window(SlidingProcessingTimeWindows.of(Time.hours(12), Time.hours(1), Time.hours(-8)))
    .<windowed transformation>(<window function>);

时间间隔可以使用 Time.milliseconds(x)Time.seconds(x)Time.minutes(x) 等来指定。

同滚动窗口的 assigners 一样,也可以传入可选的 offset 参数,用来对齐窗口。

比如说,不设置 offset 时,长度为一小时、滑动距离为 30 分钟的滑动窗口会与 linux 的 epoch 对齐,会得到如 1:00:00.000 - 1:59:59.999, 1:30:00.000 - 2:29:59.999 等;如果想改变对齐方式,可以设置一个 offset。

如果设置了 15 分钟的 offset,会得到 1:15:00.000 - 2:14:59.9991:45:00.000 - 2:44:59.999 等,可以根据 UTC-0 调整窗口的时差,在中国可能会设置 offset 为 Time.hours(-8)

d)会话窗口(Session Windows)

会话窗口 的 assigner 会把数据按活跃的会话分组,与滚动窗口滑动窗口不同,会话窗口不会相互重叠,且没有固定的开始或结束时间。

会话窗口在一段时间没有收到数据之后会关闭,即在一段不活跃的间隔之后,会话窗口的 assigner 可以设置固定的会话间隔(session gap)或用 session gap extractor 函数来动态地定义多长时间算作不活跃;当超出了不活跃的时间段,当前的会话就会关闭,并且将接下来的数据分发到新的会话窗口。

复制代码
DataStream<T> input = ...;

// 设置了固定间隔的 event-time 会话窗口
input
    .keyBy(<key selector>)
    .window(EventTimeSessionWindows.withGap(Time.minutes(10)))
    .<windowed transformation>(<window function>);
    
// 设置了动态间隔的 event-time 会话窗口
input
    .keyBy(<key selector>)
    .window(EventTimeSessionWindows.withDynamicGap((element) -> {
        // 决定并返回会话间隔
    }))
    .<windowed transformation>(<window function>);

// 设置了固定间隔的 processing-time session 窗口
input
    .keyBy(<key selector>)
    .window(ProcessingTimeSessionWindows.withGap(Time.minutes(10)))
    .<windowed transformation>(<window function>);
    
// 设置了动态间隔的 processing-time 会话窗口
input
    .keyBy(<key selector>)
    .window(ProcessingTimeSessionWindows.withDynamicGap((element) -> {
        // 决定并返回会话间隔
    }))
    .<windowed transformation>(<window function>);

固定间隔可以使用 Time.milliseconds(x)Time.seconds(x)Time.minutes(x) 等来设置。

动态间隔可以通过实现 SessionWindowTimeGapExtractor 接口来指定。

原理 :会话窗口并没有固定的开始或结束时间,在 Flink 内部,会话窗口的算子会为每一条数据创建一个窗口, 然后将距离不超过预设间隔的窗口合并;想要让窗口可以被合并,会话窗口需要拥有支持合并的 Trigger 和 Window Function, 比如说 ReduceFunctionAggregateFunctionProcessWindowFunction

f)全局窗口(Global Windows)

全局窗口 的 assigner 将拥有相同 key 的所有数据分发到一个全局窗口,此窗口模式仅在指定了自定义的 trigger 时有用,否则计算不会发生,因为全局窗口没有天然的终点去触发其中积累的数据。

复制代码
DataStream<T> input = ...;

input
    .keyBy(<key selector>)
    .window(GlobalWindows.create())
    .<windowed transformation>(<window function>);
相关推荐
拉姆哥的小屋1 小时前
时间序列早期分类中的置信度累积问题:从ECE-C到时序依赖建模
大数据·人工智能
蚁巡信息巡查系统1 小时前
政府网站与政务新媒体监测服务主要是做什么的?
大数据·人工智能
饼干吖1 小时前
hadoop安装
大数据·hadoop·教程
私域实战笔记4 小时前
选企业微信服务商哪家好?从工具适配与行业案例看选型逻辑
大数据·人工智能·企业微信
AI企微观察4 小时前
企业微信社群运营玩法有哪些?企业微信社群工具有哪些功能?——从拉新到留存的玩法设计与工具支撑
大数据·人工智能
金融小师妹6 小时前
OpenAI拟借AI估值重构浪潮冲击1.1万亿美元IPO——基于市场情绪因子与估值量化模型的深度分析
大数据·人工智能·深度学习·1024程序员节
程序员小羊!6 小时前
Flink(用Scala版本写Word Count 出现假报错情况解决方案)假报错,一直显示红色报错
flink·word·scala
wudl55666 小时前
Flink Keyed State 详解之二
大数据·flink
IT学长编程7 小时前
计算机毕业设计 基于Python的热门游戏推荐系统的设计与实现 Django 大数据毕业设计 Hadoop毕业设计选题【附源码+文档报告+安装调试】
大数据·python·django·毕业设计·课程设计·毕业论文
Ashlee_code8 小时前
什么是TRS收益互换与场外个股期权:从金融逻辑到系统开发实践
大数据·人工智能·python·金融·系统架构·清算·柜台