Flink窗口源码解析

标题Flink 窗口函数介绍以及源码解析

流式计算是一种被设计用来处理无限数据集的数据处理引擎,而无限数据集是指一种不断增长的,本质上无限的数据集。而Window 窗口是一种切割无限数据集为有限块进行处理的手段。

Window 是无限数据流处理的核心,Window 将一个无限的stream 切分成有限个小的“bucket” 桶,我们可以基于这些桶做计算操作。
在这里插入图片描述
版本:

<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-java_2.11</artifactId>
<version>2.10</version>

Flink Windows 主要分2类

1.TimeWindow (根据实现原理又可以分3类)
  1. TumblingWindow 滚动窗口

    ds.timeWindow(Time.seconds(5) ) ,
    一个参数,数据不会重复;统计每5秒窗口内的数据
    在这里插入图片描述

  2. SlidingWindow 滑动窗口

    ds.timeWindow(Time.seconds(5) ,Time.Second(3)) ,
    两个参数,窗口数据是可以重叠的,每隔3秒,统计最近5秒窗口内的数据;在这里插入图片描述

  3. SessionWindow 会话窗口
    window(ProcessingTimeSessionWindows.withGap(Time.seconds(3))),一个参数,如果连续3秒内,没有新的数据流入,那么上一个窗口关闭结束并计算输出该窗口内的数据;一旦有新数据流入,则开启新窗口在这里插入图片描述

2. CountWindow (根据实现原理又可以分2类)
  1. TumblingWindow 滚动窗口
    ds.countWindow(Time.Second(3)),
    一个参数,当元素数量达到窗口大小,即触发窗口执行。
  2. SlidingWindow 滑动窗口
    ds.keyby(0).countWindow(Time.Second(3),Time.Second(2)) ,
    两个参数,每收到两个相同key的数据,则计算一次,每次计算的window 范围是3个元素。

Window源码部分

public WindowedStream<T, KEY, TimeWindow> timeWindow(Time size) {
*// 一个参数,走滚动窗口模式,TumblingxxxxTimeWindow 刚好也对的上*
// 进来首先判断Flink的时间语义,如果是ProcessingTime(执行基于时间操作算子的本地时间),那么走
//调用TumblingProcessingTimeWindows.of(size),否则后者
if (environment.getStreamTimeCharacteristic() == TimeCharacteristic.ProcessingTime) {
            //ps:这里TimeWindow 底层调用的还是window 方法,和会话窗口方法调用是一样的,
            //只不过滑动和滚动窗口对窗口函数做了封装而已
			return window(TumblingProcessingTimeWindows.of(size));  //看A
		} else {
			return window(TumblingEventTimeWindows.of(size)); // 看E
		}
	}
// 
public WindowedStream<T, KEY, TimeWindow> timeWindow(Time size, Time slide) {
if (environment.getStreamTimeCharacteristic() == TimeCharacteristic.ProcessingTime) {
return window(SlidingProcessingTimeWindows.of(size, slide)); //看F
		} else {
		return window(SlidingEventTimeWindows.of(size, slide)); 
		}
	}
A
这里走processingTime 窗口TumblingProcessingTimeWindows 类对象的of 方法,
首先将第二个参数置零,同时窗口长度转为毫秒单位
public static TumblingProcessingTimeWindows of(Time size) {
	return new TumblingProcessingTimeWindows(size.toMilliseconds(), 0); 看B
}
B 在 TumblingProcessingTimeWindows.of(size) 和TumblingEventTimeWindows.of(size)的of 方法中,
都赋予offset 为0;offset 是时区差(用到的时候,会转为ms)
if (Math.abs(offset) >= size) {
throw new IllegalArgumentException("TumblingProcessingTimeWindows parameters must satisfy abs(offset) < size");
}

TumblingProcessingTimeWindows 类中,下面这个方法是真正分配窗口长度的代码位置。
public Collection<TimeWindow> assignWindows(Object element, long timestamp, WindowAssignerContext context) {
//上下文获取当前的processingTime
	final long now = context.getCurrentProcessingTime();
	//计算窗口的开始位置,看C
	long start = TimeWindow.getWindowStartWithOffset(now, offset, size);
	//这里是获取窗口的集合,重点我们看D
	return Collections.singletonList(new TimeWindow(start, start + size));
	}
	
C
public static long getWindowStartWithOffset(long timestamp, long offset, long windowSize) {
//这里获取窗口 的开始位置,实质上是根据窗口长度对ProcessingTime 向下取整
return timestamp - (timestamp - offset + windowSize) % windowSize;
	}
D
//TimeWindow这个类中有maxTimestamp 这个方法,类中processingTime 的最大值为end - 1 ,这个说明了,窗口本质上左闭右开的,end 实际上要小1ms
public class TimeWindow extends Window {
	@Override
	public long maxTimestamp() {
		return end - 1;
	}
}
E
//ProcesssingTime 方法和eventTime区别在于,前者通过上下文获取操作算子执行任务的时间作为窗口
//计算时间,eventTime 则是根据事件指定时间字段的时间作为窗口计算时间。两者都调用了同样的
//方法,见C
@Override
	public Collection<TimeWindow> assignWindows(Object element, long timestamp, WindowAssignerContext context) {
		if (timestamp > Long.MIN_VALUE) {
		// final long now = context.getCurrentProcessingTime(); 这个是区别核心,provessing是使用这个now 
		//作为第一个参数传到下面方法获取start, 而event是把时间制定时间作为参数计算获取start
			long start = TimeWindow.getWindowStartWithOffset(timestamp, offset, size); 
			return Collections.singletonList(new TimeWindow(start, start + size));
		} else {
			throw new RuntimeException("Record has Long.MIN_VALUE timestamp (= no timestamp marker). " +
					"Is the time characteristic set to 'ProcessingTime', or did you forget to call " +
					"'DataStream.assignTimestampsAndWatermarks(...)'?");
		}
	}
F 其实processingTime   中of 方法和eventTime 中of 方法都是一样的,赋值第三个参数offset为0,同时将
窗口长度和滚动长度作为构造器参数传递
public static SlidingProcessingTimeWindows of(Time size, Time slide) {
		return new SlidingProcessingTimeWindows(size.toMilliseconds(), slide.toMilliseconds(), 0);
	}

这个是slidingEvent划分窗口的细节在这里插入图片描述
这个是slidingProcessing划分窗口的细节,两者的区别还是在于时间语义的不一样,一个是系统的,一个是事件的。
在这里插入图片描述
未完待续。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值