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

基于Pandas按IP和时间间隔统计正则匹配日志次数的方案求助

基于Pandas的日志消息频次过滤方案

问题背景

现有日志数据结构(字典列表):

list1 =[
{'ip': '11.22.33.44', 'timestamp': 1665480231699, 'message': '{"body": "Idle time larger than time period. retry:0"}', 'ingestionTime': 1665480263198},
{'ip': '11.22.33.42', 'timestamp': 1665480231698, 'message': '{"body": "Idle time larger than time period. retry:5"}', 'ingestionTime': 1665480263198}, 
{'ip': '11.22.33.44', 'timestamp': 1665480231698, 'message': '{"body": "Idle time larger than time period. retry:0"}', 'ingestionTime': 1665480263198}
]

需要匹配的白名单规则列表(含正则表达式):

whitelist_metadata = [
  {
    'LogLevel': 'WARNING',
    'SpecificVersion': 'None',
    'TimeInterval(Min)': 1,
    'MetricMsg': 'DDR: XXXX count got lost',
    'AllowedOccurrenceInTimeInterval': 0   # 0表示始终允许出现
  },
  {
    'LogLevel': 'WARNING',
    'SpecificVersion': 'None',
    'TimeInterval(Min)': 1,
    'MetricMsg': r'Idle time larger than .* time\. retry: \d+',     # 正则表达式
    'AllowedOccurrenceInTimeInterval': 5  # 1分钟内最多允许出现5次
  }
]

需求:按单个IP维度,检查每条日志消息是否匹配白名单中的正则,统计指定时间间隔内的出现次数:

  • 若规则允许次数为0:直接保留该记录
  • 若次数超过规则阈值:保留记录;否则移除该记录

此前尝试使用Pandas rolling("5m") 时触发报错:ValueError('window must be an integer',),需要高性能的实现方案。

解决方案

步骤1:数据预处理与格式转换

将数据转为DataFrame,转换时间戳格式并解析日志消息中的正文内容:

import pandas as pd
import json
import re

# 加载数据
list1 =[
{'ip': '11.22.33.44', 'timestamp': 1665480231699, 'message': '{"body": "Idle time larger than time period. retry:0"}', 'ingestionTime': 1665480263198},
{'ip': '11.22.33.42', 'timestamp': 1665480231698, 'message': '{"body": "Idle time larger than time period. retry:5"}', 'ingestionTime': 1665480263198}, 
{'ip': '11.22.33.44', 'timestamp': 1665480231698, 'message': '{"body": "Idle time larger than time period. retry:0"}', 'ingestionTime': 1665480263198}
]

# 转为DataFrame并处理时间戳
df = pd.DataFrame(list1)
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')

# 解析message中的body字段,方便后续正则匹配
df['body'] = df['message'].apply(lambda x: json.loads(x)['body'])

步骤2:匹配白名单规则

遍历白名单规则,为每条日志标记匹配的规则及对应的阈值:

# 初始化匹配标记列
df['matched_rule'] = None
df['allowed_count'] = None
df['time_interval'] = None

for rule in whitelist_metadata:
    pattern = re.compile(rule['MetricMsg'])
    # 匹配当前规则的日志行
    match_mask = df['body'].str.contains(pattern)
    # 填充匹配规则的相关参数
    df.loc[match_mask, 'matched_rule'] = rule['MetricMsg']
    df.loc[match_mask, 'allowed_count'] = rule['AllowedOccurrenceInTimeInterval']
    df.loc[match_mask, 'time_interval'] = pd.Timedelta(minutes=rule['TimeInterval(Min)'])

步骤3:按IP+规则分组,统计时间窗口内的出现次数

使用时间窗口滚动计数的核心要求:必须将timestamp设置为分组后的索引,否则会触发窗口类型错误。

# 拆分有匹配规则和无匹配规则的日志
matched_df = df[df['matched_rule'].notna()]
unmatched_df = df[df['matched_rule'].isna()]

# 按IP和匹配规则分组,设置timestamp为索引并排序
grouped = matched_df.set_index('timestamp').sort_index().groupby(['ip', 'matched_rule'])

# 定义滚动计数逻辑
def calculate_rolling_count(group):
    window_duration = group['time_interval'].iloc[0]
    # 统计当前时间窗口内的日志出现次数
    group['rolling_count'] = group.rolling(window_duration)['body'].count()
    return group

# 应用滚动计数到每个分组
processed_grouped = grouped.apply(calculate_rolling_count).reset_index()

步骤4:根据阈值过滤记录

根据规则的允许次数过滤日志:

# 生成保留规则的掩码:允许次数为0 或 滚动计数超过阈值
keep_mask = (processed_grouped['allowed_count'] == 0) | (processed_grouped['rolling_count'] > processed_grouped['allowed_count'])
filtered_matched = processed_grouped[keep_mask]

# 合并过滤后的匹配日志和未匹配日志
final_df = pd.concat([filtered_matched, unmatched_df], ignore_index=True)

# 可选:恢复原数据的列结构
final_df = final_df[list1[0].keys()]

关键说明

  • 使用rolling时间窗口时,必须确保分组后的DataFrame索引为datetime类型,否则会触发window must be an integer错误;
  • 按IP+规则分组可避免不同IP、不同规则的日志互相干扰;
  • 基于Pandas向量化操作实现,处理大规模日志数据时性能远优于纯循环遍历。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 17:10:33