2017-01-06 3 views
2

Ich bin vor kurzem von Spark 1.6 zu Spark 2.X gewechselt und möchte - wenn möglich - auch von Dataframes zu Datasets wechseln. Ich habe versucht, einen Code wie dieseDataframe to Dataset mit dem Typ Beliebig

case class MyClass(a : Any, ...) 

val df = ... 
df.map(x => MyClass(x.get(0), ...)) 

Wie Sie sehen können MyClass ein Feld vom Typ haben Any, wie ich bei der Kompilierung nicht wissen, die Art des Feldes I mit x.get(0) abrufen. Es kann ein langer, string, int, etc. sein

Allerdings, wenn ich versuchen, Code auszuführen, ähnlich dem, was Sie oben sehen, ich eine Ausnahme erhalten:

java.lang.ClassNotFoundException: scala.Any 

Mit einigen Debugging, erkannte ich, dass Die Ausnahme wird ausgelöst, nicht weil meine Daten vom Typ Any sind, sondern weil MyClass einen Typ Any hat. Wie kann ich dann Datasets verwenden?

Antwort

1

Wenn Sie interessiert sind, in limited and ugly workarounds wie Encoders.kryo:

import org.apache.spark.sql.Encoders 

case class FooBar(foo: Int, bar: Any) 

spark.createDataset(
    sc.parallelize(Seq(FooBar(1, "a"))) 
)(Encoders.kryo[FooBar]) 

oder

spark.createDataset(
    sc.parallelize(Seq(FooBar(1, "a"))).map(x => (x.foo, x.bar)) 
)(Encoders.tuple(Encoders.scalaInt, Encoders.kryo[Any])) 

Sie dies nicht tun. Alle Felder/Spalten in einem Dataset müssen von bekanntem, homogenem Typ sein, für den ein impliziter Encoder im Geltungsbereich existiert. Dort ist einfach kein Platz für Any da.

UDT API bietet ein bisschen mehr Flexibilität und erlaubt eine begrenzte Polymorphie, aber es ist privat, nicht vollständig kompatibel mit Dataset API und kommt mit erheblichen Performance- und Storage-Penalty.

Wenn für eine gegebene Ausführung alle Werte des gleichen Typs können Sie natürlich spezialisierte Klassen erstellen und eine Entscheidung treffen, welche zur Laufzeit zu verwenden.

Verwandte Themen