【问题标题】:Comparing two text large files with URLs in Java with external memory only?仅将两个文本大文件与 Java 中的 URL 与外部存储器进行比较?
【发布时间】:2018-12-03 17:39:57
【问题描述】:

我有以下场景:

  • url文本文件A
  • url文本文件B

每个文件的大小约为 4Gb。

我需要计算:

  • A 中所有不在 B 中的 url
  • B中所有不在A中的url

我在网上找到的所有 Java-diff 示例都将整个列表加载到内存中(使用 Map 或使用 MMap 解决方案)。我的系统没有交换空间,而且没有外部内存就无法做到这一点。

有没有人知道这个问题的解决方案?

这个项目可以在不占用大量内存的情况下进行大型文件排序https://github.com/lemire/externalsortinginjava

我正在寻找类似的东西,但用于生成差异。我将首先尝试使用该项目作为基线来实现这一点。

【问题讨论】:

  • BufferedReader ?它们是文件中的许多“url”还是许多文本和一些url? => 将所有 URL 加载到内存中是一种解决方案吗?
  • 嗨。不幸的是,没有。我已经尝试过了,但我的云虚拟机太小,无法处理内存解决方案或任何内存映射。它只需要是外部存储器
  • 从你描述的方式来看,你必须做大量的传球。
  • 我上面提到的java项目中的外部排序能够以几秒钟的方式对这些文件进行排序。所以我认为一旦我提出算法,它就不会太可怕了。
  • 每个文本文件中的所有 URL 是否都是唯一的?如果不是,每个文件中唯一 URL 的大小是多少?

标签: java sorting diff


【解决方案1】:

如果系统有足够的存储空间,您可以通过 DB 执行此操作。例如:

创建一个 H2 或 sqlite DB(数据存储在磁盘上,分配尽可能多的 系统负担得起的缓存) 在表 A 和 B 中加载文本文件(在 'url' 列上创建索引)

select url from A where URL not in (select distinct url from B)
select url from B where URL not in (select distinct url from A)

【讨论】:

  • 我可以试试。
  • 查询只是一个例子,看看执行计划是否可以优化查询
  • 在不完全杀死机器的情况下甚至无法将数据加载到表中。
  • 它是哪个数据库(H2 还是 sqlite?)
  • 正在使用 h2 的 csvload。很坏。可以试试sqlite
【解决方案2】:

这是我提出的解决方案的要点:https://gist.github.com/nddipiazza/16cb2a0d23ee60a07121893c26065de4

import com.google.common.collect.Sets;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;

import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

public class DiffTextFilesUtil {
  static public int CHUNK_SIZE = 100000;

  static public class DiffResult {
    public Set<String> addedVals = new HashSet<>();
    public Set<String> removedVals = new HashSet<>();
  }

  /**
   * Gets diff result of two sorted files with each other.
   * @param lhs left hand file - sort this using com.google.code.externalsortinginjava:externalsortinginjava:0.2.5
   * @param rhs right hand file - sort this using com.google.code.externalsortinginjava:externalsortinginjava:0.2.5
   * @return DiffResult.addedVals were added from lhs to rhs. DiffResult.removedVals were removed from lhs to rhs.
   * @throws IOException
   */
  public static DiffResult diff(File lhs, File rhs) throws IOException {

    DiffResult diffResult = new DiffResult();

    LineIterator lhsIter = FileUtils.lineIterator(lhs);
    LineIterator rhsIter = FileUtils.lineIterator(rhs);

    String lhsTop = null;
    String rhsTop = null;
    while (lhsIter.hasNext()) {
      int ct = CHUNK_SIZE;

      Set<String> setLhs = Sets.newHashSet();
      Set<String> setRhs = Sets.newHashSet();
      while (lhsIter.hasNext() && --ct > 0) {
        lhsTop = lhsIter.nextLine();
        setLhs.add(lhsTop);
      }
      while (rhsIter.hasNext()) {
        if (rhsTop != null && rhsTop.compareTo(lhsTop) > 0) {
          break;
        } else if (rhsTop != null && rhsTop.compareTo(lhsTop) == 0) {
          setRhs.add(rhsTop);
          rhsTop = null;
          break;
        } else if (rhsTop != null) {
          setRhs.add(rhsTop);
        }
        rhsTop = rhsIter.next();
      }
      if (rhsTop != null) {
        setRhs.add(rhsTop);
      }
      Sets.difference(setLhs, setRhs).copyInto(diffResult.removedVals);
      Sets.difference(setRhs, setLhs).copyInto(diffResult.addedVals);
    }
    return diffResult;
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-03
    • 2016-04-07
    • 1970-01-01
    • 1970-01-01
    • 2020-01-28
    • 2017-07-14
    相关资源
    最近更新 更多