【问题标题】:Efficient way to find differences between two large groups in Java在 Java 中查找两个大型组之间差异的有效方法
【发布时间】:2014-01-05 11:53:33
【问题描述】:

就我而言,我需要比较两个大型 HashSet 以使用 removeAll 找到差异。为此,我必须将来自不同数据源的所有数据放入内存,然后进行比较。当每个 HashSet 可能包含超过 300 万条记录时,这会产生内存不足问题。是否有任何方法或库可以减少内存消耗但也能达到相同的结果?

【问题讨论】:

  • 拆分数据或使用延迟初始化
  • 数据源是数据库吗?
  • 数据是如何存储的?如果它被排序(根据一些比较器),它可以使用非常少的内存一次完成。
  • 另一种解决方案:更多内存:D
  • 数据存储在不同的数据库中。我的程序检索数据并将它们放入两个 HashSet 中,这些 HashSet 使用相同的 Java 类进行初始化,例如我的记录。然后它调用HashSet<MyRecord>.removeAll(another HashSet<MyRecord>)

标签: java algorithm memory hashset


【解决方案1】:

您可以先在Set<Integer> 中按不常见的MyRecord.hashCode()s 过滤掉 然后使用Set<MyRecord>

// Determine common hashCodes:

Set<Integer> hashCodes = new HashSet<>();
for (MyRecord record : readFirstTable()) {
    hashCodes.add(record.hashCode();
}

Set<Integer> commonHashCodes = new HashSet<>();
for (MyRecord record : readSecondTable()) {
    int hashCode = record.hashCode();
    if (hashCodes.remove(hashCode)) {
        commonHashCodes.add(hashCode);
    }
}
hashCodes = null;

// Determine common records:

Set<MyRecord> records = new HashSet<>();
for (MyRecord record : readFirstTable()) {
    if (commonHashCodes.contains(record.hashCode()) {
        records.add(record);
    }
}
Set<MyRecord> commonRecords = new HashSet<>();
for (MyRecord record : readSecondTable()) {
    if (records.remove(record) {
        commonRecords.add(record);
    }
}
commonHashCodes = null;
records = null;
return commonRecords;

【讨论】:

    【解决方案2】:

    您需要从您的描述中得到一个用于数据库的哈希联接:What is the difference between a hash join and a merge join (Oracle RDBMS )?

    简而言之,为了减少内存消耗,您可以按哈希值对数据进行分区。非常基本的例子:取一个哈希帧,即两个集合中一些值h1h2之间的哈希值并比较它们。然后在h2h3等之间比较具有哈希值的对象。这些h1h2、...hN可能很容易找到

    h[i] = i * ((long) Integer.MAX_VALUE - Integer.MIN_VALUE) / N; 
    

    或不 - 这取决于数据和您拥有的散列函数。

    此解决方案需要O(DB_SIZE / N) 内存和O(DB_SIZE * N) 记录提取操作。所以在 N = 4 的情况下,这将扫描数据库 4 次并减少 4 次内存消耗。

    【讨论】:

      【解决方案3】:

      请注意,如果数据已排序,您可以在一次通过流式传输数据时执行此操作,使用非常少的额外内存:

      i <- 0
      j <- 0
      while i < list1.size() and j < list2.size():
          if list1[i] == list2[j]:
              i <- i+1
              j <- j+1
          else if list1[i] < list2[j]: //i definetly not in list2
              yield list[i]
              i <- i+1
          else: // j is not in list1
              yield list[j]
              j <- j+1
      yield all elements in list1 from i to list1.size() if there is any
      yield all elements in list2 from j to list2.size() if there is any
      

      使用散列的另一种替代方法只需要加载一个列表(假设这里的数据是集合,如问题中所述,因此不需要重复处理):

      load list1 as hash1
      for each x in list2:
          if x is in hash1:
               hash1.remove(x)
          else:
               yield x
      yield all remaining elements in hash1
      

      请注意,如果一个列表也不适合内存,您可以拆分数据并迭代执行第二种方法。

      【讨论】:

        猜你喜欢
        • 2012-02-08
        • 2022-01-04
        • 2016-09-18
        • 1970-01-01
        • 2014-01-16
        • 1970-01-01
        • 2013-02-26
        • 2014-01-12
        • 2013-01-07
        相关资源
        最近更新 更多