SparkStreaming(16):updateStateByKey算子

一、实现功能

1.需要累加数据的场景,当前批次的计算结果,要累加之前批次的结果。这个时候,需要使用updateStateByKey算子,同时使用checkpoint来实现。

2.UpdateStateByKey 用于记录历史记录,有时,我们需要在 DStream 中跨批次维护状态(例 如流计算中累加 wordcount)。针对这种情况,updateStateByKey()提供了对一个状态变量的访问,用于键值对形式的 DStream。给定一个由(键,事件)对构成的 DStream,并传递一个指定如何根据新的事件更新每个键对应状态的函数,它可以构建出一个新的 DStream,其内部数据为(键, 状态) 对。
updateStateByKey() 的结果会是一个新的 DStream,其内部的 RDD 序列是由每个时间区间对应的(键,状态)对组成的。

二、代码实现

1.代码

package _0809kafka

import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.{SparkConf, SparkContext}

/**
 *
 * 之前做的计算当中,当前批次的计算值不会累加到下一个批次
 *
 * 当前批次的值计算完之后,存到外部存储系统中
 * 下一个批次计算完值之后,在取出上一个批次计算出来的值,
 * 做相加,更新会原位置上
 *
 * checkpoint会保留上一个程序的ssc的状态和upXXXX的结果
 * 但是构造ssc的时候,必须按照规矩写,否则就读不到upXXXX上一次的结果
 */
object UpdateStateByKeyAPI_1020 {
  def main(args: Array[String]) {
    //使用checkpoint来存储批次的数据
    //1、创建sparkConf
    val sparkConf: SparkConf = new SparkConf()
      .setAppName("UpdateStateByKeyAPI")
      .setMaster("local[2]")
    //2、创建sparkContext
    val sc = new SparkContext(sparkConf)

//    val path = s"file:///E:\\workspace\\SparkPro\\checkpoint\\streaming_05"
    val path = s"file:///E:\\Tools\\WorkspaceforMyeclipse\\scalaProjectMaven\\streaming_07"

      val ssc = new StreamingContext(sc,Seconds(10))
      ssc.checkpoint(path)
      val socketDStream: ReceiverInputDStream[String] = ssc.socketTextStream("hadoop",9999)

      //api updateStateByKey
      val resultDStream: DStream[(String, Long)] = socketDStream.mapPartitions(iter =>{
        //对于当前批次的值做数据转换
        iter.flatMap(_.split(" "))
          .filter(_.nonEmpty)
          .map(word => (word,1))
      })
        //对于当前批次的值,做累加(aggr聚合)操作
        .reduceByKey(_ + _)
        //对于value的操作,相同key怎么处理对应的value
        .updateStateByKey((seq: Seq[Int],state: Option[Long])=>{
        //当前批次的相同key的value的聚合值
        val sum = seq.sum
        val preState= state.getOrElse(0L)

        /**
         * if(sum + preState > 1000){
         * Some(sum + preState)
         * }else{
         * //清空当前key的value值
         * None
         * }
         */
        Some(sum + preState)
      })

      resultDStream.foreachRDD((rdd,time) =>{
        println(s"----------------当前时间为:${time}----------------")
        //比如说:某些key不打印,某些值过于小也可以不打印,或者打印排序后的前5
        rdd.filter(t =>{
          t._2 > 10
        }).foreach(println)
      })


    ssc.start()
    ssc.awaitTermination()


  }
}

或者

package _20200302Spark
import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}
/**
  * Created by Administrator on 2020/3/2.
  */
object UpdateStateByKeyNew {

  def main(args: Array[String]): Unit = {

    // 定义更新状态方法,参数 values 为当前批次单词频度,state 为以往批次单词频度
    val updateFunc = (values: Seq[Int], state: Option[Int]) => {
      val currentCount = values.foldLeft(0)(_ + _)
      val previousCount = state.getOrElse(0)
      Some(currentCount + previousCount)
    }


    val conf = new SparkConf().setMaster("local[*]").setAppName("NetworkWordCount")
    val ssc = new StreamingContext(conf, Seconds(3))
    ssc.checkpoint("./ck")
    // Create a DStream that will connect to hostname:port, like hadoop102:9999
    val lines = ssc.socketTextStream("hadoop", 9999)
    // Split each line into words
    val words = lines.flatMap(_.split(" "))
    //import org.apache.spark.streaming.StreamingContext._ // not necessary since Spark 1.3
    // Count each word in each batch
    val pairs = words.map(word => (word, 1))
    // 使用 updateStateByKey 来更新状态,统计从运行开始以来单词总的次数
    val stateDstream = pairs.updateStateByKey[Int](updateFunc)
    stateDstream.print()
    ssc.start() // Start the computation
    ssc.awaitTermination() // Wait for the computation to terminate
    //ssc.stop()

  }
}

2.测试

(1)打开nc
            nc -lt 9999

(2)运行程序

(3)结果:

----------------当前时间为:1540003980000 ms----------------
(hadoophadoop,36)
(hadoop,144)
(ccs,108)
----------------当前时间为:1540003990000 ms----------------
(hadoophadoop,36)
(hadoop,144)
(ccs,108)

3.重点

(1)checkpoint会保留上一个程序的ssc的状态和updateStateByKey的结果

(2)updateStateByKey当前批次的值计算完之后,存到外部存储系统中。下一个批次计算完值之后,在取出上一个批次计算出来的值。将两个批次做相加,更新会原位置上

(3)但是不能保存数据,sparkstreaming重新启动后,之前的结果是不保存的。(如果想要保存,参考下一节的ha的配置)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值