1 updateStateByKey
updateStateByKey 是一个有状态的算子
第一个参数:表示这一批次的同一个key的所有的value的值,如hello,(1,1,1,1,1,1,1)
第二个参数:就是状态数据,也就是同一个key的前n次的计算结果,如果是第一次,那么前n次没有数据,底层就是用option类型
案例,求开始时刻到现在每个单词出现的个数
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
.setAppName("_01FromKafkaCustomOffsetToRedis")
.setMaster("local[*]")
val ssc = new StreamingContext(conf,Seconds(10))
ssc.checkpoint("data")
//从nc上读取数据
val dStream: ReceiverInputDStream[String] = ssc.socketTextStream("qianfeng01", 10086)
val pairDStream: DStream[(String, Int)] = dStream.map((_, 1))
/**
* updateStateByKey: 有状态的转换算子
* 第一个参数: 表示这一批次的同一个key的所有的value值 hello,(1,1,1,1,1,1,1)
* kitty,(1)
* 第二个参数: 就是状态数据,也就是同一个key的前n次的计算结果,如果是第一次,那么前n次一定没有数据的,底层就用Option类型
*
*
* 注意:状态算子,需要设置检查点
*/
val result: DStream[(String, Int)] = pairDStream.updateStateByKey(
(seq, opt: Option[Int]) => {
var sum = 0
for (i <- seq) {
sum += i
}
sum = sum + opt.getOrElse(0)
Option(sum)
}
)
result.print()
ssc.start()
ssc.awaitTermination()
}
transform算子
- transform:转换的作用
- 将要处理的micro-batch数据转成RDD数据结构,RDD有很多DStream没有的功能
- 进行计算等。
- 最后将结果再次转成DStream
* def main(args: Array[String]): Unit = {
val conf = new SparkConf()
.setAppName("_01FromKafkaCustomOffsetToRedis")
.setMaster("local[*]")
val ssc = new StreamingContext(conf,Seconds(10))
val sc: SparkContext = ssc.sparkContext
//从nc上读取数据
val dStream: ReceiverInputDStream[String] = ssc.socketTextStream("qianfeng01", 10086)
/**
* transform:转换的作用
* 将要处理的micro-batch数据转成RDD数据结构,RDD有很多DStream没有的功能
* 进行计算等。
* 最后将结果再次转成DStream
*
*/
// println("@@@@@@") //执行的位置:driver端
// dStream.transform(rdd=>{
// println("----") //执行的位置:driver端, 一般用于每一批数据的重复执行的状态数据
// rdd.map(line=>{
// println("#######") //执行的位置 : executor端
// (line,1)
// })
//
// }).print()
dStream.transform(rdd=>{
val i: Int = rdd.aggregate(10)((v1: Int, v2: String) => {
math.max(v1, v2.toInt)
}, (v1: Int, v2: Int) => v1 + v2)
sc.makeRDD(List(i))
}).print
//对比以下map算子
// dStream.map(data=>{
// println("#####") //executor端
// data
// }
// ).print()
ssc.start()
ssc.awaitTermination()
}`
开窗算子
- window(
- windowDuration:Duration, //第一个参数:用于指定窗口的大小,即长度,必须是micro-batch处理时的时间整数倍
- slideDuration:Duration //第二个参数:用于指定窗口滑动的周期,必须是micro-batch处理时的时间整数倍
- )
- 数据的情况:
-
1. 刚启动时,窗口里一定没有数据,如果上游没有数据的时间超过窗口的长度时,窗口也没有数据
-
2. 启动程序不久,窗口的数据的变化应该是由少变多
-
3. 在处理数据过程中,窗口的数据可能会由多变少,甚至没有
*/
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
.setAppName("_01FromKafkaCustomOffsetToRedis")
.setMaster("local[*]")
val ssc = new StreamingContext(conf,Seconds(10))
//从nc上读取数据
val dStream: ReceiverInputDStream[String] = ssc.socketTextStream("qianfeng01", 10086)
val mapDStream: DStream[(String, Int)] = dStream.flatMap(_.split(" ")).map((_, 1))
/**
* window(
* windowDuration:Duration, //第一个参数:用于指定窗口的大小,即长度,必须是micro-batch处理时的时间整数倍
* slideDuration:Duration //第二个参数:用于指定窗口滑动的周期,必须是micro-batch处理时的时间整数倍
* )
*
* 数据的情况:
* 1. 刚启动时,窗口里一定没有数据,如果上游没有数据的时间超过窗口的长度时,窗口也没有数据
* 2. 启动程序不久,窗口的数据的变化应该是由少变多
* 3. 在处理数据过程中,窗口的数据可能会由多变少,甚至没有
*/
val windowDStream: DStream[(String, Int)] = mapDStream.window(Seconds(30), Seconds(10))
val resultDStream: DStream[(String, Int)] = windowDStream.reduceByKey(_ + _)
resultDStream.print()
ssc.start()
ssc.awaitTermination()
}