Windows窗口計算就是通過按照固定時間將數據切分成不同的窗口,然後對窗口內的數據進行計算。Flink DataStream API 將窗口抽象成獨立的operator,並且在Flink DataStream內已經建了大多數窗口算子。每個算子中包含了Windows Assigner、Window Trigger(窗口觸發器)、Evictor(數據剔除器)、Lateness(時延設定)、Output Tag (輸出標籤)、Windows Function等部分。
1、Windows Assigner
(1)Keyed和Non-Keyed窗口
在運行窗口計算時會根據上游數據的類型,設置不同的Windows Assigner。如果上游數據集的數據類型是KeyedStream,則調用DataStream API 的window()方法指定windows assigner;如果不是,則調用DataStream API 的windowAll()方法指定windows assigner。
(2)Windows Assigner
Flink支持兩種類型的窗口,一種是基於時間的窗口,窗口基於起始時間戳和終止時間戳來決定窗口的大小。另一種是基於數量的窗口,根據固定的數據定義窗口的大小。
windows 窗口有四種類型:滾動窗口(Tumbling Windows)、滑動窗口(Sliding Windows)、會話窗口(Ssession Windows)和全局窗口(Global Windows)。
- 滾動窗口
滾動窗口是根據固定的時間或大小進行切割,且窗口和窗口之間的元素互不重疊。DataStream API 基於Event Time 和 Process Time 兩種時間類型的Tumbling 窗口,對應的Assigner分別爲TumblingEventTime和TumblingProcessTime。
- 滑動窗口
滑動窗口是在滾動窗口基礎之上增加來窗口的滑動時間(Slide Time),且允許窗口數據發生重疊。DataStream API 基於Event Time 和 Process Time 兩種時間類型的Tumbling 窗口,對應的Assigner分別爲SlidingEventTime和SlidingProcessTime。
- 會話窗口
會話窗口是將某段時間內活躍度較高的數據聚合成一個窗口進行計算,窗口的觸發條件是Session Gap,在規定的時間內如果沒有數據活躍接入,則認爲窗口結束,觸發窗口計算結果。
Session Windows 窗口類型比較適合非連續型數據處理或週期性產生數據的場景。
//通過使用EventTimeSessionWindows 定義 EventTime 滾動窗口
window(EventTimeSessionWindows.withGap(Time.milliseconds(10)))
//通過使用ProcessTimeSessionWindows 定義 ProcessTime 滾動窗口
window(ProcessTimeSessionWindows.withGap(Time.milliseconds(10)))
- 全局窗口
全局窗口就是將所有相同的key的數據分配到單個窗口中進行計算,窗口沒有起始和結束時間,窗口需要藉助Trigger來觸發計算,如果對Global Windows 指定Trigger ,窗口是不會觸發計算。
//通過GlobalWindows 定義Global Windows
window(GlobalWindows.create())
2、Windows Function
Flink 中提供四種類型的Window Function,分別是ReduceFuntion、AggregateFunction、FoldFunction以及ProcessWindowFunction。
四種類型的Window Function 可以根據計算原理的不同可以分爲兩大類,一類是增量聚合函數,對應有ReduceFunction、AggregateFunction、FoldFunction;另一類是全量窗口函數,對應有ProcessWindowFunction。增量聚合函數計算性能比較高,佔用存儲空間少,主要因爲基於中間狀態的計算結果,窗口中只維護中間結果的狀態值,不需要緩存原始數據。而全量窗口函數使用的代價相對比較高,性能比較弱,主要是因爲此類算子需要對所有屬於此類窗口的接入數據進行緩存,然後等到窗口觸發的時候,纔對所有原始數據進行彙總計算。
- ReduceFunction
ReduceFunction 定義了對輸入的兩個相同類型的數據元素按照指定的計算方法進行整合的邏輯,然後輸出類型相同的一個結果元素。
//直接使用表達式
reduce{(v1,v2)=>(v1._1,v1._2+v2._2)}
//實現ReduceFunction接口
reduce(new ReduceFunction [(Int,Long)]) {
override def reduce(t1:(Int,Long),t2:(Int,Long)):(Int,Long) = {
(t1._1,t1._2+t2._2)
}
}
- AggregateFunction
和ReduceFunction 相似,AggregationFunction也是基於中間狀態計算結果的增量計算函數,但AggregationFunction 在窗口上更加通用。AggregationFunction接口比ReduceFunction更加靈活,實現複雜度也相對較高。AggregateFunction接口中定義了三個需要重寫的方法,add()定義數據的添加邏輯,getResult定義了根據accumulator計算結果的邏輯,merge定義合併accumulator的邏輯。
- FoldFunction
FoldFunction 定義瞭如何將窗口中的輸入元素與外部的元素合併的邏輯。
- ProcessWindowFunction
更加靈活地支持基於窗口全部數據元素的結果計算
- Incremental Aggregation 和 ProcessWindowsFunction 整合
兩者整合後在實現增量聚合計算的同時,也可以操作窗口的元數據信息以及狀態數據。
- ProcessWindowFunction 狀態操作
除了能夠通過RichFunction 操作keyed state 之外,ProcessWindowFunction 也可以操作基於窗口之上的狀態數據,這類狀態被稱爲Pre-window State 。
博主的微信公衆號,不定期發佈技術文章,喜歡的可以關注一下哈