Быстрая альтернатива grep -f
file.contain.query.txt
ENST001
ENST002
ENST003
file.to.search.in.txt
ENST001 90
ENST002 80
ENST004 50
Поскольку ENST003 не имеет записи во втором файле, а ENST004 не имеет записи в 1-м файле, ожидаемый результат:
ENST001 90
ENST002 80
Чтобы выполнить grep-запрос в конкретном файле, мы обычно делаем следующее:
grep -f file.contain.query <file.to.search.in >output.file
так как у меня есть 10000 запросов и почти 100000 raw в файле .to.search.in, это занимает очень много времени (например, 5 часов). Есть ли быстрая альтернатива grep -f?
Ответы
Ответ 1
Если вам нужен чистый параметр 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 раз больше ключей для поиска, чем для хранения.
Ответ 2
Если у вас есть фиксированные строки, используйте grep -F -f
. Это значительно быстрее, чем поиск в регулярном выражении.
Ответ 3
Этот код 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;
Ответ 4
Если файлы уже отсортированы:
join file1 file2
если нет:
join <(sort file1) <(sort file2)
Ответ 5
Если вы используете 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
Ответ 6
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";
Ответ 7
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; }
}
}