RDD memperluas antarmuka Serialisable , jadi ini bukan yang menyebabkan tugas Anda gagal. Sekarang ini tidak berarti bahwa Anda dapat membuat serial RDD
dengan Spark dan menghindariNotSerializableException
Spark adalah mesin komputasi terdistribusi dan abstraksi utamanya adalah dataset didistribusikan tangguh ( RDD ), yang dapat dilihat sebagai koleksi terdistribusi. Pada dasarnya, elemen-elemen RDD dipartisi di seluruh node cluster, tetapi Spark memisahkannya dari pengguna, membiarkan pengguna berinteraksi dengan RDD (koleksi) seolah-olah itu adalah yang lokal.
Tidak masuk ke terlalu banyak rincian, tetapi ketika Anda menjalankan transformasi yang berbeda pada RDD ( map
, flatMap
, filter
dan lain-lain), kode transformasi Anda (penutupan) adalah:
- serial pada node driver,
- dikirim ke node yang sesuai di cluster,
- deserialized,
- dan akhirnya dieksekusi pada node
Anda tentu saja dapat menjalankan ini secara lokal (seperti pada contoh Anda), tetapi semua fase tersebut (terlepas dari pengiriman melalui jaringan) masih terjadi. [Ini memungkinkan Anda menangkap bug apa pun bahkan sebelum menyebarkan ke produksi]
Apa yang terjadi dalam kasus kedua Anda adalah bahwa Anda memanggil metode, yang didefinisikan dalam kelas testing
dari dalam fungsi peta. Spark melihat itu dan karena metode tidak dapat diserialisasi sendiri, Spark mencoba untuk membuat serial seluruh testing
kelas, sehingga kode masih akan berfungsi ketika dieksekusi di JVM lain. Anda memiliki dua kemungkinan:
Entah Anda membuat pengujian kelas secara serial, sehingga seluruh kelas dapat diserialisasi dengan Spark:
import org.apache.spark.{SparkContext,SparkConf}
object Spark {
val ctx = new SparkContext(new SparkConf().setAppName("test").setMaster("local[*]"))
}
object NOTworking extends App {
new Test().doIT
}
class Test extends java.io.Serializable {
val rddList = Spark.ctx.parallelize(List(1,2,3))
def doIT() = {
val after = rddList.map(someFunc)
after.collect().foreach(println)
}
def someFunc(a: Int) = a + 1
}
atau Anda membuat someFunc
fungsi alih-alih metode (fungsi adalah objek di Scala), sehingga Spark akan dapat membuat cerita bersambung:
import org.apache.spark.{SparkContext,SparkConf}
object Spark {
val ctx = new SparkContext(new SparkConf().setAppName("test").setMaster("local[*]"))
}
object NOTworking extends App {
new Test().doIT
}
class Test {
val rddList = Spark.ctx.parallelize(List(1,2,3))
def doIT() = {
val after = rddList.map(someFunc)
after.collect().foreach(println)
}
val someFunc = (a: Int) => a + 1
}
Serupa, tetapi bukan masalah yang sama dengan serialisasi kelas yang dapat menarik bagi Anda dan Anda dapat membacanya di presentasi Spark Summit 2013 ini .
Sebagai catatan, Anda dapat menulis ulang rddList.map(someFunc(_))
untuk rddList.map(someFunc)
, mereka adalah persis sama. Biasanya, yang kedua lebih disukai karena kurang verbose dan lebih bersih untuk dibaca.
EDIT (2015-03-15): SPARK-5307 memperkenalkan SerializationDebugger dan Spark 1.3.0 adalah versi pertama yang menggunakannya. Ini menambahkan jalur serialisasi ke NotSerializableException . Ketika NotSerializableException ditemui, debugger mengunjungi grafik objek untuk menemukan jalur menuju objek yang tidak dapat diserialisasi, dan menyusun informasi untuk membantu pengguna menemukan objek.
Dalam kasus OP, inilah yang akan dicetak ke stdout:
Serialization stack:
- object not serializable (class: testing, value: testing@2dfe2f00)
- field (class: testing$$anonfun$1, name: $outer, type: class testing)
- object (class testing$$anonfun$1, <function1>)