Spark学习-累加器和广播

文章详细介绍了Spark中的累加器概念,包括其作为分布式共享的只写变量的特性,如何实现累加以及可能出现的问题。同时,提到了系统累加器和自定义数据累加器的创建过程。另外,文章还讨论了广播变量,这是一种只读的分布式共享变量,用于高效分发大对象并存储在Executor内存中以供多个操作使用。

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()
  }
}

累加器的问题

  • 少加: 转换算子中调用累加器,如果没有行动算子的话,那么不会执行
  • 多加: 转换算子中调用累加器,如果多次调用行动算子会出现多加情况
  • 一般情况下,累加器会放置在行动算子中

自定义数据累加器

自定义类要:

  1. 继承AccumulatorV2, 然后定义泛型
  2. 重写方法

具体看代码

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(持久层)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值