在Linux中:合并两个非常大的文件

时间:2014-01-15 17:29:18

标签: linux merge bigdata

我想合并两个文件(一个是空格分隔的,另一个是分隔符),只保留两个文件之间匹配的记录:

文件1:空格分隔

A B C D E F G H
s e id_234 4 t 5 7 9
r d id_45 6 h 3 9 10
f w id_56 2 y 7 3 0
s f id_67 2 y 10 3 0

文件2:制表符分隔

I L M N O P
s e 4 u id_67 88
d a 5 d id_33 67
g r 1 o id_45 89

我想将文件1字段3(“C”)与文件2字段5(“O”)匹配,并合并这样的文件:

文件3:制表符分隔

I L M N O P A B D E F G H
s e 4 u id_67 88 s f 2 y 10 3 0
g r 1 o id_45 89 r d 6 h 3 9 10

文件1中的条目没有出现在文件2中,反之亦然,但我只想保留交集(公共ID)。

我并不关心订单。

我宁愿不使用join,因为这些是非常大的未排序文件,并且join需要先按公共字段排序,这需要很长时间和很多内存。

我尝试使用awk但未成功

awk > file3 'NR == FNR {
  f2[$3] = $2; next 
}
$5 in f2 {
 print $0, f2[$2]
}' file2 file1 

有人可以帮帮我吗?

非常感谢

2 个答案:

答案 0 :(得分:2)

嗯..理想情况下,你应该避免使用基于awk的方法所需的n ^ 2解决方案。对于file1中的每个记录,您必须扫描file2以查看是否发生。这就是时间的流逝。

我建议为此编写一个python(或类似)脚本,并为其中一个文件构建一个map id->文件位置,然后在扫描另一个文件时查询该文件。这会让你成为一个nlogn运行时,至少对我来说,这看起来是你在这里做的最好的(使用索引的哈希会让你遇到寻找文件pos的昂贵问题)。

事实上,这是Python脚本:

f1 = file("file1.txt")

f1_index = {}

# Generate index for file1
fpos = f1.tell()
line = f1.readline()
while line:
    id = line.split()[2]
    f1_index[id] = fpos
    fpos = f1.tell()
    line = f1.readline()

# Now scan file2 and output matches
f2 = file("file2.txt")
line = f2.readline()
while line:
    id = line.split()[4]
    if id in f1_index:
        # Found a matching line, seek to file1 pos and read
        # the line back in
        f1.seek(f1_index[id], 0)
        line2 = f1.readline().split()
        del line2[2] # <- Remove the redundant id_XX
        new_line = "\t".join(line.strip().split() + line2)
        print new_line
    line = f2.readline()

答案 1 :(得分:0)

如果对这两个文件进行排序(在你想要匹配的列上)是一种可能性(并且不会以某种方式破坏内容),join可能是一个更好的方法,而不是试图用{{ 1}}或bash。既然你说你不关心顺序,那么这可能是一个合适的方法。

它看起来像这样:

加入-1 3 -2 5 -o'2.1,2.2,2.3,2.4,2.5,2.6,1.1,1.2,1.4,1.5,1.6,1.7,1.8'&lt;(sort -k3,3 file1)&lt ;(sort -k5,5 file2)

我希望有更好的方法告诉它输出哪些列,因为这是很多输入,但这就是它的工作方式。您也可以放弃awk内容,然后使用-o ...或其他内容对输出进行后期处理,以使其符合您想要的顺序......