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>);
相关推荐
web135085886351 小时前
9. 大数据集群(PySpark)+Hive+MySQL+PyEcharts+Flask:信用贷款风险分析与预测
大数据·hive·mysql
神秘打工猴9 小时前
Flink 集群有哪些⻆⾊?各⾃有什么作⽤?
大数据·flink
小刘鸭!9 小时前
Flink的三种时间语义
大数据·flink
天冬忘忧9 小时前
Flink优化----FlinkSQL 调优
大数据·sql·flink
LinkTime_Cloud9 小时前
GitLab 将停止为中国区用户提供服务,60天迁移期如何应对? | LeetTalk Daily
大数据·运维·gitlab
寒暄喆意10 小时前
智慧农业物联网传感器:开启农业新时代
大数据·人工智能·科技·物联网
m0_5485030310 小时前
Flink基本原理 + WebUI说明 + 常见问题分析
大数据·flink
kaoyaoyao10 小时前
小程序评论分数提高,提升用户参与感和忠诚度
大数据·小程序·seo·评论·小程序评分
乌龟跌倒12 小时前
磁盘结构、访问时间、调度算法
大数据
神秘打工猴14 小时前
Spark任务的执⾏流程
大数据·分布式·spark