
300,000行以上のFILE_Aと30,000行以上のFILE_Bがあります。 FILE_Aの各行をFILE_Bにgrepし、grepの結果を新しいファイルに書き込むbashスクリプトを作成しました。
全体のプロセスは5時間以上かかります。
私のスクリプトのパフォーマンスを向上させる方法があると思うなら、どんな提案でも探しています。
grep コマンドとして grep -F -m 1 を使用します。 FILE_Aは次のとおりです。
123456789
123455321
FILE_Bは次のようになります。
123456789,123456789,730025400149993,
123455321,123455321,730025400126097,
したがって、bashには、FILE_Aで次の行を選択し、FILE_Bでgrepするwhileループがあります。 FILE_Bでパターンを見つけたら、result.txtに書き込みます。
while read -r line; do
grep -F -m1 $line 30MFile
done < 300KFile
ご協力ありがとうございます。
答え1
パフォーマンスの鍵は、大容量ファイルを一度だけ読むことです。
複数のパターンを別々の行に配置して grep に渡すことができます。これは通常、grepにファイルからパターンを読み取るように指示することによって行われます。
grep -F -f 300KFile 30MFile
これにより、大きなファイル全体で一致を順番に出力し、複数のパターンに一致する行のみを一度だけ印刷します。また、これは行のどこでもパターンを探します。たとえば、パターンファイルに含まれている場合と1234
などの行が一致します。123456,345678,2348962342
478912,1211138,1234
前処理パターンにより、正確な列の一致を制限できます。たとえば、パターンに特殊文字が含まれていない場合()?*+\|[]{}
:
<300KFile sed -e 's/^/(^|,)/' -e 's/$/($|,)/' |
grep -E -f - 30MFile
各パターンの最初の一致のみを維持することが重要な場合は、最初のパスを作成して上記の関連行のみを抽出し、awkまたはPerlで2番目のパスを作成してどのパターンが表示されたかを追跡します。
<300KFile sed -e 's/^/(^|,)/' -e 's/$/($|,)/' |
grep -E -f - 30MFile |
perl -l -F, -ape '
BEGIN {
open P, "300KFile" or die;
%patterns = map {chomp; $_=>1} <P>;
close P;
}
foreach $c (@F) {
if ($patterns{$c}) {
print;
delete $patterns{$c};
}
}
'
答え2
次のコマンドを実行できますか?
grep -Ff FILE_A FILE_B > FILE_C
これで、ファイルAとCでのみスクリプトを実行できます。
修正する:ちょっと…順序は維持されますか?
別のアップデート:注文を維持するには追加の処理が必要です。これにより、元のスクリプトと同じ結果が得られます。 FILE_Aの300,000行とFILE_Bの300,000行について、それぞれ125分と14秒間テストされました。
#! /bin/bash
grep -Ff FILE_A FILE_B > FILE_B_TMP
grep -oFf FILE_A FILE_B_TMP > FILE_A_SHUFF
grep -Ff FILE_A_SHUFF FILE_A > FILE_A_TMP
while read -r line; do
grep -F -m1 "$line" FILE_B_TMP
done < FILE_A_TMP > result.txt
答え3
私はcommがより良いパフォーマンスをもたらすことができると信じています。
comm -12 300KFile <(sed 's/,.*//' 30MFile)
注意 300KFile の文字列が123123
30M ファイルの文字列と一致する必要があるかどうかはわかりません。gdwyedg,123123,hfsjdkfh
あなたのスクリプトでは一致しますが、私のスクリプトでは一致しません。
答え4
私はgrepベースのソリューションがまだFILE_AのすべてのレコードをFILE_Bのすべてのレコードと比較する必要があると思います。 FILE_AのN-1個以上のレコードがFILE_Bの特定のレコードと一致しないため、このアプローチには多くの重複があります。一方、ファイルをソートすると、各比較から多くのテストを削除できます。だから何か...
#!/bin/bash
# NB a faster solution would be to sort the smaller file in a seperate process
# you might also want to set a buffer size for large files
sort $1 > /tmp/$$.a
sort $2 > /tmp/$$.b
join -j1 -t',' /tmp/$$.a /tmp/$$.b
rm -f /tmp/$$.?
(未検証)
ただし、FILE_Bの特定のデータ列と一致させたい場合は、項目の順序が変更され、ソートのためにオーバーヘッドが発生しますが、これらのファイルサイズの場合は結果が速くなるはずです。