累加器作用
- 累加器:分布式只写变量(Executor端的task不能互相访问累加器的值)。
- 累加器对信息进行聚合。向Spark传递函数时,通常可以使用Driver端定义的变量,但是在Executor端使用此变量时,每个task中使用的都是此变量的副本。如果变量的值发生了变化,Driver端的变量值却不会改变。
- 我们可以通过累加器实现分片处理,同时更新变量值。
使用默认累加器
需求
不经过shuffle,实现词频统计
bject 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开头的单词出现的次数。
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
}
}