flink window之四大WindowAssigner

10 篇文章 0 订阅
5 篇文章 0 订阅

Windows是流计算的核心。Windows将流分成有限大小的“buckets”,我们可以在其上应用聚合计算(ProcessWindowFunctionReduceFunctionAggregateFunctionFoldFunction)等。在Flink中编写一个窗口计算的基本结构如下:

Keyed Windows

stream
    .keyBy(...)                
    .window(...)               <-  必须制定: 窗口类型
    [.trigger(...)]            <-  可选: "trigger" (都有默认 触发器),决定窗口什么时候触发
    [.evictor(...)]            <-  可选: "evictor" (默认 没有剔出),剔出窗口中的元素
    [.allowedLateness(...)]    <-  可选: "lateness" (默认 0),不允许又迟到的数据
    [.sideOutputLateData(...)] <-  可选: "output tag" 将迟到的数据输出到 指定流中
    .reduce/aggregate/fold/apply()  <-  必须指定: "function",实现对窗口数据的聚合计算
    [.getSideOutput(...)]      <-  可选: "output tag" 获取Sideout的数据,一般处理迟到数据

Non-Keyed Windows

stream
    .windowAll(...)            <-  必须制定: 窗口类型
    [.trigger(...)]            <-  可选: "trigger" (都有默认 触发器),决定窗口什么时候触发
    [.evictor(...)]            <-  可选: "evictor" (默认 没有剔出),剔出窗口中的元素
    [.allowedLateness(...)]    <-  可选: "lateness" (默认 0),不允许又迟到的数据
    [.sideOutputLateData(...)] <-  可选: "output tag" 将迟到的数据输出到 指定流中
    .reduce/aggregate/fold/apply()  <-  必须指定: "function",实现对窗口数据的聚合计算
    [.getSideOutput(...)]      <-  可选: "output tag" 获取Sideout的数据,一般处理迟到数据

一旦应属于该窗口的第一个元素到达,就会创建窗口,并且当时间(Event/Process Time)超过其结束时间戳时,会完全删除该窗口, Flink保证只删除基于时间的窗口,而不能删除其他类型的窗口,如全局窗口。

此外,每个窗口都会有一个触发器(Trigger)和一个函数(“ ProcessWindowFunction”,“ ReduceFunction”,“ AggregateFunction”或“ FoldFunction)附加到它。该函数将包含要应用于窗口内容的计算,而Trigger则指定条件,在该条件下,该窗口被视为可以应用该函数。

除上述内容外,您还可以指定一个“ Evictor”将能够在触发触发器之后以及应用此功能之前和/或之后从窗口中删除元素。

本文主要介绍flink的Window Assigners(窗口分配器)

Window Assigners(窗口分配器)

窗口分配器定义了如何将元素分配给窗口。 这是通过在 window(…)(对于 keyed streams)或 windowAll()(对于 noneded streams)调用中指定您选择的WindowAssigner来完成的。

WindowAssigner负责将每个传入的元素分配给一个或多个窗口。 Flink带有针对最常见用例的预定义窗口分配器,即滚动窗口滑动窗口会话窗口全局窗口,接下博主会对每个窗口分享案例,本文基于ProcessTime处理,后续会分享基于Event Time案例。

(1)Tumbling Windows

滚动窗口长度固定,滑动间隔等于窗口长度,窗口元素之间没有交叠。
在这里插入图片描述

var env=StreamExecutionEnvironment.getExecutionEnvironment
	env.socketTextStream("centos",9999)
		.flatMap(_.split("\\s+"))
		.map((_,1))
		.keyBy(0)
		.window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
		.reduce((v1,v2)=>(v1._1,v1._2+v2._2))
		.print()
env.execute("window")
(2) Sliding Windows

滑动窗口长度固定,窗口长度大于窗口滑动间隔,元素存在交叠。
在这里插入图片描述

var env=StreamExecutionEnvironment.getExecutionEnvironment
	env.socketTextStream("centos",9999)
	.flatMap(_.split("\\s+"))
	.map((_,1))
	.keyBy(_._1)
	.window(SlidingProcessingTimeWindows.of(Time.seconds(4),Time.seconds(2)))
	.process(new ProcessWindowFunction[(String,Int),String,String,TimeWindow]{
	    override def process(key: String, context: Context,
	                         elements: Iterable[(String, Int)],
	                         out: Collector[String]): Unit = {
	        val sdf = new SimpleDateFormat("HH:mm:ss")
	        val window = context.window
	        println(sdf.format(window.getStart)+"\t"+sdf.format(window.getEnd))
	        for(e <- elements){
	            print(e+"\t")
	        }
	        println()
	    }
	})
env.execute("window")
(3) Session Windows(MergerWindow)

通过计算元素时间间隔,如果间隔小于session gap,则会合并到一个窗口中;如果大于时间间隔,当前窗口关闭,后续的元素属于新的窗口。与滚动窗口和滑动窗口不同的是会话窗口没有固定的窗口大小,底层本质上做的是窗口合并。
在这里插入图片描述

var env=StreamExecutionEnvironment.getExecutionEnvironment
env.socketTextStream("centos",9999)
	.flatMap(_.split("\\s+"))
	.map((_,1))
	.keyBy(_._1)
	.window(ProcessingTimeSessionWindows.withGap(Time.seconds(5)))
	.apply(new 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")
	        println(sdf.format(window.getStart)+"\t"+sdf.format(window.getEnd))
	        for(e<- input){
	            print(e+"\t")
	        }
	        println()
	    }
	})
env.execute("window")

(4) Global Windows

全局窗口会将所有key相同的元素放到一个窗口中,默认该窗口永远都不会关闭(永远都不会触发),因为该窗口没有默认的窗口触发器Trigger,因此需要用户自定义Trigger。

注意:global window与前面的三个窗口不同,前面的三个窗口都是基于时间的,而global window是基于计数的。

var env=StreamExecutionEnvironment.getExecutionEnvironment
env.socketTextStream("centos",9999)
	.flatMap(_.split("\\s+"))
	.map((_,1))
	.keyBy(_._1)
	.window(GlobalWindows.create())
	.trigger(CountTrigger.of[GlobalWindow](3))
	.apply(new WindowFunction[(String,Int),String,String,GlobalWindow]{
	    override def apply(key: String, window: GlobalWindow, input: Iterable[(String, Int)], out: Collector[String]): Unit = {
	        println("=======window========")
	        for(e<- input){
	            print(e+"\t")
	        }
	        println()
	    }
	})
env.execute("window")

好了,关于flink的窗口WindowAssigner理解起来还是比较简单的,在这里博主做了一个简单的介绍,在接下的博文中,博主会分享flink的四大Window Functions,喜欢的点击这里吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值