累加器
Spark 计算框架为了能够进行高并发和高吞吐的数据处理,封装了三大数据结构,用于处理不同的应用场景。三大数据结构分别是:
- RDD : 弹性分布式数据集
- 累加器:分布式共享只写变量
- 广播变量:分布式共享只读变量
1.实现原理
累加器用来把Executor 端变量信息聚合到Driver 端。在Driver 程序中定义的变量,在Executor 端的每个Task 都会得到这个变量的一份新的副本,每个 task 更新这些副本的值后, 传回Driver 端进行 merge。
2.系统累加器
object Spark_rdd_01 {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("RDD").setMaster("local[*]")
val sc = new SparkContext(conf)
val rdd: RDD[Int] = sc.makeRDD(List(1,2,3,4))
//获取系统累加器
//Spark默认就提供了简单数据聚合的累加器
val sum: LongAccumulator = sc.longAccumulator("sum")
val value: RDD[Int] = rdd.map(num => {
//使用累加器
sum.add(num)
num
})
//获取累加器的值
//少加:转换算子中调用累加器,如果没有行动算子,那么不会执行
//多加:转换算子调用累加器,执行一次行动算子,累加器就会更新一次
//一般情况下,累加器会放置在行动算子中进行操作
println(sum.value)
println("------------")
value.collect()
println(sum.value)
println("------------")
value.collect()
println(sum.value)
sc.stop()
}
}
0
------------
10
------------
20
3.自定义累加器
实现wordcount
object Spark_rdd_01 {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("RDD").setMaster("local[*]")
val sc = new SparkContext(conf)
val rdd: RDD[String] = sc.makeRDD(List("hello","spark","hello"))
//创建累加器对象
val acc = new Accumulate
//向spark进行注册
sc.register(acc,"wordcount")
//遍历
rdd.foreach(word=>{
//数据的累加,使用累加器
acc.add(word)
})
//获取累加器累加的结果
println(acc.value)
sc.stop()
}
/*
自定义数据累加器
实现的功能:wordcount
继承AccumulatorV2
AccumulatorV2两个参数,IN和OUT
IN:累加器输入的数据类型
OUT:累加器返回的数据类型
*/
class Accumulate extends AccumulatorV2[String,mutable.Map[String,Long]]{
//新建一个空集合来接受累加器的值
private var accMap=mutable.Map[String,Long]()
//判断是否是初始状态
override def isZero: Boolean = {
accMap.isEmpty
}
//复制一个新累加器
override def copy(): AccumulatorV2[String, mutable.Map[String, Long]] = {
new Accumulate
}
//重置累加器,就是把集合里的数据清空
override def reset(): Unit = {
accMap.clear()
}
//获取累加器需要计算的值
override def add(word: String): Unit = {
//判断集合是否有这个单词
//如果有数量加1,表示当前出现一次,得到新的总数
//如果没有找到这个单词,默认数量为0再加1
//接下来集合的数据更新一下
val newcount: Long = accMap.getOrElse(word,0L)+1
accMap.update(word,newcount)
}
//Driver合并累加器操作
//相当于两个map的合并
override def merge(other: AccumulatorV2[String, mutable.Map[String, Long]]): Unit = {
var map1=this.accMap
var map2=other.value
map2.foreach{
case (word,count)=>
val newCount: Long = map1.getOrElse(word,0L)+count
map1.update(word,newCount)
}
}
//累加器结果
override def value: mutable.Map[String, Long] = {
accMap
}
}
}
Map(spark -> 1, hello -> 2)