I have a spark application which reads lines from a files and tries to deserialize them using jackson. To get this code to work, I needed to define the ObjectMapper inside the Map operation (otherwise I got a NullPointerException).
I have the following code which is working:
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])
})
However, If I define the mapper outside the map and broadcast it, it fails with a NullPointerException.
This code fails:
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])
})
What am I missing here?
Thanks, Aliza
It turns out you can broadcast the mapper. The problematic part was mapper.registerModule(DefaultScalaModule) which needs to be execute on each slave (executor) machine and not only on the driver.
so this code works:
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])
})
I further optimised the code by running registerModule only once per partition (and not for each element in the RDD).
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]) })
Aliza
Indeed, objectMapper isn't really suitable for broadcast. It is inherently not serializable and not a value class anyway. I would suggest to broadcast DeserializationConfig instead and pass that to ObjectMapper's constructor from the braodcast variable in your map operation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With