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
}