在 SQL/Spark 中使用窗口函数执行特定过滤器

Posted

技术标签:

【中文标题】在 SQL/Spark 中使用窗口函数执行特定过滤器【英文标题】:Performing Specific Filter Using Window Functions in SQL/Spark 【发布时间】:2021-05-30 00:23:04 【问题描述】:

我目前有一个大型数据集,但为简单起见,它看起来像这样:

Person, Friend, Friendship_Score, Days_Known
Alice, Bob, 120, 56
Alice, Candy, 20, 23
Bob, Daniel, 24, 77
Bob, Alice, 120, 56
Candy, Alice, 20, 23
Daniel, Bob, 24, 77
Daniel, Ed, 56, 65
Daniel, Fin, 52, 54
Daniel, Gin, 22, 50
...

我想在这个数据集上使用一个窗口函数让它看起来像这样:

Alice, Bob, 120, 56
Bob, Daniel, 24, 77
Bob, Alice, 120, 56
Candy, Alice, 20, 23
Daniel, Bob, 24, 77
Daniel, Ed, 56, 65
Daniel, Fin, 52, 54

过滤器背后的逻辑应该是,对于每个人,我们按照他们认识的时间长短排列他们的朋友(days_known 值越高在顶部),然后只保留足够多的朋友他们的friendship_score 为 100。

例如,Alice 只需要 Bob,因为她认识他的时间最长,并且他们的 friendship_score 超过 100。Bob 需要 Daniel 和 Alice,因为 Bob 认识 Daniel 的时间更长,但他们的 friendship_score 只有 24 . 但是,加了 Alice 之后,Bob 认识时间最长的下一个朋友,friendship_score 加起来在 100 以上。

我知道我们需要做某种窗口函数和滚动求和,但我在将这些想法放入代码时遇到了麻烦,想知道是否有人可以提供帮助。谢谢!

【问题讨论】:

【参考方案1】:

我对 Spark 没有太多经验,但文档表明它支持窗口函数和 Selects From Selects,您需要过滤窗口函数的结果。

请注意,使用 UNBOUNDED BELOW TO CURRENT ROW 窗口的运行总和会为您要保留的最后一条记录生成大于 100 的总和。你真的想要一个不包括当前行的部分总和来过滤和保留正确的记录。您可以使用 SUM 窗口函数执行此操作,然后从当前记录中减去分数。所以你的窗口函数应该读为 SUM(friendship_score) OVER (Partition By person Order By Days_Known desc ROWS UNBOUNDED BELOW TO CURRENT ROW) -friendship_score as prior_total_score

Select person, friend, friendship_score,days_known
From (
      Select *, SUM(friendship_score) OVER (Partition By person Order By Days_Known desc ROWS UNBOUNDED BELOW TO CURRENT ROW) - friendship_score as prior_total_score
      From MyTable
     )
Where prior_total_score < 100

您可以根据需要将 Order By 添加到外部 Select。

【讨论】:

以上是关于在 SQL/Spark 中使用窗口函数执行特定过滤器的主要内容,如果未能解决你的问题,请参考以下文章

sql查询语句并不是最先执行SELECT

SQL内容补充

如何使用窗口函数检查特定范围值是不是填充在 SQL 中?

在 SQL 查询中过滤掉由窗口函数 lag() 产生的空值

NX二次开发-通过获取窗口句柄方式来设置类型过滤器EnumChildWindows

pyspark 使用过滤器应用 DataFrame 窗口函数