【大数据面试知识点】Spark中的累加器

Spark累加器

累加器用来把Executor端变量信息聚合到Driver端,在driver程序中定义的变量,在Executor端的每个task都会得到这个变量的一份新的副本,每个task更新这些副本的值后,传回driver端进行merge。

累加器一般是放在行动算子中进行操作的。

Spark累加器有哪些特点?

1)累加器在全局唯一的,只增不减,记录全局集群的唯一状态

2)在Executor中修改它,在Driver读取

3)executor级别共享的,广播变量是task级别的共享两个application不可以共享累加器,但是同一个app不同的job可以共享

应用举例

不经过Shuffle实现词频统计

Scala 复制代码
object Spark06_Accumulator {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf().setAppName(this.getClass.getName).setMaster("local[*]")
    val sc = new SparkContext(conf)
    val rdd: RDD[(String, Int)] = sc.makeRDD(List(("a", 1), ("b", 2), ("a", 3), ("b", 4)))
    // 声明累加器
    val sumAcc: LongAccumulator = sc.longAccumulator("sumAcc")
    rdd.foreach {
      case (word, count) => {
        // 使用累加器
        sumAcc.add(count)
      }
    }
    // 累加器的toString方法
    //println(sumAcc)
    //取出累加器中的值
    println(sumAcc.value)
    sc.stop()
  }
}

不经过shuffle,计算以H开头的单词出现的次数。

Scala 复制代码
object Spark07_MyAccumulator {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf().setAppName(this.getClass.getName).setMaster("local[*]")
    val sc = new SparkContext(conf)
    val rdd: RDD[String] = sc.makeRDD(List("Hello", "HaHa", "spark", "scala", "Hi", "Hello", "Hi"))
    // 创建累加器
    val myAcc = new MyAccumulator
    //注册累加器
    sc.register(myAcc, "MyAcc")
    rdd.foreach{
      datas => {
        // 使用累加器
        myAcc.add(datas)
      }
    }
    // 获取累加器的结果
    println(myAcc.value)

    sc.stop()
  }
}

// 自定义累加器
// 泛型分别为输入类型和输出类型
class MyAccumulator extends AccumulatorV2[String, mutable.Map[String, Int]] {
  // 定义输出数据变量
  var map: mutable.Map[String, Int] = mutable.Map[String, Int]()

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

  // 复制累加器
  override def copy(): AccumulatorV2[String, mutable.Map[String, Int]] = {
    val MyAcc = new MyAccumulator
    // 将此累加器中的数据赋值给新创建的累加器
    MyAcc.map = this.map
    MyAcc
  }

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

  // 累加器添加元素
  override def add(v: String): Unit = {
    if (v.startsWith("H")) {
      // 判断map集合中是否已经存在此元素
      map(v) = map.getOrElse(v, 0) + 1
    }
  }

  // 合并累加器中的元素
  override def merge(other: AccumulatorV2[String, mutable.Map[String, Int]]): Unit = {
    val map1: mutable.Map[String, Int] = this.map
    val map2: mutable.Map[String, Int] = other.value
    // 合并两个map
    map = map1.foldLeft(map2) {
      (m, kv) => {
        m(kv._1) = m.getOrElse(kv._1, 0) + kv._2
        m
      }
    }
  }

  // 获取累加器中的值
  override def value: mutable.Map[String, Int] = {
    map
  }
}

参考:Spark累加器的作用和使用-CSDN博客

相关推荐
isfox30 分钟前
Google GFS 深度解析:分布式文件系统的开山之作
大数据·hadoop
boonya44 分钟前
Redis核心原理与面试问题解析
数据库·redis·面试
用户Taobaoapi20141 小时前
京东店铺所有商品API技术开发文档
大数据·数据挖掘·数据分析
在未来等你1 小时前
Kafka面试精讲 Day 8:日志清理与数据保留策略
大数据·分布式·面试·kafka·消息队列
沐怡旸2 小时前
【算法--链表】114.二叉树展开为链表--通俗讲解
算法·面试
江畔独步2 小时前
Flink TaskManager日志时间与实际时间有偏差
大数据·flink
白水清风2 小时前
关于Js和Ts中类(class)的知识
前端·javascript·面试
TDengine (老段)2 小时前
TDengine 选择函数 Last() 用户手册
大数据·数据库·sql·物联网·时序数据库·tdengine·涛思数据
TDengine (老段)3 小时前
TDengine 选择函数 First 用户手册
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
小林学习编程4 小时前
2025年最新AI大模型原理和应用面试题
人工智能·ai·面试