![](/img/trans.png)
[英]SparkException: Task not serializable on class: org.apache.avro.generic.GenericDatumReader
[英]Generic parser class `Task not serializable`
我正在尝试构造一个类,该类接收解析器作为参数,并在每一行上使用该解析器。 下面是一个最小的示例,您可以将其粘贴到spark-shell
。
import scala.util.{Success,Failure,Try}
import scala.reflect.ClassTag
class Reader[T : ClassTag](makeParser: () => (String => Try[T])) {
def read(): Seq[T] = {
val rdd = sc.parallelize(Seq("1","2","oops","4")) mapPartitions { lines =>
// Since making a parser can be expensive, we want to make only one per partition.
val parser: String => Try[T] = makeParser()
lines flatMap { line =>
parser(line) match {
case Success(record) => Some(record)
case Failure(_) => None
}
}
}
rdd.collect()
}
}
class IntParser extends (String => Try[Int]) with Serializable {
// There could be an expensive setup operation here...
def apply(s: String): Try[Int] = Try { s.toInt }
}
但是,当我尝试运行类似new Reader(() => new IntParser).read()
(类型检查就很好)时,我得到了可怕的org.apache.spark.SparkException: Task not serializable
与闭包有关的org.apache.spark.SparkException: Task not serializable
错误。
为什么会有错误,并且有办法重新设计以上内容以避免发生这种情况(同时使Reader
保持通用)?
问题是makeParser
对于class Reader
是变量,并且由于您在rdd转换中使用它,因此spark将尝试序列化整个不可序列化的Reader类。 因此,您将获得任务不可序列化的异常。
将Serializable添加到类Reader中将与您的代码一起使用。 但这不是一个好习惯,因为它将序列化可能不需要的整个类变量。
通常,您可以使用函数而不是方法来避免序列化问题。 因为在scala中,函数实际上是对象,因此将被序列化。
请参阅此答案: 任务不可序列化:仅在类而非对象上调用闭包之外的函数时,java.io.NotSerializableException
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.