Hive SQL,在滑动 10 分钟窗口中找到最大计数

Posted

技术标签:

【中文标题】Hive SQL,在滑动 10 分钟窗口中找到最大计数【英文标题】:Hive SQL, find max count in sliding 10 minute window 【发布时间】:2018-01-09 21:11:31 【问题描述】:

我有一个大致(超级简化)的表格

ts    | session | other_stuff
------------------------------
100   | A       | ...
101   | B       | ...
101   | A       | ...
102   | C       | ...
103   | A       | ...
104   | C       | ...
104   | A       | ...
9999  | D       | ...
20000 | D       | ...

ts 是存储为双精度的时间戳。我想在任何 10 分钟窗口中找到最大活动会话数。因此,在上面的示例中,答案将是 3,因为 ABC 在 10 分钟内都处于活动状态。什么是正确的查询,我已经尝试了几件事,但遇到了错误,所以我肯定没有以正确的方式思考这个问题。

我尝试过

SELECT  *,
        (
        SELECT  COUNT(DISTINCT session)
        FROM    mytable mi
        WHERE   mi.ts BETWEEN m.ts - 300 AND m.ts + 300
        ) AS maxconcurrent
FROM    mytable m
ORDER BY
    maxconcurrent DESC

但收到错误

Presto query has failed. Unexpected node: com.facebook.presto.sql.planner.plan.LateralJoinNode

编辑:这是一个表格,其中窗口的滑动特性很重要

ts    | session | other_stuff
------------------------------
100   | A       | ...
201   | B       | ...
301   | A       | ...
702   | C       | ...
1503  | A       | ...
2504  | C       | ...
3696  | A       | ...
9999  | D       | ...
20000 | D       | ...

最大值仍然是 3,但现在它来自覆盖 201 到 801 的窗口

【问题讨论】:

如果您尝试过..请包括您的尝试。 在 ts 列中,什么是 10 分钟窗口? @VK_217 它的时间戳以秒为单位,因此正负 300 秒是一个 600 秒(10 分钟)的窗口 在您的第二组数据示例中,计数不能为 3。它是 2。只有 A 和 B @Bala B @ 201 + A @ 301 + C @ 702 = 3 在 600 秒内。 【参考方案1】:

非常有趣的问题。这是我的处理方法

select * from sliding

+-------------+----------------+--+
| sliding.ts  | sliding.users  |
+-------------+----------------+--+
| 100         |  A             |
| 101         |  B             |
| 101         |  A             |
| 102         |  C             |
| 103         |  A             |
| 104         |  C             |
| 104         |  A             |
| 9999        |  D             |
| 20000       |  D             |
+-------------+----------------+--+

我们现在需要计算当前行的ts 与前一行(lag) 或下一行(lead)ts 之间的差异。 lag(ts,1,0) 很方便,它提供了前一行的ts。但是有一个问题,如果当前行是第一行会发生什么?没问题,使用lag(ts,1,0)0这里是没有前行时返回的默认值。

现在我们需要做的就是从当前行的ts 中减去lag 返回的值并应用条件(您的时间窗口)。即检查当前ts - lag_ts是否在600以内。

如果前一行的ts 比当前行的ts 高得多,有人可能会认为这会失败?但它不会,因为over 子句有order by ts

select users, ts, lag, lead  from (
    select users, ts, 
         lag(ts,1,0) over (order by ts) as lag, 
         lead(ts,1) over( order by ts) as lead
    from sliding ) tbl
where (ts - lag) <= 600

+--------+------+------+-------+--+
| users  |  ts  | lag  | lead  |
+--------+------+------+-------+--+
|  A     | 100  | 0    | 101   |
|  A     | 101  | 100  | 101   |
|  B     | 101  | 101  | 102   |
|  C     | 102  | 101  | 103   |
|  A     | 103  | 102  | 104   |
|  A     | 104  | 103  | 104   |
|  C     | 104  | 104  | 9999  |
+--------+------+------+-------+--+

应用不同的计数得到

select count(distinct users)  from (
    select users, ts, 
         lag(ts,1,0) over (order by ts) as lag, 
         lead(ts,1) over( order by ts) as lead
    from sliding ) tbl
where (ts - lag) <= 600 


+------+--+
| _c0  |
+------+--+
| 3    |
+------+--+

【讨论】:

这当然更接近答案,但我相信这意味着窗口是固定的 3 行宽对吧? 我不确定我是否理解了您的问题。请您详细说明一下? 如果我猜到了,您想知道窗口是否是固定编号。 3 行。答案是否定的。这取决于time 窗口和满足窗口条件的行数(就像正常的 where 子句一样)。尝试增加/减少300,添加更多具有不同ts 的行。 您可能知道,如果需要,它可以限制为 3 行。 可能我看不懂laglead(很有可能)让我试一试。【参考方案2】:

如果 hive 允许窗口具有动态边界宽度,我不是用户,据我所知,它只支持固定窗口宽度

但是看看这是否适合你。使用floor 舍入最接近的第 10 分钟时间戳并进行分析。

select  ts, session , count(distinct session) over (partition by floor((ts+599)/600) * 600) from your_table;

您的结果将如下所示:

ts    | session | cnt
------------------------------
100   | A       | 2
201   | B       | 2
301   | A       | 2
702   | C       | 1

floor((ts+599)/600) * 600) - 这使得时间戳为 0 - 600 的会话将落入一个存储桶,601-1200 进入另一个存储桶,依此类推。

根据您使用的配置单元版本不同部分可能/可能不适用于count(distinct session) over (..)

【讨论】:

以上是关于Hive SQL,在滑动 10 分钟窗口中找到最大计数的主要内容,如果未能解决你的问题,请参考以下文章

滑动窗口

SQL/BigQuery 中具有固定持续时间的滑动窗口

Hive 窗口与分析型函数

[PHP] 基于redis实现滑动窗口式的短信发送接口限流

如何找到[L,R]之间大小的最大和子数组

O(n) 时间内的滑动窗口最大值