首页 > 解决方案 > Spark Window 函数:是否可以直接从使用第一个/最后一个函数找到的行中获取其他值?

问题描述

在 Spark 中,可以在窗口中的列当前出现之后获取第一个非空值:

val window = Window
  .orderBy("id")

val df = Seq(
  (0, "Bob", Some(123)),
  (1, "Jack", None),
  (2, "Brian", None),
  (3, "John", Some(456)),
  (4, "Edgar", None)
).toDF("id", "name", "value")

df
  .withColumn("firstNonNullValueAfterRow", first("value", true)
    .over(window.rowsBetween(Window.currentRow, Window.unboundedFollowing)))
  .show()

输出:

+---+-----+-----+-------------------------+
| id| name|value|firstNonNullValueAfterRow|
+---+-----+-----+-------------------------+
|  0|  Bob|  123|                      123|
|  1| Jack| null|                      456|
|  2|Brian| null|                      456|
|  3| John|  456|                      456|
|  4|Edgar| null|                     null|
+---+-----+-----+-------------------------+

问题:是否可以从我们使用 .first(...) 获得的行中获取另一个值? 我想获取映射到该记录后第一个非空值的人的姓名:

+---+-----+-----+-------------------------+-------------------------+
| id| name|value|firstNonNullValueAfterRow|nameOfThatPerson         |
+---+-----+-----+-------------------------+-------------------------+
|  0|  Bob|  123|                      123|                      Bob|
|  1| Jack| null|                      456|                     John|
|  2|Brian| null|                      456|                     John|
|  3| John|  456|                      456|                     John|
|  4|Edgar| null|                     null|                     null|
+---+-----+-----+-------------------------+-------------------------+

这可以通过一些技巧来实现,但我想知道是否有办法使用 Spark 窗口函数来做到这一点。解决方法:

val idAndNameDF = df
  .select("id", "name")
  .withColumnRenamed("id", "id2")
  .withColumnRenamed("name", "nameOfThatPerson")

df
  .withColumn("idOfFirstNotNullValue", when(col("value").isNotNull, col("id")))
  .withColumn("firstNonNullIdAfterRow", first("idOfFirstNotNullValue", true)
    .over(window.rowsBetween(Window.currentRow, Window.unboundedFollowing)))
  .join(idAndNameDF, col("firstNonNullIdAfterRow") === col("id2"),"left")
  .show()

解决方法结果:

+---+-----+-----+---------------------+----------------------+----+----------------+
| id| name|value|idOfFirstNotNullValue|firstNonNullIdAfterRow| id2|nameOfThatPerson|
+---+-----+-----+---------------------+----------------------+----+----------------+
|  0|  Bob|  123|                    0|                     0|   0|             Bob|
|  1| Jack| null|                 null|                     3|   3|            John|
|  2|Brian| null|                 null|                     3|   3|            John|
|  3| John|  456|                    3|                     3|   3|            John|
|  4|Edgar| null|                 null|                  null|null|            null|
+---+-----+-----+---------------------+----------------------+----+----------------+

标签: scalaapache-sparkwindow-functions

解决方案


是和否。不,不是,如果你的意思是它应该是同一个窗口条款或整体条款的一部分。是的,如果你做一些额外的事情。

也就是说,您的解决方法是正确的。

它们是两个不同的方面:

  • 查找第一个“未来”非空事件
  • 然后找到该事件的相关数据。

这有点道理。您应该将其视为子查询情况。


推荐阅读