第五章_Spark核心编程_累加器

 


1. 什么是累加器

累加器是用来把Executor端的变量信息聚合到Driver端

2. 累加器实现原理

  *     在Driver程序中定义的变量,在Executor端的每个Task节点上都会复制这个变量的副本
  *         ,每个Task节点更新这些副本的值后,再传回Driver端进行merge

3. 怎样获取累加器?

复制代码
  *     1. 系统自带累加器
  *           long类型累加器
  *               def longAccumulator: LongAccumulator
  *               def longAccumulator(name: String): LongAccumulator
  *           double类型累加器
  *               def doubleAccumulator: DoubleAccumulator
  *               def doubleAccumulator(name: String): DoubleAccumulator
  *           collect类型累加器
  *               def collectionAccumulator[T]: CollectionAccumulator[T]
  *               def collectionAccumulator[T](name: String): CollectionAccumulator[T]
  *
  *     2. 自定义累加器
复制代码

4.怎样实现自定义累加器?

  *   1.继承AccumulatorV2,定义泛型
  *       abstract class AccumulatorV2[IN, OUT]
  *           IN : 累加器输入的数据类型(一般为要累加Rdd的元素类型)
  *           OUT : 累加器返回的数据类型
  *   2.重新方法

5. 示例(spark 自带累加器)

复制代码
  /*spark 自带累加器*/
  object accTest {
    def main(args: Array[String]): Unit = {
      val sparkconf: SparkConf = new SparkConf().setMaster("local").setAppName("distinctTest")

      val sc: SparkContext = new SparkContext(sparkconf)

      val rdd1 = sc.makeRDD(List(1, 2, 3, 4, 5, 6, 7, 8, 9), 3)

      //普通变量
      var sum: Int = 0
      //初始化 系统累加器
      val accSumLong: LongAccumulator = sc.longAccumulator("sumAcc-long")
      val accSumdouble: DoubleAccumulator = sc.doubleAccumulator("sumAcc-double")
      val accSumcollect: CollectionAccumulator[Int] = sc.collectionAccumulator("sumAcc-collect")

      //对变量进行累加
      rdd1.foreach(sum += _)

      //使用累加器对元素进行累加
      rdd1.foreach(accSumLong.add(_))
      rdd1.foreach(accSumdouble.add(_))
      rdd1.foreach(accSumcollect.add(_))

      //查看累加结果
      println(s"sum:${sum}")
      //获取累加器的value
      println(s"LongAccumulator:${accSumLong.name} - ${accSumLong.value}")
      println(s"LongAccumulator:${accSumdouble.name} - ${accSumdouble.value}")
      println(s"LongAccumulator:${accSumcollect.name} - ${accSumcollect.value}")

      sc.stop()
    }


  }
复制代码

6.示例(spark 自定义累加器)

复制代码
  /*spark 使用自定义累加器-实现wordcount*/
  object custAccTest {
    def main(args: Array[String]): Unit = {
      val sparkconf: SparkConf = new SparkConf().setMaster("local").setAppName("distinctTest")

      val sc: SparkContext = new SparkContext(sparkconf)

      val rdd = sc.textFile("Spark_319/src/data/*.txt")

      val rdd1 = rdd.flatMap(_.split(" "))

      //使用自定义累加器
      //向环境中注册累加器
      val acc = new custAccumulator
      sc.register(acc, "自定义累加器")

      //使用累加器对元素进行累加
      rdd1.foreach(acc.add(_))

      //获取累加器的value
      println(s"custAccumulator:${acc.name} - ${acc.value}")

      sc.stop()
    }
  }

  /*spark 自定义累加器*/
  /*
  * 需求 : 自定义累加器,实现 wordcount功能
  *     1.继承 AccumulatorV2抽象类
  *     2.初始化 map,利用map实现词频统计
  * */
  class custAccumulator extends AccumulatorV2[String, mutable.Map[String, Long]] {

    /*定义 可变map*/
    var map: mutable.Map[String, Long] = mutable.Map()

    /*判断 累加器是否为初始状态*/
    override def isZero: Boolean = map.isEmpty

    //为当前累加器创建一个 新副本
    //发送到不同的task节点
    override def copy(): AccumulatorV2[String, mutable.Map[String, Long]] = new custAccumulator

    //重置累加器(清空累加器)
    override def reset(): Unit = map.clear()

    //获取数据并进行累加
    //根据指定的规则,向累加器中添加元素
    override def add(word: String): Unit = {
      /*添加规则
      *   1.查询map中是否存在key=word
      *       如果存在则
      *           (key,value+1)
      *       如果不存在则
      *           (key,1
      * */
      val newCnt: Long = map.getOrElse(word, 0L) + 1
      map.update(word, newCnt)
    }

    //合并累加器
    override def merge(other: AccumulatorV2[String, mutable.Map[String, Long]]): Unit = {
      var map1 = this.map
      var map2 = other.value

      //merge-in-place
      map = map1.foldLeft(map2)(
        (innerMap, kv) => {
          innerMap(kv._1) = innerMap.getOrElse(kv._1, 0L) + kv._2
          innerMap
        }
      )

    }

    //返回当前累加器结果
    override def value: mutable.Map[String, Long] = map
  }
复制代码

 

posted @   学而不思则罔!  阅读(147)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界
点击右上角即可分享
微信分享提示