我对Java很陌生,所以请原谅我,如果我做了一件非常糟糕的事情。
我正在开展一个项目,我需要快速扫描大量数据(包含5000万行或更多行的CSV,每行5个条目)以进行重复。我使用了HashMap
,因为它的.contains()
方法很快。
然而,我最终不得不在地图中存储一百万个或更多的键。每个键都与一个int []数组相关联,该数组也有1到100个条目。很明显,除非我使用的笔记本电脑有大约16 GB的RAM,否则我最终会收到OutOfMemory
错误。
我在想,一旦HashMap
获得超过N个键或一个键获得超过N个条目,我就可以将其写入某个地方并清除它。但是,并非所有键或值都是一次找到的,所以我需要能够添加到写入的hashmap,而不是覆盖它。
我进行了广泛的搜索,仍然无法找到办法,所以非常感谢能帮助的人!
答案 0 :(得分:4)
你在这里有很多选择,我会列出其中一些:
-Xmx
compiler flag - 例如Dimitry建议-Xmx3G
将为您提供3 GB的堆,而默认值为< = 1GB。 存储更少数据:您当前正在存储整行" 1到100个条目",当我们真正需要的是知道是否数据是否唯一。 Arrays.hashCode()
函数为您提供了一个合理准确的指示,表明一行int
中的行是唯一的,因此我们可以将其用于限制您需要在内存中保存的数据量:
构建两个名为HashSet<Integer>
和seen
的{{1}}个对象。循环遍历您的数据,并将每个数组的哈希值添加到seenTwice
,如果它已经在seen
,则添加到seenTwice
,如下所示:
seen
现在我们有一组哈希,我们看过两次或更多次;从理论上讲,这将是一个比我们文件中的行数小得多的集合。我们可以让int[] arr = ... // construct the row's array
int hash = Arrays.hashCode(arr);
if(!seen.add(hash)) {
// add returns false if we've already seen this hash
seenTwice.add(hash);
}
收集垃圾,然后使用seen
重新读取文件,以填充seenTwice
实际数据,就像您第一次尝试一样:
HashSet<int[]> rows
使用Bash :如果您愿意放弃使用Java,您可以使用基本的bash命令轻松找到重复的 :
int[] arr = ... // construct the row's array
int hash = Arrays.hashCode(arr);
if(seenTwice.contains(hash)) {
// If the hash isn't in seenTwice, we know it's not a duplicate
if(!rows.add(arr)) {
System.out.println("Row "+Arrays.toString(arr))+" is a duplicate!");
}
}
使用数据库:您可以像提到的那样使用一些内存不足的解决方案,尤其是数据库。一个好的,易于使用的Java数据库是H2,但覆盖使用它超出了本答案的范围。可以说,您可以将数据从文件加载到数据库中,然后只查询重复的行:Finding duplicate values in a SQL table
但是设置数据库只是为了找到5000万行中的重复数据,这是过度的。我不会推荐这个选项。
答案 1 :(得分:1)
我不知道你究竟想做什么。但是如果您使用SQL数据库会有帮助吗?然后你可以在外部保存你的值,你不需要这么多的RAM。
如果这不适用于您,那将是不幸的。当我读到你的问题时,我确信使用数据库会解决你所有的问题。
答案 2 :(得分:-1)
使用phpmyadmin oe heideiSQL从CSV文件上传数据
您可以在.ini文件中更改phpmyadmin的上传限制 简单的数据插入数据库。
从数据库中获取数据作为java pojo对象并进行处理。 节省你的记忆