0

膨大な量のテキストをスキャンして単語の頻度を数えたいと思います(実際にはNLP / IRに精通している人にとってはn-gramの頻度です)。これにはJavaHashMapを使用します。つまり、テキストを1行ずつ処理します。行ごとに単語を抽出し、単語ごとにハッシュマップの対応する頻度を更新します。

問題は、このプロセスがどんどん遅くなることです。たとえば、約10万行/秒の処理から始まり、パフォーマンスはすぐに低下し始めます。約2800万行を超えると、パフォーマンスは1秒あたり16k行に低下し、もちろん低下し続けます。

最初に頭に浮かんだのは、ハッシュマップのエントリが多すぎることが原因で、すべてのプットとすべての取得が毎回遅くなることでした。したがって、私が試したのは、常に最も頻繁な(たとえば100k)エントリのみをハッシュマップに保持することでした。これは、頻度を単語にマップする2番目のマップを使用して行われました(ここのように:Javaの値マップによって自動的にソートされます

これは一般的にはるかに高速に実行されました。(56 kライン/秒で開始しましたが、28 milラインに達するまでに、パフォーマンスは36.5kライン/秒にしか低下していませんでした)。しかし、これもはるかに遅い速度で下降し続けました-しかし、それが下降し続けたという事実は残っています。

ハッシュマップのサイズが同じままであるのに、なぜこれが発生するのかについて、考えられる説明はありますか?これはガベージコレクターと関係があると思いますか?つまり、私がハッシュマップとの間でオブジェクトを出し入れし続けるという事実は、メモリか何かを断片化しますか?それとも、ハッシュ関数の問題でしょうか?私は文字列を使用しているので、ハッシュ関数はJavaの文字列のデフォルトのハッシュ関数です。

前述のタスクを実行するコードの一部は次のとおりです。

http://pastebin.com/P8S6Sj86

注:私はJavaの初心者なので、回答を詳しく説明することは大歓迎です。

4

2 に答える 2

3

JavaVisualVMを使用してプロファイリングを行うことをお勧めします。これにはJavaが付属しています。コマンドラインに移動し、jvisualvmと入力して実行します。これにより、メモリチャーンが問題であるかどうか、または特定のタイプのオブジェクトが数十万回作成されているかどうかを簡単に確認できます。

コードをいくつかのメソッドに分割すると、実行に時間がかかりすぎるメソッドを特定することもできます。

内側のループに不必要にたくさんのオブジェクトを作成していることに気づきました。これは確かにパフォーマンスには役立ちませんが、主な原因ではない可能性があります。

例えば:

float avg = new Float(sumItems) / new Float (freqMap.size());

する必要があります

float avg = (float)sumItems / freqMap.size();

同じく面倒かもしれないあなたのコードのもう一つの部分は次のとおりです:

System.out.println(numItems + " items counted");

オペレーティングシステムまたはIDEによっては、コンソールに100,000行を書き込むのにかなりの時間がかかります。代わりに、1000アイテムごとに進捗状況の更新を書き込むだけです。

于 2011-09-19T18:35:16.583 に答える
1

提案:

ハッシュマップに保存しているオブジェクトのカスタム hashCode メソッドを実装してみてください。ここにいくつかのリンクがあります:

Java HashMap パフォーマンスの最適化 / 代替

http://www.ibm.com/developerworks/java/library/j-jtp05273/index.html

http://www.javamex.com/tutorials/collections/hash_function_guidelines.shtml

HashMap で String キーを使用するのは悪い考えですか?

于 2011-09-19T18:36:38.660 に答える