仅将两个文本大文件与 Java 中的 URL 与外部存储器进行比较?

Posted

技术标签:

【中文标题】仅将两个文本大文件与 Java 中的 URL 与外部存储器进行比较?【英文标题】:Comparing two text large files with URLs in Java with external memory only? 【发布时间】: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 的大小是多少? 【参考方案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;
  

【讨论】:

以上是关于仅将两个文本大文件与 Java 中的 URL 与外部存储器进行比较?的主要内容,如果未能解决你的问题,请参考以下文章

如何仅将URL中的%20更改为hypen(-)

内连接与外连接

SQL内连接与外连接的区别

内连接与外连接-及其典型案例

如何仅将字母字符扫描到 C 中的数组中?

比较两个文本文件 - 并将差异保存到新文件