後で別の Java プロセスで処理するために、小さなオブジェクトの大量のデータ (約 2 ギガバイト) を単一のファイルにシリアル化する必要があります。パフォーマンスは重要です。誰かがこれを達成するための良い方法を提案できますか?
9 に答える
Google のプロトコル バッファをご覧になりましたか。それのユースケースのように聞こえます。
Javaシリアル化が却下された理由はわかりませんが、これは完全に実行可能なメカニズムです。
元の投稿からは明らかではありませんが、ヒープ内のすべての2Gのデータが同時に存在しますか?それとも何か他のものを捨てていますか?
箱から出して、シリアル化は「完璧な」ソリューションではありませんが、オブジェクトにExternalizableを実装する場合、シリアル化は問題なく機能します。シリアル化の大きな出費は、何を書き、どのように書くかを理解することです。Externalizableを実装することにより、これらの決定を手に負えなくなり、パフォーマンスが大幅に向上し、スペースを節約できます。
I / Oは大量のデータを書き込むための主要なコストですが、データを変換するための付随的なコストも非常に高くつく可能性があります。たとえば、すべての数値をテキストに変換してから元に戻す必要はありません。可能であれば、よりネイティブな形式で保存することをお勧めします。ObjectStreamには、Javaでネイティブ型を読み書きするためのメソッドがあります。
すべてのデータが単一の構造にロードされるように設計されている場合は、Externalizableを実装した後、ObjectOutputStream.writeObject(yourBigDatastructure)を実行するだけで済みます。
ただし、構造を繰り返し処理して、個々のオブジェクトに対してwriteObjectを呼び出すこともできます。
いずれにせよ、いくつかの「objectToFile」ルーチン、おそらくいくつかが必要になります。そして、それは事実上、Externalizableが提供するものであり、構造をウォークするためのフレームワークでもあります。
もちろん、もう1つの問題はバージョン管理などです。ただし、すべてのシリアル化ルーチンを自分で実装するため、それも完全に制御できます。
データベースの代替としてJOAFIPを開発しました。
Apache Avroも役立つかもしれません。言語に依存しないように設計されており、一般的な言語のバインディングがあります。
見てみな。
すぐに頭に浮かぶ最も簡単な方法は、NIO (java.nio.MappedByteBuffer) のメモリ マップ バッファを使用することです。1 つのオブジェクトのサイズに (ほぼ) 対応する単一のバッファーを使用し、必要に応じてそれらを出力ファイルにフラッシュ/追加します。メモリ マップト バッファは非常に効率的です。
Javaシリアライゼーションを試しましたか?ObjectOutputStreamを使用してそれらを書き出し、 ObjectInputStreamを使用して読み戻します。もちろん、クラスは でなければなりませんSerializable
。これは労力の少ないソリューションであり、オブジェクトがバイナリで保存されるため、コンパクトで高速です。
protocol buffers : 理にかなっています。ここに彼らのwikiからの抜粋があります: http://code.google.com/apis/protocolbuffers/docs/javatutorial.html
速度を上げる
デフォルトでは、プロトコル バッファ コンパイラは、リフレクションを使用してほとんどの機能 (解析やシリアル化など) を実装することにより、より小さなファイルを生成しようとします。ただし、コンパイラは、メッセージの種類に合わせて明示的に最適化されたコードを生成することもできます。これにより、多くの場合、パフォーマンスが桁違いに向上しますが、コードのサイズも 2 倍になります。プロファイリングにより、アプリケーションがプロトコル バッファー ライブラリで多くの時間を費やしていることが判明した場合は、最適化モードを変更してみてください。次の行を .proto ファイルに追加するだけです。
オプションoptimize_for = SPEED;
プロトコル コンパイラを再実行すると、非常に高速な解析、シリアル化、およびその他のコードが生成されます。
パフォーマンスが非常に重要である場合は、自分で作成する必要があります。コンパクトなバイナリ形式を使用する必要があります。2 GBの場合、ディスクI/O操作は非常に重要です。XMLやその他のスクリプトなど、人間が読める形式を使用する場合は、データのサイズを2倍以上に変更します。
データによっては、低い圧縮率でその場でデータを圧縮すると、速度が上がる可能性があります。
Javaを読み取る際に、既存のオブジェクトへの参照であるかどうかをすべてのオブジェクトでチェックするため、Javaのシリアル化はまったく問題ありません。
おそらくデータベース ソリューションを検討する必要があります。すべてのデータベースが行うのは情報の最適化です。Hibernate を使用する場合は、オブジェクト モデルをそのまま維持し、実際には DB について考えることさえしません (それが休止状態と呼ばれる理由だと思います。データを保存してから戻す)