Accumulator累加器

1、累加器应用场景

应用背景:在Executor进行计算的过程中,有些变量的值会在Executor多次使用,
每次使用时,就要从driver端拿取一次,就会产生大量的网络IO,而且还会影响计算效率,
此时就可以用广播变量的方式,在计算之前先把数据从driver端广播到相应的Executor端的缓存里,
后期在使用的时候,就可以直接从缓存里拿取进行计算

注意:广播变量过程,必须是把driver端的某个变量的值广播到Executor端
广播变量的值不易过大,否则会占用大量的内存

2、Accumulator版本的Wordcount

通过继承AccumulatorV2实现几个方法(使用到了伴生类):

package com.murphy.Acc

import org.apache.spark.util.AccumulatorV2
import org.apache.spark.{SparkConf, SparkContext}

import scala.collection.mutable

//伴生类
class AccWordCountDemo extends AccumulatorV2[String, mutable.HashMap[String, Int]] {
  // 初始值
  private val hashAcc = new mutable.HashMap[String, Int]()

  // 检测初始值是否为空
  override def isZero: Boolean = hashAcc.isEmpty
  // copy一个新的累加器
  override def copy(): AccumulatorV2[String, mutable.HashMap[String, Int]] = {
    val newAcc = new AccWordCountDemo
    // 有可能多个task同时往初始值里写值,有可能出现线程安全问题,此时最好加锁
    hashAcc.synchronized {
      newAcc.hashAcc ++= hashAcc
    }

    newAcc
  }
  // 重置累加器
  override def reset(): Unit = hashAcc.clear()
  // 局部累加
  override def add(v: String): Unit = {
    hashAcc.get(v) match {
      case None => hashAcc += ((v, 1))
      case Some(x) => hashAcc += ((v, x + 1))
    }
  }
  // 全局合并
  override def merge(other: AccumulatorV2[String, mutable.HashMap[String, Int]]): Unit = {
    other match {
      case o: AccumulatorV2[String, mutable.HashMap[String, Int]] => {
        for ((k, v) <- o.value) {
          hashAcc.get(k) match {
            case None => hashAcc += ((k, v))
            case Some(x) => hashAcc += ((k, x + v))
          }
        }
      }
    }
  }
  // 输出值
  override def value: mutable.HashMap[String, Int] = hashAcc
}

//伴生对象
object AccWordCountDemo {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("AccWordCountDemo").setMaster("local[2]")
    val sc = new SparkContext(conf)

    val rdd = sc.makeRDD(List("a", "c", "a", "d", "a", "c"), 2)

    // 调用累加器对象
    val acc = new AccWordCountDemo

    // 注册累加器
    sc.register(acc, "accwc")

    // 开始分布式累加
    rdd.foreach(acc.add)

    println(acc.value)


    sc.stop()
  }
}

3、自定义排序

自定义排序(二次排序):
应用场景:比如自定义了一个对象,该对象里有多个字段,需要对多个字段进行排序,
如果直接调用sortBy进行排序,会出错,因为sortBy不知道具体的比较规则。
此时可以用Spark提供的自定义排序进行操作,这样我们就可以指定具体的排序规则了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值