Spark:agg内的多个过滤器和concat not null值

时间:2018-04-05 17:22:40

标签: apache-spark-sql spark-dataframe

我尝试连接List列中的非空值。 我知道这可以通过使用UDF轻松完成,但想知道如何通过在 agg 函数中使用多个过滤条件来处理这个问题。 不知道这里遗失了什么?

val df = sc.parallelize(Seq(("foo", List(null,"bar",null)), 
                            ("bar", List("one","two",null)),
                            ("rio", List("Ria","","Kevin")))).toDF("key", "value")

+---+-----------------+
|key|            value|
+---+-----------------+
|foo|[null, bar, null]|
|bar| [one, two, null]|
|rio|   [Ria, , Kevin]|
+---+-----------------+                         

df.groupBy("key")
  .agg(concat_ws(",",first(when(($"value".isNotNull || $"value" =!= ""),$"value"))).as("RemovedNullSeq"))
  .show(false)

+---+--------------+
|key|RemovedNullSeq|
+---+--------------+
|bar|one,two       |
|rio|Ria,,Kevin    |
|foo|bar           |
+---+--------------+

我不需要第二条记录中的空白值。 谢谢

2 个答案:

答案 0 :(得分:1)

我不能立即确定是否需要根据提供的示例使用聚合函数。

如果您只是尝试连接数组中的值,那么以下工作:

val df = Seq(List(null,"abc", null),
    List(null, null, null), 
    List(null, "def", "ghi", "kjl"),
    List("mno", null, "pqr")).toDF("list")

df.withColumn("concat", concat_ws(",",$"list")).show(false)

+---------------------+-----------+
|list                 |concat     |
+---------------------+-----------+
|[null, abc, null]    |abc        |
|[null, null, null]   |           |
|[null, def, ghi, kjl]|def,ghi,kjl|
|[mno, null, pqr]     |mno,pqr    |
+---------------------+-----------+

如果需要先分组:

val df2 = Seq((123,List(null,"abc", null)),
    (123,List(null,"def", "hij"))).toDF("key","list")

df2.show(false)
+---+-----------------+
|key|list             |
+---+-----------------+
|123|[null, abc, null]|
|123|[null, def, hij] |
+---+-----------------+

你可能认为你可以做类似

的事情
val grouped = df2.groupBy($"key").agg(collect_list($"list").as("collected"))

然后将一些函数应用于数组数组以获取连接结果。但是,如果不使用UDF,我一直无法找到方法。

在这种情况下,在分组之前爆炸可以解决问题:

val grouped = df2.groupBy($"key").agg(collect_list($"list").as("collected"))
    .groupBy($"key").agg(collect_list($"listItem").as("collected"))
    .withColumn("concat", concat_ws(",",$"collected")).show(false)

+---+---------------+-----------+
|key|collected      |concat     |
+---+---------------+-----------+
|123|[abc, def, hij]|abc,def,hij|
+---+---------------+-----------+

但请注意,无法保证收集清单的顺序。

希望这有帮助

答案 1 :(得分:1)

import org.apache.spark.sql.functions._

val df = sc.parallelize(Seq(("foo", List(null,"bar",null)), 
                            ("bar", List("one","two",null)),
                            ("rio", List("Ria","","Kevin")))).toDF("key", "value")

val filtd = df.select($"key" as "key", explode($"value") as "val").where (length($"val") > 0)
val rsult = filtd.select($"*").groupBy($"key").agg(collect_list("val"))
rsult.show(5)

你可以添加像这样的多种条件

val filtd = df.select($"key" as "key", explode($"value") as "val").where (length($"val") > 0 && $"val".isNotNull)

输出

+---+-----------------+
|key|collect_list(val)|
+---+-----------------+
|bar|       [one, two]|
|rio|     [Ria, Kevin]|
|foo|            [bar]|
+---+-----------------+