Los RDD extienden la interfaz Serialable , por lo que esto no es lo que está causando que su tarea falle. Ahora esto no significa que pueda serializar un RDD
con Spark y evitarNotSerializableException
Spark es un motor informático distribuido y su abstracción principal es un conjunto de datos distribuidos ( RDD ) resistente , que puede verse como una colección distribuida. Básicamente, los elementos de RDD se dividen en los nodos del clúster, pero Spark lo abstrae del usuario, permitiendo que el usuario interactúe con el RDD (colección) como si fuera local.
No entrar en demasiados detalles, pero cuando se ejecuta diferentes transformaciones en un RDD ( map
, flatMap
, filter
y otros), el código de transformación (cierre) es:
- serializado en el nodo del controlador,
- enviado a los nodos apropiados en el clúster,
- deserializado,
- y finalmente ejecutado en los nodos
Por supuesto, puede ejecutar esto localmente (como en su ejemplo), pero todas esas fases (aparte del envío a través de la red) aún ocurren. [Esto le permite detectar cualquier error incluso antes de implementarlo en producción]
Lo que sucede en su segundo caso es que está llamando a un método, definido en clase testing
desde dentro de la función de mapa. Spark ve eso y dado que los métodos no se pueden serializar por sí mismos, Spark intenta serializar toda la testing
clase, de modo que el código seguirá funcionando cuando se ejecute en otra JVM. Tienes dos posibilidades:
Puede hacer que las pruebas de clase sean serializables, por lo que Spark puede serializar toda la clase:
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
}
o haces una someFunc
función en lugar de un método (las funciones son objetos en Scala), para que Spark pueda serializarlo:
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
}
Un problema similar, pero no el mismo, con la serialización de clases puede ser de su interés y puede leerlo en esta presentación de Spark Summit 2013 .
Como nota al margen, puede volver rddList.map(someFunc(_))
a escribir rddList.map(someFunc)
, son exactamente lo mismo. Por lo general, se prefiere el segundo ya que es menos detallado y más limpio de leer.
EDITAR (2015-03-15): SPARK-5307 introdujo SerializationDebugger y Spark 1.3.0 es la primera versión en usarlo. Agrega la ruta de serialización a una excepción NotSerializableException . Cuando se encuentra una excepción NotSerializableException, el depurador visita el gráfico de objetos para encontrar la ruta hacia el objeto que no se puede serializar, y construye información para ayudar al usuario a encontrar el objeto.
En el caso de OP, esto es lo que se imprime en 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>)