Spark和Not Serializable DateTimeFormatter

时间:2016-03-21 13:33:13

标签: java scala serialization apache-spark

我正在尝试在Spark中使用java.time.format中的DateTimeFormatter,但它似乎不可序列化。这是相关的代码块:

val pattern = "<some pattern>".r
val dtFormatter = DateTimeFormatter.ofPattern("<some non-ISO pattern>")

val logs = sc.wholeTextFiles(path)

val entries = logs.flatMap(fileContent => {
    val file = fileContent._1
    val content = fileContent._2
    content.split("\\r?\\n").map(line => line match {
      case pattern(dt, ev, seq) => Some(LogEntry(LocalDateTime.parse(dt, dtFormatter), ev, seq.toInt))
      case _ => logger.error(s"Cannot parse $file: $line"); None
    })
  })

如何避免java.io.NotSerializableException: java.time.format.DateTimeFormatter例外?是否有更好的库来解析时间戳?我已经读过Joda也不是可序列化的,并且已经被整合到Java 8的时间库中。

2 个答案:

答案 0 :(得分:25)

您可以通过两种方式避免序列化:

  1. 假设其值可以保持不变,请将格式化程序放在object中(使其成为&#34;静态&#34;)。这意味着可以在每个worker中访问静态值,而不是驱动程序将其序列化并发送给worker:

    object MyUtils {
      val dtFormatter = DateTimeFormatter.ofPattern("<some non-ISO pattern>")
    }
    
    import MyUtils._
    logs.flatMap(fileContent => {
      // can safely use formatter here
    })
    
  2. 在匿名函数内的每条记录中实例化它。这会带来一些性能损失(因为实例化会一遍又一遍地发生,每条记录),所以只有在不能应用第一个选项时才使用此选项:

    logs.flatMap(fileContent => {
      val dtFormatter = DateTimeFormatter.ofPattern("<some non-ISO pattern>")
      // use formatter here
    })
    

答案 1 :(得分:2)

另一种方法是使DateTimeFormatter 瞬变。这告诉JVM / Spark该变量将不被序列化,而是从头开始构造。对于每个执行器来说很便宜的东西,例如DateTimeFormatter,这是一个好方法。

这里是an article that describes this in more detail