我遇到了与SPARK DataFrame: select the first row of each group中类似的用例。唯一的区别是我需要选择每组的前3行。 agg
函数允许我在max
函数的帮助下选择最高值,或者先应用sort
,然后使用first
函数。
有没有办法在执行agg
后使用groupby
函数实现它?如果没有,最好的方法是什么?
答案 0 :(得分:6)
import org.apache.spark.sql.functions.{row_number, max, broadcast}
import org.apache.spark.sql.expressions.Window
df=Dataframe....
val w = Window.partitionBy($"groupColumn").orderBy($"AnyColumn".desc)
val dfTop = df.withColumn("rn", row_number.over(w)).where($"rn" ===> 3).drop("rn")
dfTop.show
答案 1 :(得分:0)
在链接问题中使用row_number
的窗口函数,但替换为:
.where($"rn" === 1)
与
.where($"rn" <= 3)
答案 2 :(得分:0)
解决方案是遍历从groupByKey()填充的值的结果列表,然后提取topN记录并将这些值附加到新列表中。 以下是工作示例,您可以在Cloudera VM上执行它,因为我使用了Cloudera示例数据集。在执行之前,请确保从mySql - retail_db数据库中存在的products表生成产品RDD。
getTopN功能 - &gt;
def getTopN(rec: (String, Iterable[String]), topN: Int): Iterable[String] = {
var prodPrices: List[Float] = List()
var topNPrices: List[Float] = List()
var sortedRecs: List[String] = List()
for(i <- rec._2) {
prodPrices = prodPrices:+ i.split(",")(4).toFloat
}
topNPrices = prodPrices.distinct.sortBy(k => -k).take(topN)
sortedRecs = rec._2.toList.sortBy(k => -k.split(",")(4).toFloat)
var x: List[String] = List()
for(i <- sortedRecs) {
if(topNPrices.contains(i.split(",")(4).toFloat))
x = x:+ i
}
return x
}
主要代码 - &gt;
##code to generate products RDD
val productsMap = products.
map(rec => (rec.split(",")(1), rec))
productsMap.
groupByKey().
flatMap(x => getTopN(x, 3)).
collect().
foreach(println)