updateStateByKey是按照key做数据状态的更新,内部其实是基于option对象
它的应用场景是在流处理的时候希望将每次计算的状态都聚拢在一起,达到持续更新状态的效果
我给大家准备了一个流处理用这个方法做按照key计算从计算开始到计算结束词频多少的例子,但是要记住,用这个方法,数据最好是key-value形式的,大家有需要可以把value做成一个自定义的class
package com.sparkstream
import org.apache.spark.SparkConf
import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Seconds, StreamingContext}
object StreamUpdateState {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setMaster("local[2]").setAppName("StreamUpdateState")
val ssc = new StreamingContext(conf, Seconds(5))//只有一个参数则是开窗时间
//ssc.sparkContext.setLogLevel("ERROR")
ssc.checkpoint("mycheckpoint")//checkpoint路径
val dataDS: ReceiverInputDStream[String] = ssc.socketTextStream("192.168.182.147",9999)//监控一个端口
val wordDS: DStream[String] = dataDS.flatMap(_.split(" "))
val tupleDS: DStream[(String, Int)] = wordDS.map((_,1))
//hello hello kitty
//(hello,1) (hello,1) (kitty,1)
//hello Seq{1,1}, kitty Seq{1}
//Option[Int] = Some(3) None 使用option记录持续的累加结果 0,
//hello : seq{1,1} option:None => Option(2)
//hello hello hello snoopy
//hello : seq{1,1,1} Option(2) => Option(5)
//这个方法每次都会把当先新数据 和之前完成的数据状态传达过来
val wordCounts: DStream[(String, Int)] = tupleDS.updateStateByKey((seq: Seq[Int], option: Option[Int]) => {
var value = 0 //每一次计算的时候准备一个变量
value += option.getOrElse(0)//取上一次累加的结果
//迭代累加当前行状态
for (elem <- seq) {
value += elem
}
//把最新状态放回去
Option(value)//本次累加结果
})
wordCounts.print()
//一定要调用这两个方法一个是启动 一个是再次迭代执行
ssc.start()
ssc.awaitTermination()
}
}
Spark的状态保存更新其实还有一个方法叫做mapWithState,是后期出来的一个方法,为了进一步节省计算资源,mapWithState方法只会计算出现的数据,而不是全部计算,比如流数据中有1 2 3 4 5,各出现2次,但是在下一次计算的时候只出现了1 2 3,那么mapWithState只会更新1 2 3的状态