【问题标题】:Duplicate detection on very large data对非常大的数据进行重复检测
【发布时间】:2014-07-30 12:54:24
【问题描述】:

我是 Java 新手,如果我做错了什么,请原谅我。

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

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

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

我已经搜索了很多地方,但仍然找不到方法,所以非常感谢任何可以提供帮助的人!

【问题讨论】:

  • 如果这些行有一些识别属性,那么你可以只存储那个,而不是整行。或者可能从该行创建一个哈希码,并且只有当您发现潜在的冲突时,才将这些哈希存储到另一个列表并进行第二次迭代以查看具有相同哈希码的条目是否真正相同。
  • 尝试在“java”命令中指定-Xmx3G(或-Xmx4G,-Xmx5G,...)。您需要尝试增加堆大小。 Hashmap 可以保存非常大的数据。
  • @tobias_k 谢谢,我会尝试迭代两次!
  • @DmitryTsechoev 也感谢 xD 我正在使用 -Xmx14g 运行它,所以我觉得这有点荒谬
  • @larrienea,不客气!

标签: java duplicates out-of-memory


【解决方案1】:

这里有很多选择,我将列出其中的一些:

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

    1. 构造两个HashSet<Integer> 对象,分别称为seenseenTwice。循环遍历您的数据,并将每个数组的哈希添加到seen,如果它已经在seen 中,则添加到seenTwice,如下所示:

      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);
      }
      
    2. 现在我们有一组我们见过两次或更多次的哈希值;理论上,这将比我们文件中的行数小得多。我们可以让seen 收集垃圾,并使用seenTwice 重新读取文件以填充实际数据的HashSet<int[]> rows,就像您最初尝试做的那样:

      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!");
        }
      }
      
  3. 使用 Bash:如果您愿意放弃 Java,您可以使用基本的 bash 命令非常轻松地找到重复项:

    cat filename | sort | uniq -d
    
  4. 使用数据库:您可以像您所暗示的那样使用一些内存不足的解决方案,特别是数据库。一个好的、易于使用的 Java 数据库是 H2,但涵盖使用它超出了此答案的范围。可以这么说,您可以将文件中的数据加载到数据库中,然后简单地查询重复行:Finding duplicate values in a SQL table

    但是设置一个数据库只是为了在 5000 万行中查找重复项是多余的。我不推荐这个选项。


另见:Script to find duplicates in a csv file

【讨论】:

  • +1 (2) 对我刚刚在评论中勾勒的想法进行了很好的描述。不过,可能想添加一条关于(根据您的链接)uniq 的注释,只查找彼此相邻的重复项。
  • 嗯...但是sort 那个有 5000 万行的文件真的是个好主意吗?
  • Bash 的sort 可以轻松地对大量数据进行排序。请参阅this question 了解更多信息。
【解决方案2】:

我不知道你到底想做什么。但是,如果您使用 SQL 数据库会有所帮助吗?然后你可以在外部保存你的值,你就不需要这么大的内存了。

如果这不适用于您,那就太遗憾了。当我阅读您的问题时,我确信使用 db 可以解决您的所有问题。

【讨论】:

  • 是的,使用数据库并使用索引或主键。
【解决方案3】:

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

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

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

【讨论】:

  • 这比仅仅发布“你可以使用数据库来解决你的问题”要好一点。请详细说明。
猜你喜欢
  • 2010-09-25
  • 1970-01-01
  • 2017-12-14
  • 2021-01-08
  • 2012-09-22
  • 1970-01-01
  • 2013-01-04
  • 2017-08-23
  • 2023-03-14
相关资源
最近更新 更多