如果没有累加器
看下面代码,我定义一个sum,想把K-V类型的RDD算子的value值都加在一起,我把这个算子分成了两个区
结果foreach循环后发现sum的值在foreach内确实是在累加的,但是在foreach外sum确是0
object FailTest {
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("test")
val sc = new SparkContext(conf)
val rdd = sc.parallelize(Array(("ssss.txt", 1), ("ssss.csv", 2), ("ssss.txt", 3), ("ssss.txt", 4), ("ssss.aaa", 4)))
var sum = 0
rdd.foreach(x => {
sum += x._2
println(sum)
//1 1
//3 1+2
//----------
//3 3
//7 3+4
//11 3+4+4
})
println(sum)
//0
}
}
最终结果
1
3
3
7
11
0
通过研究发现,spark有driver和executor两个部分,我是在driver端定义的sum,然后因为是rdd算子的foreach,所以我把sum传到executor端执行算子操作所以说sum是在executor端执行累加的
但是一旦我出了rdd.foreach我就会回到driver端,而executor是没有把两个分区内executor的结果传回来的,所以sum还是0
累加器诞生
因此spark引入累加器的概念,这个累加器在driver端和executor端共享,所以把代码改成下面这样
object Sharedata_accumulator {
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("test")
val sc = new SparkContext(conf)
val rdd = sc.parallelize(Array(("ssss.txt", 1), ("ssss.csv", 2), ("ssss.txt", 3), ("ssss.txt", 4), ("ssss.aaa", 4)))
var sum = 0L
//创建累加器
val accumulator: LongAccumulator = sc.longAccumulator
rdd.foreach(x => {
//利用累加器把values相加
accumulator.add(x._2)
})
//把累加器的结果给sum
sum = accumulator.value
println(sum)
//14
}
}
自定义累加器
先自己定义一个累加器,想要把k-v中values大于4的values放到一个集合
package spark.accumulator
import java.util
import org.apache.spark.util.AccumulatorV2
class Myaccumulator extends AccumulatorV2[Int, util.ArrayList[Int]] {
val arrlist = new util.ArrayList[Int]()
//是否是空
override def isZero: Boolean = arrlist.isEmpty
//拷贝出一份Myaccumulator
override def copy(): AccumulatorV2[Int, util.ArrayList[Int]] = new Myaccumulator()
//初始化aeelist数组,使其为空
override def reset(): Unit = arrlist.clear()
//往arrlist增加数据
override def add(v: Int): Unit =
//把值大于5的放到arrlist
if(v>3) {
arrlist.add(v)
}
//把各个分区的arrlist合并到一起
override def merge(other: AccumulatorV2[Int, util.ArrayList[Int]]): Unit =
arrlist.addAll(other.value)
//把合并好的arrlist发送给val值
override def value: util.ArrayList[Int] = arrlist
}
测试代码
object MyaccumulatorTest {
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("test")
val sc = new SparkContext(conf)
val rdd = sc.parallelize(Array(("ssss.txt", 1), ("ssss.csv", 2), ("ssss.txt", 3), ("ssss.txt", 4), ("ssss.aaa", 4)))
//创建累加器,这个累加器是把大于4的values放到一个集合内
val myaccumulator = new Myaccumulator()
sc.register(myaccumulator)
rdd.foreach(x => {
//利用累加器把values相加
myaccumulator.add(x._2)
})
//把累加器的结果给sum
val value: util.ArrayList[Int] = myaccumulator.value
println(value)
//[4, 4]
}
}