spark 累加器总结

累加器学完了,做个小总结,中间还是有些地方有点难度。
为什么要用累加器?
因为在Driver端定义的变量,如求和sum,在Executor端做求和计算之后,Eecutor端的sum是无法传回Driver端merge的。

val listRDD: RDD[(String, Long)] = sc.makeRDD(List(("xx",1L),("xx",2L),("yy",3L),2)
listRDD.foreach{
      case (k,v)=>{
      sum+=v
      }
    }

本来sum应该为6,但是实际是0在这里插入图片描述
这时就轮到累加器上场了
Accumulator简介
Accumulator是spark提供的累加器,顾名思义,该变量只能够增加。
只有driver能获取到Accumulator的值,而Executor的Task只能对其做增加操作。你也可以为Accumulator命名(不支持Python),这样就会在spark web ui中显示,可以帮助你了解程序运行的情况。

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

  var sum=0L
    //   引入累加器
     val accumulator: LongAccumulator = sc.longAccumulator

    listRDD.foreach{
      case (k,v)=>{
        sum+=v
        accumulator.add(v)
      }
    }
    println(sum)
    println(accumulator.value)

累加器完美解决
在这里插入图片描述
ok,搞清楚累加器是什么了,接下来就是自定义累加器(毕竟实际生产环境中定义好的累加器是远远不够用的)

//自定义累加器    ,
// 1. 继承AccumulatorV2,并设定泛型
// 2. 重写累加器的抽象方法

                                               输入 (k,v)           输出sum值
class  MyAccumulator extends  AccumulatorV2[(String,Long),java.lang.Long]{
**//在累加器中维护一个Long类型的变量**
  private var sum=0L
  //累加器是否初始化
  override def isZero: Boolean = {
    sum==0
  }
  //复制新的累加器
  override def copy(): AccumulatorV2[(String,Long), lang.Long] = {
    new MyAccumulator
  }
  //重置累加器
  override def reset(): Unit = {
    sum=0L
  }

**//最重要,将输入的值累加起来**
  override def add(t:(String,Long)): Unit = {
    sum+=t._2
  }

  //回到Driver端聚合
  override def merge(other: AccumulatorV2[(String,Long), lang.Long]): Unit = {
    sum+=other.value
  }
//调用value方法即可得到最终的sum值
  override def value: lang.Long = {
    sum
  }
}

接下来就是调用自定义的累加器

//创建累加器
    val myaccu = new MyAccumulator
    //注册累加器,让spark知道我的存在
    sc.register(myaccu)

    listRDD.foreach{
      data=>{
        myaccu.add(data)
      }
    }
    println(myaccu.value)

在这里插入图片描述
可以看到,自定义累加器和直接调用spark的longAccumulator效果是一样的。
目前就写这些了。累加器的知识肯定不止这点,以后学的更多了再续上。


今天项目中用到了累加器。输出是HashMap。有些小坑,记录一下

 val listRDD: RDD[(String, Long)] = sc.makeRDD(List(("xx",1L),("xx",2L),("yy",3L),("yy",3L),("yy",3L),("wy",3L)),2)
 //创建累加器
    val myaccu = new myAcc
    //注册累加器,让spark直到我的存在
    sc.register(myaccu)

    listRDD.foreach{
      data=>{
        myaccu.add(data._1)
      }
    }
   for ((k,v)<-myaccu.value){
     println(k,v)
   }
  }
**自定义累加器**
class  myAcc extends AccumulatorV2[String,mutable.HashMap[String,Int]]{
  val countMap=new mutable.HashMap[String, Int]()
  override def isZero: Boolean = countMap.isEmpty

  override def copy(): AccumulatorV2[String, mutable.HashMap[String, Int]] = {
    val acc = new myAcc
    acc.countMap++=countMap
    acc
  }

  override def reset(): Unit = countMap.clear()

  override def add(v: String): Unit = {
//    countMap(v) = countMap.getOrElse(v,0)+1
    countMap+= (v->(countMap.getOrElse(v,0)+1))

  }

  override def merge(other: AccumulatorV2[String, mutable.HashMap[String, Int]]): Unit = {
    val map: mutable.HashMap[String, Int] = other.value
    //法一foldLeft
//   map.foldLeft(countMap){
//      case (map,(k,v))=>{
//        //法一
//        map+=( k-> (map.getOrElse(k,0)+v))
//
//        //需要返回map
       map(k) =map.getOrElse(k,0) +v
       map
//
//        //法三 需要返回map
        map.put(k,map.getOrElse(k,0)+v)
        map
//        //法四
        map.update(k,map.getOrElse(k,0)+v)
        map
//      }
//    }
    
    
    //法二 foreach 
    map.foreach{
      case (k,v) =>{
        countMap += (k->(countMap.getOrElse(k,0)+v))
//        countMap(k) =countMap.getOrElse(k,0)+v
//        countMap.update(k,countMap.getOrElse(k,0)+v)
//        countMap.put(k,countMap.getOrElse(k,0)+v)
      }
    }
  }

  override def value: mutable.HashMap[String, Int] = countMap
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值