Spark-累加器
实现原理
累加器: 分布式共享的只写变量
累加器用来把Executor 端变量信息聚合到Driver 端。在Driver 程序中定义的变量,在Executor 端的每个Task 都会得到这个变量的一份新的副本,每个 task 更新这些副本的值后, 传回Driver 端进行 merge。
系统累加器
import org.apache.spark.{SparkConf, SparkContext}
object acc_01 {
def main(args: Array[String]): Unit = {
val sparConf = new SparkConf().setMaster("local").setAppName("wordCount")
val sc = new SparkContext(sparConf)
val rdd = sc.makeRDD(List(1,2,3,4))
//获取系统累加器
//Spark默认就提供了简单数据聚合的累加器
val sumAcc = sc.longAccumulator("sum")
rdd.foreach(
num => {
sumAcc.add(num)
}
)
println(sumAcc.value)
sc.stop()
}
}
累加器的问题
- 少加: 转换算子中调用累加器,如果没有行动算子的话,那么不会执行
- 多加: 转换算子中调用累加器,如果多次调用行动算子会出现多加情况
- 一般情况下,累加器会放置在行动算子中
自定义数据累加器
自定义类要:
- 继承AccumulatorV2, 然后定义泛型
- 重写方法
具体看代码
import org.apache.spark.util.AccumulatorV2
import org.apache.spark.{SparkConf, SparkContext}
import scala.collection.mutable
object acc_02 {
def main(args: Array[String]): Unit = {
val sparConf = new SparkConf().setMaster("local").setAppName("wordCount")
val sc = new SparkContext(sparConf)
val rdd = sc.makeRDD(List("hello", "spark", "hello"))
//累加器
//创建累加器对象
val wcAcc = new MyAccumulator
//向Spark进行注册
sc.register(wcAcc, "wordCountAcc")
rdd.foreach(
word => {
//使用累加器
wcAcc.add(word)
}
)
println(wcAcc.value)
sc.stop()
}
/*
自定义数据累加器:wordCount
1. 继承AccumulatorV2, 然后定义泛型
IN :累加器输入的数据类型
OUT : 累加器返回的数据类型
2. 重写方法
*/
class MyAccumulator extends AccumulatorV2[String,mutable.Map[String,Long]]{
private val 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) => {
val newCount = map1.getOrElse(word, 0L) + count
map1.update(word, newCount)
}
}
}
//累加器结果
override def value: mutable.Map[String, Long] = {
wcMap
}
}
}
Spark-广播变量
广播变量: 分布式共享的只读变量
广播变量用来高效分发较大的对象。向所有工作节点发送一个较大的只读值,以供一个或多个 Spark 操作使用。
Executor其实就是一个JVM, 所以在启动时, 会自动分配内存, 完全可以将任务重的闭包数据放置在Executor的内存中, 达到共享目的
spark的广播变量就可以将闭包数据保存到Executor的内存中
val rdd1 = sc.makeRDD(List( ("a",1), ("b", 2), ("c", 3), ("d", 4) ),4)
val list = List( ("a",4), ("b", 5), ("c", 6), ("d", 7) )
// 声明广播变量
val broadcast: Broadcast[List[(String, Int)]] = sc.broadcast(list)
val resultRDD: RDD[(String, (Int, Int))] = rdd1.map { case (key, num) => {
var num2 = 0
// 使用广播变量
for ((k, v) <- broadcast.value) { if (k == key) {
num2 = v
}
}
(key, (num, num2))
}
}
MVC&三层架构
MVC: model view controller架构模式
三层架构:: Controller(控制层) service(服务层) dao(持久层)
ount
1. 继承AccumulatorV2, 然后定义泛型
IN :累加器输入的数据类型
OUT : 累加器返回的数据类型
2. 重写方法
*/
class MyAccumulator extends AccumulatorV2[String,mutable.Map[String,Long]]{
private val 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) => {
val newCount = map1.getOrElse(word, 0L) + count
map1.update(word, newCount)
}
}
}
//累加器结果
override def value: mutable.Map[String, Long] = {
wcMap
}
}
}
# Spark-广播变量
广播变量: 分布式共享的只读变量
广播变量用来高效分发较大的对象。向**所有工作节点发送**一个较大的只读值,**以供一个或多个 Spark 操作使用**。
**Executor**其实就是一个**JVM**, 所以在启动时, 会自动分配内存, 完全可以将任务重的闭包数据放置在**Executor**的内存中, 达到共享目的
**spark的广播变量就可以将闭包数据保存到Executor的内存中**
```scala
val rdd1 = sc.makeRDD(List( ("a",1), ("b", 2), ("c", 3), ("d", 4) ),4)
val list = List( ("a",4), ("b", 5), ("c", 6), ("d", 7) )
// 声明广播变量
val broadcast: Broadcast[List[(String, Int)]] = sc.broadcast(list)
val resultRDD: RDD[(String, (Int, Int))] = rdd1.map { case (key, num) => {
var num2 = 0
// 使用广播变量
for ((k, v) <- broadcast.value) { if (k == key) {
num2 = v
}
}
(key, (num, num2))
}
}
MVC&三层架构
MVC: model view controller架构模式
三层架构:: Controller(控制层) service(服务层) dao(持久层)
文章详细介绍了Spark中的累加器概念,包括其作为分布式共享的只写变量的特性,如何实现累加以及可能出现的问题。同时,提到了系统累加器和自定义数据累加器的创建过程。另外,文章还讨论了广播变量,这是一种只读的分布式共享变量,用于高效分发大对象并存储在Executor内存中以供多个操作使用。
1291

被折叠的 条评论
为什么被折叠?



