我实际上只是坚持某些事情,需要一些帮助......
我有两个巨大的txt文件(标签分隔符),有这种格式:
文件1:
1 robert youh xpla@ioaio.fr
2 patrick yuad qqqq@ioaio.fr
3 bob fsgfq ddd@ioaio.fr
8 tim qqjh hjahj@uayua.com
9 john ajkajk rtaeraer@auiaui.com
文件2:
1 baby france paris
2 father usa detroit
3 mother uk london
4 baby italy milan
两个文件都已排序,但 File1 大于 File2 。我需要找到 File1 中没有出现在 File2 中的行(根据第一列,所以只有第一列用于比较)。
我尝试了很多方法: - awk:没有找到办法(由于长度不同) - python(用于哪个行语句和fileinput.input ...),我的脚本花了大约5分钟来执行0.3%的行。
结果:我能够使用python(对小文件进行测试)检索正确的结果,但我无法处理我的大文件。
有什么想法可以提供帮助吗?
我的文件大约有两百万行。
答案 0 :(得分:1)
假设 - 正如您所说 - 文件已排序(我没有对其进行测试,但它应该有效)
FILE1_POS = 0
FILE2_POS = 1
MAX_POS = 2
missing = []
get_rec_no = lambda l, f=FILE1_POS: int(l.split(None, MAX_POS)[f])
with open('File1') as source, open('File2') as trgt:
trgt = iter(trgt)
for line in source:
src_rec_no = get_rec_no(line)
try:
trgt_rec_no = get_rec_no(trgt.next(), FILE2_POS)
while trgt_rec_no < src_rec_no:
missing.append(src_rec_no)
trgt_rec_no = get_rec_no(trgt.next(), FILE2_POS)
except StopIteration:
break
for line in source:
missing.append(get_rec_no(line))
修改强>
我改变了你的要求
答案 1 :(得分:1)
如果由于性能而遇到问题,您可能需要考虑使用Hadoop / MapReduce之类的东西将文件拆分成许多较小的文件,然后您可以在不同的处理器上运行每个子进程以实现加速。
作为一个简单的例子,将文件分成两部分,你可以有一个子文件,其中包含[A-M],[M-Z]之间的所有键。这样,如果您知道一个文件中的密钥,您就知道要搜索哪个子文件可能匹配。从理论上讲,如果将文件分成两部分,您将把搜索时间缩短一半(但是,由于涉及开销,因此不完全是一半)。
基本上,编程将涉及编写mapper.py和reducer.py。如果你不熟悉Hadoop / MapReduce,有许多关于在Python中设置MapReduce作业的好教程,但我建议的是名为"Intro to Hadoop and MapReduce"的Udacity课程,它使用Python和MapReduce解决了一些类似的问题。
此外,您可能需要考虑编辑标记以包含Hadoop MapReduce,在这种情况下,您可以获得有关编写mapper.py和reducer.py的更具体的帮助。
答案 2 :(得分:1)
文件长度不同的事实并不排除awk解决方案。拿两个输入:
[ damien $] cat file1
cat: file1: No such file or directory
[ damien $] cat file1.txt
1 robert youh xpla@ioaio.fr
2 patrick yuad qqqq@ioaio.fr
3 bob fsgfq ddd@ioaio.fr
8 tim qqjh hjahj@uayua.com
9 john ajkajk rtaeraer@auiaui.com
[ damien $] cat file2.txt
1 baby france paris
2 father usa detroit
3 mother uk london
4 baby italy milan
[ damien $]
考虑以下脚本:
[ damien $] cat n_join.awk
#!/usr/bin/gawk -f
NR==FNR{
# file2[$1]=$0;
file2[$1]=1;
}
NR!=FNR{
if(!($1 in file2)){
# print current record if not in file2
print ;
}else{
# if $1 from file1 has been found.
# if it's really unique in file1, it
# can be deleted from file2. Otherwise
# comment this line:
delete file2[$1];
}
}
[ damien $]
给出输出:
[ damien $] chmod +x n_join.awk
[ damien $] ./n_join.awk file2.txt file1.txt
8 tim qqjh hjahj@uayua.com
9 john ajkajk rtaeraer@auiaui.com
[ damien $]
请注意,必须首先传递file2.txt。我不知道这是否适用于200万行的文件,但有兴趣知道你是否有时间尝试它。 :)
如果你可以提供文件(不太可能),我会亲自尝试......:D
编辑:我知道你已经接受了你的答案并且可能继续你的生活,但是,我想补充一些额外的信息。如果我创建了两个您指定类型的大文件:file1.bit.txt包含500万条记录:
[ damien $] seq 1 1 5000000 > file1.big.txt
[ damien $] sed -i 's|$| bob fsgfq ddd@ioaio.fr|' file1.big.txt
[ damien $] head file1.big.txt
1 bob fsgfq ddd@ioaio.fr
2 bob fsgfq ddd@ioaio.fr
3 bob fsgfq ddd@ioaio.fr
4 bob fsgfq ddd@ioaio.fr
5 bob fsgfq ddd@ioaio.fr
6 bob fsgfq ddd@ioaio.fr
7 bob fsgfq ddd@ioaio.fr
8 bob fsgfq ddd@ioaio.fr
9 bob fsgfq ddd@ioaio.fr
10 bob fsgfq ddd@ioaio.fr
[ damien $] tail file1.big.txt
4999991 bob fsgfq ddd@ioaio.fr
4999992 bob fsgfq ddd@ioaio.fr
4999993 bob fsgfq ddd@ioaio.fr
4999994 bob fsgfq ddd@ioaio.fr
4999995 bob fsgfq ddd@ioaio.fr
4999996 bob fsgfq ddd@ioaio.fr
4999997 bob fsgfq ddd@ioaio.fr
4999998 bob fsgfq ddd@ioaio.fr
4999999 bob fsgfq ddd@ioaio.fr
5000000 bob fsgfq ddd@ioaio.fr
[ damien $]
[ damien $]
[ damien $]
[ damien $]
和
[ damien $]
[ damien $] seq 2 2 5000000 > file2.big.txt
[ damien $] sed -i 's|$| baby france paris|' file2.big.txt
[ damien $] head file2.big.txt
2 baby france paris
4 baby france paris
6 baby france paris
8 baby france paris
10 baby france paris
12 baby france paris
14 baby france paris
16 baby france paris
18 baby france paris
20 baby france paris
[ damien $] tail file2.big.txt
4999982 baby france paris
4999984 baby france paris
4999986 baby france paris
4999988 baby france paris
4999990 baby france paris
4999992 baby france paris
4999994 baby france paris
4999996 baby france paris
4999998 baby france paris
5000000 baby france paris
[ damien $]
仅使用偶数键。运行我的脚本给出:
[ damien $]
[ damien $] time ./n_join.awk file2.big.txt file1.big.txt > output.big
real 0m4.154s
user 0m3.893s
sys 0m0.207s
[ damien $]
[ damien $] head output.big
1 bob fsgfq ddd@ioaio.fr
3 bob fsgfq ddd@ioaio.fr
5 bob fsgfq ddd@ioaio.fr
7 bob fsgfq ddd@ioaio.fr
9 bob fsgfq ddd@ioaio.fr
11 bob fsgfq ddd@ioaio.fr
13 bob fsgfq ddd@ioaio.fr
15 bob fsgfq ddd@ioaio.fr
17 bob fsgfq ddd@ioaio.fr
19 bob fsgfq ddd@ioaio.fr
[ damien $] tail output.big
4999981 bob fsgfq ddd@ioaio.fr
4999983 bob fsgfq ddd@ioaio.fr
4999985 bob fsgfq ddd@ioaio.fr
4999987 bob fsgfq ddd@ioaio.fr
4999989 bob fsgfq ddd@ioaio.fr
4999991 bob fsgfq ddd@ioaio.fr
4999993 bob fsgfq ddd@ioaio.fr
4999995 bob fsgfq ddd@ioaio.fr
4999997 bob fsgfq ddd@ioaio.fr
4999999 bob fsgfq ddd@ioaio.fr
[ damien $] wc -l output.big
2500000 output.big
[ damien $]
整个事情在大约4秒内完成,这似乎并不令人望而却步。要么数据集存在很大差异,要么您的脚本与我的操作有很大不同。也许这对某人有用。 :/
聚苯乙烯。根据/ proc / cpuinfo
,我有一个i7-3770 CPU @ 3.40GHz答案 3 :(得分:0)
在bash中尝试这个:
join -v 1 -j 1 file1.txt file2.txt
结果是:
8 tim qqjh hjahj@uayua.com
9 john ajkajk rtaeraer@auiaui.com
参数如下:
-j 1
是要加入的字段,即第一个字段
-v 1
表示禁止第一个文件中的行