10.累加器和广播变量

累加器和广播变量

累加器

在创建函数时,如果需要捕获自由变量,那么包含指向被捕获变量的引用的函数就被称为闭包函数。在实际计算时,Spark 会将对 RDD 操作分解为 Task,Task 运行在 Worker Node 上。在执行之前,Spark 会对任务进行闭包,如果闭包内涉及到自由变量,则程序会进行拷贝,并将副本变量放在闭包中,之后闭包被序列化并发送给每个执行者。因此,当在 foreach 函数中引用 counter 时,它将不再是 Driver 节点上的 counter,而是闭包中的副本 counter,默认情况下,副本 counter 更新后的值不会回传到 Driver,所以 counter 的最终值仍然为零。

内置累加器

自定义累加器new一个之后,方法add之中就行了。

自定义累加器

自定义的累加器需要继承AccumulatorV2并实现以下方法

  • copy() Creates a new copy of this accumulator.
  • reset() Resets this accumulator, which is zero value
  • merge() 分区间的累加器的合并
  • add()一个分区内的数据的累增
  • value() 返回当前缓存的值
class MapAcc extends AccumulatorV2[Long,Map[String,Double]]{
    private var map: Map[String, Double] = Map[String, Double]()
    override def isZero: Boolean = map.isEmpty

    override def copy(): AccumulatorV2[Long, Map[String, Double]] = {
        val acc = new MapAcc
        acc.map=map
        acc
    }

    override def reset(): Unit = map = Map[String, Double]()

    override def add(v: Long): Unit = {
        // sum求和,count计数
        map += "sum" -> (map.getOrElse("sum",0D)+v)
        map += "count" -> (map.getOrElse("count",0D)+1)
    }

    override def merge(other: AccumulatorV2[Long, Map[String, Double]]): Unit = other match {
        case o:MapAcc =>
            this.map += "sum" -> (this.map.getOrElse("sum",0D)+o.map.getOrElse("sum",0D))
            this.map += "count" -> (this.map.getOrElse("count",0D)+o.map.getOrElse("count",0D))
        case _ => throw new UnsupportedOperationException
    }

    override def value: Map[String, Double] = {
        this.map += "avg" ->(this.map.getOrElse("sum",0D)/this.map.getOrElse("count",1D))
        map
    }
}

调用时new一个分区器,然后使用add方法进行递增

注意:累加器最好用在行动算子之中

广播变量

如果说累加器是共写变量,那么广播变量就是共读变量。广播变量通过调用SparkContext.broadcast(v)来创建.实际是对v的一个包装,广播后在所有的节点上都可以通过.value获得该值。

发布了118 篇原创文章 · 获赞 5 · 访问量 7158

猜你喜欢

转载自blog.csdn.net/resilienter/article/details/103937552