2012-07-15 11 views
10

file.contain.query.txtSzybka alternatywa do grep -f

ENST001 

ENST002 

ENST003 

file.to.search.in.txt

ENST001 90 

ENST002 80 

ENST004 50 

Ponieważ ENST003 nie ma wpisu w 2. pliku i ENST004 ma brak wpisu w 1 pliku oczekiwany wynik to:

ENST001 90 

ENST002 80 

grep wielu rekordów w danym pliku zwykle wykonaj następujące czynności:

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

ponieważ mam 10000 zapytań i prawie 100000 plików raw w file.to.search.in ukończenie trwa bardzo długo (np. 5 godzin). Czy istnieje szybka alternatywa dla grep -f?

+0

Jakie są Twoje potrzeby? czy chcesz plik z liniami drugiego przefiltrowanego kluczami pierwszego? –

+0

Edytowałem oczekiwane wyniki. – user1421408

+1

Przekierowanie wejścia jest niepotrzebne. –

Odpowiedz

10

Jeśli chcesz czystego opcję Perl, odczytać klucze plików zapytanie do tabeli mieszania, a następnie sprawdzić standardowe wejście na tych kluczy:

#!/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"; } 
} 

można by użyć go tak:

lookup.pl < file.to.search.txt 

tabeli mieszania może zająć sporo pamięci, ale są znacznie wyszukiwania szybciej (wyszukiwanie tablic mieszających jest w stałym czasie), co jest przydatne, ponieważ masz 10 razy więcej kluczy do wyszukiwania niż do przechowywania.

+2

To jest Ferrari, gdy porównać z grep -f .. Dzięki – user1421408

+0

Idealne rozwiązanie; +1 –

5

Ten kod może Perl pomaga:

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; 
+0

Twój zapomniał sprawdzić wartość zwracaną przez syscalls. – tchrist

1

MySQL:

Importowanie danych do MySQL lub podobna będzie stanowić ogromną poprawę. Czy to będzie możliwe? Możesz zobaczyć wyniki w kilka sekund.

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"; 
+0

Nie testowałem tego, ale będzie działać z odrobiną poprawek w zależności od twojej sytuacji. Zajmie to bardzo mało pamięci, chyba że chcesz, aby był oparty na pamięci RAM. –

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; } 
    } 
} 
6

Jeśli mają stałe ciągi, użyj grep -F -f. Jest to znacznie szybsze niż wyszukiwanie regex.

5

Jeśli pliki są już posortowane:

join file1 file2 

jeśli nie:

join <(sort file1) <(sort file2) 
4

Jeśli używasz Perl w wersji 5.10 lub nowszej, możesz przyłączyć się do pojęć „zapytań” w wyrażeniu regularnym z terminami zapytania oddzielonymi przez "potok". (Like: ENST001|ENST002|ENST003) Perl buduje "trie", który, jak hash, sprawdza w stałym czasie. Powinien działać tak szybko, jak rozwiązanie, używając skrótu lookup. Wystarczy pokazać inny sposób, aby to zrobić.

#!/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