7

パターンの長いリスト(10,000)に一致させるために、-fを指定してテキストファイルでgrepを使用したいと思います。grepはこれを気に入らないことがわかりました(誰が知っていましたか?)。1日後、何も生成されませんでした。小さいリストはほぼ瞬時に機能します。

長いリストを分割して数回やろうと思っていました。パターンリストの適切な最大長はどれくらいか考えてみてください。

また、私はUNIXにかなり慣れていません。別のアプローチを歓迎します。パターンまたは検索語のリストは、1行に1つずつプレーンテキストファイルにあります。

皆様のご指導ありがとうございました。

4

5 に答える 5

8

コメントから、一致しているパターンは固定文字列であるように見えます。その場合は、間違いなくを使用する必要があります-F。これにより、マッチングの速度が大幅に向上します。(479,000文字列を使用して、3行の入力ファイルで一致させる-Fには、中程度の電力のマシンで1.5秒未満かかります。使用しない場合-F、同じマシンは数分後にまだ完成していません。)

于 2013-01-21T14:15:32.713 に答える
6

私は約で同じ問題を抱えています。900万行のファイルで検索する400万のパターン。RAMの問題のようです。だから私はこのきちんとした小さな回避策を手に入れました。これは分割して結合するよりも遅いかもしれませんが、この1行が必要です。

 while read line; do grep $line fileToSearchIn;done < patternFile

-Fフラグはその大きなファイルの解決策ではないため、回避策を使用する必要がありました...

編集:これは大きなファイルの場合は本当に遅いようです。さらに調査した結果、「faSomeRecords」とケントNGSの本当に他の素晴らしいツールを見つけました-編集-ツール

550万のレコードファイルから200万のfasta-recを抽出して、自分で試してみました。約かかりました。30秒。

乾杯

編集:直接ダウンロードリンク

于 2013-10-24T12:45:51.467 に答える
1

これは、ファイル(または必要に応じてファイルのサブセット)で実行できるbashスクリプトです。キーファイルをますます大きなブロックに分割し、ブロックごとにgrep操作を試行します。操作のタイミングは調整されています。現在、各grep操作のタイミングと、すべてのサブ式を処理する合計時間です。出力は数秒です-多少の努力でmsを取得できますが、問題が発生しているため、その粒度が必要になる可能性はほとんどありません。次の形式のコマンドを使用して、ターミナルウィンドウでスクリプトを実行します

./timeScript keyFile textFile 100 > outputFile

これにより、検索キーが保存されるファイルとしてkeyFile、キーを検索するファイルとしてtextFile、初期ブロックサイズとして100を使用して、スクリプトが実行されます。各ループで、ブロックサイズは2倍になります。

2番目の端末で、コマンドを実行します

tail -f outputFile

これにより、他のプロセスの出力がファイルに記録されます。outputFile

3番目のターミナルウィンドウを開き、そのウィンドウで実行することをお勧めしtopます。プロセスが使用しているメモリとCPUの量を確認できます。繰り返しになりますが、大量のメモリが消費されている場合は、状況がうまくいかないというヒントが得られます。

これにより、物事がいつ減速し始めるかを知ることができるはずです-これがあなたの質問への答えです。「マジックナンバー」はないと思います。おそらくマシン、特にファイルサイズとメモリの量によって異なります。

スクリプトの出力を取得して、grepに通すことができます。

grep entire outputFile

最終的には要約だけになります-ブロックサイズと所要時間、例:

Time for processing entire file with blocksize 800: 4 seconds

これらの数値を相互にプロットする(または単に数値を調べる)と、アルゴリズムが最適な場合と速度が低下する場合がわかります。

コードは次のとおりです。大規模なエラーチェックは行いませんでしたが、うまくいったようです。明らかに、最終的なソリューションでは、grepの出力を使用して何かを行う必要があります(wc -l一致する行の数を確認するために行ったパイプの代わりに)...

#!/bin/bash
# script to look at difference in timing
# when grepping a file with a large number of expressions
# assume first argument = name of file with list of expressions
# second argument = name of file to check
# optional third argument = initial block size (default 100)
#
# split f1 into chunks of 1, 2, 4, 8... expressions at a time
# and print out how long it took to process all the lines in f2

if (($# < 2 )); then
  echo Warning: need at leasttwo parameters.
  echo Usage: timeScript keyFile searchFile [initial blocksize]
  exit 0
fi

f1_linecount=`cat $1 | wc -l`
echo linecount of file1 is $f1_linecount

f2_linecount=`cat $2 | wc -l`
echo linecount of file2 is $f2_linecount
echo

if (($# < 3 )); then
  blockLength=100
else
  blockLength=$3
fi

while (($blockLength < f1_linecount))
do
  echo Using blocks of $blockLength
  #split is a built in command that splits the file
  # -l tells it to break after $blockLength lines
  # and the block$blockLength parameter is a prefix for the file
  split -l $blockLength $1 block$blockLength
  Tstart="$(date +%s)"
  Tbefore=$Tstart

  for fn in block*
    do
      echo "grep -f $fn $2 | wc -l"
      echo number of lines matched: `grep -f $fn $2 | wc -l`
      Tnow="$(($(date +%s)))"
      echo Time taken: $(($Tnow - $Tbefore)) s
      Tbefore=$Tnow
    done
  echo Time for processing entire file with blocksize $blockLength: $(($Tnow - $Tstart)) seconds
  blockLength=$((2*$blockLength))
  # remove the split files - no longer needed
  rm block*
  echo block length is now $blockLength and f1 linecount is $f1_linecount
done

exit 0
于 2013-01-20T23:32:46.297 に答える
0

確かにsedに、より良い結果が得られるかどうかを試してみることができますが、任意のサイズのファイルに対してどちらの方法でも実行するのは大変な作業です。問題の詳細は提供されていませんが、10kのパターンがある場合は、それらを少数の正規表現に一般化する方法があるかどうかを考えようとしています。

于 2013-01-20T23:51:33.930 に答える
0

これは、「多数のキーと多数のレコード」の問題の非常に一般的なサブセットに対処するperlスクリプト「match_many.pl」です。キーは、stdinから1行に1つずつ受け入れられます。2つのコマンドラインパラメータは、検索するファイルの名前と、キーと一致する必要があるフィールド(空白で区切られた)です。レコード内の一致の場所(存在する場合)が事前にわかっており、キーは常にレコード内のフィールド全体に対応しているため、元の問題のこのサブセットは迅速に解決できます。1つの典型的なケースでは、42899キーで9400265レコードを検索し、キーの42401と一致し、41秒で1831944レコードを発行しました。キーがレコードの任意の部分にサブストリングとして表示される可能性がある、より一般的なケースは、このスクリプトでは対処できない、より難しい問題です。

#!/usr/bin/perl -w
use strict;
use warnings;
my $kcount;
my ($infile,$test_field) = @ARGV;
if(!defined($infile) || "$infile" eq "" || !defined($test_field) || ($test_field <= 0)){
  die "syntax: match_many.pl infile field" 
}
my %keys;       # hash of keys
$test_field--;  # external range (1,N) to internal range (0,N-1)

$kcount=0;
while(<STDIN>) {
   my $line = $_;
   chomp($line);
   $keys {$line} = 1;
   $kcount++
}
print STDERR "keys read: $kcount\n";

my $records = 0;
my $emitted = 0;
open(INFILE, $infile )  or die "Could not open $infile";
while(<INFILE>) {
   if(substr($_,0,1) =~ /#/){ #skip comment lines
     next;
   }
   my $line = $_;
   chomp($line);
   $line =~ s/^\s+//;
   my @fields = split(/\s+/, $line);
   if(exists($keys{$fields[$test_field]})){
      print STDOUT "$line\n";
      $emitted++;
      $keys{$fields[$test_field]}++;
   }
   $records++;
}

$kcount=0;
while( my( $key, $value ) = each %keys ){
   if($value > 1){ 
      $kcount++; 
   }
}

close(INFILE);
print STDERR "records read: $records, emitted: $emitted; keys matched: $kcount\n";

exit;
于 2016-11-04T18:51:46.903 に答える