WindowOperator.processElement

主要的工作,将当前的element的value加到对应的window中,

            windowState.setCurrentNamespace(window);
windowState.add(element.getValue()); triggerContext.key = key;
triggerContext.window = window; TriggerResult triggerResult = triggerContext.onElement(element);

 

调用triggerContext.onElement

这里的Context只是一个简单的封装,

        public TriggerResult onElement(StreamRecord<IN> element) throws Exception {
return trigger.onElement(element.getValue(), element.getTimestamp(), window, this);
}

 

EventTimeTrigger

onElement

    @Override
public TriggerResult onElement(Object element, long timestamp, TimeWindow window, TriggerContext ctx) throws Exception {
if (window.maxTimestamp() <= ctx.getCurrentWatermark()) {
// if the watermark is already past the window fire immediately
return TriggerResult.FIRE;
} else {
ctx.registerEventTimeTimer(window.maxTimestamp());
return TriggerResult.CONTINUE;
}
}

如果当前window.maxTimestamp已经小于CurrentWatermark,直接触发

否则将window.maxTimestamp注册到TimeService中,等待触发

 

WindowOperator.Context

        public void registerEventTimeTimer(long time) {
internalTimerService.registerEventTimeTimer(window, time);
}

 

InternalTimerService
 
在AbstractStreamOperator
public abstract class AbstractStreamOperator<OUT>
implements StreamOperator<OUT>, Serializable, KeyContext {
注意这里实现了KeyContext 
所以AbstractStreamOperator实现了
    public Object getCurrentKey() {
if (keyedStateBackend != null) {
return keyedStateBackend.getCurrentKey();
} else {
throw new UnsupportedOperationException("Key can only be retrieven on KeyedStream.");
}
}
 
在AbstractStreamOperator初始化InternalTimeServiceManager
private transient InternalTimeServiceManager<?, ?> timeServiceManager;
@Override
public final void initializeState(OperatorStateHandles stateHandles) throws Exception { if (getKeyedStateBackend() != null && timeServiceManager == null) {
timeServiceManager = new InternalTimeServiceManager<>(
getKeyedStateBackend().getNumberOfKeyGroups(),
getKeyedStateBackend().getKeyGroupRange(),
this,
getRuntimeContext().getProcessingTimeService());
}

 

WindowOperator中InternalTimerService初始化,
internalTimerService =
getInternalTimerService("window-timers", windowSerializer, this);

在AbstractStreamOperator调用,

    public <K, N> InternalTimerService<N> getInternalTimerService(
String name,
TypeSerializer<N> namespaceSerializer,
Triggerable<K, N> triggerable) { checkTimerServiceInitialization(); // the following casting is to overcome type restrictions.
TypeSerializer<K> keySerializer = (TypeSerializer<K>) getKeyedStateBackend().getKeySerializer();
InternalTimeServiceManager<K, N> keyedTimeServiceHandler = (InternalTimeServiceManager<K, N>) timeServiceManager;
return keyedTimeServiceHandler.getInternalTimerService(name, keySerializer, namespaceSerializer, triggerable);
}

其实就是调用InternalTimeServiceManager.getInternalTimerService

最终得到HeapInternalTimerService

 

HeapInternalTimerService.registerEventTimeTimer
    @Override
public void registerEventTimeTimer(N namespace, long time) {
InternalTimer<K, N> timer = new InternalTimer<>(time, (K) keyContext.getCurrentKey(), namespace);
Set<InternalTimer<K, N>> timerSet = getEventTimeTimerSetForTimer(timer);
if (timerSet.add(timer)) {
eventTimeTimersQueue.add(timer);
}
}

创建InternalTimer,包含,time(window.maxTimestamp), key(keyContext.getCurrentKey), namespace(window)

 

getEventTimeTimerSetForTimer

    private Set<InternalTimer<K, N>> getEventTimeTimerSetForTimer(InternalTimer<K, N> timer) {
checkArgument(localKeyGroupRange != null, "The operator has not been initialized.");
int keyGroupIdx = KeyGroupRangeAssignment.assignToKeyGroup(timer.getKey(), this.totalKeyGroups);
return getEventTimeTimerSetForKeyGroup(keyGroupIdx);
}
    private Set<InternalTimer<K, N>> getEventTimeTimerSetForKeyGroup(int keyGroupIdx) {
int localIdx = getIndexForKeyGroup(keyGroupIdx);
Set<InternalTimer<K, N>> timers = eventTimeTimersByKeyGroup[localIdx];
if (timers == null) {
timers = new HashSet<>();
eventTimeTimersByKeyGroup[localIdx] = timers;
}
return timers;
}

先找到key所对应的,keygroup,每个keygroup对应于一个Timer集合

这样设计的目的,因为最终timer也是要checkpoint的,而checkpoint的最小单位是keygroup,所以不同keygroup所对应的timer需要分离开

最终把timer加到eventTimeTimersQueue,

private final PriorityQueue<InternalTimer<K, N>> eventTimeTimersQueue;

PriorityQueue是堆实现的,所以只要在InternalTimer里面实现compareTo,就可以让timer排序

AbstractStreamOperator.processWatermark

   public void processWatermark(Watermark mark) throws Exception {
if (timeServiceManager != null) {
timeServiceManager.advanceWatermark(mark);
}
output.emitWatermark(mark);
}

timeServiceManager.advanceWatermark

    public void advanceWatermark(Watermark watermark) throws Exception {
for (HeapInternalTimerService<?, ?> service : timerServices.values()) {
service.advanceWatermark(watermark.getTimestamp());
}
}

HeapInternalTimerService.advanceWatermark

    public void advanceWatermark(long time) throws Exception {
currentWatermark = time; InternalTimer<K, N> timer; while ((timer = eventTimeTimersQueue.peek()) != null && timer.getTimestamp() <= time) { Set<InternalTimer<K, N>> timerSet = getEventTimeTimerSetForTimer(timer);
timerSet.remove(timer);
eventTimeTimersQueue.remove(); keyContext.setCurrentKey(timer.getKey());
triggerTarget.onEventTime(timer);
}
}

从eventTimeTimersQueue从小到大取timer,如果小于传入的water mark,那么说明这个window需要触发

设置operater的current key,keyContext.setCurrentKey(timer.getKey())

这里注意watermarker是没有key的,所以当一个watermark来的时候是会触发所有timer,而timer的key是不一定的,所以这里一定要设置keyContext,否则就乱了

最终触发triggerTarget.onEventTime

triggerTarget就是WindowOperator

WindowOperator.onEventTime

        windowState.setCurrentNamespace(triggerContext.window);

        ACC contents = null;
if (windowState != null) {
contents = windowState.get();
} if (contents != null) {
TriggerResult triggerResult = triggerContext.onEventTime(timer.getTimestamp());
if (triggerResult.isFire()) {
emitWindowContents(triggerContext.window, contents);
}
if (triggerResult.isPurge()) {
windowState.clear();
}
}

这里调用triggerContext.onEventTime,得到TriggerResult

如果fire,走到这,这个肯定满足的,emitWindowContents

如果purge,就把windowState清空

emitWindowContents,调用用户定义的windowFunction来处理window的contents

    private void emitWindowContents(W window, ACC contents) throws Exception {
timestampedCollector.setAbsoluteTimestamp(window.maxTimestamp());
processContext.window = window;
userFunction.process(triggerContext.key, window, processContext, contents, timestampedCollector);
}

Flink – process watermark的更多相关文章

  1. flink的watermark机制你学会了吗?

    大家好,今天我们来聊一聊flink的Watermark机制. 这也是flink系列的的第一篇文章,如果对flink.大数据感兴趣的小伙伴,记得点个关注呀. 背景 ​ flink作为先进的流水计算引擎, ...

  2. [白话解析] Flink的Watermark机制

    [白话解析] Flink的Watermark机制 0x00 摘要 对于Flink来说,Watermark是个很难绕过去的概念.本文将从整体的思路上来说,运用感性直觉的思考来帮大家梳理Watermark ...

  3. [Flink] Flink的waterMark的通俗理解

    导读 Flink 为实时计算提供了三种时间,即事件时间(event time).摄入时间(ingestion time)和处理时间(processing time). 遇到的问题: 假设在一个5秒的T ...

  4. Flink中watermark为什么选择最小一条(源码分析)

    昨天在社区群看到有人问,为什么水印取最小的一条?这里分享一下自己的理解 首先水印一般是设置为:(事件时间 - 指定的值)  这里的作用是解决迟到数据的问题,从源码来看一下它如何解决的 先来看下wind ...

  5. [源码分析] 从源码入手看 Flink Watermark 之传播过程

    [源码分析] 从源码入手看 Flink Watermark 之传播过程 0x00 摘要 本文将通过源码分析,带领大家熟悉Flink Watermark 之传播过程,顺便也可以对Flink整体逻辑有一个 ...

  6. 老板让阿粉学习 flink 中的 Watermark,现在他出教程了

    1 前言 在时间 Time 那一篇中,介绍了三种时间概念 Event.Ingestin 和 Process, 其中还简单介绍了乱序 Event Time 事件和它的解决方案 Watermark 水位线 ...

  7. Flink Program Guide (5) -- 预定义的Timestamp Extractor / Watermark Emitter (DataStream API编程指导 -- For Java)

    本文翻译自Pre-defined Timestamp Extractors / Watermark Emitter ------------------------------------------ ...

  8. Flink DataStream API Programming Guide

    Example Program The following program is a complete, working example of streaming window word count ...

  9. <译>Flink编程指南

    Flink 的流数据 API 编程指南 Flink 的流数据处理程序是常规的程序 ,通过再流数据上,实现了各种转换 (比如 过滤, 更新中间状态, 定义窗口, 聚合).流数据可以来之多种数据源 (比如 ...

随机推荐

  1. pandas DataFrame applymap()函数

    pandas DataFrame的 applymap() 函数可以对DataFrame里的每个值进行处理,然后返回一个新的DataFrame: import pandas as pd df = pd. ...

  2. C语言 · 2n皇后问题

    基础练习 2n皇后问题   时间限制:1.0s   内存限制:512.0MB        锦囊1 搜索算法. 锦囊2 先搜索n皇后的解,在拼凑成2n皇后的解. 问题描述 给定一个n*n的棋盘,棋盘中 ...

  3. Ubuntu命令行

    1.打开图形界面的终端 打开:Ctrl+Alt+T 退出:Ctrl+D 2.打开DOS界面的终端 打开:Ctrl+Alt+F1(F1~F6) 退出:Ctrl+Alt+F7 3.用户 ubuntu初始r ...

  4. Linux 目录结构_004

    前言 Linux文件系统层次标准,英文全称Filesystem Hierarchy Standard,英文简称FHS. 由于利用Linux来开发产品的团队和个人实在太多了,如果每个人都以自己的想法来配 ...

  5. iOS中 支付宝钱包具体解释/第三方支付 韩俊强的博客

    每日更新关注:http://weibo.com/hanjunqiang  新浪微博! iOS开发人员交流QQ群: 446310206 一.在app中成功完毕支付宝支付的过程 1.申请支付宝钱包.參考网 ...

  6. js实现滑动的弹性导航

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  7. DedeCMS中channelartlist自增参数global.itemindex

    在 dede:channelartlist 标签下,使用: {dede:global.itemindex runphp='yes'} {/dede:global.itemindex} dede:cha ...

  8. [IR] Extraction-based Text Summarization

    文本自动摘要 - 阅读笔记 自动文摘要解决的问题描述很简单,就是用一些精炼的话来概括整篇文章的大意,用户通过阅读文摘就可以了解到原文要表达的意思. 问题包括两种解决思路, 一种是extractive, ...

  9. 大杂烩 -- 四种生成和解析XML文档的方法详解

    基础大杂烩 -- 目录 众所周知,现在解析XML的方法越来越多,但主流的方法也就四种,即:DOM.SAX.JDOM和DOM4J DOM:在现在的Java JDK里都自带了,在xml-apis.jar包 ...

  10. ValueError: {0} is not a valid coordinate or range问题解决

    获取excel多列方法: >>> colC = ws['C'] >>> col_range = ws['C:D'] 采用python 实现时,开始列与结束列采用变量 ...