有狀態轉化操作UpdateStateByKey

UpdateStateByKey 原語用於記錄歷史記錄,有時,我們需要在 DStream 中跨批次維護狀態(例如流計算中累加 wordcount)。針對這種情況,updateStateByKey()爲我們提供了對一個狀態變量的訪問,用於鍵值對形式的 DStream。給定一個由(鍵,事件)對構成的 DStream,並傳遞一個指定如何根據新的事件更新每個鍵對應狀態的函數,它可以構建出一個新的 DStream,其內部數據爲(鍵,狀態) 對。updateStateByKey() 的結果會是一個新的 DStream,其內部的 RDD 序列是由每個時間區間對應的(鍵,狀態)對組成的。

通俗的講:由於spark streaming是微批次的流式處理框架,並不是嚴格的實時流處理框架,還是一個批次一個批次的處理數據,只是間隔時間比較短,無狀態處理的話,這個批次的數據無法與上個批次的數據一起處理,調用updateStateByKey的話(需要配合檢查點,spark中checkpoint在此處有優化,並非保存所有的歷史數據,而是將當前計算結果保存),該算子能夠記錄流的累計狀態,就可以操作多個批次的數據。

注意: updateStateByKey操作,要求必須開啓Checkpoint機制

示例:


object UpstateByKeyDemo {
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("wordcount")
val sc = new StreamingContext(conf, Duration(3000))
sc.checkpoint("ck/")
val lineDs: ReceiverInputDStream[String] = sc.socketTextStream("localhost", 8888)
val wordMap: DStream[(String, Int)] = lineDs.flatMap(_.split(" ")).map((_, 1))
// 到了這裏,就不一樣了,之前的話,是不是直接就是wordMap.reduceByKey
// 然後,就可以得到每個時間段的batch對應的RDD,計算出來的單詞計數
// 然後,可以打印出那個時間段的單詞計數
// 但是,有個問題,你如果要統計每個單詞的全局的計數呢?
// 就是說,統計出來,從程序啓動開始,到現在爲止,一個單詞出現的次數,那麼就之前的方式就不好實現
// 就必須基於redis這種緩存,或者是mysql這種db,來實現累加
// 但是,我們的updateStateByKey,就可以實現直接通過Spark維護一份每個單詞的全局的統計次數
val Sum: DStream[(String, Int)] = wordMap.updateStateByKey[Int]((value: Seq[Int], state: Option[Int]) => {
//狀態更新函數
val current: Int = value.sum
val preValue: Int = state.getOrElse(0)
Some(current + preValue)// 更新後的狀態返回
})
Sum.print()
sc.start()
sc.awaitTermination()
}
}
 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章