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

时间:2016-06-08 05:32:44

标签: scala apache-spark

我正在尝试构造一个接收解析器作为参数的类,并在每一行上使用此解析器。以下是您可以粘贴到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错误。

为什么会出现错误,是否有办法重新设计上述内容以避免这种情况(同时保持Reader通用)?

1 个答案:

答案 0 :(得分:2)

问题是makeParser变量为class Reader,因为你在rdd转换中使用它,spark会尝试序列化整个类Reader,这是不可序列化的。因此,您将获得任务不可序列化的异常。

将Serializable添加到类Reader中将使用您的代码。但这不是一个好习惯,因为它会序列化可能不需要的整个类变量。

通常,您可以使用函数而不是方法来避免序列化问题。因为在scala函数中实际上是对象,它将被序列化。

参考这个答案: Task not serializable: java.io.NotSerializableException when calling function outside closure only on classes not objects