300,000行を超えるFILE_Aと3,000万行を超えるFILE_Bがあります。 FILE_BでFILE_Aの各行を調べ、grepの結果を新しいファイルに書き込む Bash スクリプトを作成しました。
このプロセス全体に5時間以上かかります。
スクリプトのパフォーマンスを向上させるにはどうすればよいですか?
grep -F -m 1
をgrepコマンドとして使用しています。 FILE_Aは次のようになります。
123456789
123455321
fILE_Bは次のようになります。
123456789,123456789,730025400149993,
123455321,123455321,730025400126097,
したがって、Bashを使用すると、FILE_Aの次の行を選択してFILE_Bでそれを把握するwhile
ループがあります。パターンがFILE_Bで見つかったら、result.txtファイルに書き込みます。
while read -r line; do
grep -F -m1 $line 30MFile
done < 300KFile
grep --file==FILE_A
を使用してみてください。ほとんどの場合、パターンをメモリにロードします。つまり、FILE_Bを1回だけスキャンします。
grep -F -m1 --file==300KFile 30MFile
これが後世のための Perl 答えです。 100万行から3億-3千5百万行を一致させるために、これを定期的に行います。完了するまでに約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;
大きなターゲットファイルがうまく解析できない場合、このスクリプトはその値を失います。速度の大部分は 正規表現 エンジンを起動する必要がないためです。
さらに複雑なプログラミングを気にしない場合は、 suffix trees (またはバリアント)の使用を検討してください。
FILE_B
は、線形時間で kkonenのアルゴリズム を使用して前処理できます。次に、FILE_A
の各行を時間の長さで線形にクエリし、一致するすべての行番号を取得します(ツリーを少し調整する必要がある場合があります)。これを結果ファイルに書き込むことができます。
NがFILE_B
の長さであり、N
がFILE_A
の行数であり、mが最も長い行の長さである場合、プロシージャ全体が時間O(n + Nm)で実行されます。 in FILE_A
-これは基本的に線形ランタイムです。元のアプローチに必要な2次時間を大幅に上回ります。
最近--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.