2017-04-05 2 views
3

Ich habe eine RDD[(Seq[String], Seq[String])] mit einigen Null-Werte in den Daten. Die RDD zu Datenrahmen umgewandelt sieht wie folgt ausEinige (Null) zu Stringtype Nullable scala.matcherror

+----------+----------+ 
|  col1|  col2| 
+----------+----------+ 
|[111, aaa]|[xx, null]| 
+----------+----------+ 

Es folgt der Beispielcode:

val rdd = sc.parallelize(Seq((Seq("111","aaa"),Seq("xx",null)))) 
val df = rdd.toDF("col1","col2") 
val keys = Array("col1","col2") 
val values = df.flatMap { 
    case Row(t1: Seq[String], t2: Seq[String]) => Some((t1 zip t2).toMap) 
    case Row(_, null) => None 
} 
val transposed = values.map(someFunc(keys)) 

val schema = StructType(keys.map(name => StructField(name, DataTypes.StringType, nullable = true))) 

val transposedDf = sc.createDataFrame(transposed, schema) 

transposed.show() 

Es läuft gut, bis der Punkt, den ich ein transposedDF schaffen, aber sobald ich zeigen, traf es die Würfe Folgefehler:

scala.MatchError: null 
     at org.apache.spark.sql.catalyst.CatalystTypeConverters$StringConverter$.toCatalystImpl(CatalystTypeConverters.scala:295) 
     at org.apache.spark.sql.catalyst.CatalystTypeConverters$StringConverter$.toCatalystImpl(CatalystTypeConverters.scala:294) 
     at org.apache.spark.sql.catalyst.CatalystTypeConverters$CatalystTypeConverter.toCatalyst(CatalystTypeConverters.scala:97) 
     at org.apache.spark.sql.catalyst.CatalystTypeConverters$StructConverter.toCatalystImpl(CatalystTypeConverters.scala:260) 
     at org.apache.spark.sql.catalyst.CatalystTypeConverters$StructConverter.toCatalystImpl(CatalystTypeConverters.scala:250) 
     at org.apache.spark.sql.catalyst.CatalystTypeConverters$CatalystTypeConverter.toCatalyst(CatalystTypeConverters.scala:102) 
     at org.apache.spark.sql.catalyst.CatalystTypeConverters$$anonfun$createToCatalystConverter$2.apply(CatalystTypeConverters.scala:401) 
     at org.apache.spark.sql.SQLContext$$anonfun$6.apply(SQLContext.scala:492) 
     at org.apache.spark.sql.SQLContext$$anonfun$6.apply(SQLContext.scala:492) 

Wenn es in der rdd keine Nullwerte gibt, funktioniert der Code einwandfrei. Ich verstehe nicht, warum es fehlschlägt, wenn ich NULL-Werte habe, weil ich das Schema von StringType mit NULL-Wert als wahr definiere. Mache ich etwas falsch? Ich bin mit Funken 1.6.1 und scala 2.10

Antwort

1

Pattern Match linear durchgeführt wird, wie es in den Quellen erscheint, so, diese Zeile:

case Row(t1: Seq[String], t2: Seq[String]) => Some((t1 zip t2).toMap) 

, die keine Einschränkungen haben die Werte von t1 und t2 spielt niemals eine Rolle mit dem Nullwert.

Effektiv, setzen Sie den Null-Check vor und es sollte funktionieren.

+2

IIUC, ein Typ Muster entspricht nie null, b/c instanceof ist immer falsch. –

+0

@ Som-Snytt, Sie haben Recht. – pedrofurla

0

Ich denke, Sie müssen NULL-Werte in leere oder spezielle Zeichenfolge kodieren, bevor Assert-Operationen ausgeführt werden. Bedenken Sie auch, dass Spark träge ausgeführt wird. Also ab dem gleichen "val values ​​= df.flatMap" wird alles nur ausgeführt, wenn show() ausgeführt wird.

1

Das Problem ist, dass, ob Sie null finden oder nicht das erste Muster übereinstimmt. Immerhin könnte t2: Seq[String] theoretisch null sein. Während es wahr ist, dass Sie das sofort lösen können, indem Sie einfach das null Muster zuerst erscheinen lassen, halte ich es für unbedingt erforderlich, die Einrichtungen in der Sprache Scala zu verwenden, um null insgesamt loszuwerden und weitere schlechte Laufzeitüberraschungen zu vermeiden.

So könnte man so etwas tun:

def foo(s: Seq[String]) = if (s.contains(null)) None else Some(s) 
//or you could do fancy things with filter/filterNot 

df.map { 
    case (first, second) => (foo(first), foo(second)) 
} 

Das werden Sie bieten die Some/None Tupeln Sie scheinen zu wollen, aber ich würde jene None s als auch über Verflachung sehen.

Verwandte Themen