触发多个动态聚合函数,countDistinct不起作用

时间:2019-04-11 20:31:37

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

具有多个动态聚合操作的Spark数据帧上的聚合。

我想使用Scala通过多个动态聚合操作(在JSON中由用户传递)对Spark数据帧进行聚合。我正在将JSON转换为Map

以下是一些示例数据:

colA    colB    colC    colD
1       2       3       4
5       6       7       8
9       10      11      12

我正在使用的Spark聚合代码:

var cols = ["colA","colB"]
var aggFuncMap = Map("colC"-> "sum", "colD"-> "countDistinct")
var aggregatedDF = currentDF.groupBy(cols.head, cols.tail: _*).agg(aggFuncMap)

我只需要将aggFuncMap作为Map传递,以便用户可以通过JSON配置传递任何数量的聚合。

上面的代码对于某些聚合工作正常,包括summinmaxavgcount

但是,不幸的是,此代码不适用于countDistinct(可能是因为它是驼峰式情况?)。

运行上面的代码时,出现此错误:

  

线程“ main”中的异常org.apache.spark.sql.AnalysisException:未定义的函数:'countdistinct'。此功能既不是注册的临时功能,也不是在数据库“默认”中注册的永久功能

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:1)

当前无法在agg中将countDistinctMap一起使用。从documentation中可以看到:

  

可用的汇总方法为avg,max,min,sum,count。


可能的解决方法是将Map更改为Seq[Column]

val cols = Seq("colA", "colB")
val aggFuncs = Seq(sum("colC"), countDistinct("colD"))
val df2 = df.groupBy(cols.head, cols.tail: _*).agg(aggFuncs.head, aggFuncs.tail: _*)

但是如果用户要在配置文件中指定聚合,那将无济于事。

另一种方法是使用expr,此函数将评估字符串并返回一列。但是,expr将不接受"countDistinct",而需要使用"count(distinct(...))"。 可以将其编码如下:

val aggFuncs = Seq("sum(colC)", "count(distinct(colD))").map(e => expr(e))
val df2 = df.groupBy(cols.head, cols.tail: _*).agg(aggFuncs.head, aggFuncs.tail: _*)