Scala / DataFrame / Spark:如何表达多个条件聚合?

时间:2017-04-28 21:33:15

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

假设我有一张表:

id,date,value
1,2017-02-12,3
2,2017-03-18,2
1,2017-03-20,5
1,2017-04-01,1
3,2017-04-01,3
2,2017-04-10,2

我已将此作为数据框(它来自Hive表)

现在,我想要一个看起来像(逻辑上)的输出:

id, count($"date">"2017-03"), sum($"value" where $"date">"2017-03"), count($"date">"2017-02"), sum($"value" where $"date">"2017-02")

我试图在单个agg()中表达这个,但我无法弄清楚如何做内部条件。我知道如何在聚合之前进行过滤,但这并不是我需要的两个不同的子范围。

// doesn't do the right thing
myDF.where($"date">"2017-03")
  .groupBy("id")
  .agg(sum("value") as "value_03", count("value") as "count_03")
  .where($"date">"2017-04")
  .agg(sum("value") as "value_04", count("value") as "value_04")

在SQL中,我会把所有聚合放在一个SELECT语句中,条件在count / sum子句中。如何在Spark with Scala中使用DataFrames做类似的事情?

我能想到的最接近的是计算groupBy(之前每个窗口中每个元组的成员资格,并对该成员资格时间值(和计数的直接总和)进行求和。似乎应该有<{1}}中有条件的表达方式更好的方法,但我找不到它。

1 个答案:

答案 0 :(得分:3)

  

在SQL中,我会把所有聚合放在一个SELECT语句中,条件在count / sum子句中。

你可以在这里完成同样的事情:

import org.apache.spark.sql.functions.{sum, when}

myDF
  .groupBy($"id")
  .agg(
    sum(when($"date" > "2017-03", $"value")).alias("value3"),
    sum(when($"date" > "2017-04", $"value")).alias("value4")
  )
+---+------+------+
| id|value3|value4|
+---+------+------+
|  1|     6|     1|
|  3|     3|     3|
|  2|     4|     2|
+---+------+------+