Spark DataFrame - 从列中删除空值

时间:2017-01-24 13:36:16

标签: scala apache-spark apache-spark-sql

给定数据框:

    val df = sc.parallelize(Seq(("foo", ArrayBuffer(null,"bar",null)), ("bar", ArrayBuffer("one","two",null)))).toDF("key", "value")
    df.show

    +---+--------------------------+
    |key|                     value|
    +---+--------------------------+
    |foo|ArrayBuffer(null,bar,null)|
    |bar|ArrayBuffer(one, two,null)|
    +---+--------------------------+

我想从null列中删除value。删除后,数据框应如下所示:

    +---+--------------------------+
    |key|                     value|
    +---+--------------------------+
    |foo|ArrayBuffer(bar)          |
    |bar|ArrayBuffer(one, two)     |
    +---+--------------------------+

欢迎任何建议。 10x

3 个答案:

答案 0 :(得分:3)

这里你需要一个UDF。例如,使用flatMap

val filterOutNull = udf((xs: Seq[String]) => 
  Option(xs).map(_.flatMap(Option(_))))

df.withColumn("value", filterOutNull($"value"))

其中Option外部map处理NULL列:

Option(null: Seq[String]).map(identity)
Option[Seq[String]] = None
Option(Seq("foo", null, "bar")).map(identity)
Option[Seq[String]] = Some(List(foo, null, bar))

并确保在通过映射输入NULL / null时,我们不会因NPE而失败

NULL -> null -> None -> None -> NULL

其中null是Scala nullNULL是SQL NULL

内部flatMap展开Options有效过滤nulls的序列:

Seq("foo", null, "bar").flatMap(Option(_))
Seq[String] = List(foo, bar)

更迫切的等价物可能是这样的:

val imperativeFilterOutNull = udf((xs: Seq[String]) => 
  if (xs == null) xs
  else for {
    x <- xs
    if x != null
  } yield x)

答案 1 :(得分:2)

选项1:使用UDF:

 val filterNull = udf((arr : Seq[String]) => arr.filter((x: String) => x != null))
 df.withColumn("value", filterNull($"value")).show()

选项2:无UDF

df.withColumn("value", explode($"value")).filter($"value".isNotNull).groupBy("key").agg(collect_list($"value")).show()

请注意,效率较低......

答案 2 :(得分:0)

你也可以使用spark-daria:com.github.mrpowers.spark.daria.sql.functions.arrayExNull

来自文档:

  

与数组类似,但不包含null元素