Scala Spark:广播jackson对象映射器

Scala Spark:广播jackson对象映射器,scala,apache-spark,jackson,Scala,Apache Spark,Jackson,我有一个spark应用程序,它从文件中读取行,并尝试使用jackson反序列化它们。 为了让这段代码正常工作,我需要在映射操作中定义ObjectMapper(否则我会得到一个NullPointerException) 我有以下正在运行的代码: val alertsData = sc.textFile(rawlines).map(alertStr => { val mapper = new ObjectMapper() mapper.configure(Deseria

我有一个spark应用程序,它从文件中读取行,并尝试使用jackson反序列化它们。 为了让这段代码正常工作,我需要在映射操作中定义ObjectMapper(否则我会得到一个NullPointerException)

我有以下正在运行的代码:

val alertsData = sc.textFile(rawlines).map(alertStr => {
      val mapper = new ObjectMapper()
      mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
      mapper.registerModule(DefaultScalaModule)
      broadcastVar.value.readValue(alertStr, classOf[Alert])
    })
但是,如果我在映射外部定义映射器并广播它,它将失败,并出现NullPointerException

此代码失败:

val mapper = new ObjectMapper()
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    mapper.registerModule(DefaultScalaModule)
    val broadcastVar = sc.broadcast(mapper)

    val alertsData = sc.textFile(rawlines).map(alertStr => {
      broadcastVar.value.readValue(alertStr, classOf[Alert])
    })
我错过了什么

谢谢,
实际上,objectMapper并不适合广播。它本质上是不可序列化的,也不是一个值类。我建议改为广播
反序列化配置
,并从map操作中的braodcast变量将其传递给ObjectMapper的构造函数

事实证明你可以播放地图。有问题的部分是
mapper.registerModule(DefaultScalaModule)
,它需要在每个从机(执行器)上执行,而不仅仅是在驱动程序上执行

因此,该代码起作用:

val mapper = new ObjectMapper()
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
val broadcastVar = sc.broadcast(mapper)

val alertsData = sc.textFile(rawlines).map(alertStr => {
      broadcastVar.value.registerModule(DefaultScalaModule)
      broadcastVar.value.readValue(alertStr, classOf[Alert])
})
我进一步优化了代码,每个分区只运行一次registerModule(而不是RDD中的每个元素)

val mapper=new ObjectMapper()
configure(在未知属性上反序列化feature.FAIL,false)
val broadcastVar=sc.broadcast(映射器)
val alertsRawData=sc.textFile(原始行)
val alertsData=alertsRawData.mapPartitions({iter:Iterator[String]=>broadcastVar.value.registerModule(DefaultScalaModule)

对于(我认为广播是面向不可变数据的,可能您的对象是作为浅拷贝广播的,在
ObjectMapper
.FWIW中没有使用一些状态或依赖项,
ObjectMapper
实际上是
java.io.Serializable
,应该可以工作,但您是对的,这很少是您应该做的事情(在某些情况下,你可能会想,这就是为什么它是可序列化的,但这值得一篇博文)特别是Spark(或Storm/Trident等)在我看来,它属于一类应该在本地实例化的东西。有没有一种方法可以使用spark sql UDFs在每个分区上实现这一点?附加提示:如果您试图在主对象中广播
val
,并且您的主方法已通过使用
…extensed App
继承,则广播失败。I在此处找到解决方案:
val mapper = new ObjectMapper()
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

val broadcastVar = sc.broadcast(mapper)
val alertsRawData = sc.textFile(rawlines)

val alertsData = alertsRawData.mapPartitions({ iter: Iterator[String] => broadcastVar.value.registerModule(DefaultScalaModule)
      for (i <- iter) yield broadcastVar.value.readValue(i, classOf[Alert]) })