RDD mở rộng giao diện Nối tiếp , vì vậy đây không phải là nguyên nhân khiến nhiệm vụ của bạn thất bại. Bây giờ điều này không có nghĩa là bạn có thể tuần tự hóa RDD
với Spark và tránhNotSerializableException
Spark là một công cụ tính toán phân tán và sự trừu tượng chính của nó là một bộ dữ liệu phân tán ( RDD ) có khả năng phục hồi , có thể được xem như là một bộ sưu tập phân tán. Về cơ bản, các phần tử của RDD được phân vùng trên các nút của cụm, nhưng Spark trừu tượng hóa điều này khỏi người dùng, cho phép người dùng tương tác với RDD (bộ sưu tập) như thể nó là một cục bộ.
Không để có được vào quá nhiều chi tiết, nhưng khi bạn chạy biến đổi khác nhau trên một RDD ( map
, flatMap
, filter
và những người khác), mã chuyển đổi của bạn (đóng cửa) là:
- tuần tự hóa trên nút trình điều khiển,
- vận chuyển đến các nút thích hợp trong cụm,
- khử lưu huỳnh,
- và cuối cùng được thực hiện trên các nút
Tất nhiên bạn có thể chạy cái này cục bộ (như trong ví dụ của bạn), nhưng tất cả các giai đoạn đó (ngoài vận chuyển qua mạng) vẫn xảy ra. [Điều này cho phép bạn bắt bất kỳ lỗi nào ngay cả trước khi triển khai vào sản xuất]
Điều xảy ra trong trường hợp thứ hai của bạn là bạn đang gọi một phương thức, được định nghĩa trong lớp testing
từ bên trong hàm ánh xạ. Spark thấy rằng và vì các phương thức không thể tự được tuần tự hóa, Spark cố gắng tuần tự hóa toàn bộ testing
lớp, để mã vẫn hoạt động khi được thực thi trong một JVM khác. Bạn có hai khả năng:
Hoặc là bạn thực hiện kiểm tra tuần tự hóa lớp, vì vậy toàn bộ lớp có thể được tuần tự hóa bởi 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
}
hoặc bạn tạo someFunc
hàm thay vì một phương thức (các hàm là các đối tượng trong Scala), do đó Spark sẽ có thể tuần tự hóa nó:
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
}
Tương tự, nhưng không phải vấn đề tương tự với việc xê-ri hóa lớp có thể khiến bạn quan tâm và bạn có thể đọc nó trong bài trình bày Spark Summit 2013 này .
Là một mặt lưu ý, bạn có thể viết lại rddList.map(someFunc(_))
để rddList.map(someFunc)
, họ là giống hệt nhau. Thông thường, thứ hai được ưa thích vì nó ít dài dòng và dễ đọc hơn.
EDIT (2015-03-15): SPARK-5307 đã giới thiệu SerializationDebugger và Spark 1.3.0 là phiên bản đầu tiên sử dụng nó. Nó thêm đường dẫn tuần tự hóa vào một NotSerializableException . Khi gặp NotSerializableException, trình gỡ lỗi truy cập vào biểu đồ đối tượng để tìm đường dẫn đến đối tượng không thể được tuần tự hóa và xây dựng thông tin để giúp người dùng tìm thấy đối tượng.
Trong trường hợp của OP, đây là nội dung được in ra thiết bị xuất chuẩn:
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>)