具有多个动态聚合操作的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配置传递任何数量的聚合。
上面的代码对于某些聚合工作正常,包括sum
,min
,max
,avg
和count
。
但是,不幸的是,此代码不适用于countDistinct
(可能是因为它是驼峰式情况?)。
运行上面的代码时,出现此错误:
线程“ main”中的异常org.apache.spark.sql.AnalysisException:未定义的函数:'countdistinct'。此功能既不是注册的临时功能,也不是在数据库“默认”中注册的永久功能
任何帮助将不胜感激!
答案 0 :(得分:1)
当前无法在agg
中将countDistinct
与Map
一起使用。从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: _*)