You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Pandas按用户及连续1分钟时间块分组统计API访问日志

按用户分组统计1分钟内连续请求时间块的请求数

我有包含时间戳(@timestamp)、用户ID(@id)及请求负载的API访问日志,需要按用户分组,把彼此间隔1分钟以内的连续请求归为同一个时间块,统计每个时间块的请求数量。

输入示例

@timestamp               @data      @id                                                                                                               
2023-01-21 09:46:33.478   ...      Gh8Z4
2023-01-21 09:46:33.690   ...      Gh8Z4
2023-01-21 09:46:34.189   ...      Gh8Z4
2023-01-21 09:48:28.282   ...      Gh8Z4
2023-01-21 09:51:27.652   ...      HVtpG
2023-01-21 09:51:28.682   ...      Gh8Z4
2023-01-21 09:52:17.412   ...      HVtpG

期望输出示例

@id           start                    end             count                                                                                                                  
Gh8Z4 2023-01-21 09:46:33.478  2023-01-21 09:46:34.189   3
Gh8Z4 2023-01-21 09:48:28.282  2023-01-21 09:48:28.282   1  
HVtpG 2023-01-21 09:51:27.652  2023-01-21 09:52:17.412   2
Gh8Z4 2023-01-21 09:51:28.682  2023-01-21 09:51:28.682   1    

解决方案

方法1:Python Pandas 处理本地日志

如果日志是本地文件或可加载为DataFrame,用Pandas可以快速实现需求:

import pandas as pd

# 加载日志数据(本地文件可改用pd.read_csv/pd.read_table)
data = [
    ["2023-01-21 09:46:33.478", "...", "Gh8Z4"],
    ["2023-01-21 09:46:33.690", "...", "Gh8Z4"],
    ["2023-01-21 09:46:34.189", "...", "Gh8Z4"],
    ["2023-01-21 09:48:28.282", "...", "Gh8Z4"],
    ["2023-01-21 09:51:27.652", "...", "HVtpG"],
    ["2023-01-21 09:51:28.682", "...", "Gh8Z4"],
    ["2023-01-21 09:52:17.412", "...", "HVtpG"],
]

df = pd.DataFrame(data, columns=["@timestamp", "@data", "@id"])
# 解析时间戳为datetime类型
df["@timestamp"] = pd.to_datetime(df["@timestamp"])

result_list = []
# 按用户ID分组处理每个用户的请求
for user_id, group in df.groupby("@id"):
    # 对当前用户的请求按时间排序
    sorted_group = group.sort_values("@timestamp").reset_index(drop=True)
    # 计算相邻请求的时间差(秒)
    sorted_group["time_gap"] = sorted_group["@timestamp"].diff().dt.total_seconds()
    # 标记新时间块的起始点:时间差超60秒或为第一条请求
    sorted_group["block_id"] = (sorted_group["time_gap"] > 60).cumsum()
    # 统计每个时间块的起始、结束时间和请求数
    block_stats = sorted_group.groupby("block_id").agg(
        start=("@timestamp", "first"),
        end=("@timestamp", "last"),
        count=("@timestamp", "size")
    ).reset_index(drop=True)
    block_stats["@id"] = user_id
    result_list.append(block_stats[["@id", "start", "end", "count"]])

# 合并结果并按时间排序
final_result = pd.concat(result_list).sort_values("start")
# 格式化时间输出为指定格式
final_result["start"] = final_result["start"].dt.strftime("%Y-%m-%d %H:%M:%S.%f").str[:-3]
final_result["end"] = final_result["end"].dt.strftime("%Y-%m-%d %H:%M:%S.%f").str[:-3]

# 打印结果
print(final_result.to_string(index=False))

方法2:SQL 处理数据库日志表

如果日志存储在数据库中,可通过窗口函数实现分组统计:

WITH sorted_logs AS (
    -- 按用户分组排序,获取上一条请求的时间戳
    SELECT 
        @id,
        @timestamp,
        LAG(@timestamp) OVER (PARTITION BY @id ORDER BY @timestamp) AS prev_time
    FROM api_logs
),
block_flags AS (
    -- 标记新时间块的起始:时间差超60秒或无历史记录
    SELECT 
        @id,
        @timestamp,
        CASE 
            WHEN TIMESTAMPDIFF(SECOND, prev_time, @timestamp) > 60 OR prev_time IS NULL 
            THEN 1 
            ELSE 0 
        END AS is_new_block
    FROM sorted_logs
),
block_groups AS (
    -- 为每个用户的请求分配时间块ID
    SELECT 
        @id,
        @timestamp,
        SUM(is_new_block) OVER (PARTITION BY @id ORDER BY @timestamp) AS block_id
    FROM block_flags
)
-- 统计每个时间块的信息
SELECT 
    @id,
    MIN(@timestamp) AS start,
    MAX(@timestamp) AS end,
    COUNT(*) AS count
FROM block_groups
GROUP BY @id, block_id
ORDER BY start;

内容的提问来源于stack exchange,提问作者Verbal_Kint

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 02:45:18