繁体   English   中英

通用解析器类“任务不可序列化”

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM