Some(null) 到 Stringtype 可为空的 scala.matcherror
Posted
技术标签:
【中文标题】Some(null) 到 Stringtype 可为空的 scala.matcherror【英文标题】:Some(null) to Stringtype nullable scala.matcherror 【发布时间】:2017-08-31 16:58:55 【问题描述】:我有一个RDD[(Seq[String], Seq[String])]
,数据中有一些空值。
转成dataframe的RDD是这样的
+----------+----------+
| col1| col2|
+----------+----------+
|[111, aaa]|[xx, null]|
+----------+----------+
以下是示例代码:
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()
在我创建 transposedDF 之前它运行良好,但是一旦我点击显示它就会引发以下错误:
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)
如果 rdd 中没有空值,则代码可以正常工作。我不明白为什么当我有任何空值时它会失败,因为我将 StringType 的模式指定为 nullable 为真。难道我做错了什么?我正在使用 spark 1.6.1 和 scala 2.10
【问题讨论】:
【参考方案1】:模式匹配是线性执行的,因为它出现在源代码中,所以,这一行:
case Row(t1: Seq[String], t2: Seq[String]) => Some((t1 zip t2).toMap)
其中对t1和t2的值没有任何限制,与null值无关。
有效地,将空检查放在前面,它应该可以工作。
【讨论】:
IIUC,类型模式从不匹配 null,b/c instanceof 始终为 false。【参考方案2】:我认为您需要在执行断言操作之前将空值编码为空白或特殊字符串。还要记住,Spark 是惰性执行的。因此,从“val values = df.flatMap”之类的开始,只有在执行 show() 时才会执行所有内容。
【讨论】:
【参考方案3】:问题在于您是否找到null
或第一个模式是否匹配。毕竟,t2: Seq[String]
理论上可以是null
。虽然您可以通过简单地首先出现 null
模式来立即解决这个问题,但我认为必须使用 Scala 语言中的设施来完全摆脱 null
并避免更多糟糕的运行时意外。
所以你可以这样做:
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))
这将为您提供您似乎想要的 Some
/None
元组,但我也希望将这些 None
s 扁平化。
【讨论】:
以上是关于Some(null) 到 Stringtype 可为空的 scala.matcherror的主要内容,如果未能解决你的问题,请参考以下文章
moment:Array.prototype.some调用null或undefined
pySpark:java.lang.UnsupportedOperationException:未实现类型:StringType