SPARK 数据结构(累加器+广播变量)详解

累加器用来把Executor端变量信息聚合到Driver端。在Driver程序中定义的变量,在Executor端的每个Task都会得到这个变量的一份新的副本,每个task更新这些副本的值后,传回Driver端进行merge(合并操作)

举个例子,计算1+2+3+4:

val rdd = sc.makeRDD(List(1,2,3,4))


var sum = 0
rdd.foreach(
    num => {
         sum += num
           }
)

println("sum = " + sum)
//sum = 0,因为executer的sum值无法传到driver中。
//若用rdd.collect().foreach()则为10

使用累加器(以下仅使用系统累加器,若要自定义可继承AccumulatorV2,并设定泛型 ,重写累加器的抽象方法):

val rdd = sc.makeRDD(List(1,2,3,4))

// 获取系统累加器
// Spark默认就提供了简单数据聚合的累加器
val sumAcc = sc.longAccumulator("sum")

//sc.doubleAccumulator
//sc.collectionAccumulator

rdd.foreach(
   num => {
        // 使用累加器
        sumAcc.add(num)
      }
)

// 获取累加器的值
println(sumAcc.value)

需要注意的是:

容易出现少加/多加的情况,比如转换算子中调用累加器,如果没有行动算子的话,那么不会执行。一般情况下,累加器会放置在行动算子进行操作。

 二、广播变量

广播变量用来高效分发较大的对象。向所有工作节点发送一个较大的只读值(无法更改),以供一个或多个Spark操作使用。比如,如果你的应用需要向所有节点发送一个较大的只读查询表,广播变量用起来都很顺手。在多个并行操作中使用同一个变量,但是 Spark会为每个任务分别发送。(类似全局变量)

闭包数据,都是以Task为单位发送的,每个任务中包含闭包数据,这样可能会导致一个Executor中含有大量重复的数据,并且占用大量内存,Executor其实就一个JVM,所以在启动中,会自动分配内存,完全可以将任务中的闭包数据放置在Executor的内存中,达到共享的目的。

        val rdd1 = sc.makeRDD(List(
            ("a", 1),("b", 2),("c", 3)
        ))
//        val rdd2 = sc.makeRDD(List(
//            ("a", 4),("b", 5),("c", 6)
//        ))
        val map = mutable.Map(("a", 4),("b", 5),("c", 6))



        // join会导致数据量几何增长,并且会影响shuffle的性能,不推荐使用
        //val joinRDD: RDD[(String, (Int, Int))] = rdd1.join(rdd2)
        //joinRDD.collect().foreach(println)
        // (a, 1),    (b, 2),    (c, 3)
        // (a, (1,4)),(b, (2,5)),(c, (3,6))
        rdd1.map {
            case (w, c) => {
                val l: Int = map.getOrElse(w, 0)
                (w, (c, l))
            }
        }.collect().foreach(println)

使用广播变量:

        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 l: Int = bc.value.getOrElse(w, 0)
                (w, (c, l))
            }
        }.collect().foreach(println)

 附:

  1. Spark数据结构RDD介绍可移步至:SparkRDD
  2. SparkSQL项目实操可移步至:sparksql项目实操

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数据求学家

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值