Spark累加器

来源:互联网 发布:淘宝图片版权保护 编辑:程序博客网 时间:2024/05/16 12:08
Accumulator(累加器, 计数器)
类似于MapReduce中的counter, 将数据从一个节点发送到其他各个节
点上去;

通常用于监控, 调试, 记录符合某类特征的数据数目等

累加器在Driver端被读取,使用的是 Accumulator.value

累加器在Executor端被读取,使用的是 Accumulator.localValue,获取的是Executor本地的值。Executor端可以通过 Accumulator+=1的方式进行累加(Spark1.6方式)

 创建累加器对累加器进行累加Driver端获取累加器Executor端获取累加器Spark1.6sc.accumulator(0L,"counter0")counter1 += 1println("counter1="+counter1) println("counter1="+counter1.localValue)Spark2.1sc.longAccumulator("total_counter")total_counter.add(1)println("total_counter="+total_counter.value) println("total_counter="+total_counter.value)


累加器的使用陷阱:

我们都知道,spark中的一系列transform操作会构成一串长的任务链,此时需要通过一个action操作来触发,accumulator也是一样。因此在一个action操作之前,你调用value方法查看其数值,肯定是没有任何变化的。

如果程序中有两次 action操作,就会触发两次transform操作,相应地,累加器就会加两次。问题代码如下:

val accum= sc.accumulator(0, "Error Accumulator")val data = sc.parallelize(1 to 10)//用accumulator统计偶数出现的次数,同时偶数返回0,奇数返回1val newData = data.map{x => {  if(x%2 == 0){    accum += 1      0    }else 1}}//使用action操作触发执行newData.count//此时accum的值为5,是我们要的结果accum.value//继续操作,查看刚才变动的数据,foreach也是action操作newData.foreach(println)//上个步骤没有进行累计器操作,可是累加器此时的结果已经是10了//这并不是我们想要的结果accum.value

累加器陷阱解决办法:

将任务之间的依赖关系切断,再次执行action操作就可以了

//val accum= sc.accumulator(0, "Error Accumulator")val data = sc.parallelize(1 to 10)//代码和上方相同val newData = data.map{x => {...}}//使用cache缓存数据,切断依赖。newData.cache.count//此时accum的值为5accum.valuenewData.foreach(println)//此时的accum依旧是5accum.value


调用cache,persist方法的时候会将之前的依赖切除,后续的累加器就不会再被之前的transfrom操作影响到了。

0 0
原创粉丝点击