如何通过KQL RowCumsum检测计算用户状态切换后的StatusDuration
问题描述
以下是包含两个用户状态数据的表格:
| UserId | T | status | StatusDuration(seconds) |
|---|---|---|---|
| 1 | 2023-03-20T17:09:33.572Z | RUNNING | 0 |
| 1 | 2023-03-20T17:09:28.572Z | RUNNING | 5 |
| 1 | 2023-03-20T17:09:23.568Z | Idle | 5 |
| 1 | 2023-03-20T17:09:18.628Z | stop | 5 |
| 1 | 2023-03-20T17:09:13.564Z | RUNNING | 5 |
| 2 | 2023-03-20T17:09:08.56Z | offline | 0 |
| 2 | 2023-03-20T17:09:03.764Z | offline | 5 |
| 2 | 2023-03-20T17:08:58.556Z | offline | 10 |
| 2 | 2023-03-20T17:08:53.596Z | RUNNING | 10 |
| 2 | 2023-03-20T17:08:48.552Z | Idle | 10 |
每个UserId内状态首次切换后,剩余记录的时间(T)差值与首次状态切换的时间差一致。需通过KQL的row_cumsum函数计算对应的StatusDuration(seconds)。
解决方案
通过以下KQL代码实现需求,核心逻辑是按用户分组、标记状态切换点、划分状态组后累积计算持续时间:
// 模拟原始数据 let raw_data = datatable(UserId:int, T:datetime, status:string) [ 1, datetime(2023-03-20T17:09:33.572Z), "RUNNING", 1, datetime(2023-03-20T17:09:28.572Z), "RUNNING", 1, datetime(2023-03-20T17:09:23.568Z), "Idle", 1, datetime(2023-03-20T17:09:18.628Z), "stop", 1, datetime(2023-03-20T17:09:13.564Z), "RUNNING", 2, datetime(2023-03-20T17:09:08.56Z), "offline", 2, datetime(2023-03-20T17:09:03.764Z), "offline", 2, datetime(2023-03-20T17:08:58.556Z), "offline", 2, datetime(2023-03-20T17:08:53.596Z), "RUNNING", 2, datetime(2023-03-20T17:08:48.552Z), "Idle" ]; raw_data | partition by UserId ( // 按时间降序排列,确保最新记录在前 sort by T desc // 计算当前记录与下一条记录的时间差(秒) | extend time_diff = datetime_diff('second', T, next(T)) // 标记状态是否发生切换(当前状态与下一条不同则为1,否则0) | extend status_switch = iif(status != next(status), 1, 0) // 按状态切换点分割分组,同一状态组内的记录共享同一个基准时间差 | extend group_id = row_cumsum(status_switch, 0) // 取每组内的第一个时间差作为基准(首次切换的时间差) | summarize base_diff = max(time_diff) by UserId, group_id, status // 重新关联原始数据,按组计算累积持续时间 | join kind=inner raw_data on UserId, status | partition by UserId, group_id ( sort by T desc | extend row_num = row_number() // 行号减1乘以基准时间差,得到每条记录的持续时间 | extend StatusDuration = (row_num - 1) * base_diff ) // 整理输出字段 | project UserId, T, status, StatusDuration // 按时间降序排列,还原原始顺序 | sort by UserId, T desc )
逻辑说明
- 分组排序:用
partition by UserId隔离每个用户的数据,同时按时间降序排列,保证最新记录优先处理。 - 时间差与切换标记:通过
datetime_diff计算相邻记录的时间差,用iif标记状态切换点。 - 状态组划分:使用
row_cumsum基于切换标记生成分组ID,将连续相同状态的记录归为一组。 - 基准时间差提取:每个状态组的首次切换时间差作为该组的基准值,通过
summarize提取。 - 累积计算持续时间:在每个状态组内生成行号,用行号偏移量乘以基准时间差,得到每条记录的
StatusDuration。
内容的提问来源于stack exchange,提问作者Kameshwaran R
相关产品推荐
相关产品推荐

