Spark累加器(Accumulator)陷阱及解决办法
累加器(accumulator)是Spark中提供的一种分布式的变量机制,其原理类似于mapreduce,即分布式的改变,然后聚合这些改变。累加器的一个常见用途是在调试时对作业执行过程中的事件进行计数。
Spark内置的提供了Long和Double类型的累加器。下面是一个简单的使用示例,在这个例子中我们在过滤掉RDD中奇数的同时进行计数,最后计算剩下整数的和。
val sparkConf = new SparkConf().setAppName("Test").setMaster("local[2]")
val sc = new SparkContext(sparkConf)
val accum = sc.longAccumulator("longAccum") //统计奇数的个数
val sum = sc.parallelize(Array(1,2,3,4,5,6,7,8,9),2).filter(n=>{
if(n%2!=0) accum.add(1L)
n%2==0
}).reduce(_+_)
println("sum: "+sum)
println("accum: "+accum.value)
sc.stop()
结果为:
sum: 20
accum: 5
这是结果正常的情况,但是在使用累加器的过程中如果对于spark的执行过程理解的不够深入就会遇到两类典型的错误:少加(或者没加)、多加。
少加的情况:
对于如下代码:
val accum = sc.longAccumulator("longAccum")
val numberRDD = sc.parallelize(Array(1,2,3,4,5,6,7,8,9),2).map(n=>{
accum.add(1L)
n+1
})
println("accum: "+accum.value)
执行完毕,打印的值是多少呢?答案是0,因为累加器不会改变spark的lazy的计算模型,即在打印的时候像map这样的transformation还没有真正的执行,从而累加器的值也就不会更新。
多加的情况:
对于如下代码:
val accum = sc.longAccumulator("longAccum")
val numberRDD = sc.parallelize(Array(1,2,3,4,5,6,7,8,9),2).map(n=>{
accum.add(1L)
n+1
})
numberRDD.count
println("accum1:"+accum.value)
numberRDD.reduce(_+_)
println("accum2: "+accum.value)
结果我们得到了:
accum1:9
accum2: 18
我们虽然只在map里进行了累加器加1的操作,但是两次得到的累加器的值却不一样,这是由于count和reduce都是action类型的操作,触发了两次作业的提交,所以map算子实际上被执行了了两次,在reduce操作提交作业后累加器又完成了一轮计数,所以最终累加器的值为18。究其原因是因为count虽然促使numberRDD被计出来,但是由于没有对其进行缓存,所以下次再次需要使用numberRDD这个数据集是,还需要从并行化数据集的部分开始执行计算。解释到这里,这个问题的解决方法也就很清楚了,就是在count之前调用numberRDD的cache方法(或persist),这样在count后数据集就会被缓存下来,reduce操作就会读取缓存的数据集而无需从头开始计算了。改成如下代码即可:
val accum = sc.longAccumulator("longAccum")
val numberRDD = sc.parallelize(Array(1,2,3,4,5,6,7,8,9),2).map(n=>{
accum.add(1L)
n+1
})
numberRDD.cache().count
println("accum1:"+accum.value)
numberRDD.reduce(_+_)
println("accum2: "+accum.value)
这次两次打印的值就会保持一致了。
自定义累加器
driver端的outofmemory问题,需要对收集的信息的规模要加以控制,不宜过大。
import java.util
import org.apache.spark.util.AccumulatorV2
class LogAccumulator extends AccumulatorV2[String, java.util.Set[String]] {
private val _logArray: java.util.Set[String] = new java.util.HashSet[String]()
override def isZero: Boolean = {
_logArray.isEmpty
}
override def reset(): Unit = {
_logArray.clear()
}
override def add(v: String): Unit = {
_logArray.add(v)
}
override def merge(other: AccumulatorV2[String, java.util.Set[String]]): Unit = {
other match {
case o: LogAccumulator => _logArray.addAll(o.value)
}
}
override def value: java.util.Set[String] = {
java.util.Collections.unmodifiableSet(_logArray)
}
override def copy(): AccumulatorV2[String, util.Set[String]] = {
val newAcc = new LogAccumulator()
_logArray.synchronized{
newAcc._logArray.addAll(_logArray)
}
newAcc
}
}
import java.util
import org.apache.spark.util.AccumulatorV2
class LogAccumulator extends AccumulatorV2[String, java.util.Set[String]] {
private val _logArray: java.util.Set[String] = new java.util.HashSet[String]()
override def isZero: Boolean = {
_logArray.isEmpty
}
override def reset(): Unit = {
_logArray.clear()
}
override def add(v: String): Unit = {
_logArray.add(v)
}
override def merge(other: AccumulatorV2[String, java.util.Set[String]]): Unit = {
other match {
case o: LogAccumulator => _logArray.addAll(o.value)
}
}
override def value: java.util.Set[String] = {
java.util.Collections.unmodifiableSet(_logArray)
}
override def copy(): AccumulatorV2[String, util.Set[String]] = {
val newAcc = new LogAccumulator()
_logArray.synchronized{
newAcc._logArray.addAll(_logArray)
}
newAcc
}
}
7cd 4b 2a
Spark累加器(Accumulator)陷阱及解决办法的更多相关文章
- Spark运行程序异常信息: org.apache.spark.SparkException: Task not serializable 解决办法
错误信息: 17/05/20 18:51:39 ERROR JobScheduler: Error running job streaming job 1495277499000 ms.0 org.a ...
- Spark 累加器
由于spark是分布式的计算,所以使得每个task间不存在共享的变量,而为了实现共享变量spark实现了两种类型 - 累加器与广播变量, 对于其概念与理解可以参考:共享变量(广播变量和累加器).可能需 ...
- IDEA15 下运行Scala遇到问题以及解决办法
为了让Scala运行起来还是很麻烦,为了大家方便,还是记录下来: 1.首先我下载的是IDEA的社区版本,版本号为15. 2.下载安装scala插件: 2.1 进入设置菜单. 2.2 点击安装JetBr ...
- eclipse运行spark程序时日志颜色为黑色的解决办法
自从开始学习spark计算框架以来,我们老师教的是local模式下用eclipse运行spark程序,然后我在运行spark程序时,发现控制台的日志颜色总是显示为黑色,哇,作为程序猿总有一种强迫症,发 ...
- spark运行时出现Neither spark.yarn.jars nor spark.yarn.archive is set错误的解决办法(图文详解)
不多说,直接上干货! 福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号: 大数据躺过的坑 Java从入门到架构师 人工智能躺过的坑 ...
- Spark Shell启动时遇到<console>:14: error: not found: value spark import spark.implicits._ <console>:14: error: not found: value spark import spark.sql错误的解决办法(图文详解)
不多说,直接上干货! 最近,开始,进一步学习spark的最新版本.由原来经常使用的spark-1.6.1,现在来使用spark-2.2.0-bin-hadoop2.6.tgz. 前期博客 Spark ...
- weblogic 12C 数据源配置出错的解决办法
驱动程序类名称: 11G 10.3.6与12G数据源配置有很大区别,整个一天才搞明白. 如有疑问可留言:http://www.cnblogs.com/endv/p/4110798.html 配 ...
- spark累加器、广播变量
一言以蔽之: 累加器就是只写变量 通常就是做事件统计用的 因为rdd是在不同的excutor去执行的 你在不同excutor中累加的结果 没办法汇总到一起 这个时候就需要累加器来帮忙完成 广播变量是只 ...
- 入门大数据---Spark累加器与广播变量
一.简介 在 Spark 中,提供了两种类型的共享变量:累加器 (accumulator) 与广播变量 (broadcast variable): 累加器:用来对信息进行聚合,主要用于累计计数等场景: ...
随机推荐
- ”dpkg: 处理归档 /var/cache/apt/archives/XXXXXX(--unpack)时出错“的解决方法
在安装ROS时出现了下面的问题: 解决方法: sudo dpkg -i --force-overwrite <filename> 在我的问题中我的解决方法是: sudo dpkg -i - ...
- VIM编辑器使用
- 解决axios在ie浏览器下提示promise未定义的问题
参考链接: https://blog.csdn.net/bhq1711617151/article/details/80266436 在做项目的时候发现在ie11上出现不兼容的问题,对于和后台交互这块 ...
- AppCan
启动服务 将app程序寄宿在计算机上,在计算机上调试:访问服务地址,将appToken值复制一下 在浏览器输入192.168.2.102:3000/appToken的值/文件路径后即可调试 入口文件 ...
- JavaScript—offset、client、scroll
offsetTop,offsetLeft:获取离最近父容器的位置,如果没有父容器,那么获取离body最近的位置 offsetWidth,offsetHeight:获取元素的大小,包括padding,b ...
- The Ethereum devp2p and discv4 protocol Part II
描述 本文章主上下两篇 上篇:讲述以太坊devp2p与disc4节点发现协议 下篇:实践篇,实现如何获取以太坊所有节点信息(ip,port,nodeId,client) 正文 本片为下篇:实践篇,主要 ...
- linux编译相关命令
一.编译可执行文件 g++ –c Hello.cpp 编译文件,生成目标文件Hello.o g++ Hello.o –o a.out 链接并重命名为可执行文件a.out g++ Hello.cc ...
- C# 7.0特性
一.out的形参变量无需再提前声明 befor: "; int numericResult; if (int.TryParse(input, out numericResult)) Cons ...
- SecuerCRT遇到一个致命错误且必须关闭_解决方案_软件链接(自己百度云盘的)
问题描述: 1.以前安装过SecureCRT,现在出现问题,手工卸载不完全,导致新安装的SecureCRT一直提示:以下错误. 2.出现的错误: 3.解决方案: 1)删除,上图路径中VanDyke文件 ...
- linux extglob模式 和rm反选
前言 extglob模式开启之后Shell可以另外识别出5个模式匹配操作符,能使文件匹配更加方便. 不然不识别! 正文 #开启命令: shopt -s extglob #关闭命令: shopt -u ...