无顺序保证的有条件的 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的主要内容,如果未能解决你的问题,请参考以下文章

通过 LEAD/LAG 或递归 CTE 更新?

具有 LEAD/LAG 功能的行到列

SQL windows 函数 LEAD/LAG 但只考虑某些值?

Kafka的重复、丢数据及顺序消费等问题

MySql用IN查询时(或类似IN),如何保证按输入的顺序显示

Go如何保证并发读写的顺序?—内存模型