之前一直用翻滚窗口,每条数据都只属于一个窗口,所有不需要考虑数据需要在多个窗口存的事情。

刚好有个需求,要用到滑动窗口,来翻翻 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 滑动窗口数据分配到多个窗口的更多相关文章

  1. [源码解析] Flink UDAF 背后做了什么

    [源码解析] Flink UDAF 背后做了什么 目录 [源码解析] Flink UDAF 背后做了什么 0x00 摘要 0x01 概念 1.1 概念 1.2 疑问 1.3 UDAF示例代码 0x02 ...

  2. [源码解析] Flink的groupBy和reduce究竟做了什么

    [源码解析] Flink的groupBy和reduce究竟做了什么 目录 [源码解析] Flink的groupBy和reduce究竟做了什么 0x00 摘要 0x01 问题和概括 1.1 问题 1.2 ...

  3. [源码解析] Flink的Slot究竟是什么?(1)

    [源码解析] Flink的Slot究竟是什么?(1) 目录 [源码解析] Flink的Slot究竟是什么?(1) 0x00 摘要 0x01 概述 & 问题 1.1 Fllink工作原理 1.2 ...

  4. [源码解析] Flink的Slot究竟是什么?(2)

    [源码解析] Flink 的slot究竟是什么?(2) 目录 [源码解析] Flink 的slot究竟是什么?(2) 0x00 摘要 0x01 前文回顾 0x02 注册/更新Slot 2.1 Task ...

  5. Flink 源码解析 —— Flink JobManager 有什么作用?

    JobManager 的作用 https://t.zsxq.com/2VRrbuf 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Mac ...

  6. Flink 源码解析 —— Flink TaskManager 有什么作用?

    TaskManager 有什么作用 https://t.zsxq.com/RZbu7yN 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- ...

  7. [源码解析] PyTorch 分布式(1) --- 数据加载之DistributedSampler

    [源码解析] PyTorch 分布式(1) --- 数据加载之DistributedSampler 目录 [源码解析] PyTorch 分布式(1) --- 数据加载之DistributedSampl ...

  8. [源码解析] PyTorch 分布式(2) --- 数据加载之DataLoader

    [源码解析] PyTorch 分布式(2) --- 数据加载之DataLoader 目录 [源码解析] PyTorch 分布式(2) --- 数据加载之DataLoader 0x00 摘要 0x01 ...

  9. Fresco源码解析 - DataSource怎样存储数据

    Fresco源码解析 - DataSource怎样存储数据 datasource是一个独立的 package,与FB导入的guava包都在同一个工程内 - fbcore. datasource的类关系 ...

随机推荐

  1. to_excel

    Signature: df.to_excel( ['excel_writer', "sheet_name='Sheet1'", "na_rep=''", 'fl ...

  2. JS+rem,移动端适配

    window.onresize = function () { setHtmlFz(); } setHtmlFz(); function setHtmlFz() { // 基础值 var baseVa ...

  3. cocoapods安装错误的原因

    gem 可以理解为管理RUBY库和程序包的查找,安装,升级和卸载是个非常好用的工具. gem install cocoapods过程中出现错误的问题.1.gem的源设置错误应该参照,下面来执行gem ...

  4. PDB符号文件

    一.什么是PDB文件 PDB(Program DataBase),全称为“程序数据库”文件.存储程序的所有调试信息数据.在编译连接时,如果选择了/debug选项或/debug:full选项,则最新的M ...

  5. Linux下搭建iSCSI共享存储的方法 TGT 方式 CentOS6.9系统下

    iSCSI(internet SCSI)技术由IBM公司研究开发,是一个供硬件设备使用的.可以在IP协议的上层运行的SCSI指令集,这种指令集合可以实现在IP网络上运行SCSI协议,使其能够在诸如高速 ...

  6. COGS 1151 活动安排

    - 有 N 场活动,每场活动在特定的时间需要占用场地. - 如果有两场活动需要同一时间占用场地,则不能同时举行 - 问最多能举行多少场活动? 将所有活动按照结束时间从早到晚排序后贪心即可 具体思路看代 ...

  7. 红黑树 ------ luogu P3369 【模板】普通平衡树(Treap/SBT)

    二次联通门 : luogu P3369 [模板]普通平衡树(Treap/SBT) 近几天闲来无事...就把各种平衡树都写了一下... 下面是红黑树(Red Black Tree) 喜闻乐见拿到了luo ...

  8. 再做一遍floyed

    #include<bits/stdc++.h> #define R register int using namespace std; const int inf=0x3f3f3f3f; ...

  9. Pytest权威教程21-API参考-02-标记(Marks)

    目录 标记(Marks) pytest.mark.filterwarnings pytest.mark.parametrize pytest.mark.skip pytest.mark.skipif ...

  10. CStatic 控件设置文本,不能重回问题

    CStatic m_page_text_; m_page_text_.SetWindowText(str); CRect rt; m_page_text_.GetWindowRect(&rt) ...