无顺序保证的有条件的 LEAD/LAG
Posted
技术标签:
【中文标题】无顺序保证的有条件的 LEAD/LAG【英文标题】:Conditional LEAD/LAG with no sequence guarantee 【发布时间】:2020-05-27 01:33:01 【问题描述】:如果不能保证前面或后续的领先/滞后满足特定条件,如何编写有条件的领先/滞后?就我而言,我正在查看网站流量。
示例数据(prior_path 和prior_event 是目标字段,鉴于我的条件,我无法访问其prior_event)
+-----------+-----+-------+---------------------------------------+-------+------------------------------------+-------------+
| sessionid | hit | type | path | event | prior_path | prior_event |
+-----------+-----+-------+---------------------------------------+-------+------------------------------------+-------------+
| 1001 | 1 | event | www.***.com | hover | | |
| 1001 | 2 | page | www.***.com | | | hover |
| 1001 | 3 | event | www.***.com | load | | |
| 1001 | 4 | event | www.***.com | blur | | load |
| 1001 | 5 | event | www.***.com | click | | blur |
| 1001 | 6 | page | www.***.com/post/10 | | www.***.com | click |
| 1001 | 7 | event | www.***.com/post/10#details | offer | | |
| 1001 | 8 | page | www.***.com/post/confirm | | www.***.com/post/10 | offer |
| 1001 | 9 | page | www.***.com/questions/10 | | www.***.com/post/confirm | offer |
| 1001 | 10 | event | www.***.com/questions/10 | exit | | |
+-----------+-----+-------+---------------------------------------+-------+------------------------------------+-------------+
prior_path:最后一个路径,其中 type = page 仅适用于页面点击类型 prior_event:最后一个事件,其中 type = 所有命中类型的事件
注意点击 8 和 9,“offer”事件会重复,因为它们会导致这些页面。
prior_path 看起来很简单
SELECT LAG(path) OVER (PARTITION BY sessionid, type ORDER BY hit) FROM my_table
但我不确定如何获取prior_event。
【问题讨论】:
【参考方案1】:你已经有了prior_path
的正确表达方式。您只需要将其包装在条件表达式中即可。
至于prior_event
,确实有点复杂。我建议采用以下方法:
对于事件,我们可以使用lag()
对于页面,一种选择是使用一些间隙和岛屿技术:首先使用条件总和定义组,每次遇到事件时递增,然后使用first_value()
:
这应该做你想做的:
select
t.*,
case when type = 'page'
then lag(path) over(partition by sessionid, type order by hit)
end prior_path,
case type
when 'page'
then first_value(event) over(partition by sessionid, grp order by hit)
when 'event'
then lag(event) over(partition by sessionid order by hit)
end prior_event
from (
select
t.*,
sum(case when type = 'event' then 1 else 0 end)
over(partition by sessionid order by hit) grp
from mytable t
) t
Demo on DB Fiddle(由于野外缺少 hive fiddle,我使用了 Postgres - 但这也适用于 Hive):
会话ID |打|类型 |路径 |活动 | grp |先前路径 |先验事件 --------: | --: | :---- | :------------------------------------------------ | :---- | --: | :--------------------------------- | :---------- 1001 | 1 |活动 | www.***.com |悬停 | 1 | 空 | 空 1001 | 2 |页 | www.***.com | 空 | 1 | 空 |徘徊 1001 | 3 |活动 | www.***.com |加载 | 2 | 空 | 空 1001 | 4 |活动 | www.***.com |模糊 | 3 | 空 |加载 1001 | 5 |活动 | www.***.com |点击 | 4 | 空 |模糊 1001 | 6 |页 | www.***.com/post/10 | 空 | 4 | www.***.com |点击 1001 | 7 |活动 | www.***.com/post/10#details |报价 | 5 | 空 | 空 1001 | 8 |页 | www.***.com/post/confirm | 空 | 5 | www.***.com/post/10 |提供 1001 | 9 |页 | www.***.com/questions/10 | 空 | 5 | www.***.com/post/confirm |提供 1001 | 10 |活动 | www.***.com/questions/10 |退出 | 6 | 空 | 空【讨论】:
像魅力一样工作!感谢您对间隙和岛屿技术的解释和参考。这对我来说是一个新的,所以我很感激进一步研究的参考。 有没有办法让它工作以获取页面的领先事件?例如。类似于为 prev_event 获取命中 8 和 9 的“offer”,是否可以重新设计以获取命中 10 的“退出”事件作为命中 8 和 9 的 next_event?在外部选择中,我尝试了 LEAD 和 LAST_VALUE 的组合,但效果不佳。【参考方案2】:我认为你只需要lag()
和一些条件逻辑:
select . . .,
(case when type = 'page'
then lag(path) over (partition by sessionid, type order by hit)
end) as prior_path,
lag(event) over (partition by sessionid order by hit) as prior_event
from my_table;
【讨论】:
以上是关于无顺序保证的有条件的 LEAD/LAG的主要内容,如果未能解决你的问题,请参考以下文章
SQL windows 函数 LEAD/LAG 但只考虑某些值?