我有一个数据框,其中我有子类别,并且想要每个子类别的最后一个元素。
val windowSpec = Window.partitionBy("name").orderBy("count")
sqlContext
.createDataFrame(
Seq[(String, Int)](
("A", 1),
("A", 2),
("A", 3),
("B", 10),
("B", 20),
("B", 30)
))
.toDF("name", "count")
.withColumn("firstCountOfName", first("count").over(windowSpec))
.withColumn("lastCountOfName", last("count").over(windowSpec))
.show()
给我一些奇怪的信息:
+----+-----+----------------+---------------+
|name|count|firstCountOfName|lastCountOfName|
+----+-----+----------------+---------------+
| B| 10| 10| 10|
| B| 20| 10| 20|
| B| 30| 10| 30|
| A| 1| 1| 1|
| A| 2| 1| 2|
| A| 3| 1| 3|
+----+-----+----------------+---------------+
正如我们所看到的,返回的first
值已正确计算,但last
不是,它始终是列的当前值。
有人有解决方案可以做我想要的吗?
答案 0 :(得分:5)
根据问题SPARK-20969,您应该能够通过定义窗口的足够边界来获得预期结果,如下所示。
import org.apache.spark.sql.expressions.Window
import org.apache.spark.sql.functions._
val windowSpec = Window
.partitionBy("name")
.orderBy("count")
.rowsBetween(Window.unboundedPreceding, Window.unboundedFollowing)
sqlContext
.createDataFrame(
Seq[(String, Int)](
("A", 1),
("A", 2),
("A", 3),
("B", 10),
("B", 20),
("B", 30)
))
.toDF("name", "count")
.withColumn("firstCountOfName", first("count").over(windowSpec))
.withColumn("lastCountOfName", last("count").over(windowSpec))
.show()
或者,如果您要在同一列上进行排序,那么您可以使用非有序窗口更改min
和max
,然后它也可以正常运行。< / p>
答案 1 :(得分:0)
另一种方法是使用groupby ad join计算第一个和最后一个值
val data = spark
.createDataFrame(
Seq[(String, Int)](
("A", 1),
("A", 2),
("A", 3),
("B", 10),
("B", 20),
("B", 30)
))
.toDF("name", "count")
val firstLast = data.groupBy("name").agg(first("count").as("firstCountOfName"), last("count").as("lastCountOfName"))
val result = data.join(firstLast, Seq("name"), "left")
result.show()
输出:
+----+-----+----------------+---------------+
|name|count|firstCountOfName|lastCountOfName|
+----+-----+----------------+---------------+
| A| 1| 1| 3|
| A| 2| 1| 3|
| A| 3| 1| 3|
| B| 10| 10| 30|
| B| 20| 10| 30|
| B| 30| 10| 30|
+----+-----+----------------+---------------+
希望这有帮助