列の部分文字列に基づいて大容量ファイルの重複行のみを保存する方法は?

列の部分文字列に基づいて大容量ファイルの重複行のみを保存する方法は?

2番目の列に繰り返される部分文字列を含むLinuxシステムに巨大なファイル(約100 Gb)があります。例:

92957ea93f634985;02a2a09322bbbb2d894c;acfb4aa85f577db320d5a0701210238f 62be40ee38d3d62e;1f433e74c9498f051bca;4ad1905e8ff598e9ea5b71c0e48424d9 08356a4e6e5edc25;5d41a09322bbbb2d894c;d92ef5610121033f34dd881b4b910820 c5a2cd0c4e2191e3;83fdc9498f051bcab9e8;5bcb136cfd3326br9d1f52ce7537b901 1e3a1f877316966d;12ff3e74c9498f051bca;a9547b3db00e821bf5e8db900121038e 00c5a857928fbfaf;547b3db00e821b1604eh;11919d5616e4306x4a495118f52c41d4 92ea3e74c9498f04;8faca09322bbbb2d894c;10256a9ff1787f483db00e862119030a

次のような結果が出ると予想されます。

92957ea93f634985;02a2a09322bbbb2d894c;acfb4aa85f577db320d5a0701210238f 62be40ee38d3d62e;1f433e74c9498f051bca;4ad1905e8ff598e9ea5b71c0e48424d9 08356a4e6e5edc25;5d41a09322bbbb2d894c;d92ef5610121033f34dd881b4b910820 1e3a1f877316966d;12ff3e74c9498f051bca;a9547b3db00e821bf5e8db900121038e 92ea3e74c9498f04;8faca09322bbbb2d894c;10256a9ff1787f483db00e862119030a

(行の順序は重要ではありません)

次のコードを使用して小さなテストファイルを作成しました。

awk -F";" '!_[substr($2,5,16)]++' test.csv

ただし、最初の項目のみが表示されるため、すべて保存する必要があります。大容量ファイルなので、メモリにロードするという解決策が利用できないので、上記のコードは良くないと思います。上記で定義したように、列2に同じ部分文字列値を含む行だけを保存するだけで済みますので、よろしくお願いいたします。

編集:間違いをしました。上記のコードは機能しません。無効な区切り文字を入力したため、最初の重複が表示されます。正しい場合は、ファイルの内容全体が表示されます。

ベストアンサー1

アッ

テストする部分文字列が各行の約20%でファイルが100 GBの場合、一般的なawkソリューションには最大20 GBのメモリが必要になることがあります。このソリューションを使用するには、ファイルを2回解析する必要があります(またはすべての行をメモリに保存する必要があり、これはより悪い)。まず、部分文字列を連想配列に保存しながら、発生回数をカウントし、固有の内容ではなく内容を印刷する必要があります。

awk 'FNR==NR{seen[substr($0,22,16)]++; next} seen[substr($0,22,16)] > 1' file file

ただし、お客様の場合、この連想配列がメモリーに収まらない可能性があります。


タイプ

メモリを扱うソリューションの場合は、利用sort可能なメモリのみを使用し、必要に応じて一時ファイルを使用してマージソートします。少し遅いかもしれませんが、メモリが足りなくても実行できます。

LC_ALL=C sort -k1.22,1.37 file | uniq -D -s21 -w16

LC_ALL=CファイルにUTF-8以外のマルチバイト文字が含まれている場合は、その文字を削除できます。そうでない場合は、100 GBの空き領域と必要な権限を持つ場所を指すコマンドにsort別のtmp場所を定義する必要があります。 100GBの空き容量がありません(時にはパーティションが小さくなります)。-T, --temporary-directory=DIR/tmp/

上記のコードはuniq最初の21文字をスキップし、その後の最初の16文字をテストして一意性をテストします。-D重複した行だけが印刷されます。同様に、上記のsortコマンドは各行に対して同じ固定文字範囲をテストします。


重複した部分文字列とawkのみを抽出する

データに基づいてこのソリューションを試してみて、上記のアイデアを組み合わせてメモリに合わせてより速く試してみてください。実際、これはawkメモリに適したソリューションです。このコマンドは次のとおりです。

cut -c22-37 file | sort | uniq -d > subs.txt

ファイル内の指定された固定位置で複数回発生する部分文字列を抽出します。それぞれ一度だけ印刷されますsubs.txt。固有値が除外されたため、 のサイズは、subs.txt最初のソリューションの連想配列サイズよりも小さくなります。

これでsubs.txt、サイズが十分に小さくメモリに収まる場合(繰り返しの頻度によって異なります)、ファイルを一度だけ解析できます。

awk 'FNR==NR{seen[$0]; next} (substr($0,22,16) in seen)' subs.txt file >> output

あるいは、このファイルをN個の部分に分割し、split -l上記のコマンドを使用して実行してファイルをN回解析し、毎回同じ出力ファイルに追加することもできます。大きさに応じsubs.txtて1~2段階で出来れば、全体分類ソリューションよりも早いと思います。

おすすめ記事