【源码解析】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的类关系 ...
随机推荐
- LightOJ - 1369 - Answering Queries(规律)
链接: https://vjudge.net/problem/LightOJ-1369 题意: The problem you need to solve here is pretty simple. ...
- 2019-2020-1 20199302《Linux内核原理与分析》第三周作业
云班课学习内容 一.C语言中嵌入汇编代码 1.内嵌汇编语法 (1)C语言中嵌入汇编代码的写法: asm( 汇编语句模板: 输出部分: 输入部分: 破坏描述部分): 说明:输出部分和输入部分对应着C语言 ...
- JQuery通过click事件获取当前点击对象的id,name,value属性等
$(".test").click(function () { var val=$(this).attr("id"); })
- CDH 大数据平台搭建
一.概述 Cloudera版本(Cloudera’s Distribution Including Apache Hadoop,简称“CDH”),基于Web的用户界面,支持大多数Hadoop组件,包括 ...
- Go Node.js 生成的exe公布成windows服务
环境变量 GOBIN E:\01_SOFT\go1.9.2\bin GOROOT E:\01_SOFT\go1.9.2 GOPATH(下载包的存放位置:go get github.com/gin-go ...
- 在运维中的shell经验总结
来自良许Linux公众号 编写 脚本开头部分应有脚本功能说明.参数使用说明.作者姓名.创建/修改日期.版本信息,格式为: 脚本编写时,注意格式对齐,如所有的循环或者判断语句前后的语句进行对齐,以及ca ...
- sed、awk命令速查
awk与sed.grep一样都是为了加工数据流而做成的文本加工过滤器命令.awk会事先把输入的数据根据字段单位进行分割.在没有指定分割单位的情况下,以输入数据中的空格或Tab为分隔符.与sed相比,它 ...
- (4)Angular的开发
angular框架,库,是一款非常优秀的前端高级JS框架,有了这个框架就可以轻松构建SPA应用程序,通过指令宽展了HTML,通过表达式绑定数据到HTML. 轻松构建SPA应用程序,单一页面应用程序 h ...
- macos high sierra 删除多余的管理员的步骤
自己查看了好多文档, 一个比较可靠的地址有两个,不过发现跟我的不一样, 我没有采用. 也在这里贴出来, 供需要的"折腾者"们看看. [某个外国大大的方法] (https://med ...
- [昆仑会员卡系统]老会员数据导入 从临时表插入会员至member_info_svc表 SQL
第一版无UUID版本 从临时表插入会员至member_info_svc表 insert into member_info_svc ( gh_no,chname,sex,birthday,tel,ema ...