(9)累加器 & 广播变量

累加器 – 分布式共享只写变量

为什么要使用累加器

如果不使用累加器 求和,如下代码:

    val sparkConf = new SparkConf().setMaster("local[*]").setAppName("flatmap")
    val sc = new SparkContext(sparkConf)

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

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

    println(sum)

    sc.stop()

结果为0,因为变量sum和println 都在rdd之外,属于Driver端
rdd内的foreach方法,执行在Executor端,sum在分布式节点中累加之后,并没有将数据传回Driver端,
所以Driver端的sum还是0,打印出来也就是0
在这里插入图片描述

使用累加器之后

累加器用来把Executor端变量信息聚合到Driver端。在Driver程序中定义的变量,在Executor端的每个Task都会得到这个变量的一份新的副本,每个task更新这些副本的值后,传回Driver端进行merge。
在这里插入图片描述

累加器怎么使用

系统累加器

如果在转换算子中调用累加器,后续没有行动算子,累加器不会执行。后续如果调用了两次行动算子,会执行两次累加器,出现多加的情况。

所以一般情况下, 累加器会放在行动算子中进行操作。
如下代码所示:

    val rdd = sc.makeRDD(List(1,2,3,4))
    //注册累加器
    val sum: LongAccumulator = sc.longAccumulator("sum")
    rdd.foreach(num => sum.add(num))

    println(sum.value)

自定义累加器

object spark_acc {
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setMaster("local[*]").setAppName("flatmap")
    val sc = new SparkContext(sparkConf)

    //用自定义累加器实现wordCount
    val rdd1 = sc.makeRDD(List("hello","spark","hello","word"))
    //创建累加器
    val wcAccmulator: MyAccmulator = new MyAccmulator
    //注册累加器
    sc.register(wcAccmulator,"wcAccmulator")

    rdd1.foreach(word=>{
      wcAccmulator.add(word)
    })
    println(wcAccmulator.value)


    sc.stop()
  }
}

class MyAccmulator extends AccumulatorV2[String,mutable.Map[String,Long]]{
  var map: mutable.Map[String, Long] = mutable.Map()

  //判断是否 为 初始累加器
  override def isZero: Boolean = {
      map.isEmpty
  }

  //复制累加器
  override def copy(): AccumulatorV2[String,mutable.Map[String,Long] ]= {
    new MyAccmulator
  }

  //重置累加器
  override def reset(): Unit = {
    map.clear()
  }

  //向累加器中 累加数据
  override def add(word: String): Unit = {
    //传入新单词后,在map中查找该单词原始数量,进行+1 操作
    val newCount = map.getOrElse(word,0L) +1
    map.update(word,newCount)
  }

  //将多个map中累加的结果再相加
  override def merge(other: AccumulatorV2[String,mutable.Map[String,Long]]): Unit  = {
      val map1 = this.map
      val map2: mutable.Map[String, Long] = other.value

      map2.foreach{
        case (word,cnt)=>{
          val newCount = map1.getOrElse(word,0L) + cnt
          map1.update(word,newCount)
        }
      }

    }

  override def value: mutable.Map[String,Long] = map
}

广播变量 --分布式共享只读变量

广播变量的好处,不需要每个task带上一份数据,而是变成每个节点的executor一份数据,多个task共享这份数据。
在这里插入图片描述

代码演示:

object spark_bc {
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setMaster("local[*]").setAppName("flatmap")
    val sc = new SparkContext(sparkConf)

    val rdd = sc.makeRDD(List(("a",1),("b",2),("c",3)))
    val map = mutable.Map(("a",3),("b",4),("c",5))
    
    //将map广播
    val bc = sc.broadcast(map)

    //最后需要实现的结果为 ("a",(1,3)),("b",(2,4)),("c",(3,5))
    rdd.map{
      case (key,num) =>{
        val otherNum = bc.value.getOrElse(key,0)
        (key,(num,otherNum))
      }
    }.collect().foreach(println)

  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值