文章目录
- 说明
- 连续窗口
- 独立窗口
- 连续窗口
- wondow 多流合并
- 滚动窗口关联
- 滑动窗口关联
- 会话窗口关联
- 间隔关联
- 总结
说明
- 本博客每周五更新一次。
- 之前介绍了窗口和窗口函数,这次分享连续窗口和混合窗口的相关知识。
连续窗口
独立窗口
- 针对同一个DataStream窗口进行不同的窗口处理,窗口间相对独立,输出结果在不同的DataStream中,这时Flink Runtime执行环境中,将分为两个Window Operator在不同的Task中执行,相互之间元数据不会进行共享。实例代码如下:
val input :DataStream[T]=...;
//定义Session Gap为100s的窗口并计算结果WindowStream1
val windowStream1 = inputStream.keyBy(_._1)
//指定窗口类型
.window(EventTimeSessionWindows.withGap(Time.milliseconds(100)))
.process(...)
//定义Session Gap为10S的窗口并计算结果WindowStream2
val windowStream2 = inputStream.keyBy(_._1)
//指定窗口类型
.window(EventTimeSessionWindows.withGap(Time.milliseconds(10)))
.process(...)
连续窗口
- 连续窗口是将上游窗口的计算结果作为下游窗口的输入,窗口算子和算子间上下游关联,窗口之间的元数据信息能共享。
- 实例代码如下,上游窗口统计最近10种每个Key的最小值,通过下游窗口统计出整个窗口上TopK的值,可看出,两个窗口类型和End-Time都是一致的,上游将窗口元数据(Watermark)信息传递到下游窗口中,真正触发计算时下游窗口,窗口的计算结果全部在下游窗口中统计得到,最终完成同一个窗口中同时计算与Key相关和非Key相关的指标。实例代码如下:
val input:DataStream[T]=...
//定义Session Gap为100S的窗口并计算结果windowStream1
val windowStream1 = inputStream.keyBy(_._1)
//指定窗口
.window(TumblingEventTimeWindows.of(Time.milliseconds(10)))
.reduce(new min())
//将window1上定义的Session Gap为10S的窗口并计算结果windowStream2
val windowStream2 = WwindowStream1
//指定窗口
.windowAll(TumblingEventTimeWindows.of(Time.milliseconds(10)))
.process(new TopKWindowFunction())
wondow 多流合并
- Flink中支持窗口上的多流合并,即在一个窗口中按照相同条件对两个输入数据流并进行关联操作,需要保证输入的Stream要构建在相同的Window上,并使用相同类型的key作为关联条件。
- 如想通过join将inputStream1和inputStream2数据集关联,形成JoinedStream类型数据集,调用where()方法指定inputStream1数据集的Key,调用equealTo()方法指定inputStream2对应关联的Key,通过window()方法指定Window Assigner,最终通过apply()方法中传入用户定义的JoinFunction获知FlatJoinFunction对输入的数据元素进行窗口计算。实例代码如下:
inputStream1:DataStream[(Long,String,Int)]=...;
inputStream2:DataStream[(Long,String,Int)]=...;
//通过DataStream Join方法将两个数据流关联
inputStream1.join(inputStream2)
//指定inputStream1的关联Key
.where(_._1)
//指定inputStream2的关联key
.equalsTo(_._2)
//指定WindowAssigner
.window(TumblingEventTimeWindows.of(Time.milliseconds(10)))
.apply(<JoinFunction>) //指定窗口计算函数
- 在Windows Join过程中所有的Join操作都是Inner-join类型,也就是说相同窗口中,每个Stream中,都要有Key且Key相同才能完成关联操作并输出结果,任何数据集中的key不存在或缺失都会造成关联计算结果不输出。
- 在Window Join中,指定不同的Windows Assigner,DataStream的关联过程也不同,包括数据计算的方式也会不同。
滚动窗口关联
- 该窗口是将滑动窗口中相同Key的两个DataStream数据集中的元素进行管理,并应用用户自定义的JoinFunction计算关联结果。
- 数据在相关的窗口中进行关联,如果key相同,使用JoinFunction计算出结果并输出。在窗口中任何一个DataStream没有对应的Key的元素,窗口都不好输出计算结果。
val blackStream:DataStream[(Int,Long)]=...;
val whiteStream:DataStream[(Int,Long)]=...;
//通过DataStream Join方法将两个数据流关联
val windowStream:DataStream[(Int,Long)]=blackStream.join(whiteStream)
//指定blackStream的关联Key
.where(_._1)
//指定whiteStream的关联key
.equalsTo(_._2)
//指定窗口类型
.window(TumblingEventTimeWindows.of(Time.milliseconds(10)))
.apply((black,white) => (black._1,black._2+white._2)) //应用JoinFunction
滑动窗口关联
- 滑动窗口指窗口在指定SlideTime的间隔内进行滑动,同时允许窗口重叠。所以输出结果很可能出现重叠。实例代码如下:
val blackStream:DataStream[(Int,Long)]=...;
val whiteStream:DataStream[(Int,Long)]=...;
//通过DataStream Join方法将两个数据流关联
val windowStream:DataStream[(Int,Long)]=blackStream.join(whiteStream)
//指定blackStream的关联Key
.where(_._1)
//指定whiteStream的关联key
.equalsTo(_._2)
//指定窗口类型
.window(SlidingEventTimeWindows.of(Time.milliseconds(10),Time.milliseconds(2)))
.apply((black,white) => (black._1,black._2+white._2)) //应用JoinFunction
会话窗口关联
- 会话窗口关联是更加Session Gap将数据集划分成不同的窗口,会话窗口关联对两个Stream的数据元素进行窗口关联操作,窗口中含有两个数据集元素,并且元素且有相同的key,输出关联计算结果。
- 如果两个DataStream的会话时间不在一个频道上,可能导致一段时间内两个DataStream都无法连接,这时需要根据情况重新设置Gap的大小。
- 实例代码如下:
val blackStream:DataStream[(Int,Long)]=...;
val whiteStream:DataStream[(Int,Long)]=...;
//通过DataStream Join方法将两个数据流关联
val windowStream:DataStream[(Int,Long)]=blackStream.join(whiteStream)
//指定blackStream的关联Key
.where(_._1)
//指定whiteStream的关联key
.equalsTo(_._2)
//指定窗口类型
.window(EventTimeSessionWindows.withGap(Time.milliseconds(10)))
.apply((black,white) => (black._1,black._2+white._2)) //应用JoinFunction
间隔关联
- 与其他窗口关联不同,间隔关联的数据元素关联范围不依赖窗口划分,而是通过DataStream元素的时间加上或减去指定的Interval作为关联窗口,再和另外一个DataStream的数据元素时间在窗口内进行Join操作。
- 间隔关联结果依赖于Ineval的大小,越大关联数据越多,反之亦然。
- 代码如下,blackStream调用IntervalJoin关联whiteStream,此时blackStream和whiteStream都是转换成keyedStream类型,同时在between()方法中指定blackStream()数据元素的上下界,然后在process()方法中指定定义的ProcessJoinFunction,完成窗口内的数据计算和输出。
//创建黑色数据集
val blackStream:DataStream[(Int,Long)]=env.fromElements((2,21L),(4,1L),(5,4L));
//创建白色数据集
val whiteStream:DataStream[(Int,Long)]=env.fromElements((2,21L),(1,1L),(3,4L));
//通过DataStream Join方法将两个数据流关联
val windowStream:DataStream[(Int,Long)]=blackStream.keyBy(_._1)
//调用intervalJoin方法关联另一个DataStream
.intervalJoin(whiteStream.keyBy(_._1)
//设置时间上限和下限
.between(Time.milliseconds(-2),Time.milliseconds(1))
.process(new ProcessWindowFunction())
//通过单独定义ProcessWindowFunction实现ProcessJoinFunction
class ProcessWindowFunction extends ProcessJoinFunction[(Int,Long),(Int,Long),String]{
override def processElement(in1: (Int,Long),in2:(Int,Long),context:ProcessJoinFunction[(Int,Long),(Int,Long),String],collector:Collector[String]):Unit = {
collector.collect(in1+":"+(in1._2+in2._2))
}
}
总结
- flink连续窗口和混合窗口使用于复杂计算场景,功能强大,有很强的订制性。
- 默默学习成长的过程孤独且平淡,当我相信,态度坚定,积少成多,终有一天,转身看现在的自己,一定不会后悔这一路的付出和收获,人生没有捷径,加油。