Flink 彻底理解 window窗口(含图解和代码)

本文深入探讨了Flink中的窗口机制,包括窗口的生命周期、Keyed和Non-keyed Window的区别,以及不同类型的窗口如Tumbling Windows、Sliding Windows、Session Windows和Global Windows的使用方法。通过实例展示了如何在数据流上应用这些窗口。

一、描述


Window 是处理无限流的核心。Flink 认为 Batch 是 Streaming 的一个特例,所以 Flink 底层的引擎是一个流式引擎,在上面实现了流处理和批处理。

而窗口(Window)就是从Streaming 到 batch 的一个桥梁。Flink 提供了非常完善的窗口机制,这是 Flink 最大的亮点之一(其他的亮点包括消息乱序处理和 Checkpoint 机制)

二、窗口的生命周期


窗口的生命周期,就是创建和销毁。
窗口的开始时间和结束时间是基于自然时间创建的,比如指定一个5s的窗口,那么1分钟内就会创建12个窗口。
什么时候窗口会被创建?当第一个元素进入到窗口开始时间的时候,这个窗口就被创建了。
什么时候窗口会被销毁?当时间(ProcessTime、EventTime或者 IngestionTime)越过了窗口的结束时间,再加上用户自定义的窗口延迟时间(allowed lateness),窗口就会被销毁。
举个例子来说,假设我们定义了一个基于事件时间的窗口,长度是5分钟,并且允许有1分钟的延迟。
当第一个元素包含了一个12:00的事件时间进来时,Flink会创建一个12:00 到 12:05 的窗口;在水位到 12:06 的时候,会销毁这个窗口。
每个窗口都会绑定一个触发器和一个执行函数。触发器定义了何时会触发窗口的执行函数的计算
比如在窗口元素数量大于等于4的时候,或者水位经过了窗口结束时间的时候。
另外,每个窗口可以指定 驱逐器(Evictor),它的作用是在触发器触发后,执行函数执行前,移除一些元素。

三、Keyed 和 Non-keyed Window


在定义窗口之前,首先要指定你的流是否应该被分区,使用 keyBy(…) 后,相同的 key 会被划分到不同的流里面,每个流可以被一个单独的 task 处理。如果 不使用 keyBy ,所有数据会被划分到一个窗口里,只有一个task处理,并行度是1

四、窗口的分类和选择


在指定了数据流是否分区之后,下一步是要去指定窗口的类型。窗口分配器(window assigner)定义了元素如何划分到不同的窗口中。
对于 keyed Streams,使用 window (…) 来定义,对于 非 keyed Streams,使用 windowAll(…)来定义。
Flink 预定义了很多种窗口类型,可以满足大多数日常使用需求:tumbling windows(翻滚窗口), sliding windows(滑动窗口), session windows(会话窗口) and global windows(全局窗口)。
所有内置的窗口(除了全局窗口)都是基于时间(ProcessTime或 EventTime)的。

1、Tumbling Windows
翻滚窗口有一个固定的长度,并且不会重复。比如,下图是指定了一个5分钟的翻滚窗口的样子:
在这里插入图片描述
(每个窗口都不重叠,每5分钟一个窗口)


// 例子1:tumbling event-time windows
// 定义一个数据流
val input: DataStream[T] = ...
// 这里的 key selector,如果是元组的化,可以使用_._1,如果是case class 可以使用字段名来指定
input
    .keyBy(<key selector>)
// 指定了一个TumblingEventTimeWindows,窗口大小为5分钟
    .window(TumblingEventTimeWindows.of(Time.seconds(5)))
// 窗口的操作
    .<windowed transformation>(<window function>)

// 例子2:tumbling processing-time windows
input
    .keyBy(<key selector>)
    .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
    .<windowed transformation>(<window function>)

// 例子3:daily tumbling event-time windows offset by -8 hours.
// 
input
    .keyBy(<key selector>)
    .window(TumblingEventTimeWindows.of(Time.days(1), Time.hours(-8)))
    .<windowed transformation>(<window function>)

在例子3中,TumblingEventTimeWindows.of 指定了第二个参数 offset,它的作用是改变窗口的时间。

如果我们指定了一个15分钟的窗口,那么每个小时内,每个窗口的开始时间和结束时间为:

[00:00,00:15)

[00:15,00:30)

[00:30,00:45)

[00:45,01:00)

如果我们指定了一个5分钟的offset,那么每个窗口的开始时间和结束时间为:

[00:05,00:20)

[00:20,00:35)

[00:35,00:50)

[00:50,01:05)

一个实际的应用场景是,我们可以使用 offset 使我们的时区以0时区为准。比如我们生活在中国,时区是

UTC+08:00,可以指定一个 Time.hour(-8),使时间以0时区为准。

2、Slidding Windows
滑动窗口指定了两个参数,第一个参数是窗口大小,第二个参数控制了新的窗口开始的频率。
如果 滑动距离小于窗口距离的话,那么一个元素可能被分配到多个窗口中。
比如,窗口大小10分钟,每5分钟滑动一次,如下图:
在这里插入图片描述

val input: DataStream[T] = ...

// 例子1:sliding event-time windows
input
    .keyBy(<key selector>)
    .window(SlidingEventTimeWindows.of(Time.seconds(10), Time.seconds(5)))
    .<windowed transformation>(<window function>)

// 例子2:sliding processing-time windows
input
    .keyBy(<key selector>)
    .window(SlidingProcessingTimeWindows.of(Time.seconds(10), Time.seconds(5)))
    .<windowed transformation>(<window function>)

// 例子3,sliding processing-time windows offset by -8 hours
input
    .keyBy(<key selector>)
    .window(SlidingProcessingTimeWindows.of(Time.hours(12), Time.hours(1), Time.hours(-8)))
    .<windowed transformation>(<window function>)

3、Session Windows
会话窗口根据会话的间隔来把数据分配到不同的窗口。
会话窗口不重叠,没有固定的开始时间和结束时间。
比如音乐 app 听歌的场景,我们想统计一个用户在一个独立的 session 中听了多久的歌曲(如果超过15分钟没听歌,那么就是一个新的 session 了)
我们可以用 spark Streaming ,每一个小时进行一次批处理,计算用户session的数据分布,但是 spark Streaming 没有内置对 session 的支持,我们只能手工写代码来维护每个 user 的 session 状态,里面仍然会有诸多的问题。
下一次会单独写一篇文章来讨论,如何使用flink 的 session window 来实现这个问题

4、Global Windows

全局 window 把所有相同 key 的数据,放到一个 window 来,它没有自然的窗口结束时间,所以我们需要自己指定触发器

val input: DataStream[T] = ...

input
    .keyBy(<key selector>)
    .window(GlobalWindows.create())
    .<windowed transformation>(<window function>)

欢迎加群学习:797853299
资料多,大佬多,学习氛围好!

<think>好的,用户想理解Flink中的水位线窗口机制,需要详细解释示例。首先我得回忆下Flink的基本概念,水位线(Watermark)是用来处理事件时间乱序的机制,而窗口则是将无限数据流切分成有限块进行处理的方式。用户可能已经有一些流处理的基础,但需要更深入的机制解析。 根据用户提供的引用内容,我需要整合这些信息。比如引用[4]提到水位线是插入到数据流中的特殊标记,时间戳单调递增,并且可以设置延迟处理乱序数据。而窗口部分,引用[2][3]分别解释了滑动窗口滚动窗口的分配方式。用户给的示例中提到了水位线如何触发窗口关闭,比如事件15导致水位线超过窗口结束时间,从而关闭窗口,这需要详细说明。 用户可能想知道水位线窗口是如何协同工作的,特别是水位线如何影响窗口的触发数据的延迟处理。比如引用[1]中的例子,水位线延迟允许处理晚到的数据,避免数据被丢弃。这部分需要结合水位线的生成窗口的lateness属性来解释。 另外,用户可能需要实际代码示例来理解如何应用这些概念。引用[3]中有代码片段关于创建滚动窗口,可以引用并扩展,展示如何设置水位线延迟窗口函数。同时,要确保示例符合用户提到的使用$$...$$格式,比如数学公式的正确排版。 还需要考虑用户可能的疑问点,比如水位线的时间戳计算、窗口的类型(滚动、滑动、会话)、窗口分配器的作用等。需要分步骤解释,从水位线生成到窗口触发,再到数据处理,确保逻辑清晰。 最后,生成相关问题时要围绕核心概念,比如水位线延迟的影响、不同窗口类型的适用场景、如何优化水位线设置等,帮助用户进一步深入学习。同时,引用标记要正确添加,比如在解释水位线延迟时引用[1][4]。 总结下,回答的结构应该是先解释水位线窗口的基本概念,再详细说明它们的工作原理协同过程,接着给出代码示例,最后总结关键点。过程中需要引用提供的材料,确保信息准确,并且用中文简洁明了地表达。</think>### Flink水位线与窗口机制解析 #### 一、水位线(Watermark)核心特性 1. **时间戳标记**:水位线是嵌入数据流的特殊标记,携带时间戳$T$,表示事件时间进展到$T$[^4] 2. **乱序处理**:通过延迟设置(如允许5秒延迟)处理迟到数据,水位线时间戳计算方式为: $$ Watermark = max(当前事件时间) - 延迟时间 $$ 3. **单调递增**:确保事件时间始终向前推进,避免时间回退导致逻辑错误[^4] #### 二、窗口机制类型 | 窗口类型 | 特点描述 | 数学表达式示例 | |------------------|--------------------------------------------------------------------------|-----------------------------| | 滚动窗口 | 无重叠区间,固定时间划分 | $[t_0, t_0+5s)$ | | 滑动窗口 | 允许重叠区间,定义窗口大小与滑动步长 | 窗口大小=2s,滑动步长=1s[^2] | | 会话窗口 | 根据数据活跃度动态划分 | 会话间隔>阈值时分割 | #### 三、协同工作原理 1. **窗口生命周期** - 创建:数据首次进入窗口范围时生成 - 关闭:当水位线$T_w \geq 窗口结束时间T_{end}$时触发[^1] 2. **迟到数据处理** 通过`allowedLateness`设置额外容忍延迟: ```java .window(TumblingEventTimeWindows.of(Time.seconds(5))) .allowedLateness(Time.seconds(2)) ``` #### 四、完整代码示例(事件时间处理) ```java DataStream<Tuple2<String, Long>> input = ...; DataStream<Tuple2<String, Long>> result = input .assignTimestampsAndWatermarks( WatermarkStrategy.<Tuple2<String, Long>>forBoundedOutOfOrderness(Duration.ofSeconds(5)) .withTimestampAssigner((event, timestamp) -> event.f1)) .keyBy(event -> event.f0) .window(TumblingEventTimeWindows.of(Time.seconds(10))) .allowedLateness(Time.seconds(3)) .reduce((a, b) -> new Tuple2<>(a.f0, a.f1 + b.f1)); ``` #### 五、关键过程解析 1. **水位线触发条件** 当事件21(时间戳22:07:16)到达时: $$ Watermark = 22:07:16 - 5s = 22:07:11 > 窗口结束时间22:07:10 $$ 触发窗口关闭并输出计算结果[^1] 2. **延迟窗口关闭优势** 事件13(时间戳22:07:08)虽晚于窗口理论关闭时间,但因水位线延迟设置仍被正确处理[^1] #### 六、配置优化建议 1. 根据网络延迟情况设置合理的水位线延迟 2. 使用`sideOutputLateData`捕获超时数据进行分析 3. 会话窗口适用于用户行为分析等非固定时间间隔场景
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值