文章目录

  • 说明
  • 连续窗口
  • 独立窗口
  • 连续窗口
  • 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连续窗口和混合窗口使用于复杂计算场景,功能强大,有很强的订制性。
  • 默默学习成长的过程孤独且平淡,当我相信,态度坚定,积少成多,终有一天,转身看现在的自己,一定不会后悔这一路的付出和收获,人生没有捷径,加油。