Spark上使用json4s的NotSerializableException

时间:2014-07-16 16:49:17

标签: json scala hdfs apache-spark json4s

基本上,我必须使用Spark分析HDFS上的一些复杂的JSON。

我使用“for comprehensions”来(预)过滤JSON和“extract”方法 json4s将其包装到案例类

这个工作正常!

def foo(rdd: RDD[String]) = {

case class View(C: String,b: Option[Array[List[String]]],  t: Time)
case class Time($numberLong: String)
implicit val formats = DefaultFormats

rdd.map { jsonString =>
  val jsonObj = parse(jsonString)
  val listsOfView = for {
    JObject(value) <- jsonObj
    JField(("v"), JObject(views)) <- value
    normalized <- views.map(x => (x._2))
  } yield normalized
}

到目前为止一切顺利!

当我尝试将(预)过滤的JSON提取到我的 CaseClass我明白了:

  

线程“main”中的异常org.apache.spark.SparkException:由于阶段失败而中止作业:任务不可序列化:java.io.NotSerializableException:org.json4s.DefaultFormats $

此处带有提取的代码:

def foo(rdd: RDD[String]) = {

case class View(C: String,b: Option[Array[List[String]]],  t: Time)
case class Time($numberLong: String)
implicit val formats = DefaultFormats

rdd.map { jsonString =>
  val jsonObj = parse(jsonString)
  val listsOfView = for {
    JObject(value) <- jsonObj
    JField(("v"), JObject(views)) <- value
    normalized <- views.map(x => (x._2))
  } yield normalized.extract[View]
}

我已经在scala上尝试了我的代码,以及它的工作!我真的很擅长使用hdfs和spark,所以我会很感激。

3 个答案:

答案 0 :(得分:6)

Spark序列化RDD转换上的闭包,并且&#39;发货&#39;那些分散执行的工人。 这要求闭包内的所有代码(通常也包含在包含对象中)应该是可序列化的。

查看org.json4s.DefaultFormat$(该特征的伴随对象)的impl:

object DefaultFormats extends DefaultFormats {
    val losslessDate = new ThreadLocal(new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"))
    val UTC = TimeZone.getTimeZone("UTC")

}

很明显,这个对象不是可序列化的,不能这样做。 (ThreadLocal本身就是不可序列化的)

您似乎没有在代码中使用Date类型,因此您可以摆脱 implicit val formats = DefaultFormats或用可序列化的东西替换DefaultFormats?

答案 1 :(得分:3)

这实际上已经修复了; JSON4S可以从版本3.3.0开始序列化:https://github.com/json4s/json4s/issues/137

答案 2 :(得分:0)

解决我问题的方法是,我在implicit val formats = DefaultFormats循环中使用了rdd.foreach{}。它解决了我的可序列化异常。

这是我的代码段,解决了该问题:

case class rfId(rfId: String) {}

// ... some code here ...

 rdd.foreach { record =>
    val value = record.value()

    // Bring in default date formats etc and makes json4s serializable
    implicit val formats = DefaultFormats
    val json = parse(value)
    println(json.camelizeKeys.extract[rfId])  // Prints `rfId(ABC12345678)`
 }