解析非常大的日志文件(> 1Gb,< 5Gb)

时间:2009-05-29 20:41:39

标签: parsing text logging

我需要解析非常大的日志文件(> 1Gb,< 5Gb) - 实际上我需要将数据剥离到对象中,以便将它们存储在数据库中。日志文件是顺序的(没有换行符),如:

TIMESTAMP = 200901.01亿; PARAM1 = Value11; PARAM2 = Value21;参数3 = Value31; TIMESTAMP = 20090101000100; PARAM1 = Value11; PARAM2 = Value21;参数3 = Value31; TIMESTAMP = 20090101000152; PARAM1 = Value11; PARAM2 = Value21;参数3 = Value31 ; ...

我需要将其删除到表格中:

TIMESTAMP | PARAM1 | PARAM2 |参数3

该过程需要尽可能快。我正在考虑使用Perl,但任何使用C / C ++的建议都会非常受欢迎。有什么想法吗?

致以最诚挚的问候,

亚瑟

11 个答案:

答案 0 :(得分:11)

在Perl中编写原型,并将其性能与从存储介质读取数据的速度进行比较。我的猜测是你将受到I / O限制,这意味着使用C不会提供性能提升。

答案 1 :(得分:8)

关于使用Python生成器的演示文稿引起了我的注意: http://www.dabeaz.com/generators-uk/

David M. Beazley通过基本为每个处理步骤定义生成器来演示如何处理多GB的日志文件。然后将发生器“插入”到另一个,直到你有一些简单的实用功能

lines = lines_from_dir("access-log*","www")
log   = apache_log(lines)
for r in log:
    print r

然后可以用于各种查询:

stat404 = set(r['request'] for r in log
                if r['status'] == 404)

large = (r for r in log
           if r['bytes'] > 1000000)
for r in large:
    print r['request'], r['bytes']

他还表明,性能与标准的unix工具(如grep,find等)的性能相当。 当然这是Python,它比perl或awk脚本更容易理解,更重要的是更容易定制或适应不同的问题集。

(上面的代码示例是从演示幻灯片中复制的。)

答案 2 :(得分:5)

Lex非常好地处理了这类事情。

答案 3 :(得分:3)

但实际上,请使用AWK。即使与Perl等相比,它的性能还不错.Cource Map / Reduce可以很好地工作,但是将文件拆分成适当的块会有什么开销呢?

尝试AWK

答案 4 :(得分:3)

密钥不是语言,因为问题是I / O限制,所以选择你觉得最舒服的语言。

关键是如何编码。只要不将整个文件加载到内存中 - 一次加载块,并一次保存数据块,就会更好。

Java有一个PushbackInputStream可以使代码更容易。这个想法是你想要读多少,如果你读的太少,那么推回数据,然后读一个更大的块。

然后当你读得太多时,处理数据,然后推回剩余的位并继续循环的下一次迭代。

答案 5 :(得分:3)

这样的事情应该有效。

use strict;
use warnings;

my $filename = shift @ARGV;

open my $io, '<', $filename or die "Can't open $filename";

my ($match_buf, $read_buf, $count);

while (($count = sysread($io, $read_buf, 1024, 0)) != 0) {
    $match_buf .= $read_buf;
    while ($match_buf =~ s{TIMESTAMP=(\d{14});PARAM1=([^;]+);PARAM2=([^;]+);PARAM3=([^;]+);}{}) {
        my ($timestamp, @params) = ($1, $2, $3, $4);
        print $timestamp ."\n";
        last unless $timestamp;
    }
}

答案 6 :(得分:1)

这在Perl,Awk或C中很容易处理。以下是C版本的开头:

#include <stdio.h>
#include <err.h>

int
main(int argc, char **argv)
{
        const char      *filename = "noeol.txt";
        FILE            *f;
        char            buffer[1024], *s, *p;
        char            line[1024];
        size_t          n;
        if ((f = fopen(filename, "r")) == NULL)
                err(1, "cannot open %s", filename);
        while (!feof(f)) {
                n = fread(buffer, 1, sizeof buffer, f);
                if (n == 0)
                       if (ferror(f))
                               err(1, "error reading %s", filename);
                       else
                               continue;
                for (s = p = buffer; p - buffer < n; p++) {
                        if (*p == ';') {
                                *p = '\0';
                                strncpy(line, s, p-s+1);
                                s = p + 1;
                                if (strncmp("TIMESTAMP", line, 9) != 0)
                                        printf("\t");
                                printf("%s\n", line);
                        }
                }
        }
        fclose(f);
}

答案 7 :(得分:1)

听起来像是sed的工作:

sed -e 's/;\?[A-Z0-9]*=/|/g' -e 's/\(^\|\)\|\(;$\)//g' < input > output

答案 8 :(得分:0)

您可能需要查看Hadoop(java)或Hadoop Streaming(使用任何可执行文件或脚本运行Map / Reduce作业)。

答案 9 :(得分:0)

如果您编写自己的解决方案,您可能会从文件中读取更大的数据块并批量处理(而不是使用readline())并查找标记结束的换行符。每一行。使用这种方法,您需要注意您可能没有检索到最后一行的全部内容,因此需要一些逻辑来处理它。

我不知道你会意识到什么性能优势,因为我没有测试它,但我已经成功地利用了类似的技术。

答案 10 :(得分:0)

我知道这是一种奇特的语言,可能不是最好的解决方案,但是当我有临时数据时,我会考虑PADS