我的文件很大,大约有1500万个条目。 文件中的每一行都包含一个字符串(称之为键)。
我需要使用java在文件中找到重复的条目。 我尝试使用散列图并检测重复的条目。 显然这种方法给我一个“java.lang.OutOfMemoryError:Java堆空间”错误。
我该如何解决这个问题?
我想我可以增加堆空间并尝试它,但我想知道是否有更好的有效解决方案而不必调整堆空间。
答案 0 :(得分:29)
关键是你的数据不适合内存。您可以使用external merge sort:
将文件分区为适合内存的多个较小块。对每个块进行排序,消除重复(现在是相邻的元素)。
合并块并在合并时再次消除重复项。由于你将在这里进行n-nway合并,你可以保留内存中每个块的下一个k元素,一旦块的项目耗尽(它们已经合并)从磁盘中获取更多。
答案 1 :(得分:11)
我不确定你是否考虑在java之外做这个,但如果是这样的话,这在shell中非常简单:
cat file | sort | uniq
答案 2 :(得分:6)
您可能无法一次加载整个文件,但您可以将哈希和行号存储在HashSet中没问题。
伪代码......
for line in file
entries.put(line.hashCode, line-number)
for entry in entries
if entry.lineNumbers > 1
fetch each line by line number and compare
答案 3 :(得分:4)
我认为您不需要对数据进行排序以消除重复数据。只需使用快速启发方法。
请注意,k可以等于1.
答案 4 :(得分:3)
我可以想象解决这个问题的一种方法是首先使用external sorting algorithm对文件进行排序(搜索external sort java
会产生大量带代码的结果)。然后你可以逐行迭代文件,重复现在显然会直接相互跟随,所以你只需要在迭代时记住前一行。
答案 5 :(得分:2)
如果由于内存不足而无法构建完整列表,则可以尝试在循环中执行此操作。即创建一个hashmap但只存储一小部分项目(例如,那些以A开头的项目)。然后你收集重复项,然后继续'B'等。
当然,您可以选择任何类型的“分组”(即前3个字符,前6个等)。
只需要(多次)迭代。
答案 6 :(得分:1)
如果您愿意接受一定数量的统计错误,可以尝试Bloom filter。番石榴provides一个,但现在有一个相当大的错误,可能会在下周发布11.0.2版本。