一.窗口(window)操作
1.定义
window操作是流式计算过程中一个比较常用的处理方式
通过按照固定时间或者固定的数量将数据进行切分的操作
每切分出来一个就是一个窗口,可以对每个窗口进行统计分析的操作
2.window的分类
1.时间窗口(TimeWindow)(固定时间来固定数量量)
1)滚动时间窗口(车轮)(TumblingTimeWindow)
以某个固定时间为周期,数据没有交叉
只有一个参数,窗口的长度(以时间为单位)
/**
* 做时间滚动窗口
* @param dataStreamOriginal
*/
def window_TimeTumbling(dataStreamOriginal:DataStream[SensorReading]) = {
dataStreamOriginal.keyBy(0)
//以15秒为窗口长度
.window(TumblingProcessingTimeWindows.of(Time.seconds(15)))
}
2)滑动时间窗口(SlidingTimeWindow)(一个窗口折叠另一个窗口)
以某个固定时间为周期,数据可以有交叉
有两个参数,窗口的长度(以时间为单位),另一个是滑动的时间
/**
* 做时间滑动窗口
* @param dataStreamOriginal
*/
def window_TimeSlinding(dataStreamOriginal:DataStream[SensorReading]) = {
dataStreamOriginal.keyBy(0)
//以15秒为窗口长度,以10秒为滑动间隔
.window(SlidingProcessingTimeWindows.of(Time.seconds(15),Time.seconds(10)))
}
简单写法
/**
* 时间窗口的简单写法
* @param dataStreamOriginal
*/
def window_TimeEasy(dataStreamOriginal:DataStream[SensorReading]) = {
dataStreamOriginal.keyBy(0)
//如果一个参数就是滚动时间窗口,如果两个参数为滑动时间窗口
//其他参数为默认
//时间语义会从环境中env获取,进行判断
.timeWindow(Time.seconds(15))
}
3)会话窗口(sessionTimeWindow)
以一个固定的时间(发送数据的间隔时间)为超时时间
如果两条数据发送的时间间隔<超时时间,在同一个会话窗口
如果两条数据发送的时间间隔>超时时间,就重新开启一个新会话窗口
/**
* 时间会话窗口
* @param dataStreamOriginal
*/
def window_TimeSession(dataStreamOriginal:DataStream[SensorReading]) = {
dataStreamOriginal.keyBy(0)
//如果两条数据处理时间间隔达到了15秒,就创建新的session窗口
.window(ProcessingTimeSessionWindows.withGap(Time.seconds(15)))
}
2.计数窗口(CountWindow)
(按数据条数进行固定)底层需要通过全局窗口来实现
1)滚动计数窗口
/**
* 滚动计数窗口:以固定1000条数据进行一个窗口
* @param dataStreamOriginal
* @return
*/
def window_CountSliding(dataStreamOriginal:DataStream[SensorReading]) = {
dataStreamOriginal.keyBy(0)
//只做全局窗口相等与没有窗口,必须添加触发器,才能添加触发窗口执行
.window(GlobalWindows.create())
//数数量达到一1000条触发一次窗口
//设置触发器
.trigger(CountTrigger.of(1000))
}
2)滑动计数窗口
/**
* 滑动计数窗口:数据之间有交叉
* 以1000条数据为一个窗口,当数据到第900条时执行下一个窗口,本窗口达到1000条数据自动停止
* @param dataStreamOriginal
* @return
*/
def window_CountTumbling(dataStreamOriginal:DataStream[SensorReading]) = {
dataStreamOriginal.keyBy(0)
//只做全局窗口相等与没有窗口,必须添加触发器,才能添加触发窗口执行
.window(GlobalWindows.create())
//以1000条数据为一个窗口,所以读物1000条数据之后截止当前的窗口
.evictor(CountEvictor.of(1000))
//数数量达到一1000条触发一次窗口
//设置触发器
.trigger(CountTrigger.of(900))
}
简便写法
/**
* 计数窗口的简便写法
* @param dataStreamOriginal
*/
def window_CountEasy(dataStreamOriginal:DataStream[SensorReading]) = {
dataStreamOriginal
.keyBy(0)
//一个参数是滚动,两个参数是滑动
.countWindow(1000,900)
}
3.全局窗口(globalWindow) 计数窗口底层就是通过全局窗口实现的
如果做键控操作,每个key被分配到同一个窗口中执行
如果不做键控操作,所有数据被分配到同一个窗口中执行
数据量不固定,没有任何限制,所有数据都分配到同一个窗口,本身就是无界数据流,这种窗口没有结束的时候,需要设置一个触发器,没有触发器相当于没有做窗口,跟普通流一样,全局窗口一定要加触发器,相当于固定计数窗口