我们一直执行 hadoop fs -put a.txt /hdfs
的话,
第1次执行是(spark,4)
第2次执行是(spark,4)
第3次执行是(spark,4)
但是如果我们想要这种效果呢?
第1次执行是(spark,4)
第2次执行是(spark,8)
第3次执行是(spark,12)
这样的话,就重用了历史数据。
package com.llcc.sparkSql.MyTimeSort
import org.apache.spark.streaming.StreamingContext
import org.apache.spark.SparkConf
import org.apache.spark.streaming.Seconds
object NetWordCountUpdateStateByKey {
def main(args: Array[String]): Unit = {
/**
* local[1] 中括号里面的数字都代表的是启动几个工作线程
* 默认情况下是一个工作线程。那么做为sparkstreaming 我们至少要开启
* 两个线程,因为其中一个线程用来接收数据,这样另外一个线程用来处理数据。
*/
val conf=new SparkConf().setMaster("local[2]").setAppName("NetWordCountUpdateStateByKey")
/**
* Seconds 指的是每次数据数据的时间范围 (bacth interval)
*/
val ssc=new StreamingContext(conf,Seconds(2));
val fileDS=ssc.socketTextStream("hadoop1", 9999)
/**
* 需要设置一个checkpoint的目录
* 因为我们的计算结果有中间状态,这些中间状态需要存储
*/
ssc.checkpoint(".")
val wordDS=fileDS.flatMap { line => line.split("\t") }
.map { word => (word,1) }
/**
* updateFunc: (Seq[Int], Option[S]) => Option[S]
* updateFunc 这是一个匿名函数
* (Seq[Int], Option[S]) 两个参数
* Option[S] 返回值
* 首先我们考虑一个问题
* wordDS 做的bykey的计算,说明里面的内容是tuple类型,是键值对的形式,说白了是不是
* 就是【K V】
* wordDS[K,V]
* (Seq[Int], Option[S])
* 参数一:Seq[Int] Seq代表的是一个集合,int代表的是V的数据类型
* ---分组的操作,key相同的为一组 (hadoop,{1,1,1,1})
* 参数二:Option[S] S代表的是中间状态State的数据类型,S对于我们的这个wordcount例子来讲,应该是
* int类型。中间状态存储的是单词出现的次数。 hadoop -> 4
*
* Option[S] 返回值 应该跟中间状态一样吧。
* Option Some/None
*
*/
val wordcountDS=wordDS.updateStateByKey((values:Seq[Int],state:Option[Int]) =>{
val currentCount= values.sum; //获取此次本单词出现的次数
val count=state.getOrElse(0);//获取上一次的结果 也就是中间状态
Some(currentCount+count);
})
wordcountDS.print()
//启动应用
ssc.start()
//等待任务结束
ssc.awaitTermination()
}
}