2013-01-08 10 views
13

gzipで圧縮された非常に大きなファイルがディスクに置かれています。運用環境は「クラウド」ベースなので、ストレージのパフォーマンスはひどいですが、CPUは問題ありません。以前は、データ処理パイプラインがgzip -dcから始まり、ディスクからデータをストリーミングしていました。gzippedファイルへのランダムアクセス?

作業を並列化するために、それぞれ開始オフセットと終了オフセットのペアを取る複数のパイプラインを実行し、そのファイルのチャンクを取得します。プレーンファイルの場合、これはheadtailで実現できますが、圧縮ファイルで効率的に処理する方法がわかりません。もし私がgzip -dcとパイプheadには、ファイルの終わりに向かっているオフセットのペアはゆっくりと解凍されているので、ファイル全体を無駄に検索することになります。

私の質問は実際にgzipアルゴリズムに関するものです。理論的には、基礎ファイルのバイトオフセットを探したり、任意のチャンクを取得したりできます。ファイル全体を解凍してそのポイントまで解凍することはできますか?そうでなければ、I/Oスループットのオーバーヘッドを最小限に抑えながら、複数のプロセスで「ランダム」なアクセスを効率的にファイルに分割する方法はありますか?

答えて

11

これはgzipではできませんが、ストリームベースではなくブロックであるbzip2で行うことができます。これはHadoop DFSがMapReduce内の異なるマッパーを持つ巨大ファイルの読み込みをどのように分割して並列化するかですアルゴリズム。おそらく、bz2としてファイルを再圧縮すると意味がありますので、これを利用することができます。ファイルをチャンクアップする特別な方法よりも簡単です。

私はここに、Hadoopの中でこれを実装しているパッチを見つけました:ここhttps://issues.apache.org/jira/browse/HADOOP-4012

は、トピックに関する別のポストです:BZip2 file read in Hadoop

はおそらく、Hadoopのソースコードを閲覧することはあなたのbzip2を読み取る方法のアイデアを与えるだろうファイルをブロックごとに表示します。

+0

まず、ブロックを見つけるためにbzip2ファイルを順番に読み取る必要があります。その後、個別にアクセスできます。 gzip形式でも同じことができます。 –

+0

あなたが言及したことは、圧縮ファイルにランダムアクセスするための最良の方法だとは思いません。この記事をご覧ください:http://blastedbio.blogspot.com/2011/11/bgzf-blocked-bigger-better-gzip.htmlまた、Hadoopのこの課題トラッカー:https://issues.apache.org/jira/browse/HADOOP-4012 –

+0

私が答えたように、最適化されたランダムアクセスのためのgzipファイルを用意することができます。ランダムアクセスのアプリケーションの中には、gzipファイルの作成を制御しているものがあります。その場合、その目的のためにgzipファイルを準備し、同時にインデックスを作成します。いくつかのアプリケーションはgzipファイルの作成を制御していません。その場合、インデックスを構築するために一度解凍する必要があります。 –

7

gzip実際には最初からファイルをストリームできることが期待されます。真ん中から始めることはできません。

あなたができることは、ファイルをgzipでピース単位で圧縮してから連結したブロックに分割することです。どの作品でも好きなサイズを選ぶことができます。たとえば、10MBや100MBです。次に、必要なバイトオフセットを含むピースの先頭から開始して圧縮を解除します。 gzipという知られていない機能(いくつかの小さなgzipファイルを連結したファイルを解凍すると、小さなファイルのそれぞれを解凍して結果を連結するのと同じ出力が生成されるため)、区分圧縮された大きなファイルも機能します全体をダウンロードする場合は、標準gzip -d/gunzipとなります。

トリッキーな部分:大きなファイルの各圧縮ピースの先頭のバイトオフセットを含むインデックスを維持する必要があります。

+2

gzipストリームの途中で開始することができます。ただし、最初から一度解凍してエントリポイントを作成している限りです。または、圧縮したときにエントリポイントを作成した場合。 –

+0

これは本当に面白いです、@マークアドラー、チップのおかげで。あなたはインデックスに各アクセスポイントと共に32KiB相当のデータを保存する必要がありますが、アクセスポイント間の距離が大きい場合はおそらく問題ありません。 – Celada

+0

正しい。 gzipファイルの作成を制御している場合は、32Kを必要としない履歴のないエントリポイントを入れることができます。 pigz(並列gzip圧縮プログラム)は-iオプションでこれを行います。 –

18

はい、gzipファイルにアクセスするには、一度全体を一度読み込んでインデックスを作成します。 zlibディストリビューションのexamples/zran.cを参照してください。

gzipファイルの作成を制御している場合は、ランダムアクセスエントリポイントを作成し、圧縮しながらインデックスを構築することで、この目的のためにファイルを最適化できます。

はまた、二つのマーカーを挿入するためにはzlibのdeflate()Z_FULL_FLUSH続いZ_SYNC_FLUSHを使用して、前のデータとは独立して次のブロックを作ることにより、マーカーとgzipファイルを作成することができます。これにより圧縮率は低下しますが、あまり頻繁に圧縮しないと圧縮率が低下します。例えば。 1メガバイトあたりの影響はほとんどありません。次に、9バイトのマーカー(bzip2の6バイトマーカーよりも偽陽性の可能性が低い):00 00 ff ff 00 00 00 ff ffを検索することができます。

+1

zranの使用に関するチュートリアルはありますか?つまり、gzip形式のファイルのインデックスを作成し、続いて私の選択した行番号(または文字番号?)にアクセスするにはどうすればよいですか?私はこれが私が探していた銀色の弾丸だと思う。 –

+1

いいえ、ソースファイルのコメントを超えるものはありません。あなたは 'build_index()'と 'extract()'のコメントを読む必要があり、 'main()'でその使い方の例を見ることができます。 –

+0

また、以下のブログ記事がここで興味深いかもしれません:http://lh3.github.io/2014/07/05/random-access-to-zlib-compressed-files/ – PhiS

関連する問題