2017-01-20 125 views
6
val df = (Seq((1, "a", "10"),(1,"b", "12"),(1,"c", "13"),(2, "a", "14"), 
       (2,"c", "11"),(1,"b","12"),(2, "c", "12"),(3,"r", "11")). 
      toDF("col1", "col2", "col3")) 

所以我有一個3列火花數據幀。火花數據幀groupby多次

我的要求實際上是我需要執行兩個級別的groupby,如下所述。

Level1: 如果我在col1上做groupby並做一個Col3的總和。我會得到兩列以下。 1. col1 2. sum(col3) 我會在這裏鬆散col2。

Level2: 如果我想再次在col1和col2上進行分組,然後做一個Col3的總和,我會得到3列以下的內容。 1. COL1 2. COL2 3.總和(COL3)

我的要求其實是我需要執行的GroupBy的兩個層次,並有level2的這兩個列(SUM(COL3)1級的,總和(COL3) )在最後一個數據幀中。

我該怎麼做,任何人都可以解釋?

火花:1.6.2 斯卡拉:2.10

回答

8

一種選擇是分別做兩個和,然後加入他們回:

(df.groupBy("col1", "col2").agg(sum($"col3").as("sum_level2")). 
    join(df.groupBy("col1").agg(sum($"col3").as("sum_level1")), Seq("col1")).show) 

+----+----+----------+----------+ 
|col1|col2|sum_level2|sum_level1| 
+----+----+----------+----------+ 
| 2| c|  23.0|  37.0| 
| 2| a|  14.0|  37.0| 
| 1| c|  13.0|  47.0| 
| 1| b|  24.0|  47.0| 
| 3| r|  11.0|  11.0| 
| 1| a|  10.0|  47.0| 
+----+----+----------+----------+ 

另一種選擇是使用的窗口功能,考慮到level1_sum是由col1分組的level2_sum的總和的事實:

import org.apache.spark.sql.expressions.Window 
val w = Window.partitionBy($"col1") 

(df.groupBy("col1", "col2").agg(sum($"col3").as("sum_level2")). 
    withColumn("sum_level1", sum($"sum_level2").over(w)).show) 

+----+----+----------+----------+ 
|col1|col2|sum_level2|sum_level1| 
+----+----+----------+----------+ 
| 1| c|  13.0|  47.0| 
| 1| b|  24.0|  47.0| 
| 1| a|  10.0|  47.0| 
| 3| r|  11.0|  11.0| 
| 2| c|  23.0|  37.0| 
| 2| a|  14.0|  37.0| 
+----+----+----------+----------+ 
+1

Seq(「col1」)是加入時的關鍵嗎? – Ramesh

+1

是的,'Seq(「col1」)'指定加入密鑰。 – Psidom

+0

當我執行這個時,我看到兩個交換機,一個用於groupBy,另一個用於Window。有沒有辦法避免第二次交換?看起來好像你一旦完成了groupBy(「col1」,「col2」),就不需要爲第二步移動數據 - 除非一些col1組遍歷節點。 –