Spark累加器LongAccumulator

探讨了Spark中的Accumulator,强调其在Driver和Executor间的协作,以及如何通过RDD和LongAccumulator进行累加和统计。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.Accumulator是由Driver端总体进行维护的,读取当前值也是在Driver端,各个Task在其所在的Executor上也维护了Accumulator变量,但只是局部性累加操作,运行完成后会到Driver端去合并累加结果。Accumulator有两个性质:

1、只会累加,合并即累加;

2、不改变Spark作业懒执行的特点,即没有action操作触发job的情况下累加器的值有可能是初始值。

object AccumulatorTest {

  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf().setAppName("test003").setMaster("local")
    val sc = new SparkContext(conf)
    sc.setLogLevel("ERROR")

    println("***********************************")
    // 使用scala集合完成累加
    var count1:Int = 0;
    var data = Seq(1,2,3,4)
    data.map(x=> count1 +=x)
    println("scala集合进行累加:" + count1)
    println("***********************************")

// 使用RDD累加,但是count2打印结果为0
// 使用foreach传递的是函数,driver在把变量发送到work时,work中Executor都有一份count2变量副本,
// 最后执行计算时每个Executor的count2会加上自己的x,与dirver短中定义的count2没有关系,所以打印结果是0,
    var count2:Int = 0
    val dataRDD: RDD[Int] = sc.parallelize(data)
    dataRDD.foreach(x=> count2 +=x)
    println(count2)

    println("**************使用累加器*********************")
    val acc: LongAccumulator = sc.longAccumulator("accumulatorTest")
    dataRDD.foreach(x=>acc.add(x))
    println("计算元素累积和:" + acc.value)
    println("统计元素个数:" + acc.count)
    println("统计元素平均值:" + acc.avg)
    println("统计元素总和:" + acc.sum)
  }
}

### Spark 累加器的使用方法 #### 什么是累加器累加器Spark 提供的一种只读共享变量,能够在分布式环境中安全地执行跨任务的累积操作。它们通常被用来实现求和、计数等功能,并且只能通过 `add` 方法增加其值[^4]。 #### 创建数值型累加器 可以通过调用 `SparkContext.longAccumulator()` 或者 `SparkContext.doubleAccumulator()` 来创建 Long 类型或者 Double 类型的累加器实例。这些累加器主要用于简单的数值累计操作。 ```java // Java 示例代码 import org.apache.spark.api.java.JavaRDD; import org.apache.spark.SparkConf; import org.apache.spark.api.java.JavaSparkContext; public class AccumulatorExample { public static void main(String[] args) { SparkConf conf = new SparkConf().setAppName("accumulator-example").setMaster("local"); JavaSparkContext sc = new JavaSparkContext(conf); // 创建一个 long 型的累加器 long accumulatorValue = sc.sc().longAccumulator(0); JavaRDD<Integer> rdd = sc.parallelize(Arrays.asList(1, 2, 3, 4)); // 对 RDD 的每个元素应用 add 操作更新累加器 rdd.foreach(x -> accumulatorValue.add(x)); System.out.println("累加器最终值:" + accumulatorValue.value()); sc.close(); } } ``` 这段代码展示了如何初始化一个长整型累加器并将 RDD 中的数据逐项加入其中。 #### 自定义累加器 除了内置支持的基础数据类型外,还可以开发自己的累加器以适应更复杂的应用场景。比如针对电商数据分析中的商品热度统计问题,可以设计专门用于记录不同用户行为(如点击、下单、付款)频次的对象作为累加单元[^5]。 下面是一个基于 Scala 实现的例子: ```scala case class HotCategory(var clickCount: Int, var orderCount: Int, var payCount: Int) class CategoryAccumulator extends AccumulatorParam[Map[String, HotCategory]] { override def zero(initialValue: Map[String, HotCategory]): Map[String, HotCategory] = initialValue.mapValues(h => h.copy(clickCount = 0, orderCount = 0, payCount = 0)) override def addInPlace(t1: Map[String, HotCategory], t2: Map[String, HotCategory]): Map[String, HotCategory] = { (t1.keySet ++ t2.keySet).map { key => val hc1 = t1.getOrElse(key, HotCategory(0, 0, 0)) val hc2 = t2.getOrElse(key, HotCategory(0, 0, 0)) key -> HotCategory( hc1.clickCount + hc2.clickCount, hc1.orderCount + hc2.orderCount, hc1.payCount + hc2.payCount ) }.toMap } } val categoryAccumulator = sc.accumulableCollection(new mutable.HashMap[String, HotCategory])() categoryAccumulator.register() rdd.foreachPartition(partition => partition.foreach(record => { record.behaviorType match { case "click" => categoryAccumulator += ((record.categoryId, HotCategory(1, 0, 0))) case "order" => categoryAccumulator += ((record.categoryId, HotCategory(0, 1, 0))) case "pay" => categoryAccumulator += ((record.categoryId, HotCategory(0, 0, 1))) } })) println(categoryAccumulator.value.mkString("\n")) ``` 此脚本构建了一个名为 `HotCategory` 的样例类来保存各类别的三种主要活动指标;接着定义了继承自 `AccumulatorParam[T]` 抽象类的新类 `CategoryAccumulator` ,从而实现了对多个类别下各种交互动作次数的有效汇总[^3]。 #### 注意事项 - **线程安全性**:由于累加器的设计初衷就是在多线程环境下工作良好,因此无需担心同步问题。 - **访问权限限制**:仅驱动程序能够获取累加器当前状态而工作者节点上的进程则无权查询该信息。 - **性能考量**:尽管累加器有助于减少网络传输开销,但在某些情况下仍需注意可能引发过多的小规模通信请求影响整体效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

新鲜氧气

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值