比较一个大约 100 亿行的文件和另一个 400 万行的文件

Compare a file with ~10 billion lines with another with 4 million lines

我需要比较两个文件;一个超过 100 亿行,其他超过 400 万行。我用以下命令尝试了 awk;但由于内存问题而终止。还有其他聪明的方法可以做到这一点吗?

awk 'FNR==NR{a[,,,]=1; next}a[,,,]' File1.txt File2.txt

谢谢

编辑:测试文件

文件1

1   16800236    16800237    A   G
12  104524484   104524485   C   T

文件2

1   16800235    A   C   -0.092665
1   16800235    A   G   -0.070122
1   16800235    A   T   -0.085638
1   16800236    A   C   -0.093024
1   16800236    A   G   -0.070481
1   16800236    A   T   -0.085997
1   16800237    A   C   -0.093024
1   16800237    A   G   -0.070481
1   16800237    A   T   -0.085997
12  104524483   T   A   0.074230 
12  104524483   T   C   0.090521 
12  104524483   T   G   0.066109 
12  104524484   C   A   0.014942 
12  104524484   C   G   0.004392 
12  104524484   C   T   0.063112 
12  104524485   A   C   0.264035 
12  104524485   A   G   0.286578 
12  104524485   A   T   0.271062 

我估计在 400 万行时 File1.txt 将需要几百兆字节的内存(用于 awk 数组存储),这对于过去十年中制造的任何计算机都是可行的。

这使得 File2.txt 成为 内存不足 问题的潜在罪魁祸首。 [我估计超过 10.5 亿行 File2.txt 的大小约为 450 GBytes]

OP awk 脚本的第二部分对 File2.txt 中的每一行应用以下内容:

a[,,,]

虽然目的是测试此数组条目是否存在且值 > 0,但在 awk 中,这将 创建数组条目,对于超过 105 亿行 table,很容易在所有台式机和中小型工作站中出现 内存不足 错误。

OP 真正应该做的是测试 File2.txt 字段是否作为索引存在于 awk 数组中,如下所示:

(,,,) in a

这应该将内存使用量限制为将 File1.txt 加载到 awk 数组所需的内存。

将其滚动到 OP 的当前代码中,我们得到:

awk 'FNR==NR{a[,,,]=1; next} (,,,) in a' File1.txt File2.txt

如果 OP 需要在 File2.txt 上执行大量与此类似的操作,那么可能值得研究一个与数据库相关的解决方案。

任何命令行解决方案(bashawkperl 等)都需要执行相当于 [=15 的(数据库)table 扫描=] 每次处理都是运行;使用数据库,您可以构建一次持久性索引并根据需要经常重复使用它。

由于文件未排序,因此每次比较都是独立的 你有一个交叉连接,这是蛮力而且非常昂贵 这也意味着您可以按照自己喜欢的方式(整行)自由拆分文件以适合您的记忆,并在完成后合并结果。

如果小文件行是(或可以是)精确匹配大文件的开头(即删除第三列)你可以取消多字符串匹配并使用一个与 fgrep 或类似(包括分隔符)完全匹配的字符串

我认为任何更有效的方法都必须提前进行一些排序。