awkを使用して少ないメモリを使用してファイルを分割する方法

awkを使用して少ないメモリを使用してファイルを分割する方法

gzipを使用して圧縮されたnginxログイン36GBファイルがあります。この小さなファイルをメモリ不足なしで私が書く別のスクリプトの入力として使用できるように、このファイルをより小さなファイルに分割したいと思います。ファイルの最初の列にはIPアドレスが含まれており、特定のIPアドレスからのすべての要求は分割後に同じファイルに存在する必要があります。

現在達成すべきことは次のとおりです。

#!/bin/bash

FILENAME=$1
NUM_FILES=$(($2))
PREFIX=$3

unpigz -c  $FILENAME | awk -v NUM_FILES=$NUM_FILES -v PREFIX=$PREFIX \
'! ($1 in out) {out[$1] = (idx++ %NUM_FILES) } '\
'{ outfile= PREFIX"." out[$1] ".txt"; print | ("pigz >" outfile) ; next} '

すべてが期待どおりに機能しますが、メモリを使いすぎてコンピュータに空き容量が16GBしかないため、xGBより大きいファイルに分割することはできません。

この場合、どういうわけかメモリを無駄にすることができないのだろうか。

ベストアンサー1

今週はユニコーンと虹を追うそうです。私は3つの戦略のスケジュールを開発しました。すべてのタイミングで私の2000万行をユーザーの(推定)80億行と推定していますが、タイミングは私のラップトップとハードドライブによって異なります。タイミングを合わせるためにテストファイルを圧縮しましたが、解凍にはgunzipのみを使用できます。

(A)行でいっぱいの読み出しメモリ(約10GB)をクリックしてからファイルにストリーミングします(一度に1つのファイル)。各IPを別のファイルに入れる必要があるという要件を誤解しました。これには、10 GB のデータごとに約 400,000 個のファイルを追加して閉じる作業が含まれます。私のランニングタイムは120時間。また、管理するファイルが400,000個残ります。これらのどれも良くありません。

(B) 36GBファイル多重処理(圧縮解除時360GB)。この時、私は分離すると500GBのデータ全体を保存するスペースが足りないと誤解しました。

実際、マルチパスコストはそれほど高価ではありません。アイデアは、IPをインデックスにグループ化することです。したがって、8回のパスを実行して、それぞれ100個のファイル、各ファイルに500個のIP、ファイルあたり約1000万行、800個のファイルを作成できます。実行時間は次のようにする必要があります。33時間、マルチパスはマルチファイルの追加よりはるかに高速です。他の利点もあります:

.. 次のグループを開始する前に、グループ内のすべてのファイルを圧縮できるため、ディスク容量が少なくなります。

.. たとえば、システム需要が低いときに夜間に実行するように各グループをスケジュールできます。

..各グループには、障害が発生したときに再起動ポイントがあります。

..グループファイルは、特定のIPを含むファイルを見つけるために使用されるインデックスです。

(C)あなたが言ったように、すべてのものを解凍したコピーを保存するのに十分なディスク容量があり、元のスクリプトも完璧に大丈夫です。、3つのマイナーな修正が行われた。

..プロセス内のすべての出力ファイルを圧縮することはできませんが、GNU並列処理を使用して注意してすべてのファイルに書き込んで後で圧縮できます。

.. awk出力ファイルの数から適切なタイミングを見つけることができます。経験的には、100個の出力ファイル(同じデータ量全体)は80個または120個の出力ファイルよりも高速です。 100を超える方法を分割しようとすると賢明ではない可能性があるため、各ファイルには約8000万のファイルラインと4000のIPを含む100のファイルがあります。

.. 各 IP に対してファイル名を 1 回書き込むのは、毎回書き込むよりもきれいです。

このアプローチの私の見積もりは次のとおりです。24時間

これで、オリジナルは次のようになります。

time gunzip -c ../trial.data.gz | awk '
! ($1 in X) { X[$1] = sprintf ("Prefix_%.4d.dat", q++ % 100); }
{ print > X[$1]; }'

おすすめ記事