用 Spark 或 SQL 分析稀疏时间序列事件

Analysis of sparse time series events with Spark or SQL

我有一组用户状态更改事件,为简单起见,我们说激活 (A) 和停用 (D)。

场景类似于例如youtube 高级订阅,用户可能会多次激活或停用他们的订阅。因此,这两个事件对于同一用户可能发生多次,中间有多个时间点(例如几天、几个月)。

我想根据事件历史计算每个月处于 ACTIVATED 状态的用户数。

时间轴示例可以是

t: Time point (end of month) of aggregation
u: One user
A: ACTIVATED event
D: DEACTIVATED even

       t:   Jan Feb Mar Apr May
       u1   A               
       u2   A   D           A
       u3       A       D   A
Expected:   2   2   2   1   3    

数据本身在 CSV 中可用/table,其中列 用户 ID,事件类型时间戳 。对于上面的示例,原始数据为:

user-id event-type time-stamp
u1      A          2020-Jan-01
u2      A          2020-Jan-15
u2      D          2020-Feb-05
u2      A          2020-May-17
u3      A          2020-Feb-04
u3      D          2020-Apr-10
u3      A          2020-May-09

请注意,尽管我想在每个月末进行计数,但事件当然不会同时发生。一个用户也可以在同一个月内有多个事件。

绝对计数没有问题,“计算最后一个事件为 A 的所有用户”。

棘手的事情是针对没有变化事件的个别月份进行计算。例如。示例时间轴中的 Mar。

我不能按月分组,因为 3 月没有发生任何事件,但我需要注意,激活或停用发生在之前的时间点。

我可以想出两种方法:

这两种方法似乎都有些粗糙(尽管它们会起作用)。

有什么好的选择吗?也许我应该注意一些神奇的 Spark 函数?

很高兴在这里得到一些意见。我也不是 100% 确定要 google 做什么。我认为这个一般问题甚至可能有一个名称,因为如前所述,所有具有稀疏事件的开/关订阅服务都应该有相同的问题。

谢谢

您可以对数据进行逆透视、聚合和使用 window 函数:

with t as (
      select userid, 't1' as t,
             (case when t1 = 'A' then 1 else -1 end)
      from t
      where t1 in ('A', 'D')
      union all
      select userid, 't2' as t,
             (case when t2 = 'A' then 1 else -1 end)
      from t
      where t2 in ('A', 'D')
      union all
      . . .   -- need to repeat for all times
     )
select t, sum(inc) as change_at_time,
       sum(sum(inc)) over (order by t) as active_on_day
from t
group by t
order by t;

't1' 是该列表示的任何时间。它可能真的是一个数字(你的问题对数据的表示不清楚)。

如果您只包含包含 useridtime'A'/'D' 的行,而不是将值分布在许多列中,那么查询会更简单。