累加器
原理
用来把Executor端变量信息聚合到Driver端。在Driver程序中定义的变量,在Executor端的每个Task都会得到这个变量的一份新的副本,每个task更新这些副本的值后,传回Driver端进行merge。
系统累加器
累加器的少加/多加问题在于转换算子没有/多次执行
object Spark03_Acc {
def main(args: Array[String]): Unit = {
val sparkConf = new SparkConf().setMaster("local[4]").setAppName("acc")
val sc = new SparkContext(sparkConf)
val rdd = sc.makeRDD(List(1, 2, 3, 4))
// println(rdd.reduce(_ + _))
val sum = sc.longAccumulator("sum")
//少加
/*rdd.map(num=>{
sum.add(num)
})*/
val mapRDD = rdd.map(num => {
sum.add(num)
})
mapRDD.collect()
//多加
mapRDD.collect()
println("sum="+sum.value)
sc.stop()
}
}
自定义累加器
-
继承AccumulatorV2,并设定泛型
-
重写累加器的抽象方法
object Spark04_Acc {
def main(args: Array[String]): Unit = {
val sparkConf = new SparkConf().setMaster("local[4]").setAppName("acc")
val sc = new SparkContext(sparkConf)
val rdd = sc.makeRDD(List("hello","spark","hello"))
val wcAcc = new MyAccumulator
sc.register(wcAcc,"wordCountAcc")
rdd.foreach(word=>{
wcAcc.add(word)
})
println(wcAcc.value)
sc.stop()
}
}
class MyAccumulator extends AccumulatorV2[String,mutable.Map[String,Long]]{
private val wcMap: mutable.Map[String, Long] = mutable.Map[String, Long]()
override def isZero: Boolean = wcMap.isEmpty
override def copy(): AccumulatorV2[String, mutable.Map[String, Long]] = new MyAccumulator
override def reset(): Unit = wcMap.clear()
override def add(v: String): Unit = {
val count = wcMap.getOrElse(v, 0L) + 1
wcMap.update(v,count)
}
override def merge(other: AccumulatorV2[String, mutable.Map[String, Long]]): Unit = {
other.value.foreach{case(w,c)=>{
val newCount = wcMap.getOrElse(w,0L)+c
wcMap.update(w,newCount)
}}
}
override def value: mutable.Map[String, Long] = wcMap
}
广播变量
在多个并行操作中使用同一个变量,但是 Spark会为每个任务分别发送。
广播变量用来高效分发较大的对象。向所有工作节点发送一个较大的只读值,以供一个或多个Spark操作使用。
//使用广播变量模拟join
object Spark06_Bc {
def main(args: Array[String]): Unit = {
val sparkConf = new SparkConf().setMaster("local[4]").setAppName("acc")
val sc = new SparkContext(sparkConf)
val rdd1 = sc.makeRDD(List(
("a", 1), ("b", 2), ("c", 3)
))
/*val rdd2 = sc.makeRDD(List(
("a", 4), ("b", 5), ("c", 6)
))
val joinRDD = rdd1.join(rdd2)*/
val map = mutable.Map(("a", 4), ("b", 5), ("c", 6))
val bc: Broadcast[mutable.Map[String, Int]] = sc.broadcast(map)
rdd1.map{
case (w,c)=>{
//访问广播变量
val i = bc.value.getOrElse(w, 0)
(w,(c,i))
}
}.collect().foreach(println)
sc.stop()
}