当前位置: 首页 > 知识库问答 >
问题:

火花窗口函数:筛选出在其他行的开始和结束日期范围内的开始和结束日期的行

鲍建业
2023-03-14

我有一个类似于以下内容的DataFrame(sqlDF)(在本例中进行了简化),其中我试图删除在另一行的开始日期和结束日期范围内具有start_date和end_date的所有行:

+-------+-------------+-------------------+-------------------+
|    id |         type|         start_date|           end_date|
+-------+-------------+-------------------+-------------------+
|  1    |      unknown|2018-11-14 16:03:47|2018-12-06 21:23:22| (remove as it's within the next rows start and end dates)
|  1    |          ios|2018-10-13 14:58:22|2019-08-26 15:50:45|
|  1    |      android|2019-08-29 02:41:40|2019-09-05 23:03:20|
|  2    |          ios|2017-12-19 02:25:34|2019-08-09 15:41:30|
|  2    |      windows|2018-07-10 05:30:52|2018-07-13 10:11:34| (remove as it's within the previous row's start and end dates)
|  2    |      android|2019-05-14 18:33:15|2019-08-27 06:10:53| (remove as it's within another row's start and end dates)

首先,最终用户要求我删除start_date和end_date之间间隔小于5天的所有记录,我使用了以下方法

val dfWithoutTempHandsets = sqlDF.filter(datediff(col("end_date"), col("start_date")) > 5)

从而产生如下所示的数据frame:

+-------+-------------+-------------------+-------------------+
|    id |         type|         start_date|           end_date|
+-------+-------------+-------------------+-------------------+
|  1    |      unknown|2018-11-14 16:03:47|2018-12-06 21:23:22| 
|  1    |          ios|2018-10-13 14:58:22|2019-08-26 15:50:45|
|  1    |      android|2019-08-29 02:41:40|2019-09-05 23:03:20|
|  2    |          ios|2017-12-19 02:25:34|2019-08-09 15:41:30|
|  2    |      android|2019-05-14 18:33:15|2019-06-27 06:10:53|

现在,我需要筛选出开始日期和结束日期在同一id的另一行开始日期和结束日期“内”的行,这样得到的DataFrame看起来如下所示:

+-------+-------------+-------------------+-------------------+
|    id |         type|         start_date|           end_date|
+-------+-------------+-------------------+-------------------+
|  1    |          ios|2018-10-13 14:58:22|2019-08-26 15:50:45|
|  1    |      android|2019-08-29 02:41:40|2019-09-05 23:03:20|
|  2    |          ios|2017-12-19 02:25:34|2019-08-09 15:41:30|

在阅读了几篇关于spark窗口函数的博客文章和堆栈溢出文章后,我知道这就是答案。但是我很难找到类似用例的例子,其中多个日期以这种方式与另一行的日期进行比较。我相信我有一个关闭的windowSpec:

val windowSpec = Window.partitionBy("id", "type").orderBy("start_date")

但是,从那里我不确定如何利用windowSpec只选择那些在其他行中没有开始日期和结束日期的行。

编辑:我得到了一个新的要求,只对具有“null”或“unknown”类型的行应用上述逻辑。但这里的答案让我离得更近了!

共有1个答案

秦博达
2023-03-14

下面是我考虑使用的逻辑:

在按IDstart_date升序排列的窗口分区下,如果当前行中的end_date早于或等于前面任何行中的end_date,则当前行中的日期范围必须包含在前面行中的某个日期范围内。

将其转换为示例代码(还包括>5天筛选):

import java.sql.Timestamp
import org.apache.spark.sql.expressions.Window
import org.apache.spark.sql.functions._
import spark.implicits._

val df = Seq(
  (1, "unknown", Timestamp.valueOf("2018-11-14 16:03:47"), Timestamp.valueOf("2018-12-06 21:23:22")),
  (1, "ios", Timestamp.valueOf("2018-10-13 14:58:22"), Timestamp.valueOf("2019-08-26 15:50:45")),
  (1, "android", Timestamp.valueOf("2019-08-29 02:41:40"), Timestamp.valueOf("2019-09-05 23:03:20")),
  (2, "ios", Timestamp.valueOf("2017-12-19 02:25:34"), Timestamp.valueOf("2019-08-09 15:41:30")),
  (2, "unknown", Timestamp.valueOf("2018-07-10 05:30:52"), Timestamp.valueOf("2018-07-13 10:11:34")),
  (2, "android", Timestamp.valueOf("2019-05-14 18:33:15"), Timestamp.valueOf("2019-06-27 06:10:53"))
).toDF("id", "type", "start_date", "end_date")

val win = Window.partitionBy("id").orderBy($"start_date").
  rowsBetween(Window.unboundedPreceding, -1)

df.
  where(unix_timestamp($"end_date") - unix_timestamp($"start_date") > 5*24*3600).
  withColumn("isContained",
    when($"end_date" <= max($"end_date").over(win), true).otherwise(false)
  ).
  where(! $"isContained").
  show
// +---+-------+-------------------+-------------------+-----------+
// | id|   type|         start_date|           end_date|isContained|
// +---+-------+-------------------+-------------------+-----------+
// |  1|    ios|2018-10-13 14:58:22|2019-08-26 15:50:45|      false|
// |  1|android|2019-08-29 02:41:40|2019-09-05 23:03:20|      false|
// |  2|    ios|2017-12-19 02:25:34|2019-08-09 15:41:30|      false|
// +---+-------+-------------------+-------------------+-----------+

请注意,对于>5天筛选,我使用的是UNIX_TIMESTAMP而不是datediff,后者仅机械地比较day值的差异(例如datediff(2019-01-06 12:00:002019-01-01 00:00:00)>5为false)。

 类似资料:
  • 问题内容: 我想检查日期是否在开始日期和结束日期之间。 我添加了一个where子句 但问题在于它不包含“ 2010-04-15”。 它应该包括结束日期,我该怎么办? 请帮我 问候, 潘卡 问题答案: 明确指定时间部分:

  • 问题内容: 我一直在尝试从时间戳字段中的第一个日期到最后一个日期生成一系列日期(YYYY-MM-DD HH)。我已经有了所需的内容,但是在尝试从表中获取开始日期和结束日期时遇到了一个问题。我有以下一个大概的想法: Postgres 9.3 问题答案: 您不需要CTE,这将比必要的成本更高。 而且您不需要强制转换为,当您向类型提供数据时,结果已经 是 数据类型。详细信息在这里: 在PostgreSQ

  • 问题内容: 我在从表中显示正确的数据时遇到了麻烦。我不太确定要搜索什么。我不确定min(column)或max(column)在这里对我有帮助。让我们看看我是否可以解释我的问题。 我的表包含以下数据: 我将以一种观点来介绍这一点。它将按代码分组。 我想要的是此输出: 如您所见,DateTo和DateFrom之间是否存在间隙,我希望将其显示为两行。但是,如果具有相同代码的下一个“ DateFrom”

  • 问题内容: 我需要Java中本月的开始日期和结束日期。当JSP页面加载了当前月份时,它将自动计算该月份的开始和结束日期。它应该与年份和月份无关。也就是说某个月有31天或30天或28天。这也应该满足a年。你能帮我吗? 例如,如果我在列表框中选择“五月”,则需要开始日期为1,结束日期为31。 问题答案: 你去了: PS:类只是两个值的一对。

  • 问题内容: 我有一个事件表,其中记录了一个开始和结束时间,作为MySQL DATETIME对象(格式。我想查找在特定日期范围内发生的所有事件。但是,事件可能跨越多天(并且超出了我的范围)日期范围,但是如果它们与我的日期范围重叠1秒或更长时间,我想返回它们。 有什么建议吗? 问题答案: 这将找到范围内完全包含的每个事件: 这将查找事件的任何部分与范围的任何部分重叠的任何事件:

  • 问题内容: 好吧,假设我有一个看起来像这样的表: 任何人都有关于如何查询它的想法,因此数据看起来像 问题答案: 我不会将ID放在这里,因为我认为它与查询无关。如果您愿意,请稍后再说。这是一个MSSQL查询。 可以很容易地将其翻译为其他数据库类型。