Spark序列化如何用于案例类?

时间:2018-10-09 16:26:33

标签: scala apache-spark

我在Spark 2.2中遇到了一些奇怪的事情,以及它如何反序列化case类。对于这些示例,假定该案例类:

TreeMap<Date, Double> sum = 
    list.stream()
        .collect(Collectors.groupingBy(Payment::getDate,
                                       TreeMap::new, 
                                       Collectors.summingDouble(Payment::getAmount)
                                      )
                );

如果执行以下映射操作,则在执行程序日志中同时看到我的构造函数和'a'消息的值。

case class X(a:Int, b:Int) {
  println("in the constructor!!!")
}

通过以下映射操作,我看不到构造函数消息,但在执行程序日志中确实看到了“ a”消息的值。构造函数消息在驱动程序日志中。

ds.map(x => {
  val x = X(1, 2)
  println(s"a=${x.a})
}

如果我使用广播变量,也会得到相同的行为。

val x = X(1, 2)
ds.map(x => println(s"a=${x.a}"))

知道发生了什么吗? Spark是否根据需要序列化每个字段?我本来希望将整个对象运送过来并反序列化。有了这种反序列化,我期望有一个构造函数调用。

当我查看Products的编码器代码时,看起来好像它从构造函数中获取了必填字段。我猜我以为它会在这些东西上使用那些编码器。

我什至反编译了case类的类文件,并且生成的构造函数似乎很合理。

1 个答案:

答案 0 :(得分:0)

Spark默认情况下使用Java序列化(之所以可用,是因为案例类扩展了Serializable),它不需要使用构造函数来反序列化。参见this StackOverflow question for details on Java serialization/deserialization

请注意,这种对Java序列化的依赖可能会导致问题,因为内部序列化格式没有固定设置,因此JVM版本差异可能导致反序列化失败。