某些(null)到Stringtype可为null的scala.matcherror

某些(null)到Stringtype可为null的scala.matcherror,scala,apache-spark,Scala,Apache Spark,我有一个RDD[(Seq[String],Seq[String])],数据中有一些空值。 转换为dataframe的RDD如下所示 +----------+----------+ | col1| col2| +----------+----------+ |[111, aaa]|[xx, null]| +----------+----------+ 以下是示例代码: val rdd = sc.parallelize(Seq((Seq("111","aaa"),Seq("xx

我有一个
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()
在我创建TransposedF之前,它一直运行良好,但是一旦我点击show,它就会抛出以下错误:

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为true。我做错什么了吗?我使用的是spark 1.6.1和scala 2.10

模式匹配是在源代码中线性执行的,因此,这一行:

case Row(t1: Seq[String], t2: Seq[String]) => Some((t1 zip t2).toMap)
它对t1和t2的值没有任何限制,与空值匹配也不重要


实际上,在执行断言操作之前,先进行空检查,它应该会工作。

我认为您需要将空值编码为空白或特殊字符串。还要记住,Spark执行起来很懒。因此,从类似“val values=df.flatMap”开始,只有在执行show()时才会执行所有操作

问题在于您是否找到第一个模式匹配的
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))
}

这将为您提供您想要的
一些
/
元组,但我也会考虑将那些
的元组展平。

IIUC,类型模式从不匹配null,b/c instanceof总是false。