非常大的文件之间的Grep模式匹配太慢了

时间:2014-05-21 03:53:31

标签: regex linux grep large-files sequencing

我花了太多时间在这上面,我正在寻找建议。我有太大的文件(来自Illumina测序运行的FASTQ文件,对于那些感兴趣的人)。我需要做的是匹配两个文件之间共同的模式,并将该行和下面的3行打印成两个单独的文件,没有重复(存在于原始文件中)。 Grep这样做很好,但文件大约是18GB,它们之间的匹配非常慢。我需要做的事情的例子如下。

FILEA:

@DLZ38V1_0262:8:1101:1430:2087#ATAGCG/1
NTTTCAGTTAGGGCGTTTGAAAACAGGCACTCCGGCTAGGCTGGTCAAGG
+DLZ38V1_0262:8:1101:1430:2087#ATAGCG/1
BP\cccc^ea^eghffggfhh`bdebgfbffbfae[_ffd_ea[H\_f_c
@DLZ38V1_0262:8:1101:1369:2106#ATAGCG/1
NAGGATTTAAAGCGGCATCTTCGAGATGAAATCAATTTGATGTGATGAGC
+DLZ38V1_0262:8:1101:1369:2106#ATAGCG/1
BP\ccceeggggfiihihhiiiihiiiiiiiiihighiighhiifhhhic
@DLZ38V1_0262:8:2316:21261:100790#ATAGCG/1
TGTTCAAAGCAGGCGTATTGCTCGAATATATTAGCATGGAATAATAGAAT
+DLZ38V1_0262:8:2316:21261:100790#ATAGCG/1
__\^c^ac]ZeaWdPb_e`KbagdefbZb[cebSZIY^cRaacea^[a`c

您可以看到以@开头的3个唯一标题,后跟3个额外的行

FILEB:

@DLZ38V1_0262:8:1101:1430:2087#ATAGCG/2
GAAATCAATGGATTCCTTGGCCAGCCTAGCCGGAGTGCCTGTTTTCAAAC
+DLZ38V1_0262:8:1101:1430:2087#ATAGCG/2
_[_ceeeefffgfdYdffed]e`gdghfhiiihdgcghigffgfdceffh
@DLZ38V1_0262:8:1101:1369:2106#ATAGCG/2
GCCATTCAGTCCGAATTGAGTACAGTGGGACGATGTTTCAAAGGTCTGGC
+DLZ38V1_0262:8:1101:1369:2106#ATAGCG/2
_aaeeeeegggggiiiiihihiiiihgiigfggiighihhihiighhiii
@DLZ38V1_0262:8:1101:1369:2106#ATAGCG/2
GCCATTCAGTCCGAATTGAGTACAGTGGGACGATGTTTCAAAGGTCTGGC
+DLZ38V1_0262:8:1101:1369:2106#ATAGCG/2
_aaeeeeegggggiiiiihihiiiihgiigfggiighihhihiighhiii
@DLZ38V1_0262:8:1101:1369:2106#ATAGCG/2
GCCATTCAGTCCGAATTGAGTACAGTGGGACGATGTTTCAAAGGTCTGGC
+DLZ38V1_0262:8:1101:1369:2106#ATAGCG/2
_aaeeeeegggggiiiiihihiiiihgiigfggiighihhihiighhiii

这里有4个标题,但只有2个是唯一的,因为其中一个重复3次

我需要两个文件之间没有重复的公共标题加上它们下面的3行。每个文件的顺序相同。

这是我到目前为止所拥有的:

grep -E @DLZ38V1.*/ --only-matching FileA | sort -u -o FileA.sorted
grep -E @DLZ38V1.*/ --only-matching FileB | sort -u -o FileB.sorted
comm -12 FileA.sorted FileB.sorted > combined

结合

@DLZ38V1_0262:8:1101:1369:2106#ATAGCG/
@DLZ38V1_0262:8:1101:1430:2087#ATAGCG/

这只是两个文件之间的公共标题,没有重复。这就是我要的。 现在我需要将这些标题与原始文件匹配,然后抓住它们下面的3行但只有一行。

如果我使用grep,我可以得到我想要的每个文件

while read -r line; do
   grep -A3 -m1 -F $line FileA
done < combined > FileA.Final

FileA.Final

@DLZ38V1_0262:8:1101:1369:2106#ATAGCG/1
NAGGATTTAAAGCGGCATCTTCGAGATGAAATCAATTTGATGTGATGAGC
+DLZ38V1_0262:8:1101:1369:2106#ATAGCG/1
BP\ccceeggggfiihihhiiiihiiiiiiiiihighiighhiifhhhic
@DLZ38V1_0262:8:1101:1430:2087#ATAGCG/1
NTTTCAGTTAGGGCGTTTGAAAACAGGCACTCCGGCTAGGCTGGTCAAGG
+DLZ38V1_0262:8:1101:1430:2087#ATAGCG/1
BP\cccc^ea^eghffggfhh`bdebgfbffbfae[_ffd_ea[H\_f_c

重复while循环以生成 FileB.Final

@DLZ38V1_0262:8:1101:1369:2106#ATAGCG/2
GCCATTCAGTCCGAATTGAGTACAGTGGGACGATGTTTCAAAGGTCTGGC
+DLZ38V1_0262:8:1101:1369:2106#ATAGCG/2
_aaeeeeegggggiiiiihihiiiihgiigfggiighihhihiighhiii
@DLZ38V1_0262:8:1101:1430:2087#ATAGCG/2
GAAATCAATGGATTCCTTGGCCAGCCTAGCCGGAGTGCCTGTTTTCAAAC
+DLZ38V1_0262:8:1101:1430:2087#ATAGCG/2 

这可行,但FileA和FileB大约为18GB,我的组合文件大约为2GB。有没有人对如何大幅加快最后一步提出任何建议?

2 个答案:

答案 0 :(得分:1)

取决于您需要多长时间运行一次:

  1. 您可以将您的数据转储(您可能希望随后构建索引的批量插入)到Postgres(sqlite?)数据库中,在其上构建索引,并享受40年研究成果高效实施关系数据库,几乎没有您的投资。

  2. 你可以通过使用unix实用程序'join'来模仿关系数据库,但是没有太多的乐趣,因为它不会给你一个索引,但它可能比' grep',你可能遇到了物理限制......我从未试图加入两个18G文件。

  3. 你可以写一些C代码(把你最喜欢的编译(到机器代码)语言放在这里),它将你的字符串(只有四个字母,对吧?)转换为二进制并构建一个索引(或更多)基于它。由于你的五十个字符串只占用两个64位字,因此闪存速度快,占用内存小。

答案 1 :(得分:1)

我想我应该发布我想出的修复方法。一旦我获得了组合文件(上面),我使用perl哈希引用将它们读入内存和扫描文件A.文件A中的匹配被哈希并用于扫描文件B.这仍然需要大量内存但工作速度非常快。从grep的20多天到~20分钟。