PrestoSQL 将事件数据转换为每小时摘要
PrestoSQL transform event data into hourly summary
我有一个 table 包含事件和时间戳
ts
event
name
1650000000
everything is ok
process_a
1650003700
something is broken!
process_a
1650007100
everything is ok
process_a
1650010000
everything is ok
process_b
1650013100
something is broken!
process_b
1650017400
everything is ok
process_b
我想计算,对于每个进程,每小时有多少百分比的时间“一切正常”以及有多少百分比的时间“有问题!”。最终结果应该是这样的
hour
name
ok_perc
...
...
...
2022-04-22 7:00:00
process_a
.912
2022-04-22 8:00:00
process_a
.634
2022-04-22 9:00:00
process_a
1
2022-04-22 1:00:00
process_b
.354
2022-04-22 2:00:00
process_b
.533
2022-04-22 3:00:00
process_b
.987
...
...
...
我已经研究过各种子查询来帮助我达到我想要的目的。我意识到我将要遇到的第一个问题是我不会有所有的时间,只有状态发生变化的时间。所以我创建了:
select
timestamp_column
from
(values
(sequence(cast('2022-01-01' as timestamp), --don't bother that this doesn't match my pseudo timestamps in the events table
cast(now() as timestamp),
interval '1' hour
)
)
) as t(timestamp_array)
cross join
unnest(timestamp_array) as t1(timestamp_column)
上面给出了事件将要发生的所有小时间隔。
然后我在 date_trunc
和 from_unixtime(ts)
上加入了我的事件 table 的每小时时间戳,所以如果那个小时有一个事件,我有其他值空值。请注意,一个小时内可以有多个事件。
出于某种原因,我认为将最后一个事件保留到下一个小时(如果下一个小时的事件为空)是个好主意
coalesce
(
event,
lag(event) ignore nulls over
(
partition by name
order by timestamp_column
)
)
而且我还认为可以帮助我解决这个问题的其他方法是计算每个事件的持续时间,以这种方式(用前一个事件时间戳减去当前事件时间戳):
lead(ts) over
(
partition by
name
order by ts
) - ts as seconds_in_state
出于某种原因,我认为我会知道在给定的一小时内,我处于一种状态有多少秒,我处于另一种状态有多少秒。但是我的seconds_in_state
有时会超过一个小时,这说明我的方向不对。
总的来说,这似乎是一个很常见的问题:如何按特定时间间隔总结事件 table,每个事件是否都有一个事物的隐式状态 name
?
不知何故,我被困在了这个问题上,我固执地在 Presto SQL 中修复它,而不是下载事件数据并在 Python 中进行一些操作 - 这绝对是可能的!
这是一种可能的方法 - 按名称为分区生成当前时间戳和下一个时间戳之间的每小时间隔,然后使用 unnest
展平生成的数组并使用 group by
名称和小时来执行所需的计算:
-- sample data
WITH dataset (ts, event, name) AS (
VALUES (1650000000, 'everything is ok', 'process_a'),
(1650003700, 'something is broken!', 'process_a'),
(1650007100, 'everything is ok', 'process_a'),
(1650010000, 'everything is ok', 'process_b'),
(1650013100, 'something is broken!', 'process_b'),
(1650017400, 'everything is ok','process_b')
)
-- query
select name,
ts_hour_exp hour,
count_if(is_ok) * 1.0 / count(*) ok_perc
from (
select date_trunc('hour', from_unixtime(ts)) ts_hour,
if(event = 'everything is ok', true, false) is_ok, -- reduced strings to boolean flag
lead(date_trunc('hour', from_unixtime(ts))) over(
partition by name
order by ts
) next_ts,
name
from dataset
)
cross join unnest ( -- some magic for interval generation
coalesce(
array_except(
sequence(ts_hour, next_ts, interval '1' hour),
array [ ts_hour, next_ts ] -- exclude borders
),
array [ ] -- in case of null
) || ts_hour -- attach current hour
) as t(ts_hour_exp)
group by name, ts_hour_exp
order by name, ts_hour_exp
输出:
name
hour
ok_perc
process_a
2022-04-15 05:00:00.000
1.0
process_a
2022-04-15 06:00:00.000
0.0
process_a
2022-04-15 07:00:00.000
1.0
process_b
2022-04-15 08:00:00.000
0.5
process_b
2022-04-15 09:00:00.000
0.0
process_b
2022-04-15 10:00:00.000
1.0
我有一个 table 包含事件和时间戳
ts | event | name |
---|---|---|
1650000000 | everything is ok | process_a |
1650003700 | something is broken! | process_a |
1650007100 | everything is ok | process_a |
1650010000 | everything is ok | process_b |
1650013100 | something is broken! | process_b |
1650017400 | everything is ok | process_b |
我想计算,对于每个进程,每小时有多少百分比的时间“一切正常”以及有多少百分比的时间“有问题!”。最终结果应该是这样的
hour | name | ok_perc |
---|---|---|
... | ... | ... |
2022-04-22 7:00:00 | process_a | .912 |
2022-04-22 8:00:00 | process_a | .634 |
2022-04-22 9:00:00 | process_a | 1 |
2022-04-22 1:00:00 | process_b | .354 |
2022-04-22 2:00:00 | process_b | .533 |
2022-04-22 3:00:00 | process_b | .987 |
... | ... | ... |
我已经研究过各种子查询来帮助我达到我想要的目的。我意识到我将要遇到的第一个问题是我不会有所有的时间,只有状态发生变化的时间。所以我创建了:
select
timestamp_column
from
(values
(sequence(cast('2022-01-01' as timestamp), --don't bother that this doesn't match my pseudo timestamps in the events table
cast(now() as timestamp),
interval '1' hour
)
)
) as t(timestamp_array)
cross join
unnest(timestamp_array) as t1(timestamp_column)
上面给出了事件将要发生的所有小时间隔。
然后我在 date_trunc
和 from_unixtime(ts)
上加入了我的事件 table 的每小时时间戳,所以如果那个小时有一个事件,我有其他值空值。请注意,一个小时内可以有多个事件。
出于某种原因,我认为将最后一个事件保留到下一个小时(如果下一个小时的事件为空)是个好主意
coalesce
(
event,
lag(event) ignore nulls over
(
partition by name
order by timestamp_column
)
)
而且我还认为可以帮助我解决这个问题的其他方法是计算每个事件的持续时间,以这种方式(用前一个事件时间戳减去当前事件时间戳):
lead(ts) over
(
partition by
name
order by ts
) - ts as seconds_in_state
出于某种原因,我认为我会知道在给定的一小时内,我处于一种状态有多少秒,我处于另一种状态有多少秒。但是我的seconds_in_state
有时会超过一个小时,这说明我的方向不对。
总的来说,这似乎是一个很常见的问题:如何按特定时间间隔总结事件 table,每个事件是否都有一个事物的隐式状态 name
?
不知何故,我被困在了这个问题上,我固执地在 Presto SQL 中修复它,而不是下载事件数据并在 Python 中进行一些操作 - 这绝对是可能的!
这是一种可能的方法 - 按名称为分区生成当前时间戳和下一个时间戳之间的每小时间隔,然后使用 unnest
展平生成的数组并使用 group by
名称和小时来执行所需的计算:
-- sample data
WITH dataset (ts, event, name) AS (
VALUES (1650000000, 'everything is ok', 'process_a'),
(1650003700, 'something is broken!', 'process_a'),
(1650007100, 'everything is ok', 'process_a'),
(1650010000, 'everything is ok', 'process_b'),
(1650013100, 'something is broken!', 'process_b'),
(1650017400, 'everything is ok','process_b')
)
-- query
select name,
ts_hour_exp hour,
count_if(is_ok) * 1.0 / count(*) ok_perc
from (
select date_trunc('hour', from_unixtime(ts)) ts_hour,
if(event = 'everything is ok', true, false) is_ok, -- reduced strings to boolean flag
lead(date_trunc('hour', from_unixtime(ts))) over(
partition by name
order by ts
) next_ts,
name
from dataset
)
cross join unnest ( -- some magic for interval generation
coalesce(
array_except(
sequence(ts_hour, next_ts, interval '1' hour),
array [ ts_hour, next_ts ] -- exclude borders
),
array [ ] -- in case of null
) || ts_hour -- attach current hour
) as t(ts_hour_exp)
group by name, ts_hour_exp
order by name, ts_hour_exp
输出:
name | hour | ok_perc |
---|---|---|
process_a | 2022-04-15 05:00:00.000 | 1.0 |
process_a | 2022-04-15 06:00:00.000 | 0.0 |
process_a | 2022-04-15 07:00:00.000 | 1.0 |
process_b | 2022-04-15 08:00:00.000 | 0.5 |
process_b | 2022-04-15 09:00:00.000 | 0.0 |
process_b | 2022-04-15 10:00:00.000 | 1.0 |