给定数据框:
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
答案 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 null
而NULL
是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)