在C / C ++中搜索大文件中的数据

时间:2010-02-05 20:34:42

标签: c++ c file indexing search

我有一个日志文件,其格式为:

DATE-TIME ### attribute1  ### attribute2 ###attribute3 

我必须在此日志文件中搜索输入属性(从命令行输入)并输出与输入属性匹配的行。
一种天真的方法可能是这样的:

scan the entire file line by line
search for the attribute
print if found, else ignore.

这种方法很慢,因为它需要O(n)比较,其中n是可能非常大的行数。
另一种方法可能是使用散列表,但是可能无法为大文件保留这样的内存中散列表。
那么,最可行的解决方案是什么?如何在各种属性上索引整个文件?

修改:
日志文件可能大约是100K行,几乎就像linux上的系统日志文件一样。 在一次调用中,用户可以搜索多个属性,这些属性在第一个属性的搜索完成之前是未知的,就像交互式控制台一样。

谢谢,

10 个答案:

答案 0 :(得分:4)

如果你只搜索一次,你就不能比O(n)做得更好。

如果哈希索引太大而无法容纳在内存中,请使用像dbmgdbm这样的磁盘上哈希值。

编辑:我想指出KeithB建议的Berkeley数据库工具属于磁盘上哈希的这一类。 Berkeley DB不是一个使用SQL的关系数据库。

答案 1 :(得分:3)

您可以使用Berkley DB索引此文件。基本上,遍历整个文件一次,对于找到的每个属性,存储属性的文件位置。 Berkley DB使用高效的B-Tree实现,并不需要将整个索引存储在内存中,只需要存储所需的部分。 我之前已经取得了很好的成功。

答案 2 :(得分:2)

您可以通过仅在其中存储哈希值和文件偏移来减小哈希表的大小。如果属性仅具有固定的,相对较少的值,则您更有可能将整个哈希表适合内存。您为该属性的每个可能值分配一个id,然后为每个id值存储一个大的文件偏移列表。

当然,如果在程序的同一次运行中你进行了几次不同的搜索,哈希表才会有用。

显而易见的解决方案是将数据填充到数据库中,但我认为OP足够聪明,已经意识到已经并且有其他理由专门请求非数据库解决问题。

答案 3 :(得分:2)

听起来像数据库系统的工作。

  

如何在各种属性上索引整个文件?

您真的不在实施数据库解决方案。您最好的赌注可能是一些离线搜索算法并维护索引文件。

您可能还会感兴趣Map-Reduce

答案 4 :(得分:2)

没有有效的方法直接搜索可变长度行的文本文件。最有效的方法需要开销来将数据变更为更适合更有效搜索方法的形式。对于不经常搜索,这种开销可能不值得。

不经常搜索

如果文件只搜索一次或不经常搜索,我建议逐行扫描。其他方法可能会浪费时间设置数据以加快搜索速度。例如,使用您的程序查找包含一个或多个属性的第一行。

经常搜索

程序需要多次搜索文件。在这种情况下,您可能需要设置一些数据结构以便更好地进行搜索。一种技术是创建索引文件。这些文件包含属性的文件位置,按属性排序。像[属性] [第一次出现] [第二次出现]等等。

另一种方法是让程序将文件转换为更好的工具可以使用的格式,例如电子表格或数据库。一个例子是逗号分隔值,或者某些工具,例如将值分隔为“|”。

更改发电机

然而,生成日志文件的程序可以更改为生成电子表格或数据库友好的日志文件。我用嵌入式系统做到了这一点。我将数据输入电子表格并使用电子表格函数来分析数据。编写程序来搜索(和分析)日志文件要容易得多。

答案 5 :(得分:0)

在一个单独的线程中进行搜索,可能需要一段时间,但我认为在这种情况下,构建然后搜索哈希表的权衡是不值得的。

如果用户反复搜索不同属性,可能值得,但我对此表示怀疑。

要搜索,请尝试boost::regexQRegExp

对于只搜索日志文件,我认为您可能会使用数据库或哈希表对其进行过度设计。

答案 6 :(得分:0)

我将使用b-tree或哈希表构建索引。我会将索引存储在磁盘上。如果您控制此文件的更新,则还可以在更新文件时更新索引。如果您无法控制更新,请使用该文件的哈希值来确定是否需要重新生成。

在考虑了这一点后,我意识到我通常在命令行上使用grep搜索600k +行(100M)的日志文件。它很快。所以,我不认为100k是一个问题,除非你的文件有更多的数据。

如果日志文件变大,您可能还希望使用日志循环。

答案 7 :(得分:0)

您可以尝试直接线性搜索文件,但启动工作线程进行搜索。这样,您可以生成多个工作线程并在文件中的不同点启动它们。在具有多个处理器/内核的计算机上,这种并行性应该比普通的单线程线性搜索产生性能提升。

执行搜索后,您可能希望将输入参数和搜索结果存储在数据文件中。这样,如果将来重复搜索,您可以使用此缓存数据,只需搜索自上次搜索后修改的文件部分。

答案 8 :(得分:0)

别担心。只需扫描它。

严重。你说这个文件是100K行,这与我正在键入的计算机上的/ var / log / messages几乎完全相同。嗯,这是一个上网本,即按现代标准来说非常慢 - 而且我/ var / log / messages的直接grep非常快,以至于将结果打印到屏幕所花费的时间相形见绌。 / p>

所以我真的不认为你有什么值得担心的 - 特别是如果这是一个只在人类要求时运行搜索的交互式进程,而不是一些可能在后台不断搜索的守护进程。你可能已经浪费了更多的时间来担心这个问题,而不是希望通过实现索引来节省!

答案 9 :(得分:0)

来吧,认真的家伙们。日志文件的数据库?

日志文件始终或至少每天都在变化。所以你真正想要的是做一些日志文件轮换,其中有很多预制和失败,如果你知道甚至一点perl就可以在几个小时内完成。你可能真的不需要C ++。它只会使开发时间变慢,最终结果更加缓慢。