Spark中的错误处理
来源:互联网 发布:贩卖淘宝店铺犯法吗? 编辑:程序博客网 时间:2024/05/18 11:37
从网路冷眼的微博上看到这一篇文: Try again, Apache Spark!, 主要解释了为何Spark的函数式和异步使得错误处理过程更加复杂,读罢受益匪浅,简单翻译并加入自己的见解, 分享一下.
1. 典型错误处理
在很多语言中, exceptions用来标识程序的异常行为.如果你需要单独处理一类异常,你将要用到try
-catch
语句来包裹引起异常的语句.
try{ someMethod()} catch(Exception e) {// Handle the exception behaviour in some way}
在Scala语言中,上述语句变为:
try { someMethod} catch {case e:Exception => // Handle the exception behaviour in some way}
注意观察,处理异常语句的位置和引起异常语句的位置.前者应该包围后者.
2.异步执行和异常处理
Spark使用RDD
作为基本单元来构建基于大量数据的算法.
在RDD
上你有两个操作:转换 transformation和行动 actions.转换操作会通过前一个RDD构建一个新的RDD.比如map
和flatMap
.
val lines:RDD[String]=sc.textFile("large_file.txt")val tokens = lines.flatMap(_ split " ")
而行动操作则基于RDD
计算结果出来.然后返回给驱动程序或者保存到外部的存储系统(HDFS,HBase)等
tokens.saveAsTextFile("/some/uotput/file.txt")
最后,关于RDD
, 你需要记住:
although you can define new RDDs any time, Spark computes them only in a lazy fashion —that is, the first time they are used in an action.
在RDD
上处理转换操作的时候, 可能会出错和抛出异常.通常的处理方法就是把转换操作用try-catch
包裹起来
val lines: RDD[String] = sc.textFile("large_file.txt")try { val tokens = lines.flatMap(_ split " ") // This transformation can throw an exception .map(s => s(10))} catch { case e : StringIndexOutOfBoundsException => // Doing something in response of the exception}tokens.saveAsTextFile("/some/output/file.txt")
不幸的是, 转换里的代码直到第一次行动 执行时才会真的执行.也就是说上面的处理异常的代码是完全无用的.我们能做的也就只能时把行动 操作用try-catch
包裹起来
val lines: RDD[String] = sc.textFile("large_file.txt")val tokens = lines.flatMap(_ split " ") .map(s => s(10))try { // This try-catch block catch all the exceptions thrown by the // preceding transformations. tokens.saveAsTextFile("/some/output/file.txt")} catch { case e : StringIndexOutOfBoundsException => // Doing something in response of the exception}
你可以看到,我们丢失了异常处理的位置
使用这种方法,我们会丢失抛出异常的元素.此外,Spark是用来处理大量数据的:我们能确定我们的目的就是仅仅因为一个RDD
里一个元素的错误就要阻塞整个执行过程吗?
3. 函数式编程和异常处理
第二种处理方法则是将try-catch
移动到转换 操作中. 以上代码变为:
val tokens = lines.flatMap(_ split " ") .map { s => try { s(10) } catch { case e : StringIndexOutOfBoundsException => // What the hell can we return in this case? } } // end of map
通过这么做,我们重新获得了位置 特征! 但是,通过这种方法,我们又引入了另一个问题.先前说过: 一个转换操作从旧的RDD
里构建了一个新的RDD
.转换操作map
的偏函数输入的原始类型是String=>Char
为了保留这个特征,我们不得不在case语句中返回一个Char
或他的子类型.我们该怎么选择?空的字符?一个特殊的字符? 这些选择显然迟早会造成其他的问题.
从这个僵局中逃脱出来的唯一办法就是重整monad
.粗略的说monad
是为简单的类型提供额外属性的泛型容器. Scala至少提供了三中不同的monad
类型来帮助我们处理异常情况.
Option
和他的两个子类,Some[T]
和None
.这个monad
提供了一个列表,其中有零或一个元素.当我们对错误情况的详情不感兴趣的时候,可以使用他们.Either
和他的两个子类,Left[T]
和Right[K]
.这个monad
可以返回两个不同类型的对象,T
和K
,分别表述正常行为和异常行为.Try
和他的两个子类,Success[T]
和Failure[T]
.它和Either
很像. 使用泛型T
替代Left
子类.Failure
总是Throwable
的一个子类.(Try
在Scala 2.10引入)
然后, 如果你的目标是RDD
处理过程中的异常, 那么Try[T]
就能完美的满足你的需求. 这个奇妙的类型的半生对象中自带一个有用的apply
工厂方法, 让你直接从计算结果中构建一个Success
或者Failure
对象.
// ...omissis...val tokens = lines.flatMap(_ split " ") .map (s => Try(s(10)))
如果计算过程产生了一个值, 那么Success[T]
就会构建,其他情况则由Failure
构建. 这个类型是不可变的.Failure
类型可以通过函数get来访问异常中的错误信息(Failure.get).
所以,你的RDD[T]
将会变成RDD[Try[T]]
.通过此操作,我们又可以开心的使用相同的数据结构来处理数据和异常了.
4. 链式操作
现在,我们有了RDD[Try[T]]
了.我们怎么用这个类型的实例呢? 因为这个类型是个monad
,所以我么可以用map
和flatMap
来处理.
如果你不得不转换一个Try
对象, 你可以使用map
方法.但是如何在链式计算中连续使用Try
呢,如果只使用map
那么Try[B]
就会变为Try[Try[B]]
.所以我们应该使用flatMap,将Try[B]
中的B
取出来,再算.
// ...omissis... lines.flatMap(_ split " ") .map (s => Try(s(10))) // Using a flatMap the final type will be a RDD[Try[Char]] // and not a RDD[Try[Try[Char]]] .flatMap(x => Try(x(20)))
总结
有时候,你的程序仅仅需要从RDD[Try[T]]
中获取Success
或者Failure
实例.最为推荐的方法是collect
// successes has type RDD[Int], no more Try monadval successes = rdd.collect { // The method is applied only to elements of type Success. case Success(x) => x }
- Spark中的错误处理
- spark运行中的各种错误
- Spark中的事件处理分析
- spark整合kafka打包运行错误处理
- spark整合kafka打包运行错误处理
- dotnet中的错误处理
- dotnet中的错误处理
- MPICH中的错误处理
- VBScript 中的错误处理...
- Erlang中的错误处理
- VBA中的错误处理
- Erlang中的错误处理
- SP 中的错误处理
- VBA中的错误处理
- VBA中的错误处理
- Windows中的错误处理
- .NET中的错误处理
- SPEL + 中的错误处理
- 史上最详细的Android Studio系列教程
- 后台存储数据到数据库中文乱码
- 换脸代码笔记
- WEB后台传数据给前台
- iOS 多线程编程<四、GCD线程间通信>
- Spark中的错误处理
- php时间格式
- 折线图
- 使用Gson解析Retrofit返回结果
- 两个字符串的最大公共子字符串
- Python.Pip - Python包管理工具
- 功能强大的Android日志程序:logger
- Linux的页面回收与反向映射机制
- CDN基础知识