用python处理许多大型日志文件

用python处理许多大型日志文件,python,logging,Python,Logging,我正在使用一些python脚本来进行统计。 日志的一种内容是这样的,我称之为日志: 每个A日志的格式为: [2012-09-12 12:23:33] SOME_UNIQ_ID filesize [2012-09-12 12:24:00] SOME_UNIQ_ID 另一个日志我称之为B日志,其格式为: [2012-09-12 12:23:33] SOME_UNIQ_ID filesize [2012-09-12 12:24:00] SOME_UNIQ_ID 我需要计算A日志中有多少条记录也

我正在使用一些python脚本来进行统计。 日志的一种内容是这样的,我称之为日志: 每个A日志的格式为:

[2012-09-12 12:23:33] SOME_UNIQ_ID filesize
[2012-09-12 12:24:00] SOME_UNIQ_ID
另一个日志我称之为B日志,其格式为:

[2012-09-12 12:23:33] SOME_UNIQ_ID filesize
[2012-09-12 12:24:00] SOME_UNIQ_ID

我需要计算A日志中有多少条记录也在B日志中,并获得具有相同记录id的两条记录的时间间隔。我的实现是将所有时间和B日志id加载到映射中,然后迭代A日志,检查它的ID是否存在于映射中。问题是它占用了太多内存,因为我在B日志中有近1亿条记录。有没有改进性能和内存使用率的建议?谢谢。

您可以尝试反转查找,具体取决于“A”是否适合内存,然后依次扫描“B”

否则,将日志文件加载到一个SQLite3数据库中,该数据库有两个表(log_a,log_b),其中包含(timestamp,uniq_id,rest_of_line),然后在
uniq_id
上执行SQL联接,并对其结果执行所需的任何处理。这将保持较低的内存开销,使SQL引擎能够进行连接,但当然需要有效地复制磁盘上的日志文件(但这在大多数系统上通常不是问题)

示例

import sqlite3
from datetime import datetime

db = sqlite3.connect(':memory:')

db.execute('create table log_a (timestamp, uniq_id, filesize)')
a = ['[2012-09-12 12:23:33] SOME_UNIQ_ID filesize']
for line in a:
    timestamp, uniq_id, filesize = line.rsplit(' ', 2)
    db.execute('insert into log_a values(?, ?, ?)', (timestamp, uniq_id, filesize))
db.commit()

db.execute('create table log_b (timestamp, uniq_id)')
b = ['[2012-09-12 13:23:33] SOME_UNIQ_ID']
for line in b:
    timestamp, uniq_id = line.rsplit(' ', 1)
    db.execute('insert into log_b values(?, ?)', (timestamp, uniq_id))
db.commit()

TIME_FORMAT = '[%Y-%m-%d %H:%M:%S]'
for matches in db.execute('select * from log_a join log_b using (uniq_id)'):
    log_a_ts = datetime.strptime(matches[0], TIME_FORMAT)
    log_b_ts = datetime.strptime(matches[3], TIME_FORMAT)
    print matches[1], 'has a difference of', abs(log_a_ts - log_b_ts)
    # 'SOME_UNIQ_ID has a difference of 1:00:00'
    # '1:00:00' == datetime.timedelta(0, 3600)
请注意:

  • sqlite3上的
    .connect
    应该是一个文件名
  • a
    b
    应该是您的文件

首先,ID的格式是什么?是全球独一无二的吗

我会从这三个选项中选择一个

  • 使用数据库
  • 两组ID的并集
  • Unix工具
我想你更喜欢第二种选择。只加载A和B中的id。假设id适合32位整数,内存使用量将小于1GB。然后加载相同ID的datetime并计算间隙。第一个选项是最适合需求的

试试这个:

  • 从外部对两个文件进行排序
  • 读取A日志文件并保存一些统一ID(A)
  • 读取B日志文件并保存一些UNIQ\u ID(B)
  • 比较SOME_UNIQ_ID(B)和SOME_UNIQ_ID(A)
    • 如果较小,请再次读取B日志文件
    • 如果更大,请再次读取日志文件,并与保存的某些\u UNIQ\u ID(B)进行比较
    • 如果相等,则找出时间间隔

假设外部排序有效,则只需读取两个文件一次即可结束该过程。

如果可以对唯一ID进行排序(例如,按字母顺序或数字顺序),则可以批处理比较

例如,假设ID为数值,范围为1-10^7。然后,您可以首先将前10^6个元素放在哈希表中,对第二个文件进行顺序扫描以找到匹配的记录

在pseudopython中,我没有测试过这一点:

for i in xrange(0,9):
    for line in file1:
        time, id = line.split(']')
        id = int(id)
        if i * 10**6 < id < (i+1) * 10**6:
            hash_table[id] = time

    for line in file2:
        time, id = line.split(']') # needs a second split to get the id
        id = int(id)
        if id in hashtable:
            # compare timestamps

由于瓶颈是时间戳的转换。我将此操作拆分为许多独立的机器,生成A日志和B日志。这些机器将字符串戳转换为一个纪元时间,而使用所有这些日志计算结果的中心机器现在几乎需要原始方式的1/20。我在这里发布我的解决方案,谢谢你们大家

我建议使用既支持
日期时间
又支持
uniqueidentifier
唯一id显示形式的数据库。它来自Windows,如果您使用Windows执行任务,您可以使用Microsoft SQL 2008 R2 Express edition(免费)。这两个表将不使用任何类型的键

您可以使用MS SQL,这可能是从文本文件(或命令)插入数据的最快方法之一


uniqueidentifier上的索引应仅在插入所有记录后创建。否则,索引的存在会降低插入操作的速度。那么内部连接应该在技术上尽可能快。

一个映射中有多少条记录?还有1亿?A日志中的记录不会加载到地图中,只需加载B中的日志即可。A和B的大小几乎相同。另请参见@nneonno谢谢,问题是我还必须计算时间间隔……这似乎很难,但我会先尝试SQLite。我同意-将数据放入数据库(任何风格)然后你可以尽情地玩它。见鬼-甚至将其导入excel!我没有这样的经验,将记录插入SQLite会花费太多时间吗?我必须计算时间间隔,SQL是否支持某些函数来获得它?@cheneydeng不会这么认为-取决于硬件,不会超过几分钟。。。这是其中一个尝试一下,看看会发生什么事情我担心@cheneydeng最长的部分是
连接
,因为SQLite3可能会决定对文件进行排序(这意味着实际上,您将从Georgee Naliyath提出的合并排序中检索结果)@cheneydeng添加了一个可以用作模板的基本示例谢谢。我尝试了SQLite3,在我没有使用SQLite的“内存”模式的情况下,将所有日期插入数据库几乎需要3个小时。我认为这不是处理我的问题的有效方法。id是这样的uuid/48d4493d-cb57-4505-a64d-b12c89c09dcais是128位随机哈希吗?200mln*16字节概率。太多。如果对{id,date}上的两个文件进行预排序,则合并步骤的最大内存占用将是具有最大数量的匹配/重叠a*B记录的id。“如果较小,则读取B如果较大,则读取a”id是GUID而不是序列号。id不必是序列号。只要ID可以排序,该算法就可以工作。