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 元组,但我也希望将这些 Nones 扁平化。

【讨论】:

以上是关于Some(null) 到 Stringtype 可为空的 scala.matcherror的主要内容,如果未能解决你的问题,请参考以下文章

moment:Array.prototype.some调用null或undefined

pySpark:java.lang.UnsupportedOperationException:未实现类型:StringType

如何将 MapType(StringType, StringType) 的列转换为 StringType?

管道传输到可写流时暂停可读流

在 Swift 中,我如何避免选项和 nil 对象引用?

java解析文件jsoup报错java.lang.NullPointerException,求解决方案!