巨大なファイルに対するgreppingのパフォーマンスの向上


10

300,000行を超えるFILE_Aと3,000万行を超えるFILE_Bがあります。FILE_Aの各行をFILE_Bで確認し、grepの結果を新しいファイルに書き込むBashスクリプトを作成しました。

このプロセス全体に5時間以上かかります。

スクリプトのパフォーマンスを向上させるにはどうすればよいですか?

grep -F -m 1grepコマンドとして使用しています。FILE_Aは次のようになります。

123456789 
123455321

FILE_Bは次のようになります。

123456789,123456789,730025400149993,
123455321,123455321,730025400126097,

したがって、Bashではwhile、FILE_Aの次の行を選択して、FILE_Bでそれを調べるループがあります。パターンがFILE_Bで見つかったら、result.txtファイルに書き込みます。

while read -r line; do
   grep -F -m1 $line 30MFile
done < 300KFile

回答:


17

を使用してみてくださいgrep --file==FILE_A。ほとんどの場合、パターンをメモリにロードします。つまり、FILE_Bを1回だけスキャンします。

grep -F -m1 --file==300KFile 30MFile

これは、十分なメモリがあることを前提としてのみ機能しますか?
rogerio_marcio 2012年

正直なところ、私はそのサイズのファイルで自分で試したことはありませんが、速度が劇的に向上するはずです。最新のマシンを使用している場合は、300Kファイルをメモリに保持しても問題はありません。(またはその問題のために30Mのもの)
Gort the Robot

-f(--file)オプションを使用すると、基本的に30MFileが再作成されました。私は何か間違ったことをしていますか?
rogerio_marcio 2012年

うーん... 300Kファイルに空白行があったのでしょうか?
Gort the Robot、2012

その場で!それでおしまい!完璧に機能し、30秒で終了しました。ありがとうございました!!
rogerio_marcio 2012年

2

これが後世のためのPerlの答えです。100万行から30〜35万行に一致させるために、これを定期的に行います。完了するまでに約10秒かかります。

まず、FILE_Aをハッシュ化します。

my %simple_hash;
open my $first_file, '<', 'FILE_A' or die "What have you done?! $!";
while (<$first_file>) {
  chomp;                 ## Watch out for Windows newlines
  $simple_hash{$_} = 1;  ## There may be an even faster way to define this
}
close $first_file;

次に、大きなファイルが区切られていて、その後に続く列がわかっている場合は、FILE_Bを実行するときに、ハッシュキーの存在だけを確認します。これは、等価または正規表現の一致を確認するよりもはるかに高速です。

open my $second_file, '<', 'FILE_B' or die "Oh no, not again.. $!";
while (<$second_file>) {
  my ($col1, undef) = split ',';
  if (exists($simple_hash{$col1}) {
    print $_;
  }
}
close $second_file;

大きなターゲットファイルがうまく解析できない場合、このスクリプトはその値を失います。速度の大部分は、正規表現エンジンを起動する必要がないためです。


1

さらに複雑なプログラミングを気にしない場合は、サフィックスツリー(またはバリアント)の使用を検討してください。

Ukkonenのアルゴリズムを使用して、線形時間で前処理FILE_Bを行うことができます。次に、各行を時間的に線形の長さで線形にクエリし、一致するすべての行番号を取得します(ツリーを少し調整する必要がある場合があります)。これを結果ファイルに書き込むことができます。FILE_A

時間O(N + M)nはの長さである場合における全体の手順の実行FILE_BNの行の数でありFILE_Aそしてmは最長の行の長さでありFILE_A、これは本質的に線形ランタイム-です。元のアプローチに必要な2次時間を大幅に上回ります。


1

私は--mmap最近旗を見つけました、それをテストする機会がありませんでした、しかし私はあなたの調査結果について喜んで聞くでしょう。これはmanページの説明です:

--mmap If  possible, use the mmap(2) system call to read input, instead
      of the default read(2) system call.  In some situations,  --mmap
      yields  better performance.  However, --mmap can cause undefined
      behavior (including core dumps) if an input file  shrinks  while
      grep is operating, or if an I/O error occurs.

の詳細については、こちらまたはこちらをご覧くださいmmap


私は間違いなくこれを試してみるつもりです、そしてそれがどうなるかをあなたに知らせます。コアダンプが発生する可能性はどのくらいありますか?
rogerio_marcio

@rogerio_marcioまあ、私がその男を理解しているように、「grepの動作中にファイルが縮小した場合、またはI / Oエラーが発生した場合」。おそらくそうではないかもしれませんが、これについてもっとよく知っておく必要があります。(grepの実行中にファイルが変更されていない場合-これは発生しないはずです)
Ramzi Kahil

--mmap何もダンプしないテストでは、を使用して実行することと--mmap、使用しないことをお勧めします。次に、を使用wcして、同じ量の出力があることを確認します。これは、grepを2回実行したことと、フラグが異なるだけであることを考えると、堅牢なテストになるはずです。
Ramzi Kahil、2012年

@rogerio_marcioこれを試しましたか?洞察はありますか?
Ramzi Kahil

-1

そのファイルをデータベースに入れてみませんか?データベースのこのような効率的なマージ、ハッシュ、ネストループ結合を実行するのは本当に優れています。そして、彼らは仮想メモリの利用に本当に優れています


他のすべての答えを使ってやっているのは、データベースホイールを再発明することです
Andyz Smith
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.