在JAVA中多次处理大文件

时间:2015-08-24 18:00:25

标签: java file java-io

我有一个文件A,其中包含40Millon附近的一些记录。我有另一个文件B,其中包含70Millon左右的一些记录。现在我必须遍历文件A,对于每个记录搜索,如果文件B中有条目。如果是,则在文件C中写入条目。

请提出有关如何实现这一目标的建议,而不会浪费内存并且时间最短。我已经尝试过apache lucene,但它有额外的创建索引的开销,因为文件B有7000万条记录每天都会改变(即我们从外部系统获取这个文件)每天重新创建索引是非常难的

3 个答案:

答案 0 :(得分:2)

您可以使用Chronicle Map。

您应该可以在几秒到几分钟内加载7000万条记录,具体取决于记录的大小。如果需要,您可以实时更新记录。

由于Chronicle Map是持久存在且不在堆外,如果有帮助,你可以离线或在另一个进程中执行此操作。

或者您可以使用数据库,批量加载此类表格不应该花费超过几分钟的时间。

答案 1 :(得分:1)

如果数据库不是一个选项,我有一个想法:

预处理您的第二个文件:抓取并按字母顺序对其进行排序:

Anna
Aqua
Claire
Jeremy
Joseph
Vill

现在创建一个文件,将每个字母字符映射到用作名称起始字符的行号:

A,0
C,2
J,3
V,5

之前的步骤称为预处理,您应该在编译程序之前执行这些步骤。显然,对这样一个巨大的文件进行排序会花费很多时间,但是如果使用这种方法,那么部署的程序将会快得多:

当您迭代第一个文件时,假设您找到了Joseph。你所做的是获取第一个字符J,然后使用映射来确定使用该字符的第一个行号。映射将生成3,因此您将迭代第二个文件到这样的行号。这样可以节省大量时间,因为您可以在显然不符合搜索条件的多行上跳过equals()。要查找Joseph,您只需要检查Jeremy然后Joseph

现在您已了解此技术,您可以通过使用两个级别来提高效率:对于字母表中的每个字符,为字母表中的每个字符创建另一个映射。在J的情况下,它将是

JE,3
JO,4

由于您正在寻找Joseph,因此您可以轻松确定开始寻找它的行号是第四行,从而跳过更多的比较。

你可以在更多级别上执行此操作:三,四等......由您来决定哪一个是您的最佳选择。映射不会占用太多空间,它们可以通过跳过不必要的条目来节省大量时间。

显而易见的缺点是,预处理包含7000万条目的文件非常详尽 - 但这是您的最终用户无需体验的内容。

这是一种方法。

注意:您仍需要迭代第二个文件的每一行以达到所需的行号。关键是你不需要进行任何类型的比较 - 你会发现这将为你节省大量的处理时间。

答案 2 :(得分:0)

假设您没有足够的内存来加载数据,并且没有便于索引的数据库,最好的办法是使用sort-merge join

实质上,按连接/查找条件对两个文件进行排序,然后并行读取文件(“合并”)。