Spark——累加器的理解

博客介绍了在 Spark 中遇到的问题,即在 foreach 循环中变量无法正确累加,原因是 driver 和 executor 之间的数据隔离。为解决此问题,文章引入了 Spark 的累加器,并展示了如何使用 LongAccumulator 实现数值累加。此外,还自定义了一个累加器,用于收集值大于 4 的元素,进一步说明了累加器如何在不同分区间合并结果。
摘要由CSDN通过智能技术生成

如果没有累加器

看下面代码,我定义一个sum,想把K-V类型的RDD算子的value值都加在一起,我把这个算子分成了两个区
结果foreach循环后发现sum的值在foreach内确实是在累加的,但是在foreach外sum确是0

object FailTest {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("test")
    val sc = new SparkContext(conf)
    val rdd = sc.parallelize(Array(("ssss.txt", 1), ("ssss.csv", 2), ("ssss.txt", 3), ("ssss.txt", 4), ("ssss.aaa", 4)))
    var sum = 0
    rdd.foreach(x => {
      sum += x._2
        println(sum)
   	  //1		1
      //3		1+2
      //----------
      //3		3
      //7		3+4
      //11		3+4+4
    })
    println(sum) 
    //0
  }
}

最终结果

1
3
3
7
11
0

通过研究发现,spark有driver和executor两个部分,我是在driver端定义的sum,然后因为是rdd算子的foreach,所以我把sum传到executor端执行算子操作所以说sum是在executor端执行累加的

但是一旦我出了rdd.foreach我就会回到driver端,而executor是没有把两个分区内executor的结果传回来的,所以sum还是0

累加器诞生

因此spark引入累加器的概念,这个累加器在driver端和executor端共享,所以把代码改成下面这样

object Sharedata_accumulator {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("test")
    val sc = new SparkContext(conf)
    val rdd = sc.parallelize(Array(("ssss.txt", 1), ("ssss.csv", 2), ("ssss.txt", 3), ("ssss.txt", 4), ("ssss.aaa", 4)))
    var sum = 0L
    //创建累加器
    val accumulator: LongAccumulator = sc.longAccumulator
    rdd.foreach(x => {
      //利用累加器把values相加
      accumulator.add(x._2)
    })
    //把累加器的结果给sum
    sum = accumulator.value
    println(sum)
    //14
  }
}

自定义累加器

先自己定义一个累加器,想要把k-v中values大于4的values放到一个集合

package spark.accumulator

import java.util

import org.apache.spark.util.AccumulatorV2

class Myaccumulator extends AccumulatorV2[Int, util.ArrayList[Int]] {
  val arrlist = new util.ArrayList[Int]()

  //是否是空
  override def isZero: Boolean = arrlist.isEmpty

  //拷贝出一份Myaccumulator
  override def copy(): AccumulatorV2[Int, util.ArrayList[Int]] = new Myaccumulator()

  //初始化aeelist数组,使其为空
  override def reset(): Unit = arrlist.clear()

  //往arrlist增加数据
  override def add(v: Int): Unit =
  //把值大于5的放到arrlist
    if(v>3) {
      arrlist.add(v)
    }

  //把各个分区的arrlist合并到一起
  override def merge(other: AccumulatorV2[Int, util.ArrayList[Int]]): Unit =
    arrlist.addAll(other.value)

  //把合并好的arrlist发送给val值
  override def value: util.ArrayList[Int] = arrlist
}

测试代码

object MyaccumulatorTest {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("test")
    val sc = new SparkContext(conf)
    val rdd = sc.parallelize(Array(("ssss.txt", 1), ("ssss.csv", 2), ("ssss.txt", 3), ("ssss.txt", 4), ("ssss.aaa", 4)))
    //创建累加器,这个累加器是把大于4的values放到一个集合内
    val myaccumulator = new Myaccumulator()
    sc.register(myaccumulator)
    rdd.foreach(x => {
      //利用累加器把values相加
      myaccumulator.add(x._2)
    })
    //把累加器的结果给sum
    val value: util.ArrayList[Int] = myaccumulator.value
    println(value)
    //[4, 4]
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值