从事件中提取会话
Posted
技术标签:
【中文标题】从事件中提取会话【英文标题】:Extract sessions from events 【发布时间】:2018-12-21 10:16:25 【问题描述】:在 Clickhouse 中,我有一个表格,其中列出了带有用户 ID 和标签的事件。 我的目标是从这些数据中提取会话。
会话是一组时间相近的事件。例如,如果一个事件在前一个事件之后半小时以上,它就在另一个会话中。但是,如果每 1500 万个事件发生一次,则会话可能长达 12 小时。
我查看了 timeslot 函数的文档,其中描述了一个与我类似的用例,但我不知道如何编写查询。 (https://clickhouse.yandex/docs/en/query_language/functions/date_time_functions/#timeslot)
例如:
事件:
date | user | tag
2018-12-21 00:00:00 │ user1 │ tag1
2018-12-21 00:00:00 │ user2 │ tag1
2018-12-21 00:15:00 │ user1 │ tag1
2018-12-21 00:15:00 │ user2 │ tag2
2018-12-21 00:30:00 │ user1 │ tag1
2018-12-21 00:45:00 │ user1 │ tag1
2018-12-21 01:45:00 │ user1 │ tag1
产生的会话:
date | date_end | user | tag | count
2018-12-21 00:00:00 | 2018-12-21 00:45:00 | user1 | tag1 | 4
2018-12-21 00:00:00 | 2018-12-21 00:00:00 | user2 | tag1 | 1
2018-12-21 00:15:00 | 2018-12-21 00:15:00 | user2 | tag2 | 1
2018-12-21 01:45:00 | 2018-12-21 01:45:00 | user1 | tag1 | 1
【问题讨论】:
【参考方案1】:此查询依赖于默认的 timeSlot-函数将日期四舍五入到半小时:
SELECT user, tag, eventCount, length(sessionStartDateArray) sessionCount, sessionStartDateArray
FROM
(
SELECT
user,
tag,
-- a count of events with rounded date (remove DISTINCT-clause from nested query to get a real count of events).
count() as eventCount,
-- an array of rounded dates
groupArray(roundedDate) AS roundedDateArray,
-- an array of rounded dates shifted to 30 minutes (where 30 min taken from timeSlot-function)
arrayMap(i -> (i + 1800), roundedDateArray) AS shiftedRoundedDateArray,
-- to intersect two arrays to find the dates when sessions start
arrayFilter(x -> (has(shiftedRoundedDateArray, x) = 0), roundedDateArray) AS sessionStartDateArray
FROM
(
SELECT DISTINCT
user,
tag,
-- rounds down the time to the half hour.
timeSlot(date) AS roundedDate
FROM test01
)
GROUP BY user, tag
)
ORDER BY user, tag;
【讨论】:
非常感谢您的回答,我还不习惯使用数组。我只是对 eventCount 有一个评论:如果从子查询中删除了 DISTINCT,则必须将 groupArray 替换为 groupUniqArray 以避免重复条目。【参考方案2】:create table C (D DateTime',' user String',' tag String) Engine = Memory;
insert into C values
('2018-12-21 00:00:00','user1','tag1'),
('2018-12-21 00:00:00','user2','tag1'),
('2018-12-21 00:15:00','user1','tag1'),
('2018-12-21 00:15:00','user2','tag2'),
('2018-12-21 00:30:00','user1','tag1'),
('2018-12-21 00:45:00','user1','tag1'),
('2018-12-21 01:45:00','user1','tag1'),
SELECT user, tag,
toDateTime(((arrayJoin(arraySplit((k, j) -> j, Arr,
arrayMap(i -> i > 1800,
arrayDifference(arraySort(groupArray(toUnixTimestamp(D))) as Arr)))))
as R)[1]) b,
toDateTime(R[-1]) e,
length(R) c
from C
group by user, tag
┌─user──┬─tag──┬───────────────────b─┬───────────────────e─┬─c─┐
│ user2 │ tag2 │ 2018-12-21 00:15:00 │ 2018-12-21 00:15:00 │ 1 │
│ user1 │ tag1 │ 2018-12-21 00:00:00 │ 2018-12-21 00:45:00 │ 4 │
│ user1 │ tag1 │ 2018-12-21 01:45:00 │ 2018-12-21 01:45:00 │ 1 │
│ user2 │ tag1 │ 2018-12-21 00:00:00 │ 2018-12-21 00:00:00 │ 1 │
└───────┴──────┴─────────────────────┴─────────────────────┴───┘
【讨论】:
以上是关于从事件中提取会话的主要内容,如果未能解决你的问题,请参考以下文章
从 Window 日志的 .evtx 文件中提取审计事件信息