SPARK DataFrame:选择每个组的前3行

时间:2016-12-22 17:58:08

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

我遇到了与SPARK DataFrame: select the first row of each group中类似的用例。唯一的区别是我需要选择每组的前3行。 agg函数允许我在max函数的帮助下选择最高值,或者先应用sort,然后使用first函数。

有没有办法在执行agg后使用groupby函数实现它?如果没有,最好的方法是什么?

3 个答案:

答案 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)