Window Assigners
指定流是否为keyed之后,下一步是定义Window Assigner。Window Assigners定义了如何将元素分配给Window。这是通过window (...)
(对于keyed流)或windowAll()
(对于非keyed流)调用中指定您选择的WindowAssihner来完成的。
WindowAssigner负责将每个传入元素分配给一个或多个窗口。Flink为最常见的用例提供了预定义的窗口分配器,即滚动窗口,滑动窗口,会话窗口和全局窗口。还可以通过扩展WindowAssigner类来实现自定义窗口分配器。所有内置窗口分配器(全局窗口除外)均根据时间将元素分配给窗口,时间可以是处理时间,也可以是事件时间。
基于时间的窗口具有开始时间戳(包括端点)和结束时间戳(排除端点),他们共同描述了窗口的大小。在代码中,Flink在使用基于时间的窗口时使用TimeWindow,该窗口具有用于查询开始时间戳和结束时间戳的方法,以及用于返回给定窗口的最大允许时间戳的附加方法maxTimestamp ()
。
Tumbling Windows
滚动窗口分配器将每个元素分配给在指定窗口大小的窗口。滚动窗口具有固定的大小,并且不重叠。
env.socketTextStream("Spark", 9999)
.flatMap(_.split("\\s+"))
.map((_,1))
.keyBy(t =>t._1)
.window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
.reduce((v1,v2)=>(v1._1,v1._2+v2._2))
.print()
Sliding Windows
滑动窗口分配器将元素分配给固定长度的窗口。类似于滚动窗口分配器,窗口的大小由窗口大小参数配置。附加的窗口滑动参数控制滑动窗口启动的频率。因此,如果滑动间隔小于窗口大小,则滑动窗口可能会重叠。在这种情况下,元素被分配给多个窗口。
env.socketTextStream("CentOS", 9999)
.flatMap(_.split("\\s+"))
.map((_,1))
.keyBy(t =>t._1)
.window(SlidingProcessingTimeWindows.of(Time.seconds(10), Time.seconds(5)))
.aggregate(new AggregateFunction[(String,Int),(String,Int),(String,Int)]{
override def createAccumulator(): (String, Int) = ("",0)
override def add(value: (String, Int), accumulator: (String, Int)): (String, Int) = (value._1,value._2+accumulator._2)
override def getResult(accumulator: (String, Int)): (String, Int) = accumulator
override def merge(a: (String, Int), b: (String, Int)): (String, Int) = (a._1,a._2+b._2)
})
.print()
Session Windows
会话窗口分配器按活动会话对元素进行分组。与滚动窗口和滑动窗口相比,会话窗口不重叠且没有固定的开始和结束时间。相反,当会话窗口在一定时间段内未接收到元素时(发生不活动间隙时),它将关闭。会话窗口分配器可以配置有静态会话间隔,也可以配置有会话间隔提取器功能,该功能定义不活动的时间长度。当该时间段到期时,当前会话关闭,随后的元素被分配给新的会话窗口。
//import org.apache.flink.streaming.api.scala.function.WindowFunction
class UserDefineWindowFunction extends WindowFunction[(String,Int),String,String,TimeWindow]{
override def apply(key: String,
window: TimeWindow,
input: Iterable[(String, Int)],
out: Collector[String]): Unit = {
val sdf = new SimpleDateFormat("HH:mm:ss")
val start = sdf.format(window.getStart)
val end = sdf.format(window.getEnd)
var maxTimestamp=sdf.format(window.maxTimestamp())
println(s"key:${key},start:${start},end:${end},maxTimestamp:"+maxTimestamp)
out.collect(s"${key},${input.map(_._2).sum}")
}
}
Global Windows
全局窗口分配器将具有相同键的元素分配给同一单个全局窗口。仅当指定自定义触发器时,此窗口方案才有用。否则,将不会执行任何计算,因为全局窗口没有可以处理聚合元素的自然终点(因为该窗口的触发器使用的是Never Trigger)
class UserDefineProcessWindowFunction extends ProcessWindowFunction[(String,Int),String,String,GlobalWindow]{
override def process(key: String,
context: Context,
elements: Iterable[(String, Int)],
out: Collector[String]): Unit = {
out.collect(s"${key},${elements.toList.map(_._2).sum}")
}
}
env.socketTextStream("CentOS", 9999)
.flatMap(_.split("\\s+"))
.map((_,1))
.keyBy(t =>t._1)
.window(GlobalWindows.create())
.trigger( CountTrigger.of(4))
.process(new UserDefineProcessWindowFunction)
.print()