我需要解析非常大的日志文件(> 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 ++的建议都会非常受欢迎。有什么想法吗?
致以最诚挚的问候,
亚瑟
答案 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