【源码解析】Flink 滑动窗口数据分配到多个窗口
之前一直用翻滚窗口,每条数据都只属于一个窗口,所有不需要考虑数据需要在多个窗口存的事情。
刚好有个需求,要用到滑动窗口,来翻翻 flink 在滑动窗口中,数据是怎么分配到多个窗口的
一段简单的测试代码:
val input = env.addSource(kafkaSource)
val stream = input
.map(node => {
Event(node.get("id").asText(), node.get("createTime").asText())
})
.windowAll(SlidingProcessingTimeWindows.of(Time.minutes(1), Time.seconds(10)))
.process(new ProcessAllWindowFunction[Event, Event, TimeWindow] {
override def process(context: Context, elements: Iterable[Event], out: Collector[Event]): Unit = {
val it = elements.iterator
var xx: Event = null
while (it.hasNext) {
xx = it.next()
}
out.collect(xx)
}
})
stream.print()
定义了一个长度为1分钟,滑动距离 10秒的窗口,所以正常每条数据应该对应 6 个窗口
在 process 中打个断点就可以追这段处理的源码了
数据的流向和 TumblingEventTimeWindows 是一样的,所以直接跳到对应数据分配的地方
WindowOperator.processElement,代码比较长,这里就精简一部分
@Override
public void processElement(StreamRecord<IN> element) throws Exception {
// 对应的需要分配的窗口
final Collection<W> elementWindows = windowAssigner.assignWindows(
element.getValue(), element.getTimestamp(), windowAssignerContext); //if element is handled by none of assigned elementWindows
boolean isSkippedElement = true; final K key = this.<K>getKeyedStateBackend().getCurrentKey(); if (windowAssigner instanceof MergingWindowAssigner) { } else {
// 循环遍历,将数据放到对应的窗口状态的 namesspace 中
for (W window: elementWindows) { // drop if the window is already late
if (isWindowLate(window)) {
continue;
}
isSkippedElement = false;
// 将数据放到对应的窗口中
windowState.setCurrentNamespace(window);
windowState.add(element.getValue()); registerCleanupTimer(window);
}
} }
for 循环就是将数据放到多个窗口的循环,看下 dubug 信息

看对应的6个窗口,从后往前的
窗口分配的代码,就对应这个方法的第一句:
final Collection<W> elementWindows = windowAssigner.assignWindows(
element.getValue(), element.getTimestamp(), windowAssignerContext);
assignWindows 的源码是根据 windowAssigner 的不同而改变的,这里是: SlidingProcessingTimeWindows,对应源码:
@Override
public Collection<TimeWindow> assignWindows(Object element, long timestamp, WindowAssignerContext context) {
timestamp = context.getCurrentProcessingTime();
List<TimeWindow> windows = new ArrayList<>((int) (size / slide));
long lastStart = TimeWindow.getWindowStartWithOffset(timestamp, offset, slide);
for (long start = lastStart;
start > timestamp - size;
start -= slide) {
windows.add(new TimeWindow(start, start + size));
}
return windows;
}
有个list 存储对应的窗口时间对象,list 的长度就是 窗口的长度 / 滑动的距离 (即一条数据会出现在几个窗口中)
这里用的是处理时间,所有Timestamp 直接从 处理时间中取,数据对应的 最后一个窗口的开始时间 lastStart 就用处理时间传到TimeWindow.getWindowStartWindOffset 中做计算
算出最后一个窗口的开始时间后,减 滑动的距离,就是上一个窗口的开始时间,直到 窗口的开始时间超出窗口的范围
对应的关键就是 lastStart 的计算,看源码:
/**
* Method to get the window start for a timestamp.
*
* @param timestamp epoch millisecond to get the window start.
* @param offset The offset which window start would be shifted by.
* @param windowSize The size of the generated windows.
* @return window start
*/
public static long getWindowStartWithOffset(long timestamp, long offset, long windowSize) {
return timestamp - (timestamp - offset + windowSize) % windowSize;
}
没指定 offset ,所以 offset 为0, lastStart = timestamp - (timestamp - offset + windowSize) % windowSize
windowSize 是 滑动的距离,这里画了个图来说明计算的公式:

算出最后一个窗口的时间后,下面的 for 循环计算出数据对应的所有窗口,并创建一个时间窗口(这个时间窗口,并不是一个窗口,只是窗口的时间,表达一个窗口的开始时间和结束时间)
long lastStart = TimeWindow.getWindowStartWithOffset(timestamp, offset, slide);
for (long start = lastStart;
start > timestamp - size;
start -= slide) {
windows.add(new TimeWindow(start, start + size));
}
所以 17 对应的这条数据对应的窗口就有 (10-20), (15,25)
一条数据属于多少个窗口分配好了以后,就是把数据放到对应的窗口中了,flink 的窗口对应 state 的 namespace , 所以放到多个窗口,就是放到多个 namespace 中,对应的代码是:
windowState.setCurrentNamespace(window);
windowState.add(element.getValue());
选择 namespace,把数据放到对应的 state 中,后面窗口 fire 的时候,会从对应的 namespace 中 get 数据
欢迎关注Flink菜鸟公众号,会不定期更新Flink(开发技术)相关的推文

【源码解析】Flink 滑动窗口数据分配到多个窗口的更多相关文章
- [源码解析] Flink UDAF 背后做了什么
[源码解析] Flink UDAF 背后做了什么 目录 [源码解析] Flink UDAF 背后做了什么 0x00 摘要 0x01 概念 1.1 概念 1.2 疑问 1.3 UDAF示例代码 0x02 ...
- [源码解析] Flink的groupBy和reduce究竟做了什么
[源码解析] Flink的groupBy和reduce究竟做了什么 目录 [源码解析] Flink的groupBy和reduce究竟做了什么 0x00 摘要 0x01 问题和概括 1.1 问题 1.2 ...
- [源码解析] Flink的Slot究竟是什么?(1)
[源码解析] Flink的Slot究竟是什么?(1) 目录 [源码解析] Flink的Slot究竟是什么?(1) 0x00 摘要 0x01 概述 & 问题 1.1 Fllink工作原理 1.2 ...
- [源码解析] Flink的Slot究竟是什么?(2)
[源码解析] Flink 的slot究竟是什么?(2) 目录 [源码解析] Flink 的slot究竟是什么?(2) 0x00 摘要 0x01 前文回顾 0x02 注册/更新Slot 2.1 Task ...
- Flink 源码解析 —— Flink JobManager 有什么作用?
JobManager 的作用 https://t.zsxq.com/2VRrbuf 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Mac ...
- Flink 源码解析 —— Flink TaskManager 有什么作用?
TaskManager 有什么作用 https://t.zsxq.com/RZbu7yN 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- ...
- [源码解析] PyTorch 分布式(1) --- 数据加载之DistributedSampler
[源码解析] PyTorch 分布式(1) --- 数据加载之DistributedSampler 目录 [源码解析] PyTorch 分布式(1) --- 数据加载之DistributedSampl ...
- [源码解析] PyTorch 分布式(2) --- 数据加载之DataLoader
[源码解析] PyTorch 分布式(2) --- 数据加载之DataLoader 目录 [源码解析] PyTorch 分布式(2) --- 数据加载之DataLoader 0x00 摘要 0x01 ...
- Fresco源码解析 - DataSource怎样存储数据
Fresco源码解析 - DataSource怎样存储数据 datasource是一个独立的 package,与FB导入的guava包都在同一个工程内 - fbcore. datasource的类关系 ...
随机推荐
- drf框架 - 序列化组件 | ModelSerializer (查,增,删,改)
ModelSerializer 序列化准备: 配置 settings.py # 注册rest_framework框架 INSTALLED_APPS = [ ... 'rest_framework' ] ...
- 0.0.Pycharm使用技巧
调整自动字体大小 Increase(字体变大) Decrease(字体变小) 背景颜色设置 pycharm 左侧菜单问题 解决 pycharm中配置启动Django项目 1.先打开mange.py,然 ...
- COM Error---HRESULT
一.COM Error 调用COM接口产生的错误.几乎所有的COM函数和接口方法都返回类型为HRESULT的值.HRESULT(用于结果句柄)是返回成功.警告和错误值的一种方法.HRESULTs实际上 ...
- apt-get 和dpkg命令
软件包下载:apt-get 1.apt-get install vim 下载vim 2.apt-get upgrade vim 升级vim 3.apt-get update 列出更新 debian软 ...
- leetcode解题报告(31):Kth Largest Element in an Array
描述 Find the kth largest element in an unsorted array. Note that it is the kth largest element in the ...
- 2017.10.7 国庆清北 D7T2 第k大区间
题目描述 定义一个长度为奇数的区间的值为其所包含的的元素的中位数. 现给出n个数,求将所有长度为奇数的区间的值排序后,第K大的值为多少. 输入输出格式 输入格式: 输入文件名为kth.in. 第一行两 ...
- (8)打鸡儿教你Vue.js
监听属性 监听属性 watch 通过 watch 来响应数据的变化 <div id = "app"> <p style = "font-size:25p ...
- Beego没gin配置静态页面方便
上代码 腾讯这个例子还是很值得学习的,不轻有东西,单也不重到看着都蒙圈的样子. https://github.com/Tencent/bk-cmdb/blob/master/src/web_serve ...
- vs code 修改选中后匹配的代码的颜色
打开设置文件 输入 { "workbench.colorCustomizations": { "editor.selectionBackground": &qu ...
- C平衡二叉树(AVL)创建和删除
AVL是最先发明的自平衡二叉查找树算法.在AVL中任何节点的两个儿子子树的高度最大差别为一,所以它也被称为高度平衡树,n个结点的AVL树最大深度约1.44log2n.查找.插入和删除在平均和最坏情况下 ...