快速替代grep -f

时间:2012-07-15 06:48:00

标签: perl awk

file.contain.query.txt

ENST001

ENST002

ENST003

file.to.search.in.txt

ENST001  90

ENST002  80

ENST004  50

因为ENST003在第二个文件中没有条目而且ENST004在第一个文件中没有条目,所以预期的输出是:

ENST001 90

ENST002 80

要在特定文件中grep多查询,我们通常会执行以下操作:

grep -f file.contain.query <file.to.search.in >output.file

因为我在file.to.search中有10000个查询和几乎100000个raw.in需要很长时间才能完成(比如5个小时)。是否有快速替代grep -f?

8 个答案:

答案 0 :(得分:11)

如果您需要纯Perl选项,请将查询文件密钥读入哈希表,然后根据这些密钥检查标准输入:

#!/usr/bin/env perl
use strict;
use warnings;

# build hash table of keys
my $keyring;
open KEYS, "< file.contain.query.txt";
while (<KEYS>) {
    chomp $_;
    $keyring->{$_} = 1;
}
close KEYS;

# look up key from each line of standard input
while (<STDIN>) {
    chomp $_;
    my ($key, $value) = split("\t", $_); # assuming search file is tab-delimited; replace delimiter as needed
    if (defined $keyring->{$key}) { print "$_\n"; }
}

你会这样使用它:

lookup.pl < file.to.search.txt

哈希表可以占用大量内存,但搜索速度要快得多(哈希表查找处于恒定时间内),这很方便,因为您查找的密钥比存储密钥多10倍。

答案 1 :(得分:6)

如果您有固定字符串,请使用grep -F -f。这比正则表达式搜索要快得多。

答案 2 :(得分:5)

此Perl代码可以帮助您:

use strict;
open my $file1, "<", "file.contain.query.txt" or die $!;
open my $file2, "<", "file.to.search.in.txt" or die $!;

my %KEYS = ();
# Hash %KEYS marks the filtered keys by "file.contain.query.txt" file

while(my $line=<$file1>) {
    chomp $line;
    $KEYS{$line} = 1;
}

while(my $line=<$file2>) {
    if( $line =~ /(\w+)\s+(\d+)/ ) {
        print "$1 $2\n" if $KEYS{$1};
    }
}

close $file1;
close $file2;

答案 3 :(得分:4)

如果文件已经排序:

join file1 file2

如果不是:

join <(sort file1) <(sort file2)

答案 4 :(得分:4)

如果您使用的是perl版本5.10或更高版本,则可以将“查询”术语加入正则表达式,查询术语由“管道”分隔。 (比如:ENST001|ENST002|ENST003)Perl构建了一个'trie',它像哈希一样,在恒定时间内进行查找。它应该使用查找散列以与解决方案一样快的速度运行。只是为了表明另一种方法。

#!/usr/bin/perl
use strict;
use warnings;
use Inline::Files;

my $query = join "|", map {chomp; $_} <QUERY>;

while (<RAW>) {
    print if /^(?:$query)\s/;
}

__QUERY__
ENST001
ENST002
ENST003
__RAW__
ENST001  90
ENST002  80
ENST004  50

答案 5 :(得分:1)

MySQL的:

将数据导入Mysql或类似内容将提供巨大的改进。这可行吗?你可以在几秒钟内看到结果。

mysql -e 'select search.* from search join contains using (keyword)' > outfile.txt 

# but first you need to create the tables like this (only once off)

create table contains (
   keyword   varchar(255)
   , primary key (keyword)
);

create table search (
   keyword varchar(255)
   ,num bigint
   ,key (keyword)
);

# and load the data in:

load data infile 'file.contain.query.txt' 
    into table contains fields terminated by "add column separator here";
load data infile 'file.to.search.in.txt' 
    into table search fields terminated by "add column separator here";

答案 6 :(得分:0)

use strict;
use warings;

system("sort file.contain.query.txt > qsorted.txt");
system("sort file.to.search.in.txt  > dsorted.txt");

open (QFILE, "<qsorted.txt") or die();
open (DFILE, "<dsorted.txt") or die();


while (my $qline = <QFILE>) {
  my ($queryid) = ($qline =~ /ENST(\d+)/); 
  while (my $dline = <DFILE>) {
    my ($dataid) = ($dline =~ /ENST(\d+)/);
    if ($dataid == $queryid)   { print $qline; }
    elsif ($dataid > $queryid) { break; } 
  }
}

答案 7 :(得分:0)

这可能有点过时,但是是为简单的UNIX实用程序量身定制的。鉴于:

  • 键是固定长度的(这里是7个字符)
  • 文件已排序(在示例中为true),允许使用快速合并排序

然后:

$ sort -m file.contain.query.txt file.to.search.in.txt | tac | uniq -d -w7

ENST002  80

ENST001  90

变量:

要去除键后打印的数字,请删除tac命令:

$ sort -m file.contain.query.txt file.to.search.in.txt | uniq -d -w7

要保持排序顺序,请在末尾添加一个额外的tac命令:

$ sort -m file.contain.query.txt file.to.search.in.txt | tac | uniq -d -w7 | tac