累加器:分布式共享只写变量
1. 把Executor端的信息聚合到Driver端
2. 在Driver程序中定义的变量,在Executor端的每个Task都会得到这个变量的新的副本
每个task更新副本的值之后,传回Driver端进行merge(合并)
3.原理类似于mapreduce,分布式改变,然后聚合这些改变
自定义累加器:
package com.hch.acc
import org.apache.spark.util.AccumulatorV2
import org.apache.spark.{SparkConf, SparkContext}
import scala.collection.mutable
/**
* @author Joey413
*/
object Spark03_Acc_WordCount {
def main(args: Array[String]): Unit = {
val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Acc_WordCount")
val sc: SparkContext = new SparkContext(sparkConf)
val rdd = sc.makeRDD(List("judy", "joey", "rose"))
// 累加器
// 创建累加器对象
val wcAcc = new MyAccumulator
// 向spark进行注册
sc.register(wcAcc, "wordCountAcc")
rdd.foreach(
word => {
// 使用累加器
wcAcc.add(word)
}
)
println(wcAcc.value)
sc.stop()
}
/**
* 自定义数据累加器:WordCount
* 1. 继承AccumulatorV2 定义泛型
* IN : 累加器输入的数据类型 String
* OUT : 累加器返回的数据类型 Map
*/
class MyAccumulator extends AccumulatorV2[String, mutable.Map[String, Long]] {
private var wcMap = 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(word: String): Unit = {
val newCnt = wcMap.getOrElse(word, 0L) + 1
wcMap.update(word, newCnt)
}
// Driver端合并多个累加器
override def merge(other: AccumulatorV2[String, mutable.Map[String, Long]]): Unit = {
val map1 = this.wcMap
val map2 = other.value
map2.foreach{
case (word, count) => {
// map1数据累加
val newCount = map1.getOrElse(word, 0L) + count
// 更新map1数据更新
map1.update(word, newCount)
}
}
}
// 累加器结果
override def value: mutable.Map[String, Long] = {
wcMap
}
}
}
广播变量: 分布式共享只读变量
1. 用来分发较大的对象,以供一个或多个Spark操作使用
2. 在多个并行操作中使用同一个变量,但是Spark会为每个任务分别发送
3. 闭包数据以task为单位发送,每个任务包含闭包数据(冗余数据过多消耗内存,降低性能)
4. Executor 即相当于一个JVM进程,启动时会自动分配内存,将任务中的闭包数据放置在Executor的内存中达到共享目的
5. Spark中的广播变量可以将闭包的数保存到Executor的内存中(只读 = 不可修改)
广播变量案例:
package com.hch.acc
import org.apache.spark.broadcast.Broadcast
import org.apache.spark.{SparkConf, SparkContext}
import scala.collection.mutable
/**
* @author Joey413
*/
object Spark05_Bc {
def main(args: Array[String]): Unit = {
val sparkConf = new SparkConf().setMaster("local[*]").setAppName("BC2")
val sc: SparkContext = new SparkContext(sparkConf)
val rdd1 = sc.makeRDD(List(
("a", 1), ("b", 2), ("c", 3)
))
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()
}
}
浙公网安备 33010602011771号