RDD ขยายส่วนต่อประสาน Serialisableดังนั้นนี่ไม่ใช่สิ่งที่ทำให้งานของคุณล้มเหลว ตอนนี้ไม่ได้หมายความว่าคุณสามารถซีเรียลRDD
กับ Spark และหลีกเลี่ยงNotSerializableException
Spark เป็นเอ็นจิ้นการคำนวณแบบกระจายและนามธรรมหลักคือชุดข้อมูลแบบกระจายที่ยืดหยุ่น ( RDD ) ซึ่งสามารถดูได้เป็นคอลเลกชันแบบกระจาย โดยทั่วไปองค์ประกอบของ RDD จะถูกแบ่งพาร์ติชันข้ามโหนดของคลัสเตอร์ แต่ Spark จะแยกสิ่งนี้ออกจากผู้ใช้ทำให้ผู้ใช้โต้ตอบกับ RDD (คอลเลกชัน) ราวกับว่ามันเป็นโลคัล
จะไม่ได้รับเข้าไปในรายละเอียดมากเกินไป แต่เมื่อคุณเรียกใช้การเปลี่ยนแปลงที่แตกต่างกันใน RDD ( map
, flatMap
, filter
และอื่น ๆ ) รหัสการเปลี่ยนแปลงของคุณ (ปิด) เป็น:
- ต่อเนื่องบนโหนดไดรเวอร์
- ส่งไปยังโหนดที่เหมาะสมในคลัสเตอร์
- deserialized,
- และในที่สุดก็ดำเนินการบนโหนด
แน่นอนคุณสามารถเรียกใช้สิ่งนี้ในพื้นที่ (เช่นในตัวอย่างของคุณ) แต่ขั้นตอนเหล่านั้นทั้งหมด (นอกเหนือจากการจัดส่งผ่านเครือข่าย) ยังคงเกิดขึ้น [สิ่งนี้ช่วยให้คุณสามารถดักจับข้อบกพร่องก่อนที่จะปรับใช้กับการผลิต]
สิ่งที่เกิดขึ้นในกรณีที่สองของคุณคือคุณกำลังเรียกวิธีการที่กำหนดไว้ในชั้นเรียนtesting
จากภายในฟังก์ชั่นแผนที่ Spark เห็นว่าและเนื่องจากวิธีการไม่สามารถจัดลำดับด้วยตนเองได้ Spark จึงพยายามทำให้เป็น อนุกรมทั้งtesting
คลาสดังนั้นโค้ดจะยังคงทำงานได้เมื่อดำเนินการใน JVM อื่น คุณมีความเป็นไปได้สองอย่าง:
ไม่ว่าคุณจะทำการทดสอบคลาสที่สามารถทำให้เป็นอนุกรมได้ดังนั้น 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
}
หรือคุณสร้างsomeFunc
ฟังก์ชั่นแทนวิธีการ (ฟังก์ชั่นเป็นวัตถุใน Scala) ดังนั้น 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 {
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
}
ปัญหาที่คล้ายกัน แต่ไม่ใช่ปัญหาเดียวกันกับการจัดลำดับชั้นสามารถเป็นที่สนใจของคุณและคุณสามารถอ่านได้ในการนำเสนอ Spark Summit 2013นี้
ตามบันทึกข้างคุณสามารถเขียนrddList.map(someFunc(_))
เพื่อrddList.map(someFunc)
ที่พวกเขาจะตรงเดียวกัน โดยปกติแล้วสิ่งที่สองควรได้รับการพิจารณาเนื่องจากเป็นคำที่ละเอียดและอ่านง่ายกว่า
แก้ไข (2015-03-15): SPARK-5307แนะนำSerializationDebuggerและ Spark 1.3.0 เป็นรุ่นแรกที่ใช้งาน มันจะเพิ่มเส้นทางอนุกรมกับNotSerializableException เมื่อพบ NotSerializableException ตัวดีบักจะเข้าสู่กราฟวัตถุเพื่อค้นหาเส้นทางไปยังวัตถุที่ไม่สามารถต่อเนื่องกันได้และสร้างข้อมูลเพื่อช่วยให้ผู้ใช้สามารถค้นหาวัตถุได้
ในกรณีของ OP นี่คือสิ่งที่จะพิมพ์ไปยัง 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>)