RDDs erweitern die Serialisable-Schnittstelle , sodass Ihre Aufgabe nicht fehlschlägt. Dies bedeutet nicht, dass Sie eine RDD
mit Spark serialisieren und vermeiden könnenNotSerializableException
Spark ist eine verteilte Computer-Engine und ihre Hauptabstraktion ist ein ausfallsicheres verteiltes Dataset ( RDD ), das als verteilte Sammlung angesehen werden kann. Grundsätzlich sind die RDD-Elemente auf die Knoten des Clusters verteilt, aber Spark abstrahiert dies vom Benutzer weg, sodass der Benutzer mit der RDD (Sammlung) interagieren kann, als wäre es eine lokale.
Nicht , um in zu vielen Details, aber wenn man verschiedene Transformationen auf einem RDD laufen ( map
, flatMap
, filter
und andere), Ihr Transformationscode (Verschluss) ist:
- auf dem Treiberknoten serialisiert,
- an die entsprechenden Knoten im Cluster gesendet,
- deserialisiert,
- und schließlich auf den Knoten ausgeführt
Sie können dies natürlich lokal ausführen (wie in Ihrem Beispiel), aber alle diese Phasen (außer Versand über Netzwerk) treten weiterhin auf. [Auf diese Weise können Sie Fehler bereits vor der Bereitstellung in der Produktion erkennen.]
In Ihrem zweiten Fall rufen Sie eine Methode auf, die in der Klasse testing
innerhalb der Map-Funktion definiert ist. Spark sieht das und da Methoden nicht alleine serialisiert werden können, versucht Spark, die gesamte testing
Klasse zu serialisieren , damit der Code weiterhin funktioniert, wenn er in einer anderen JVM ausgeführt wird. Sie haben zwei Möglichkeiten:
Entweder machen Sie Klassentests serialisierbar, sodass die gesamte Klasse von Spark serialisiert werden kann:
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
}
oder Sie machen eine someFunc
Funktion anstelle einer Methode (Funktionen sind Objekte in Scala), damit Spark sie serialisieren kann:
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
}
Ein ähnliches, aber nicht dasselbe Problem bei der Klassenserialisierung kann für Sie von Interesse sein, und Sie können es in dieser Präsentation zum Spark Summit 2013 nachlesen .
Als Randnotiz, können Sie umschreiben rddList.map(someFunc(_))
zu rddList.map(someFunc)
, sie sind genau gleich. Normalerweise wird die zweite bevorzugt, da sie weniger ausführlich und sauber zu lesen ist.
BEARBEITEN (2015-03-15): SPARK-5307 führte SerializationDebugger ein und Spark 1.3.0 ist die erste Version, die es verwendet. Es fügt einer NotSerializableException einen Serialisierungspfad hinzu . Wenn eine NotSerializableException auftritt, besucht der Debugger das Objektdiagramm, um den Pfad zum Objekt zu finden, der nicht serialisiert werden kann, und erstellt Informationen, die dem Benutzer helfen, das Objekt zu finden.
Im Fall von OP wird Folgendes auf stdout gedruckt:
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>)