これは 前の質問 に似ていますが、その答えは私のニーズを満たしておらず、私の質問は少し異なります。
現在、並べ替えられたデータを含む非常に大きなファイルにgzip圧縮を使用しています。ファイルが圧縮されていない場合、バイナリ検索は、ソートされたデータ内の場所へのシークをサポートするための便利で効率的な方法です。
しかし、ファイルが圧縮されると、事態は複雑になります。私は最近 zlib の_Z_FULL_FLUSH
_オプションについて知りました。これは圧縮中に「同期ポイント」を圧縮出力に挿入するために使用できます(inflateSync()
は読み取りを開始できますファイルのさまざまなポイントから)。これは問題ありませんが、この機能を追加するには、すでに持っているファイルを再圧縮する必要があります(そして、奇妙なことに、gzip
にはこのオプションがありませんが、必要に応じて、独自の圧縮プログラムを作成するつもりです)。
1つのソース から、_Z_FULL_FLUSH
_でさえ完全なソリューションではないようです...すべてのgzipアーカイブでサポートされているだけでなく、アーカイブ内の同期ポイントを検出するという非常にアイデアが生み出す可能性があります誤検知(同期点のマジックナンバーとの一致、または_Z_SYNC_FLUSH
_も同期点を生成するがランダムアクセスには使用できないという事実による)。
より良い解決策はありますか?可能であれば、インデックス作成用の補助ファイルを避け、準ランダムアクセスの明示的でデフォルトのサポートを有効にしたいと思います(10 MB間隔で読み取りを開始できるなど、粒度が粗い場合でも)。 gzipよりもランダム読み取りをサポートする別の圧縮形式はありますか?
編集:前述のように、圧縮データでバイナリ検索を実行したいと思います。特定の(圧縮されていない)位置にシークする必要はありません。圧縮されたファイル内で粗い粒度でシークするだけです。 「この圧縮ファイルへの道の約50%(25%、12.5%など)からデータを解凍する」のようなもののサポートが欲しいだけです。
非圧縮データの特定の場所へのランダムアクセスをサポートする圧縮ファイル形式(マルチメディア形式を除く)はわかりませんが、独自に作成することはできます。
たとえば、bzip2圧縮ファイルは、サイズが1MB未満の非圧縮の独立した圧縮ブロックで構成されており、マジックバイトのシーケンスで区切られているため、bzip2ファイルを解析してブロック境界を取得し、適切なブロックを圧縮解除できます。これには、ブロックがどこから始まるのかを覚えておくためのインデックスが必要です。
それでも、最善の解決策は、ファイルを任意のチャンクに分割し、アーカイブ内の個々のファイルへのランダムアクセスをサポートするZipやrarなどのアーカイバーで圧縮することです。
dictzipを見てください。 gzipと互換性があり、粗いランダムアクセスが可能です。
Manページからの抜粋:
dictzipは、gzip(1)アルゴリズム(LZ77)を使用してファイルを圧縮しますgzipファイル形式と完全に互換性のある方法。 gzipファイル形式の拡張(RFC 1952の2.3.1.1で説明されている追加フィールド)により、圧縮ファイルのヘッダーに追加のデータを格納できます。 gzipやzcatなどのプログラムは、この余分なデータを無視します。ただし、[dictzcat --start]はこのデータを使用して、ファイルに擬似ランダムアクセスを実行します。
Ubuntuにdictzipパッケージがあります。または、そのソースコードは dictd-*。tar.gz にあります。ライセンスはGPLです。あなたはそれを自由に研究できます。
ファイルサイズの制限がないようにdictzipを改善しました。 私の実装 はMITライセンスの下にあります。
。xzファイル形式 (LZMA圧縮を使用)はこれをサポートしているようです:
ランダムアクセス読み取り:データを個別に圧縮されたブロックに分割できます。すべての.xzファイルにはブロックのインデックスが含まれているため、ブロックサイズが十分に小さい場合にランダムアクセスの読み取りを制限できます。
これで十分です。欠点は、liblzmaのAPI(これらのコンテナーと対話するため)が十分に文書化されていないように見えるため、ブロックにランダムにアクセスする方法を理解するのに多少の労力を要する場合があります。
Gzipおよびbzip2アーカイブへのランダムアクセスを提供するソリューションが存在します。
bgzip
は、インデックス付け可能なgzip
バリアントでファイルを圧縮できます(gzip
で解凍できます)。これは、tabix
インデクサーと一緒に、いくつかのバイオインフォマティクスアプリケーションで使用されます。
ここで説明を参照してください: http://blastedbio.blogspot.fr/2011/11/bgzf-blocked-bigger-better-gzip.html 、およびここ: http:// www。 htslib.org/doc/tabix.html 。
それが他のアプリケーションにどの程度適応できるかわかりません。
ロスレス圧縮は一部の領域で他の領域よりも適切に機能するため、各ブロックの圧縮バイト数がまったく同じでも、圧縮データを便利な長さのBLOCKSIZEのブロックに格納すると、一部の圧縮ブロックは他よりもはるかに長いプレーンテキストに展開されます。
Computerマガジン11月号のNivio Ziviani、Edleno Silva de Moura、Gonzalo Navarro、Ricardo Baeza-Yatesによる「圧縮:次世代テキスト検索システムの鍵」をご覧ください。 2000 http://doi.ieeecomputersociety.org/10.1109/2.88169
それらの圧縮解除プログラムは、1、2、または3バイトの圧縮データを受け取り、(語彙リストを使用して)Word全体に圧縮解除します。圧縮されたテキストから直接単語や語句を検索できます。これは、圧縮されていないテキストを検索するよりもはるかに高速であることがわかります。
それらの圧縮解除プログラムを使用すると、通常の(バイト)ポインターでテキスト内の任意のWordをポイントし、そのポイントから直ちに圧縮解除を開始できます。
テキスト内の一意の単語はおそらく65,000未満なので、すべてのWordに一意の2バイトコードを与えることができます。 (KJV聖書にはほぼ13,000のユニークな単語があります)。 65,000語を超える場合でも、最初の256個の2バイトコード「単語」をすべての可能なバイトに割り当てるのは非常に簡単なので、65,000語程度の辞書にない単語を「最も頻繁に」綴ることができます。語句」。 (頻繁に使用される単語や語句を2バイトにパックすることで得られる圧縮は、通常、1文字につき2バイトを使用してWordを時々綴る「拡張」の価値があります)。適切な圧縮を行う「頻繁な語句」のレキシコンを選択するには、さまざまな方法があります。たとえば、LZWコンプレッサーを微調整して、LZWコンプレッサーが使用する「フレーズ」をレキシコンファイルに1フレーズにつき1行ずつダンプし、すべてのデータに対して実行することができます。または、非圧縮データをレキシコンファイルの5バイトのフレーズに任意に切り分け、フレーズごとに1行にすることもできます。または、非圧縮データを実際の英語の単語に切り分けて、各単語(単語の先頭のスペースを含む)を辞書ファイルに挿入することもできます。次に、「sort --unique」を使用して、そのレキシコンファイル内の重複する単語を削除します。 (完璧な「最適な」辞書の単語リストを選ぶことは、それでもNP難しいと考えられていますか?)
巨大な圧縮ファイルの先頭にレキシコンを格納し、それをいくつかの便利なBLOCKSIZEまでパディングしてから、圧縮テキスト(一連の2バイトの「ワード」)をそこからファイルの末尾に格納します。おそらく検索者はこのレキシコンを1回読み取り、「2バイトコード」から「可変長フレーズ」への解凍を高速化するために、解凍中に「RAM」といういくつかのクイックデコード形式で保持します。私の最初のドラフトは、フレーズリストごとに1行の単純な行から始まりますが、後で、何らかのインクリメンタルコーディングまたはzlibを使用して、レキシコンをより圧縮された形式で格納するように切り替えることができます。
ランダムな偶数バイトオフセットを圧縮テキストに選択し、そこから解凍を開始できます。きめ細かいランダムアクセスの圧縮ファイル形式を作成することは不可能だと思います。
2つの可能な解決策:
OSに圧縮を処理させ、すべてのテキストファイルを含む圧縮ファイルシステム(SquashFS、clicfs、cloop、cramfs、e2comprなど)を作成してマウントし、アプリケーションプログラムでの圧縮については何もしません。
ファイルシステムイメージを圧縮する代わりに、各テキストファイルでclicfsを直接使用します(テキストファイルごとに1つのclicfs)。 "mkclicfs mytextfile mycompressedfile"を "gzip <mytextfile> mycompressedfile"および "clicfs mycompressedfile directory"と考えると、ファイル "directory/mytextfile"を介してデータにランダムにアクセスできます。
これがあなたの正確な状況で実用的であるかどうかはわかりませんが、大きなファイルをそれぞれ10 MBずつ、小さなファイルにgzipするだけではどうでしょうか。最終的に、file0.gz、file1.gz、file2.gzなどの一連のファイルが作成されます。元のラージ内の特定のオフセットに基づいて、"file" + (offset / 10485760) + ".gz"
という名前のファイルを検索できます。圧縮されていないアーカイブ内のオフセットはoffset % 10485760
。
それがまだ言及されているかどうかはわかりませんが、Kiwixプロジェクトはこの点で素晴らしい仕事をしました。彼らは彼らのプログラムKiwixを通じて、ZIMファイルアーカイブへのランダムアクセスを提供します。圧縮も良好です。このプロジェクトは、Wikipediaのオフラインコピー(非圧縮形式で100 GBを超え、すべてのメディアを含む)が必要になったときに始まりました。彼らは25 GBのファイル(ほとんどのメディアを除いたWikipediaの単一ファイルの実施形態)を正常に取得し、それをわずか8 GBのzimファイルアーカイブに圧縮しました。また、Kiwixプログラムを使用すると、関連するすべてのデータを含むウィキペディアの任意のページを、ネットサーフィンよりも速く呼び出すことができます。
KiwixプログラムはWikipediaのデータベース構造に基づいたテクノロジーですが、優れた圧縮率とランダムアクセスを同時に実現できることが証明されています。
これは非常に古い質問ですが、 zindex は良い解決策を提供できるように見えます(私はそれについてあまり経験がありません)
私は、特定の種類の生物学的データを圧縮するためのオープンソースツールの作成者です。このツールはstarch
と呼ばれ、データを染色体ごとに分割し、それらの分割をインデックスとして使用して、より大きなアーカイブ内の圧縮データユニットに高速にアクセスします。
染色体ごとのデータは変換されてゲノム座標の冗長性が取り除かれ、変換されたデータはbzip2
またはgzip
アルゴリズムで圧縮されます。オフセット、メタデータ、および圧縮されたゲノムデータは、1つのファイルに連結されます。
ソースコードは GitHub サイトから入手できます。 LinuxおよびMac OS Xでコンパイルしました。
あなたのケースでは、カスタムアーカイブ形式のヘッダーにオフセット(10 MBなど)を格納できます。ヘッダーを解析し、オフセットを取得して、current_offset_sum
+ header_size
によってファイルをfseek
ずつ増分します。
razipは、gzip/bzip2よりも優れたパフォーマンスでランダムアクセスをサポートしています。gzip/ bzip2は、このサポートのために調整する必要があります。 "ok"ランダムアクセスを犠牲にして圧縮を減らします。