【问题标题】:In Spark scala, how to check between adjacent rows in a dataframe在 Spark scala 中,如何检查数据帧中的相邻行之间
【发布时间】:2019-03-23 10:51:57
【问题描述】:

如何检查 Dataframe 中相邻行(前一行和后一行)的日期。这应该发生在关键级别

在按关键日期排序后,我有以下数据

source_Df.show()
+-----+--------+------------+------------+
| key | code   | begin_dt   | end_dt     |
+-----+--------+------------+------------+
| 10  |  ABC   | 2018-01-01 | 2018-01-08 |
| 10  |  BAC   | 2018-01-03 | 2018-01-15 |
| 10  |  CAS   | 2018-01-03 | 2018-01-21 |
| 20  |  AAA   | 2017-11-12 | 2018-01-03 |
| 20  |  DAS   | 2018-01-01 | 2018-01-12 |
| 20  |  EDS   | 2018-02-01 | 2018-02-16 |
+-----+--------+------------+------------+

当日期在这些行的范围内时(即当前行 begin_dt 位于前一行的开始日期和结束日期之间),我需要在所有此类行中设置最低开始日期和最高结束日期日期。 这是我需要的输出..

final_Df.show()
+-----+--------+------------+------------+
| key | code   | begin_dt   | end_dt     |
+-----+--------+------------+------------+
| 10  |  ABC   | 2018-01-01 | 2018-01-21 |
| 10  |  BAC   | 2018-01-01 | 2018-01-21 |
| 10  |  CAS   | 2018-01-01 | 2018-01-21 |
| 20  |  AAA   | 2017-11-12 | 2018-01-12 |
| 20  |  DAS   | 2017-11-12 | 2018-01-12 |
| 20  |  EDS   | 2018-02-01 | 2018-02-16 |
+-----+--------+------------+------------+

欣赏任何实现这一目标的想法。提前致谢!

【问题讨论】:

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


【解决方案1】:

这是一种方法:

  1. 如果begin_dt 在上一行的日期范围内,则使用null 值创建新列group_id;否则为唯一整数
  2. last 非空值在group_id 中回填nulls
  3. 在每个 (key, group_id) 分区内计算 min(begin_dt)max(end_dt)

下面的例子:

import org.apache.spark.sql.functions._
import org.apache.spark.sql.expressions.Window

val df = Seq(
  (10, "ABC", "2018-01-01", "2018-01-08"),
  (10, "BAC", "2018-01-03", "2018-01-15"),
  (10, "CAS", "2018-01-03", "2018-01-21"),
  (20, "AAA", "2017-11-12", "2018-01-03"),
  (20, "DAS", "2018-01-01", "2018-01-12"),
  (20, "EDS", "2018-02-01", "2018-02-16")
).toDF("key", "code", "begin_dt", "end_dt")

val win1 = Window.partitionBy($"key").orderBy($"begin_dt", $"end_dt")
val win2 = Window.partitionBy($"key", $"group_id")

df.
  withColumn("group_id", when(
      $"begin_dt".between(lag($"begin_dt", 1).over(win1), lag($"end_dt", 1).over(win1)), null
    ).otherwise(monotonically_increasing_id)
  ).
  withColumn("group_id", last($"group_id", ignoreNulls=true).
      over(win1.rowsBetween(Window.unboundedPreceding, 0))
  ).
  withColumn("begin_dt2", min($"begin_dt").over(win2)).
  withColumn("end_dt2", max($"end_dt").over(win2)).
  orderBy("key", "begin_dt", "end_dt").
  show
// +---+----+----------+----------+-------------+----------+----------+
// |key|code|  begin_dt|    end_dt|     group_id| begin_dt2|   end_dt2|
// +---+----+----------+----------+-------------+----------+----------+
// | 10| ABC|2018-01-01|2018-01-08|1047972020224|2018-01-01|2018-01-21|
// | 10| BAC|2018-01-03|2018-01-15|1047972020224|2018-01-01|2018-01-21|
// | 10| CAS|2018-01-03|2018-01-21|1047972020224|2018-01-01|2018-01-21|
// | 20| AAA|2017-11-12|2018-01-03| 455266533376|2017-11-12|2018-01-12|
// | 20| DAS|2018-01-01|2018-01-12| 455266533376|2017-11-12|2018-01-12|
// | 20| EDS|2018-02-01|2018-02-16| 455266533377|2018-02-01|2018-02-16|
// +---+----+----------+----------+-------------+----------+----------+

【讨论】:

  • 谢谢利奥。你是最棒的!
  • 我想要一个像 group_id 这样的列。但是,它应该从一个特定的数字开始并增加 1。任何建议请..
  • @Lux,不幸的是,monotonically_increasing_id 只保证生成唯一递增的数字。要对生成的数字进行更多控制,您必须考虑使用不带分区的 Window 函数(无法缩放)或将其 zipWithIndex 方法转换为 RDD,如 SO link 所示。
猜你喜欢
  • 1970-01-01
  • 2021-10-14
  • 1970-01-01
  • 2017-08-11
  • 1970-01-01
  • 2020-09-24
  • 1970-01-01
  • 2019-01-03
  • 2023-04-07
相关资源
最近更新 更多