比较一个大约 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
上执行大量与此类似的操作,那么可能值得研究一个与数据库相关的解决方案。
任何命令行解决方案(bash
、awk
、perl
等)都需要执行相当于 [=15 的(数据库)table 扫描=] 每次处理都是运行;使用数据库,您可以构建一次持久性索引并根据需要经常重复使用它。
由于文件未排序,因此每次比较都是独立的
你有一个交叉连接,这是蛮力而且非常昂贵
这也意味着您可以按照自己喜欢的方式(整行)自由拆分文件以适合您的记忆,并在完成后合并结果。
如果小文件行是(或可以是)精确匹配大文件的开头(即删除第三列)你可以取消多字符串匹配并使用一个与 fgrep 或类似(包括分隔符)完全匹配的字符串
我认为任何更有效的方法都必须提前进行一些排序。
我需要比较两个文件;一个超过 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
上执行大量与此类似的操作,那么可能值得研究一个与数据库相关的解决方案。
任何命令行解决方案(bash
、awk
、perl
等)都需要执行相当于 [=15 的(数据库)table 扫描=] 每次处理都是运行;使用数据库,您可以构建一次持久性索引并根据需要经常重复使用它。
由于文件未排序,因此每次比较都是独立的 你有一个交叉连接,这是蛮力而且非常昂贵 这也意味着您可以按照自己喜欢的方式(整行)自由拆分文件以适合您的记忆,并在完成后合并结果。
如果小文件行是(或可以是)精确匹配大文件的开头(即删除第三列)你可以取消多字符串匹配并使用一个与 fgrep 或类似(包括分隔符)完全匹配的字符串
我认为任何更有效的方法都必须提前进行一些排序。