[英]Why does writeObject throw java.io.NotSerializableException and how do I fix it?
[英]Why does this Spark code throw java.io.NotSerializableException
我想在RDD上的轉換中訪問伴隨對象的方法。 為什么以下不起作用:
import org.apache.spark.rdd.RDD
import spark.implicits._
import org.apache.spark.sql.{Encoder, Encoders}
class Abc {
def transform(x: RDD[Int]): RDD[Double] = { x.map(Abc.fn) }
}
object Abc {
def fn(x: Int): Double = { x.toDouble }
}
implicit def abcEncoder: Encoder[Abc] = Encoders.kryo[Abc]
new Abc().transform(sc.parallelize(1 to 10)).collect
上面的代碼拋出了一個java.io.NotSerializableException
:
org.apache.spark.SparkException: Task not serializable
at org.apache.spark.util.ClosureCleaner$.ensureSerializable(ClosureCleaner.scala:298)
at org.apache.spark.util.ClosureCleaner$.org$apache$spark$util$ClosureCleaner$$clean(ClosureCleaner.scala:288)
at org.apache.spark.util.ClosureCleaner$.clean(ClosureCleaner.scala:108)
at org.apache.spark.SparkContext.clean(SparkContext.scala:2094)
at org.apache.spark.rdd.RDD$$anonfun$map$1.apply(RDD.scala:370)
at org.apache.spark.rdd.RDD$$anonfun$map$1.apply(RDD.scala:369)
at org.apache.spark.rdd.RDDOperationScope$.withScope(RDDOperationScope.scala:151)
at org.apache.spark.rdd.RDDOperationScope$.withScope(RDDOperationScope.scala:112)
at org.apache.spark.rdd.RDD.withScope(RDD.scala:362)
at org.apache.spark.rdd.RDD.map(RDD.scala:369)
at Abc.transform(<console>:19)
... 47 elided
Caused by: java.io.NotSerializableException: Abc
Serialization stack:
- object not serializable (class: Abc, value: Abc@4f598dfb)
- field (class: Abc$$anonfun$transform$1, name: $outer, type: class Abc)
- object (class Abc$$anonfun$transform$1, <function1>)
at org.apache.spark.serializer.SerializationDebugger$.improveException(SerializationDebugger.scala:40)
at org.apache.spark.serializer.JavaSerializationStream.writeObject(JavaSerializer.scala:46)
at org.apache.spark.serializer.JavaSerializerInstance.serialize(JavaSerializer.scala:100)
at org.apache.spark.util.ClosureCleaner$.ensureSerializable(ClosureCleaner.scala:295)
... 57 more
即使為Abc類定義一個Encoder
也無濟於事。 但更重要的問題是,為什么要嘗試Abc類對象的序列化呢? 我的第一個想法是伴侶對象是類的單個對象,所以可能嘗試序列化它。 但似乎並非如此,因為當我從另一個類調用Abc.fn時:
class Xyz {
def transform(x: RDD[Int]): RDD[Double] = { x.map(Abc.fn) }
}
implicit def xyzEncoder: Encoder[Xyz] = Encoders.kryo[Xyz]
new Xyz().transform(sc.parallelize(1 to 10)).collect
我得到一個java.io.NotSerializableException: Xyz
這篇文章討論了Apache Spark中的“可序列化”與“不可序列化的對象”:
使用Apache Spark中的非可序列化對象,Nicola Ferraro
該文提出了以下幾點建議:
在你的特定情況下發生了什么
一些替代方案,因此您的對象不需要“可序列化”
主要的抽象os spark是RDD,它在集群的節點上進行分區。 因此,當我們運行RDD時,它在驅動程序節點中被序列化,並被分發到其他適當的節點。 然后工作節點反序列化並執行。
在您的情況下,ABC類無法序列化並分發到其他工作節點。 您需要使用Serializable序列化ABC類
class Abc with Serializable{
def transform(x: RDD[Int]): RDD[Double] = { x.map(Abc.fn) }
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.