在Spark Dataframe上执行第一个和最后一个聚合函数时获得意外结果。
我有一个火花数据框,其中包含colA,colB,colC,colD,colE,extraCol1,extraCol2列
我需要对此数据帧进行汇总
分组-> colA&colB,max-> colC,max-> colD,第一-> colE,extraCol1,extraCol2
所以下面是我正在使用的数据帧(df),正在使用Spark分区(3)
colA colB colC colD colE extraCol1 extracol2
Harshit 23 43 44 A q z
Mohit 24 56 62 B w x
Harshit 23 32 44 C e c
Kali 10 20 460 D r v
Aman 20 30 180 E t b
Ram 30 100 270 F yu n
Kali 10 600 360 G io m
Kali 10 600 460 k p o
下面是我用来执行groupBy操作的scala和spark的代码
val cols = List("colA","colB")
var aggFuncSeq = List(max(`colC`) as colC_new, max(`colD`) as colD_new, first(`colE`,true) as colE, first(`extracol2`,true) as extracol2, first(`extraCol1`,true) as extraCol1)
var aggFuncs = aggFuncSeq.map(e => expr(e))
df = df.groupBy(cols.head, cols.tail: _*).agg(aggFuncs.head, aggFuncs.tail: _*)
df.show(10)
执行后,出现以下意外结果。
colA colB colC_new colD_new colE extracol2 extraCol1
Harshit 23 43 44 C c e
Aman 20 30 180 E b t
Kali 10 600 460 D v r
Ram 30 100 270 F n yu
Mohit 24 56 62 B x w
但是根据分组条件和聚合操作,对于colE,extracol2,extracol1,输出结果应具有与Harshit对应的第一行
因此,预期结果如下
colA colB colC_new colD_new colE extracol2 extraCol1
Harshit 23 43 44 A q z
Aman 20 30 180 E b t
Kali 10 600 460 D v r
Ram 30 100 270 F n yu
Mohit 24 56 62 B x w
但是我无法理解这个SQL概念,即如何实现。因此,如果有人可以帮助我解决这个奇怪的问题。
是因为分区吗?
它如何提供此结果以及如何将其修复为预期结果?
感谢您的帮助。 谢谢
答案 0 :(得分:0)
在Spark中groupBy
时,可以更改DataFrame的顺序。但并非总是如此(例如,如果您的数据包含在一个工作人员中,它将不会更改)。因此,为了确保并拥有可扩展的解决方案,您需要在窗口函数中重新排序。
在这种情况下,请尝试以下操作:
val w = Window.partitionBy($"key").orderBy($"value")
df
.withColumn("row_number", row_number.over(w))
.where($"row_number" === 1)
.drop("row_number")
这仅选择第一行,并在row_number
上过滤,其中row_number
被定义为订购后该行的索引。此后将其删除,因为它变得无用了。
备注:您可以将 $
操作员替换为 col
操作员。这只是更简洁代码的快捷方式。
答案 1 :(得分:0)
import org.apache.spark.sql.functions.{max, _}
import spark.implicits._
val columnsDF = Seq(
("Harshit", 23, 43, 44, "A", "q", "z"),
("Mohit", 24, 56, 62, "B", "w", "x"),
("Harshit", 23, 32, 44, "C", "e", "c"),
("Kali", 10, 20, 460, "D", "r", "v"),
("Aman", 20, 30, 180, "E", "t", "b"),
("Ram", 30, 100, 270, "F", "yu", "n"),
("Kali", 10, 600, 360, "G", "io", "m"),
("Kali", 10, 600, 460, "k", "p", "o")
).toDF("ColA", "ColB", "ColC", "ColD", "ColE", "extraCol1", "extraCol2")
println("Before Aggregation")
columnsDF.show()
val cols = List("colA", "colB")
println("After Aggregation")
val aggSeqFunction = columnsDF.agg(max(columnsDF.columns(2)),
max(columnsDF.columns(3)),
first(columnsDF.columns(4)),
first(columnsDF.columns(6)),
first(columnsDF.columns(5)))
val aggFunction = aggSeqFunction.columns.map(en => expr(en))
columnsDF.groupBy(cols.head, cols.tail: _*).agg(aggFunction.head, aggFunction.tail: _*).show()
/*
+-------+----+---------+---------+------------------+-----------------------+-----------------------+
| colA|colB|max(ColC)|max(ColD)|first(ColE, false)|first(extraCol2, false)|first(extraCol1, false)|
+-------+----+---------+---------+------------------+-----------------------+-----------------------+
|Harshit| 23| 43| 44| A| z| q|
| Aman| 20| 30| 180| E| b| t|
| Kali| 10| 600| 460| D| v| r|
| Ram| 30| 100| 270| F| n| yu|
| Mohit| 24| 56| 62| B| x| w|
+-------+----+---------+---------+------------------+-----------------------+-----------------------+
*/
我能够得出预期的结果。
希望这会有所帮助。