【问题标题】:"Task not serializable" trying to parse JSON“任务不可序列化”试图解析 JSON
【发布时间】:2016-05-19 18:18:07
【问题描述】:

虽然

import play.api.libs.json._

case class Person(name: String, lovesPandas: Boolean)
implicit val personFormat = Json.format[Person]

val text = """{"name":"Sparky The Bear", "lovesPandas":true}"""

val jsonParse = Json.parse(text)
val result = Json.fromJson[Person](jsonParse)
result.get

在带有 Apache Toree 内核的 Jupyter notebook 上工作,

import org.apache.spark._
import play.api.libs.json._
import play.api.libs.functional.syntax._

case class Person(name: String, lovesPandas: Boolean)
implicit val personReads = Json.format[Person]

val text = """{"name":"Sparky The Bear", "lovesPandas":true}"""

val input = sc.parallelize(List(text))
val parsed = input.map(Json.parse(_))
val result = parsed.flatMap(record => {    
    personReads.reads(record).asOpt
})
result.filter(_.lovesPandas).map(Json.toJson(_)).saveAsTextFile("files/out/pandainfo.json")

返回

Name: org.apache.spark.SparkException
Message: Task not serializable
StackTrace: org.apache.spark.util.ClosureCleaner$.ensureSerializable(ClosureCleaner.scala:304)
[...]

即使上述示例来自https://github.com/databricks/learning-spark/blob/master/src/main/scala/com/oreilly/learningsparkexamples/scala/BasicParseJson.scala

我知道传递给其他节点的对象需要序列化,这似乎是不可能的。那么这个例子有问题还是我做错了什么?我该如何解决这个问题?


顺便说一句

import org.apache.spark._
import play.api.libs.json._
import play.api.libs.functional.syntax._

val text = """{"name":"Sparky The Bear", "lovesPandas":true}"""

case class Person(name: String, lovesPandas: Boolean)

val input = sc.parallelize(List(text))
val parsed = input.map(Json.parse(_))
val result = parsed.flatMap(record => {
    implicit val personReads = Json.format[Person]
    personReads.reads(record).asOpt
})
result.collect

会导致

Name: org.apache.spark.SparkException
Message: Job aborted due to stage failure: Task 3.0 in stage 0.0 (TID 3) had a not serializable result: play.api.libs.json.OFormat$$anon$1
Serialization stack:
    - object not serializable (class: play.api.libs.json.OFormat$$anon$1, value: 
[...]

我用result.collect来测试这部分代码是否正确。

另外,如果我写的话

result. filter(_.lovesPandas).map{Json.toJson(_)}.saveAsTextFile("files/out/pandainfo.json")

我得到的不是result.collect

Name: Compile Error
Message: <console>:166: error: No Json serializer found for type Person. Try to implement an implicit Writes or Format for this type.
                      Json.toJson(_)
                                 ^
StackTrace: 

所以我想必须将Person 声明为Serializable。但是,在最后添加extends Serializable 没有效果,而with Serializable 会抛出错误

Name: Compile Error
Message: <console>:2: error: ';' expected but 'with' found.
       case class Person(name: String, lovesPandas: Boolean) with Serializable
                                                             ^

【问题讨论】:

  • with 用于扩展多个特征......你需要extends Serializable
  • 我不确定 Spark 的可序列化与 Java 的可序列化有什么关系,因此仅添加“扩展可序列化”不会有任何作用。此外,您引用的示例页面上的确切代码是否适合您? (即没有您的任何更改)?
  • @TheArchetypalPaul Spark 没有自己的 Serializable 属性。它在运行 CloserCleaner 时查找 Java 可序列化。
  • 好的,但无论如何,只是在最后添加一个“扩展可序列化”并不能解决任何问题。我想知道未修改的示例是否适用于 OP....
  • 案例类自动实现Serializable,无需扩展。

标签: json scala apache-spark jupyter-notebook apache-toree


【解决方案1】:

我会凭直觉说Json.format 返回的值不可序列化。

要绕过它,您可以在flatMap 中声明值:

val result = parsed.flatMap(record => {    
  val personReads = Json.format[Person]
  val jsValue = Json.parse(record)
  personReads.reads(jsValue).asOpt
})

编辑

我认为造成麻烦的是Json.parse 返回不可序列化的JsValue。

您可以将其缩小为单个 map:

sc
  .parallelize(List(text))
  .map(record => {
    val personReads = Json.format[Person]
    val jsValue = Json.parse(record)
    personReads.reads(jsValue).asOpt
  })
 .filter(_.lovesPandas)
 .map(Json.toJson(_).toString)
 .saveAsTextFile("files/out/pandainfo.json")

【讨论】:

  • @Make42 运行此代码时,您能否发布带有错误消息的完整堆栈跟踪?我想看看 Spark 打印出来的对象层次结构。
  • 我不明白您所说的“将其缩小到单个 map”是什么意思。你的意思是我应该摆脱flatMap 并将其简化为单个map?另外,用你的代码我得到Message: &lt;console&gt;:163: error: type mismatch; found : String required: play.api.libs.json.JsValue personReads.reads(record).asOpt如果你真的想融合map和flatMap,你必须写personReads.reads(Json.parse(record)).asOpt,然后你会带着我的旧错误信息回来。
  • @Make42 你有一个map,它遍历文本文件中的所有字符串元素,为什么你需要先创建一个JsValue,然后把它变成一个对象而不是解析它您的案例类直接在一次迭代中。
  • @Make42 查看我编辑的代码。我添加了Json.parse 行以生成JsValue
  • 是的,我就是这么想的(你忘了Json.parse)。我相应地编辑了我的评论,但你更快;-)。无论如何:正如您在我上一条评论中看到的那样:这只会导致众所周知的错误No Json serializer found for type Person.。
猜你喜欢
  • 1970-01-01
  • 2019-02-22
  • 2020-07-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-06
  • 2021-03-16
  • 2018-09-19
  • 2015-05-31
相关资源
最近更新 更多