1.GlobalWindow和KeyedWindow
在運用窗口計算時,Flink根據上游數據集是否爲KeyedStream類型,對應的Windows也會有所不同。
KeyedWindow:上游數據集如果是KeyedStream類型,則調用DataStreamAPI的window()方法,數據會根據Key在不同的Task實例中並行分別計算,最後得出針對每個Key統計的結果。
GlobalWindow:如果是Non-Keyed類型,則調用WindowsAll()方法,所有的數據都會在窗口算子中由到一個Task 中計算,並得到全局統計結果。
2.TimeWindow和CountWindow
基於業務數據的方面考慮,Flink又支持兩種類型的窗口,一種是基於時間的窗口叫TimeWindow。還有一種基於輸入數據數量的窗口叫CountWindow。
val env = StreamExecutionEnvironment.getExecutionEnvironment
val stream = env.socketTextStream(hostname, 9999)
val output = stream.flatMap {
_.toLowerCase.split("\\W+") filter {
_.nonEmpty
}
}.map {
(_, 1)
}.keyBy(0) //通過Tuple的第一個元素進行分組
// 每隔2秒中計算最近5秒的數據 等價於 SlidingEventTimeWindows
.timeWindow(Time.seconds(5), Time.seconds(2))
.sum(1)
TimeWindow(時間窗口)根據不同的業務場景,TimeWindow也可以分爲三種類型,分別是滾動窗口(Tumbling Window)、滑動窗口(Sliding Window)和會話窗口(Session Window)
1.滾動窗口(Tumbling Window)
滾動窗口是根據固定時間進行切分,且窗口和窗口之間的元素互不重疊。這種類型的窗口的最大特點是比較簡單。只需要指定一個窗口長度(windowsize)。其中時間間隔可以是Time.milliseconds(x)、Time.seconds(x)或Time.minutes(x)。
// 每隔5秒中的翻滾操作
val output = stream.flatMap { _.toLowerCase.split("\\W+") filter { _.nonEmpty } }
.map { (_, 1) }
.keyBy(0)
.window(TumblingEventTimeWindows.of(Time.seconds(5)))
.sum(1)
2. 滑動窗口(Sliding Window)
滑動窗口也是一種比較常見的窗口類型,其特點是在滾動窗口基礎之上增加了窗口滑動時間(Slide Time),且允許窗口數據發生重疊。當Windows size 固定之後,窗口並不像滾動窗口按照Windows Size 向前移動,而是根據設定的Slide Time 向前滑動。窗口之間的數據重疊大小根據Windows size 和Slide time 決定,當Slide time 小於Windows size便會發生窗口重疊,Slide size 大於Windows size 就會出現窗口不連續,數據可能不能在任何一個窗口內計算,Slide size 和Windows size 相等時,Sliding Windows 其實就是Tumbling Windows。
// 每隔5秒鐘處理前10S的數據
val output = stream.flatMap {
_.toLowerCase.split("\\W+") filter {
_.nonEmpty
}
}
.map {
(_, 1)
}
.keyBy(0)
.window(SlidingEventTimeWindows.of(Time.seconds(10),Time.seconds(5)))
.sum(1)
3. 會話窗口(Session Window)
會話窗口(Session Windows)主要是將某段時間內活躍度較高的數據聚合成一個窗口進行計算,窗口的觸發的條件是Session Gap,是指在規定的時間內如果沒有數據活躍接入,則認爲窗口結束,然後觸發窗口計算結果。需要注意的是如果數據一直不間斷地進入窗口,也會導致窗口始終不觸發的情況。與滑動窗口、滾動窗口不同的是,Session Windows 不需要有固定windows size 和slide time,只需要定義session gap,來規定不活躍數據的時間上限即可。
val output = stream.flatMap {
_.toLowerCase.split("\\W+") filter {
_.nonEmpty
}
} //nonEmpty非空的
.map {
(_, 1)
}
.keyBy(0) //通過Tuple的第一個元素進行分組
// 如果用戶30秒沒有活動則視爲會話斷開(假設raw data stream是單個用戶的購買行爲流)
.window(ProcessingTimeSessionWindows.withGap(Time.seconds(30)))
.sum(1)
Count Window(數量窗口)也有滾動窗口、滑動窗口等。由於使用比較少,並未深究。
val output = stream.flatMap {
_.toLowerCase.split("\\W+") filter {
_.nonEmpty
}
} //nonEmpty非空的
.map {
(_, 1)
}
.keyBy(0) //通過Tuple的第一個元素進行分組
// 每當窗口中填滿100的元素時,就會對窗口進行計算, 翻滾窗口
.countWindow(100)
.sum(1)