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>);
相关推荐
极客先躯9 分钟前
Hadoop krb5.conf 配置详解
大数据·hadoop·分布式·kerberos·krb5.conf·认证系统
2301_786964363 小时前
3、练习常用的HBase Shell命令+HBase 常用的Java API 及应用实例
java·大数据·数据库·分布式·hbase
matlabgoodboy3 小时前
“图像识别技术:重塑生活与工作的未来”
大数据·人工智能·生活
happycao1234 小时前
Flink 03 | 数据流基本操作
大数据·flink
Neituijunsir4 小时前
2024.09.22 校招 实习 内推 面经
大数据·人工智能·算法·面试·自动驾驶·汽车·求职招聘
Data 3176 小时前
Hive数仓操作(十一)
大数据·数据库·数据仓库·hive·hadoop
qtj-0017 小时前
普通人在刚开始做副业时要注意哪些细节?
大数据·微信·新媒体运营·创业创新
知识分享小能手8 小时前
mysql学习教程,从入门到精通,SQL 修改表(ALTER TABLE 语句)(29)
大数据·开发语言·数据库·sql·学习·mysql·数据分析
a6953188_8 小时前
如何评估一个副业项目的可行性?
大数据·微信·创业创新
州周8 小时前
Flink一点整理
大数据·flink