spark中 3大数据结构
- RDD : (弹性分布,分布式数据集)
- 广播变量 : 分布式的 只读共享变量
- 累加器 : 分布式的只写共享变量
在某些情况下用rdd计算不是很好,所以有了 广播变量和累加器
例:
val ints: RDD[Int] = spark.sparkContext.makeRDD(Array(1, 2, 3, 4), 2)
var sum = 0
ints.foreach(x=> {
sum += x
})
println(sum) // 0
//解释如下: sum 在 drver 端, 当executor 端 需要用到 driver端的sum 变量是, driver端会发送sum=0到executor,在 executor端 会进行累加计算,
//但是累加后的值不会返回给driver端 所以sum端的值还是 0
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200410102003381.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3pwMTIyMA==,size_16,color_FFFFFF,t_70)
因此需要使用共享变量 (累加器)
val conf = new SparkConf()
conf.setMaster("local[*]").setAppName("SessionStepTime01")
val spark = SparkSession.builder().config(conf).enableHiveSupport().getOrCreate()
spark.sparkContext.setLogLevel("warn")
val ints: RDD[Int] = spark.sparkContext.makeRDD(Array(1, 2, 3, 4), 2)
var sum = 0
//ints.foreach(x=> {
sum += x
// })
// println(sum)
val accumulator: LongAccumulator = spark.sparkContext.longAccumulator
ints.foreach(x=> {
//执行累加器累加功能
accumulator.add(x)
})
//获取累加器的值
sum = accumulator.value
println(sum ) // 10
自定义累加器使用
import org.apache.spark.util.AccumulatorV2
import scala.collection.mutable
/**
* 自定义累加器
*/
/**
* AccumulatorV2 里面需要两个参数 一个输入类型, 一个输出类型
*/
class SessionAggrStatAccumulator extends AccumulatorV2[String, mutable.HashMap[String, Int]] {
// 保存所有聚合数据 定义输出的对象(返回的对象)
private val aggrStatMap = mutable.HashMap[String, Int]()
//单钱你累加器是否为出事状态
override def isZero: Boolean = {
aggrStatMap.isEmpty
}
//复制累加器状态
override def copy(): AccumulatorV2[String, mutable.HashMap[String, Int]] = {
val newAcc = new SessionAggrStatAccumulator
aggrStatMap.synchronized{
newAcc.aggrStatMap ++= this.aggrStatMap
}
newAcc
}
//重置累加器对象
override def reset(): Unit = {
aggrStatMap.clear()
}
//根据业务逻辑,向累加器中增加数据
override def add(v: String): Unit = {
if (!aggrStatMap.contains(v))
aggrStatMap += (v -> 0)
aggrStatMap.update(v, aggrStatMap(v) + 1)
}
//合并累加器 (不同executor端的数据进行合并 返回driver端)
override def merge(other: AccumulatorV2[String, mutable.HashMap[String, Int]]): Unit = {
other match {
case acc:SessionAggrStatAccumulator => {
(this.aggrStatMap /: acc.value){ case (map, (k,v)) => map += ( k -> (v + map.getOrElse(k, 0)) )}
}
}
}
//输出的值
override def value: mutable.HashMap[String, Int] = {
this.aggrStatMap
}
}
// 设置自定义累加器,实现所有数据的统计功能,注意累加器也是懒执行的
val sessionAggrStatAccumulator = new SessionAggrStatAccumulator
// 注册自定义累加器
sc.register(sessionAggrStatAccumulator, "sessionAggrStatAccumulator")
//添加值
sessionAggrStatAccumulator.add("1-2");
//获取值
val value: mutable.HashMap[String, Int] = sessionAggrStatAccumulator.value