对非常大的数据进行重复检测

时间:2014-07-30 12:54:25

标签: java duplicates out-of-memory

我对Java很陌生,所以请原谅我,如果我做了一件非常糟糕的事情。

我正在开展一个项目,我需要快速扫描大量数据(包含5000万行或更多行的CSV,每行5个条目)以进行重复。我使用了HashMap,因为它的.contains()方法很快。

然而,我最终不得不在地图中存储一百万个或更多的键。每个键都与一个int []数组相关联,该数组也有1到100个条目。很明显,除非我使用的笔记本电脑有大约16 GB的RAM,否则我最终会收到OutOfMemory错误。

我在想,一旦HashMap获得超过N个键或一个键获得超过N个条目,我就可以将其写入某个地方并清除它。但是,并非所有键或值都是一次找到的,所以我需要能够添加到写入的hashmap,而不是覆盖它。

我进行了广泛的搜索,仍然无法找到办法,所以非常感谢能帮助的人!

3 个答案:

答案 0 :(得分:4)

你在这里有很多选择,我会列出其中一些:

  1. 更多内存:听起来您已经尝试过为Java提供更多内存,但如果没有,请使用-Xmx compiler flag - 例如Dimitry建议-Xmx3G将为您提供3 GB的堆,而默认值为< = 1GB。
  2. 存储更少数据:您当前正在存储整行" 1到100个条目",当我们真正需要的是知道是否数据是否唯一。 Arrays.hashCode()函数为您提供了一个合理准确的指示,表明一行int中的行是唯一的,因此我们可以将其用于限制您需要在内存中保存的数据量:

    1. 构建两个名为HashSet<Integer>seen的{​​{1}}个对象。循环遍历您的数据,并将每个数组的哈希值添加到seenTwice,如果它已经在seen,则添加到seenTwice,如下所示:

      seen
    2. 现在我们有一组哈希,我们看过两次或更多次;从理论上讲,这将是一个比我们文件中的行数小得多的集合。我们可以让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
  3. 使用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!");
      }
    }
    
  4. 使用数据库:您可以像提到的那样使用一些内存不足的解决方案,尤其是数据库。一个好的,易于使用的Java数据库是H2,但覆盖使用它超出了本答案的范围。可以说,您可以将数据从文件加载到数据库中,然后只查询重复的行:Finding duplicate values in a SQL table

    但是设置数据库只是为了找到5000万行中的重复数据,这是过度的。我不会推荐这个选项。


  5. 另请参阅:Script to find duplicates in a csv file

答案 1 :(得分:1)

我不知道你究竟想做什么。但是如果您使用SQL数据库会有帮助吗?然后你可以在外部保存你的值,你不需要这么多的RAM。

如果这不适用于您,那将是不幸的。当我读到你的问题时,我确信使用数据库会解决你所有的问题。

答案 2 :(得分:-1)

使用phpmyadmin oe heideiSQL从CSV文件上传数据

您可以在.ini文件中更改phpmyadmin的上传限制 简单的数据插入数据库。

从数据库中获取数据作为java pojo对象并进行处理。 节省你的记忆