Spark Dataframe实现类似于Oracle的LISTAGG函数-无法在组中订购

时间:2018-07-07 05:44:16

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

我想实现类似于Oracle LISTAGG函数的功能。

等效的oracle代码是

select KEY,
listagg(CODE, '-') within group (order by DATE) as CODE
from demo_table
group by KEY

这是我的spark scala数据框实现,但是无法在每个组中对值进行排序。

输入:

val values = List(List("66", "PL", "2016-11-01"), List("66", "PL", "2016-12-01"),
  List("67", "JL", "2016-12-01"), List("67", "JL", "2016-11-01"), List("67", "PL", "2016-10-01"), List("67", "PO", "2016-09-01"), List("67", "JL", "2016-08-01"),
  List("68", "PL", "2016-12-01"), List("68", "JO", "2016-11-01"))
  .map(row => (row(0), row(1), row(2)))

val df = values.toDF("KEY", "CODE", "DATE")

df.show()

+---+----+----------+
|KEY|CODE|      DATE|
+---+----+----------+
| 66|  PL|2016-11-01|
| 66|  PL|2016-12-01|----- group 1
| 67|  JL|2016-12-01|
| 67|  JL|2016-11-01|
| 67|  PL|2016-10-01|
| 67|  PO|2016-09-01|
| 67|  JL|2016-08-01|----- group 2
| 68|  PL|2016-12-01|
| 68|  JO|2016-11-01|----- group 3
+---+----+----------+

udf实现:

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

val listAgg = udf((xs: Seq[String]) => xs.mkString("-"))

df.groupBy("KEY")
  .agg(listAgg(collect_list("CODE")).alias("CODE"))
  .show(false)

+---+--------------+
|KEY|CODE          |
+---+--------------+
|68 |PL-JO         |
|67 |JL-JL-PL-PO-JL|
|66 |PL-PL         |
+---+--------------+

预期输出:-按日期排序

+---+--------------+
|KEY|CODE          |
+---+--------------+
|68 |JO-PL         |
|67 |JL-PO-PL-JL-JL|
|66 |PL-PL         |
+---+--------------+

1 个答案:

答案 0 :(得分:1)

使用struct 内置函数CODEDATE列组合在一起,并在{{1 }}聚合函数。然后在collect_list函数中按日期排序,然后收集代码作为udf分隔的字符串

-

应该给您

import org.apache.spark.sql.functions._
def sortAndStringUdf = udf((codeDate: Seq[Row])=> codeDate.sortBy(row => row.getAs[Long]("DATE")).map(row => row.getAs[String]("CODE")).mkString("-"))

df.withColumn("codeDate", struct(col("CODE"), col("DATE").cast("timestamp").cast("long").as("DATE")))
      .groupBy("KEY").agg(sortAndStringUdf(collect_list("codeDate")).as("CODE"))

我希望答案会有所帮助

更新

我确信这会比使用+---+--------------+ |KEY| CODE| +---+--------------+ | 68| JO-PL| | 67|JL-PO-PL-JL-JL| | 66| PL-PL| +---+--------------+ 函数

更快
udf

应该会为您提供与上述相同的结果