我在Scala Spark中使用了一个简单的groupby查询,其目的是获取已排序数据框中组中的第一个值。这是我的Spark数据框
+---------------+------------------------------------------+
|ID |some_flag |some_type | Timestamp |
+---------------+------------------------------------------+
| 656565654| true| Type 1|2018-08-10 00:00:00|
| 656565654| false| Type 1|2017-08-02 00:00:00|
| 656565654| false| Type 2|2016-07-30 00:00:00|
| 656565654| false| Type 2|2016-05-04 00:00:00|
| 656565654| false| Type 2|2016-04-29 00:00:00|
| 656565654| false| Type 2|2015-10-29 00:00:00|
| 656565654| false| Type 2|2015-04-29 00:00:00|
+---------------+----------+-----------+-------------------+
这是我的汇总查询
val sampleDF = df.sort($"Timestamp".desc).groupBy("ID").agg(first("Timestamp"), first("some_flag"), first("some_type"))
预期结果是
+---------------+-------------+---------+-------------------+
|ID |some_falg |some_type| Timestamp |
+---------------+-------------+---------+-------------------+
| 656565654| true| Type 1|2018-08-10 00:00:00|
+---------------+-------------+---------+-------------------+
但是跟随更奇怪的输出,并且像随机行一样不断变化
+---------------+-------------+---------+-------------------+
|ID |some_falg |some_type| Timestamp |
+---------------+-------------+---------+-------------------+
| 656565654| false| Type 2|2015-10-29 00:00:00|
+---------------+-------------+---------+-------------------+
还请注意,数据框中没有空值。我在做错事情的地方挠头。需要帮助!
答案 0 :(得分:3)
您尝试获取所有第一个值的方式将返回错误的结果。每个列的值可能来自不同的行。
相反,每个组只应按降序排列order by
时间戳,并获得第一行。一种简单的方法是使用row_number
之类的函数。
import org.apache.spark.sql.functions._
import org.apache.spark.sql.expressions.Window
val sampleDF = df.withColumn("rnum",row_number().over(Window.partitionBy(col("ID")).orderBy(col("Timestamp").desc)))
sampleDF.filter(col("rnum") == 1).show
答案 1 :(得分:3)
只需添加到Vamsi的答案中即可;问题是groupBy
结果组中的值没有以任何特定顺序返回(特别是考虑到Spark操作的分布式性质),因此first
函数的名称可能会引起误解。它返回为该列找到的第一个非空值,即组中该列的几乎所有非空值。
在groupBy
之前对行进行排序不会以任何可重复的方式影响组内的顺序。
另请参见此blog post,该解释说明,由于上述行为,您从多个first
调用中获得的值甚至可能不是来自该组中的同一行。
输入带有3列“ k,t,v”的数据
z, 1, null
z, 2, 1.5
z, 3, 2.4
代码:
df.groupBy("k").agg(
$"k",
first($"t"),
first($"v")
)
输出:
z, 1, 1.5
此结果混合了2条记录!