I RDD estendono l'interfaccia Serializzabile , quindi questo non è ciò che causa il fallimento dell'attività . Questo non significa che è possibile serializzare un RDD
con Spark ed evitareNotSerializableException
Spark è un motore di elaborazione distribuito e la sua principale astrazione è un set di dati distribuito resiliente ( RDD ), che può essere visualizzato come una raccolta distribuita. Fondamentalmente, gli elementi di RDD sono partizionati attraverso i nodi del cluster, ma Spark lo estrae dall'utente, permettendo all'utente di interagire con il RDD (raccolta) come se fosse locale.
Non entrare in troppi dettagli, ma quando esegui trasformazioni diverse su un RDD ( map
,flatMap
, filter
e altri), il codice di trasformazione (chiusura) è:
- serializzato sul nodo del driver,
- spedito ai nodi appropriati nel cluster,
- deserializzati,
- e infine eseguito sui nodi
Ovviamente puoi eseguirlo localmente (come nel tuo esempio), ma tutte quelle fasi (ad eccezione della spedizione in rete) si verificano comunque. [Ciò consente di rilevare eventuali bug anche prima di implementarli in produzione]
Quello che succede nel secondo caso è che stai chiamando un metodo, definito in classe testing
dall'interno della funzione map. Spark vede che e poiché i metodi non possono essere serializzati da soli, Spark tenta di serializzare l'intera testing
classe, in modo che il codice continuerà a funzionare quando eseguito in un'altra JVM. Hai due possibilità:
O rendi serializzabile il test di classe, quindi l'intera classe può essere serializzata da 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
}
oppure fai la someFunc
funzione invece di un metodo (le funzioni sono oggetti in Scala), così Spark sarà in grado di serializzarlo:
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
}
Simile, ma non lo stesso problema con la serializzazione di classe può essere di tuo interesse e puoi leggerlo in questa presentazione di Spark Summit 2013 .
Come nota a margine, puoi riscrivere rddList.map(someFunc(_))
a rddList.map(someFunc)
, essi sono esattamente gli stessi. Di solito, il secondo è preferito in quanto è meno dettagliato e più pulito da leggere.
EDIT (2015-03-15): SPARK-5307 ha introdotto SerializationDebugger e Spark 1.3.0 è la prima versione a usarlo. Aggiunge il percorso di serializzazione a NotSerializableException . Quando viene rilevata NotSerializableException, il debugger visita il grafico dell'oggetto per trovare il percorso verso l'oggetto che non può essere serializzato e costruisce informazioni per aiutare l'utente a trovare l'oggetto.
Nel caso di OP, questo è ciò che viene stampato su 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>)