web-dev-qa-db-ja.com

尾のないgzファイルの最後の行をzgrepする方法

これが私の問題です。大きなgzログファイルのセットがあり、行の最初の情報は日時テキストです(例:2014-03-20 05:32:00)。

特定のデータを保持しているログファイルのセットを確認する必要があります。 initの場合は、次のようにします。

           '-query-data-'
zgrep -m 1 '^20140320-04' 20140320-0{3,4}*gz

しかし、zcatで行うのと同じように、ファイル全体を処理せずに最後の行で同じことを行うには(重い):

zcat foo.gz | tail -1

追加情報、これらのログは最初のレコードのデータ時間で作成されるため、14:00:00でログをクエリしたい場合は、14:00:00より前に作成されたファイルもファイルと同様に検索する必要があります。 13:50:00に作成され、14:10:00に閉じられます。

16
Rodrigo Gurgel

最も簡単な解決策は、ログローテーションを変更して小さなファイルを作成することです。

2番目に簡単な解決策は、ランダムアクセスをサポートする圧縮ツールを使用することです。

dictzip[〜#〜] bgzf [〜#〜] 、および csio のようなプロジェクトは、それぞれ追加 sync flush points = gzip圧縮されたデータ内のさまざまな間隔で、その追加情報を認識しているプログラムでシークできるようにします。標準には存在しますが、Vanilla gzipはデフォルトでもオプションでもこのようなマーカーを追加しません。

これらのランダムアクセス対応のユーティリティで圧縮されたファイルは、マーカー自体のために少し大きい(おそらく2〜20%)が、これらのマーカーを認識しないgzipまたは別のユーティリティでの解凍を完全にサポートします。

さまざまな圧縮形式でのランダムアクセス に関するこの質問で詳細を学ぶことができます。

このトピックに関するいくつかの投稿を含む、Peter Cockによる「Blasted Bioinformatics」ブログもあります。


xzの実験

xz[〜#〜] lzma [〜#〜] 圧縮形式)は実際にはブロックごとのレベルでランダムアクセスをサポートしていますが、デフォルトの単一ブロックのみを取得します。

ファイル作成

xzは複数のアーカイブを連結できます。その場合、各アーカイブには独自のブロックがあります。 GNU split はこれを簡単に行うことができます:

split -b 50M --filter 'xz -c' big.log > big.log.sp.xz

これはsplitbig.logを50MBのチャンク(before圧縮)に分割し、圧縮されたチャンクを標準に出力するxz -cを通じてそれぞれを実行するように指示します出力。次に、その標準出力をbig.log.sp.xzという名前の単一のファイルに収集します。

GNUなしでこれを行うには、ループが必要です。

split -b 50M big.log big.log-part
for p in big.log-part*; do xz -c $p; done > big.log.sp.xz
rm big.log-part*

解析中

xz --verbose --list FILE.xzを使用してブロックオフセットのリストを取得できます。最後のブロックが必要な場合は、その圧縮サイズ(列5)+オーバーヘッド用の36バイトが必要です(サイズをhd big.log.sp0.xz |grep 7zXZと比較するとわかります)。 tail -cを使用してそのブロックをフェッチし、xzを介してパイプします。上記の質問ではファイルの最後の行が必要なので、tail -n1を介してパイプします。

SIZE=$(xz --verbose --list big.log.sp.xz |awk 'END { print $5 + 36 }')
tail -c $SIZE big.log.sp.xz |unxz -c |tail -n1

サイドノート

バージョン5.1.1では、--block-sizeフラグのサポートが導入されました。

xz --block-size=50M big.log

ただし、ブロック間の完全なヘッダーが含まれていないため、特定のブロックを抽出できませんでした。これはコマンドラインから行うのは簡単なことではないかと思います。

gzipの実験

gzipは連結もサポートしています。私は(簡単に)gzipに対してこのプロセスを模倣しようとしましたが、運がありませんでした。 gzip --verbose --listは十分な情報を提供しておらず、ヘッダーが可変であることがわかりません。

これには同期フラッシュポイントを追加する必要があり、それらのサイズは前回の圧縮の最後のバッファーのサイズによって異なるため、コマンドラインで実行するのは困難です(dictzipまたは前述の別のツールを使用します)。

私はapt-get install dictzipをしてdictzipで遊んでみましたが、ほんの少しです。引数なしでは機能せず、dictunzipgunzipも理解できない(大量の).dzアーカイブを作成します。

bzip2の実験

bzip2には、見つけることができるヘッダーがあります。これはまだ少し厄介ですが、動作します。

創作

これは、上記のxzプロシージャと同じです。

split -b 50M --filter 'bzip2 -c' big.log > big.log.sp.bz2

これはかなりxzよりも遅いことに注意してください(bzip2の48分vs xzの17分vs xz -0の1分)。かなり大きい(bzip2の97M対xz -0の25M対xzの15M)、少なくとも私のテストログファイルでは。

解析中

ニースインデックスがないため、これは少し難しいです。どこに行くべきかを推測する必要があり、スキャンのしやすさを誤る必要がありますが、ファイルが大きい場合でも、I/Oを節約できます。

このテストの私の推測は50000000でした(元の52428800のうち、H.264映画などには十分に悲観的ではない悲観的推測です)。

GUESS=50000000
LAST=$(tail -c$GUESS big.log.sp.bz2 \
         |grep -abo 'BZh91AY&SY' |awk -F: 'END { print '$GUESS'-$1 }')
tail -c $LAST big.log.sp.bz2 |bunzip2 -c |tail -n1

これは、最後の5,000万バイトだけを取り、最後のBZIP2ヘッダーのバイナリオフセットを見つけ、それを推測サイズから差し引いて、ファイルの末尾からそのバイト数を引き出します。その部分だけが解凍され、tailにスローされます。

これは圧縮ファイルを2回クエリする必要があり、追加のスキャン(ヘッダーを探すgrep呼び出し、推測された領域全体を調べる)があるため、これは最適ではないソリューションです。 bzip2が実際にどれほど遅いかについては、以下のセクションもご覧ください。

遠近法

xzがどれほど高速であるかを考えると、簡単に最善の策です。最も高速なオプション(xz -0)を使用すると、圧縮または解凍が非常に高速になり、テストしたログファイルにgzipまたはbzip2よりも小さいファイルが作成されます。他のテスト(およびオンラインのさまざまなソース)は、すべてのシナリオでxz -0bzip2よりも望ましいことを示唆しています。

 —————ランダムアクセスなし—————— ———————ランダムアクセス——————— 
フォーマットサイズ比率書き込み読み取りサイズ比率書き込みシーク
 ————————— ————————————————————————————————————— ————————————————————— 
(元の)7211M 1.0000-0:06 7211M 1.0000-0:00 
 bzip2 96M 0.0133 48 :31 3:15 97M 0.0134 47:39 0:00 
 gzip 79M 0.0109 0:59 0:22 
 dictzip 605M 0.0839 1:36(失敗)
 xz -0 25M 0.0034 1:14 0:12 25M 0.0035 1:08 0:00 
 xz 14M 0.0019 16:32 0:11 14M 0.0020 16:44 0:00 

タイミングテストは包括的ではなく、何も平均化せず、ディスクキャッシュが使用されていました。それでも、それらは正しいように見えます。 splitによるオーバーヘッドはごくわずかで、1つではなく145個の圧縮インスタンスを起動します(これはネットゲインの場合もあります)それ以外の場合はマルチスレッド化されていないユーティリティが複数のスレッドを使用できるようにする場合)。

23
Adam Katz

さて、以前に各ファイルにindexを作成した場合、できますgzip圧縮ファイルにランダムにアクセスできます。 。

gzipファイルのインデックスを作成するコマンドラインツールを開発しました。これにより、ファイル内でのランダムアクセスが非常に高速になりますhttps:// github.com/circulosmeos/gztool

このツールには、次の2つのオプションがあります。

  • -Sオプションは、まだ成長しているファイルを監視し、成長するにつれてそのインデックスを作成します-これは、gzipされたrsyslogファイルがゼロになるため、便利です実際には、インデックス作成時。
  • -tgzipファイルの末尾:この方法で実行できます:$ gztool -t foo.gz | tail -1インデックスが存在しない場合、完全な解凍と同じ時間がかかりますが、インデックスが再利用可能であるため、次回の検索にかかる時間が大幅に短縮されることに注意してください。

このツールは 元のzlibのzran.cデモンストレーションコード に基づいているため、ルール外の魔法はありません。

1
circulosmeos