我有几个事件日志文件(每行一个事件)。日志可能会重叠。日志是在可能的多个时区的不同客户端计算机上生成的(但我假设我知道时区)。每个事件都有一个标准化为公共时间的时间戳(通过使用适合于日志文件的时区实例化每个日志解析器日历实例,然后使用getTimeInMillis获取UTC时间)。日志已按时间戳排序。多个事件可以同时发生,但它们绝不是平等的事件。
这些文件可能相对较大,如单个日志中的500000个事件或更多,因此将日志的全部内容读入简单的Event []是不可行的。
我正在尝试将每个日志中的事件合并到一个日志中。它有点像mergesort任务,但每个日志已经排序,我只需将它们组合在一起。第二个组件是每个单独的日志文件中都可以看到相同的事件,我想在文件输出日志中“删除重复的事件”。
这可以“就地”完成,例如,顺序处理每个日志文件的一些小缓冲区吗?我不能简单地将所有文件读入Event [],对列表进行排序,然后删除重复项,但到目前为止,我的有限编程功能只能让我将其视为解决方案。当我同时从每个日志中读取事件时,是否有一些更复杂的方法可以用来做这个?
答案 0 :(得分:10)
从每个日志文件中读取第一行
LOOP
一个。找到“最早”的行。
湾将“最早”行插入主日志文件
℃。从包含最早行
你可以检查b和c之间的重复,推进每个文件的指针。
答案 1 :(得分:4)
当然 - 打开每个日志文件。将第一行读入每个“当前”行数组。然后重复选择当前数组中具有最低时间戳的行。将其写入输出,并从相应的源文件中读取新行以替换它。
这是Python中的一个例子,但它也是很好的伪代码:
def merge_files(files, key_func):
# Populate the current array with the first line from each file
current = [file.readline() for file in files]
while len(current) > 0:
# Find and return the row with the lowest key according to key_func
min_idx = min(range(len(files)), key=lambda x: return key_func(current[x]))
yield current[min_idx]
new_line = files[min_idx].readline()
if not new_line:
# EOF, remove this file from consideration
del current[min_idx]
del files[min_idx]
else:
current[min_idx] = new_line
答案 2 :(得分:1)
结帐此链接:http://www.codeodor.com/index.cfm/2007/5/10/Sorting-really-BIG-files/1194
使用堆(基于数组)。此堆/数组中的元素数将等于您拥有的日志文件数。
从所有文件中读取第一条记录并将它们插入堆中。
循环直到(任何文件中没有更多记录)
> remove the max element from the heap > write it to the output > read the next record from the file to which the (previous) max element belonged if there are no more records in that file remove it from file list continue > if it's not the same as the (previous) max element, add it to the heap
现在,您将所有事件都放在一个日志文件中,它们已经过排序,并且没有重复项。算法的时间复杂度为(n log k),其中n是记录总数,k是日志文件的数量。
在读取文件和从文件读取时,应使用缓冲的读取器和缓冲的写入器对象,以最大限度地减少磁盘读写次数,以便优化时间。
答案 3 :(得分:1)
我们需要按时间顺序合并几个日志文件,每个日志条目有多行(java应用程序经常这样做 - 它们的堆栈跟踪是相同的)。我决定实现简单的shell + perl脚本。它涵盖了我们的任务。如果您对此感兴趣,请点击链接http://code.google.com/p/logmerge/
答案 4 :(得分:0)
从两个源文件一次只读一行。 比较这些行并将旧的行写入输出文件(并前进到下一行)。 这样做直到你到达两个文件的末尾并且你已经合并了文件。
并确保删除重复项:)
我想C#中的这段代码可以说明这种方法:
StringReader fileStream1;
StringReader fileStream2;
Event eventCursorFile1 = Event.Parse(fileStream1.ReadLine());
Event eventCursorFile2 = Event.Parse(fileStream2.ReadLine());
while !(fileStream1.EOF && fileStream2.EOF)
{
if (eventCursorFile1.TimeStamp < eventCursorFile2.TimeStamp)
{
WriteToMasterFile(eventCursorFile1);
eventCursorFile1 = Event.Parse(fileStream1.ReadLine());
}
else if (eventCursorFile1.TimeStamp == eventCursorFile2.TimeStamp)
{
WriteToMasterFile(eventCursorFile1);
eventCursorFile1 = Event.Parse(fileStream1.ReadLine());
eventCursorFile2 = Event.Parse(fileStream2.ReadLine());
}
else
{
WriteToMasterFile(eventCursorFile1);
eventCursorFile2 = Event.Parse(fileStream2.ReadLine());
}
}
休息条件不完全正确,因为这只是Quick'n'dirty,但看起来应该类似..
答案 5 :(得分:0)
或者您可以从Awstats借用日志合并实用程序,这是一个开源网站统计工具。
logresolvemerge.pl是一个可以合并多个日志文件的perl脚本:你甚至可以使用多个线程来合并日志文件(需要使用perl 5.8进行多线程使用)。为什么不尝试使用现成的工具而不是构建一个?