СДР расширяют интерфейс Serialisable , так что это не то, что приводит к сбою вашей задачи. Теперь это не значит, что вы можете сериализовать RDD
с Spark и избежатьNotSerializableException
Spark - это механизм распределенных вычислений, и его основной абстракцией является устойчивый распределенный набор данных ( RDD ), который можно рассматривать как распределенную коллекцию. По сути, элементы RDD распределены по узлам кластера, но Spark абстрагирует это от пользователя, позволяя пользователю взаимодействовать с RDD (коллекцией), как если бы он был локальным.
Чтобы не попасть в слишком много деталей, но при запуске различных преобразований на РДУ ( map
, flatMap
, filter
и другие), код преобразования (закрытие) является:
- сериализовано на узле драйвера,
- отправлены на соответствующие узлы в кластере,
- десериализации,
- и, наконец, выполняется на узлах
Конечно, вы можете запустить это локально (как в вашем примере), но все эти фазы (кроме доставки по сети) все же происходят. [Это позволяет выявлять любые ошибки еще до развертывания в производство]
Во втором случае происходит то, что вы вызываете метод, определенный в классе, 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 это то, что выводится на стандартный вывод:
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>)