用 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 月没有发生任何事件,但我需要注意,激活或停用发生在之前的时间点。
我可以想出两种方法:
在某个循环中对每个时间点进行递增分区window计算。因此,“对于 1 月到 5 月的 tCursor 做:计算范围 'Jan - tCursor' 中最后一个事件被激活的所有用户”。
用感兴趣的时间粒度的冗余事件填充历史记录,并为每个用户使用一些预处理循环。那么我就可以避免迭代增加的时间window.
这两种方法似乎都有些粗糙(尽管它们会起作用)。
有什么好的选择吗?也许我应该注意一些神奇的 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'
是该列表示的任何时间。它可能真的是一个数字(你的问题对数据的表示不清楚)。
如果您只包含包含 userid
、time
和 'A'
/'D'
的行,而不是将值分布在许多列中,那么查询会更简单。
我有一组用户状态更改事件,为简单起见,我们说激活 (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 月没有发生任何事件,但我需要注意,激活或停用发生在之前的时间点。
我可以想出两种方法:
在某个循环中对每个时间点进行递增分区window计算。因此,“对于 1 月到 5 月的 tCursor 做:计算范围 'Jan - tCursor' 中最后一个事件被激活的所有用户”。
用感兴趣的时间粒度的冗余事件填充历史记录,并为每个用户使用一些预处理循环。那么我就可以避免迭代增加的时间window.
这两种方法似乎都有些粗糙(尽管它们会起作用)。
有什么好的选择吗?也许我应该注意一些神奇的 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'
是该列表示的任何时间。它可能真的是一个数字(你的问题对数据的表示不清楚)。
如果您只包含包含 userid
、time
和 'A'
/'D'
的行,而不是将值分布在许多列中,那么查询会更简单。