Scala Spark函数不可序列化

Scala Spark函数不可序列化,scala,apache-spark,Scala,Apache Spark,我有一门课: class DataLoader { def rdd2RddTransform( ss: SparkSession, inputRDD: RDD[GenericRecord]): RDD[GenericRecord] = { inputRDD.asInstanceOf[RDD[TrainingData]] .map(reformatTrainingData) } private def reformatTrainin

我有一门课:

class DataLoader {

  def rdd2RddTransform(
    ss: SparkSession,
    inputRDD: RDD[GenericRecord]): RDD[GenericRecord] = {

    inputRDD.asInstanceOf[RDD[TrainingData]]
            .map(reformatTrainingData)
  }

  private def reformatTrainingData: TrainingData => ReFormatedData
               = (trainingData: TrainingData) => {func implement}

}
它工作得很好,但引发了一个异常:
org.apache.spark.SparkException:任务不可序列化
在我对RDD的映射做了一个小更改之后:

inputRDD.asInstanceOf[RDD[TrainingData]].map(reformatTrainingData(_))

我认为这两个功能应该是相同的,但似乎不是。为什么它们不同?

这是因为方法和函数在Scala中不太可互换

函数是独立的对象(即类的实例,如
Function1
Function2
Function3
…),但方法仍然与其封闭类绑定。如果封闭类不可序列化,这可能会在Spark中产生问题-当Spark尝试序列化方法时,它无法序列化关联的类实例

请注意,
reformatTrainingData
是一个返回函数的方法

所以当你打电话时,比如:

rdd.map(reformatTrainingData)
实际上,您正在调用no-arg
reformatTrainingData
方法,并返回一个可以安全序列化的独立
Function1
实例。你也可以这样写

private def reformatTrainingData(): TrainingData => ReFormatedData ...

rdd.map(reformatTrainingData())
强调有一个方法调用正在发生

当您更改为
reformatTrainingData(41;
时,您使用的是部分应用的方法;当Spark尝试对此进行序列化时,它需要拉入并序列化封闭的
数据加载器
类,该类未标记为
可序列化

如果
reformatTrainingData
是类型为
TrainingData=>ReFormatedData
的简单方法,则会出现相同的问题

如果将
DataLoader
标记为
extends Serializable
,则两个版本都可以工作

reformatTrainingData
转换为
val
也可以,因为val在序列化时不会拉入封闭类:

private val reformatTrainingData: TrainingData => ReFormatedData ...

rdd.map(reformatTrainingData)

我怀疑这是由于Scala中函数和方法之间的差异造成的。能否发布堆栈跟踪中包含序列化调试信息的部分?请参阅以获取示例