使用json4s解析JSON时Spark不可序列化的异常

时间:2015-04-15 22:36:16

标签: scala serialization apache-spark json4s

我在尝试解析我的火花工作中的json时遇到了问题。我使用spark 1.1.0json4sCassandra Spark Connector。抛出的异常是:

java.io.NotSerializableException: org.json4s.DefaultFormats

检查DefaultFormats伴随对象,并且使用此stack问题,很明显无法序列化DefaultFormats。问题是现在该做什么。

我可以看到ticket显然通过添加关键字transient来解决此问题,但我不确定如何或在何处将其应用于我的案例。解决方案是仅在执行程序上实例化DefaultFormats类,以避免序列化在一起吗?是否有人们正在使用scala / spark的另一个JSON解析库?我最初尝试使用jackson本身,但遇到了一些我无法轻易解决的注释错误,json4s开箱即用。这是我的代码:

import org.json4s._
import org.json4s.jackson.JsonMethods._
implicit val formats = DefaultFormats

val count = rdd.map(r => checkUa(r._2, r._1)).reduce((x, y) => x + y) 

我在checkUa函数中进行json解析。我试图让计数懒惰,希望它以某种方式延迟执行,但它没有效果。也许在checkUA中移动隐式val?任何建议都非常感谢。

2 个答案:

答案 0 :(得分:16)

an open ticket with json4s已经回答了这个问题。解决方法是将implicit声明放在函数

val count = rdd
               .map(r => {implicit val formats = DefaultFormats; checkUa(r._2, r._1)})
               .reduce((x, y) => x + y) 

答案 1 :(得分:3)

当我将implicit val formats = ...声明放在包含解析的方法中时,我遇到了同样的错误,而不是在类(对象)上声明它。

所以这会引发错误:

object Application {

  //... Lots of other code here, which eventually calls 
  // setupStream(...)

  def setupStream(streamingContext: StreamingContext,
                          brokers: String,
                          topologyTopicName: String) = {
    implicit val formats = DefaultFormats
    _createDStream(streamingContext, brokers, topologyTopicName)
      // Remove the message key, which is always null in our case
      .map(_._2)
      .map((json: String) => parse(json).camelizeKeys
        .extract[Record[TopologyMetadata, Unused]])
      .print()
}

但这没关系:

object Application {

  implicit val formats = DefaultFormats

  //... Lots of other code here, which eventually calls 
  // setupStream(...)

  def setupStream(streamingContext: StreamingContext,
                          brokers: String,
                          topologyTopicName: String) = {
    _createDStream(streamingContext, brokers, topologyTopicName)
      // Remove the message key, which is always null in our case
      .map(_._2)
      .map((json: String) => parse(json).camelizeKeys
        .extract[Record[TopologyMetadata, Unused]])
      .print()
}