web-dev-qa-db-ja.com

データの膨大なリストをJava

私はJavaで小さなシステムを書いています。そこでは、テキストファイルからn-gram特徴を抽出し、後で最も識別力のある特徴を選択するために特徴選択プロセスを実行する必要があります。

単一ファイルの特徴抽出プロセスは、一意の特徴ごとに、ファイル内でのその出現を含むマップを返します。すべてのファイルのマップ(マップ)を、すべてのファイルから抽出されたすべての一意の特徴のドキュメント頻度(DF)を含む1つのマップにマージします。統合マップには、10,000,000を超えるエントリを含めることができます。

現在、特徴抽出プロセスはうまく機能しており、情報ゲインまたはゲイン比を実装する必要がある特徴選択を実行したいと思います。最終的に(各特徴について、その特徴選択スコア)のリストを取得するには、最初にマップを並べ替え、計算を実行し、結果を保存する必要があります。

私の質問は、この大量のデータ(〜1,000万)を保持して計算を実行するためのベストプラクティスと最良のデータ構造は何ですか?

10
Aviadjo

これは非常に幅広い質問なので、答えも幅広くなります。解決策は(少なくとも)次の3つに依存します。

  1. エントリのサイズ

10,000,000の整数を格納するには、約40MiBのメモリが必要ですが、10,000,000 x 1KiBのレコードを格納するには、9GiB以上が必要です。これらは2つの異なる問題です。 1000万の整数を任意のストックのメモリに保存するのは簡単ですJavaコレクション、9GiBをメモリに保持すると、Javaヒープとガベージ)を微調整して調整する必要がありますコレクター。エントリがさらに大きい場合、たとえば1MiBの場合、メモリ内ストレージを完全に忘れることができます。代わりに、ディスクに裏打ちされた適切なデータ構造、おそらくデータベースを見つけることに集中する必要があります。

  1. 使用しているハードウェア

8 GiBのRAMを搭載したマシンに1,000万の1KiBレコードを保存することは、128GiBを搭載したサーバーに保存することと同じではありません。前者のマシンではほとんど不可能なことは、後者では簡単です。 。

  1. 実行する計算のタイプ

ソートについて言及したので、 TreeMap または多分 PriorityQueue のようなものが思い浮かびます。しかし、それは最も集中的な計算ですか?そして、それらをソートするために使用しているキーは何ですか?キーではない他のプロパティに基づいてエンティティを検索(取得)する予定はありますか?もしそうなら、それは別の計画が必要です。それ以外の場合は、1,000万を超えるエントリすべてを繰り返す必要があります。

計算は単一のスレッドで実行されますか、それとも複数のスレッドで実行されますか?データを同時に変更する可能性がある場合は、別のソリューションが必要です。 TreeMapやPriorityQueueなどのデータ構造は、ロックするか、 ConcurrentLinkedHashMap または ConcurrentSkipListMap などの並行構造に置き換える必要があります。

5
Malt

私の直感では、最初の MapReduce パラダイムからインスピレーションを得て、問題をいくつかの小さいが類似した問題に分割し、これらの部分的な結果を集約して完全なソリューションに到達することができます。

一度に1つの小さな問題インスタンス(つまり、ファイルチャンク)を解決する場合、これにより、この単一インスタンスのスペース要件によって制限されるスペース消費ペナルティが保証されます。

ファイルを遅延処理するこのアプローチは、選択したデータ構造に関係なく機能します。

1
Radu Stoenescu

キャッシングシステムを使用できます。チェックしてください MapDB 非常に効率的で、ツリーマップが実装されています(データを簡単に並べ替えることができます)。また、メモリに保持できない場合にデータをディスクに保存するためのデータストアを提供します。

// here a sample that uses the off-heap memory to back the map
Map<String, String> map = DBMaker.newMemoryDirectDB().make().getTreeMap("words");

//put some stuff into map
map.put("aa", "bb");
map.put("cc", "dd");
1
bachr