AWK处理文件需要很长时间

AWK处理文件需要很长时间,awk,Awk,我有一个大约600万条记录的大文件。我需要根据前17个字符将此文件分为更小的文件。因此,前17个字符相同的记录将被分组到具有相同名称的文件中 我用于此操作的命令是: awk -v FIELDWIDTHS="17" '{print > $1".txt"}' $file_name 问题是,这是痛苦的缓慢。对于一个有800K条记录的文件,大约需要一个小时才能完成 样本输入为:- AAAAAAAAAAAAAAAAAAAAAAAAAAAA75838458 AAAAAAAAAAAAAAAAAAA

我有一个大约600万条记录的大文件。我需要根据前17个字符将此文件分为更小的文件。因此,前17个字符相同的记录将被分组到具有相同名称的文件中

我用于此操作的命令是:

awk -v  FIELDWIDTHS="17"  '{print > $1".txt"}' $file_name
问题是,这是痛苦的缓慢。对于一个有800K条记录的文件,大约需要一个小时才能完成

样本输入为:-

AAAAAAAAAAAAAAAAAAAAAAAAAAAA75838458
AAAAAAAAAAAAAAAAAAAAAAAAAAAA48234283
BBBBBBBBBBBBBBBBBBBBBBBBBBBB34723643
AAAAAAAAAAAAAAAAAAAAAAAAAAAA64734987
BBBBBBBBBBBBBBBBBBBBBBBBBBBB18741274
CCCCCCCCCCCCCCCCCCCCCCCCCCCC38123922
这个问题有没有更快的解决方案

我读到perl也可以用来分割文件,但在perl中找不到像fieldwidths这样的选项

任何帮助都将不胜感激

uname:Linux

bash-4.1$ulimit-n
1024

我创建了此表单的测试文件:

% head file
SXXYTTLDCNKRTDIHE00004
QAMKKMCOUHJFSGFFA00001
XGHCCGLVASMIUMVHS00002
MICMHWQSJOKDVGJEO00005
AIDKSTWRVGNMQWCMQ00001
OZQDJAXYWTLXSKAUS00003
XBAUOLWLFVVQSBKKC00005
ULRVFNKZIOWBUGGVL00004
NIXDTLKKNBSUMITOA00003
WVEEALFWNCNLWRAYR00001
% wc -l file
  600000 file
也就是说,有120000个不同的17个字母的前缀,以随机顺序追加
01-05

如果您想要自己的版本,以下是测试脚本:

perl -le 'for (1..120000) {print map { (q(A)..q(Z))[rand(26)] } 1 .. 17} ' | awk '{for (i=1; i<6; i++) printf ("%s%05i\n", $0, i)}' | awk 'BEGIN{srand();} {printf "%06d %s\n", rand()*1000000, $0;}'| sort -n | cut -c8- > /tmp/test/file
大约15分钟后我就放弃了

您可以这样做:

% time awk -v  FIELDWIDTHS="17"  '{of=$1 ".txt"; if (of in seen){ print >>of } else {print >of; seen[of]; } close(of);}' file
您询问了Perl,这里有一个类似的Perl程序,速度非常快:

perl -lne '$p=unpack("A17", $_); if ($seen{$p}) { open(fh, ">>", "$p.txt"); print fh $_;} else { open(fh, ">", "$p.txt"); $seen{$p}++; }close fh' file
下面是一个将Ed的awk与以下内容进行比较的小脚本:

#!/bin/bash

# run this in a clean directory Luke!

perl -le 'for (1..12000) {print map { (q(A)..q(Z))[rand(26)] } 1 .. 17} ' 
| awk '{for (i=1; i<6; i++) printf ("%s%05i\n", $0, i)}' 
| awk 'BEGIN{srand();} {printf "%06d %s\n", rand()*1000000, $0;}'
| sort -n 
| cut -c8- > file.txt

wc -l file.txt

#awk -v  FIELDWIDTHS="17"  '{cnt[$1]++} END{for (e in cnt) print e, cnt[e]}' file
echo "abd awk"
time awk -v  FIELDWIDTHS="17"  '{of=$1 ".txt"; if (of in seen){ print >>of } else {print >of; seen[of]; } close(of);}' file.txt

echo "abd Perl"
time perl -lne '$p=unpack("A17", $_); if ($seen{$p}) { open(fh, ">>", "$p.txt"); print fh $_;} else { open(fh, ">", "$p.txt"); $seen{$p}++; }close fh' file.txt

echo "Ed 1"
time sort file.txt |
awk '{out=substr($0,1,17)".txt"} out != prev{close(prev); prev=out} {print > out}'

echo "Ed 2"
time sort file.txt | awk '{out=substr($0,1,17)".txt"} out != prev{close(prev); prev=out} {print > out}'

echo "Ed 3"
time awk '{print substr($0,1,17)".txt", NR, $0}' file.txt | sort -k1,1 -k2,2n | awk '$1 != prev{close(prev); prev=$1} {print $3 > $1}'
业绩改进包括:

  • 通过不引用任何字段,它允许awk不进行字段拆分
  • 通过先排序并仅在输入的关键部分更改时更改输出文件名,awk一次只使用一个输出文件,而不必管理打开/关闭数千个输出文件
  • 而且它可以移植到所有AWK,因为它不使用特定于gawk的扩展,比如FIELDWIDTHS

    如果每个输出文件中的行在排序后必须保持其原始的相对顺序,则如下所示(假设输入中没有空格,如您提供的示例所示):


    借用@dawg的脚本(
    perl-le'for(1..120000){print map{(q(A)…q(Z))[rand(26)]}1..17}{for(i=1;ii如果所有记录都有唯一的前缀,我认为任何改进都不会对性能产生显著影响。有多少唯一的前缀?它可能更快(与直觉相反)首先根据前缀对文件进行排序,以便一次写入所有前缀文件。由于文件数量太多,您可能还会遇到性能问题……您的脚本生成了多少文件?请将
    ulimit-n
    的输出和操作系统的名称添加到您的问题中。@dawg我们预计大约有5-6条记录共享相同的前缀..所以一个800K的记录文件生成了大约12000个更小的文件files@Cyrus:将uname和ulimit的输出添加到上述问题中。您是否介意共享您为创建测试输入文件而编写的脚本(或根据您的输入测试我答案中的2个脚本并发布结果)?我假设您正在进行第三次运行计时,以消除任何缓存影响。这不是我最漂亮的;-)。但我会补充答案。幸运的是,“漂亮”并不是一次性代码生成临时文件的目标,特别是如果它可以节省我们其他人为自己创建临时文件的时间:-).谢谢!你介意在你的盒子上测试我两个脚本的计时吗?我想在同一个盒子上用相同的输入发布我和你两个脚本的计时,以便进行比较,但在我的笔记本电脑上,你的脚本已经运行了几分钟,因此我失去了尝试更多次以避免缓存问题的意愿。完成。你的更快-)在我的机器上注意:它是一个16核的Mac Pro,在RAID 0中有6个SSD。不一定具有代表性。
    #!/bin/bash
    
    # run this in a clean directory Luke!
    
    perl -le 'for (1..12000) {print map { (q(A)..q(Z))[rand(26)] } 1 .. 17} ' 
    | awk '{for (i=1; i<6; i++) printf ("%s%05i\n", $0, i)}' 
    | awk 'BEGIN{srand();} {printf "%06d %s\n", rand()*1000000, $0;}'
    | sort -n 
    | cut -c8- > file.txt
    
    wc -l file.txt
    
    #awk -v  FIELDWIDTHS="17"  '{cnt[$1]++} END{for (e in cnt) print e, cnt[e]}' file
    echo "abd awk"
    time awk -v  FIELDWIDTHS="17"  '{of=$1 ".txt"; if (of in seen){ print >>of } else {print >of; seen[of]; } close(of);}' file.txt
    
    echo "abd Perl"
    time perl -lne '$p=unpack("A17", $_); if ($seen{$p}) { open(fh, ">>", "$p.txt"); print fh $_;} else { open(fh, ">", "$p.txt"); $seen{$p}++; }close fh' file.txt
    
    echo "Ed 1"
    time sort file.txt |
    awk '{out=substr($0,1,17)".txt"} out != prev{close(prev); prev=out} {print > out}'
    
    echo "Ed 2"
    time sort file.txt | awk '{out=substr($0,1,17)".txt"} out != prev{close(prev); prev=out} {print > out}'
    
    echo "Ed 3"
    time awk '{print substr($0,1,17)".txt", NR, $0}' file.txt | sort -k1,1 -k2,2n | awk '$1 != prev{close(prev); prev=$1} {print $3 > $1}'
    
       60000 file.txt
    abd awk
    
    real    0m3.058s
    user    0m0.329s
    sys 0m2.658s
    abd Perl
    
    real    0m3.091s
    user    0m0.332s
    sys 0m2.600s
    Ed 1
    
    real    0m1.158s
    user    0m0.174s
    sys 0m0.992s
    Ed 2
    
    real    0m1.069s
    user    0m0.175s
    sys 0m0.932s
    Ed 3
    
    real    0m1.174s
    user    0m0.275s
    sys 0m0.946s
    
    sort file |
    awk '{out=substr($0,1,17)".txt"} out != prev{close(prev); prev=out} {print > out}'
    
    awk '{print substr($0,1,17)".txt", NR, $0}' file |
    sort -k1,1 -k2,2n |
    awk '$1 != prev{close(prev); prev=$1} {print $3 > $1}'
    
    $ time sort ../file | awk '{out=substr($0,1,17)".txt"} out != prev{close(prev); prev=out} {print > out}'
    
    real    0m45.709s
    user    0m15.124s
    sys     0m34.090s
    
    $ time awk '{print substr($0,1,17)".txt", NR, $0}' ../file | sort -k1,1 -k2,2n | awk '$1 != prev{close(prev); prev=$1} {print $3 > $1}'
    
    real    0m49.190s
    user    0m11.170s
    sys     0m34.046s
    
    $ time awk -v  FIELDWIDTHS="17"  '{of=$1 ".txt"; if (of in seen){ print >>of } else {print >of; seen[of]; } close(of);}' ../file
    
    real    14m23.473s
    user    0m7.328s
    sys     1m0.296s