私は多くのツイートを処理しているプロジェクトに取り組んでいます。目標は重複を削除することです。私はtweet IDを持っています。これは、フォーマットの文字列として入っています。"166471306949304320"
Java:大規模な重複検出のためにハッシュセットを最適化する
これはしばらくの間うまく動作するHashSet<String>
です。しかし、私が約1000万アイテムに達する頃には、私は激減し、最終的には再ハッシュからGCエラーが発生するでしょう。私は
tweetids = new HashSet<String>(220000,0.80F);
とのより良いサイズ/ロードを定義しようと、それはそれは遠く少しを取得することができますが、それでも(約10百万処理する限り3Xを取っている)耐え難いほど遅いです。これをどのように最適化できますか?私は、最終的にどれくらいの数のアイテムがセットに収まるべきかを概観しているので(この場合、2億2000万-200万)、2〜3回しか再ハッシュしないハッシュセットを作成するか、セットはあまりにも多くの時間ペナルティを被るでしょうか?文字列を使用していない場合や、別のHashCode関数(文字列の特定のインスタンスの場合は、どうすればよいかわかりません)を定義すると、よりうまくいくのでしょうか?実装コードのこの部分は以下のとおりです。あなたの勧告に
tweetids = new HashSet<String>(220000,0.80F); // in constructor
duplicates = 0;
...
// In loop: For(each tweet)
String twid = (String) tweet_twitter_data.get("id");
// Check that we have not processed this tweet already
if (!(tweetids.add(twid))){
duplicates++;
continue;
}
SOLUTION
おかげで、私はそれを解決しました。問題は、ハッシュ表現に必要なメモリ量でした。まず、HashSet<String>
は、この規模のために大量のものであるため、単純に莫大で無防備でした。次に、私はトライを試しましたが、ちょうど100万を超えるエントリーで墜落しました。配列を再割り当てするのは問題がありました。私はHashSet<Long>
を使用して効果を上げ、ほぼ完成させましたが、スピードが落ち込み、最終的に処理の最後の頃にクラッシュしました(約1900万)。この解決策は、標準ライブラリを去り、Troveを使用して行われました。重複を何もチェックしないよりも、2200万レコードが数分早く終了しました。最終的な実装がシンプルであり、このように見えた:
import gnu.trove.set.hash.TLongHashSet;
...
TLongHashSet tweetids; // class variable
...
tweetids = new TLongHashSet(23000000,0.80F); // in constructor
...
// inside for(each record)
String twid = (String) tweet_twitter_data.get("id");
if (!(tweetids.add(Long.parseLong(twid)))) {
duplicates++;
continue;
}
IDの番号を扱い、良いベース値を見つけて、その違いを扱うのはどうでしょうか?文字列を上回るはずの 'HashSet'を使うことができます。 Troveライブラリを使用してプリミティブを操作することもできます。 –
ヒープのサイズを単純に大きくすることはできませんか? – assylias
セットに最終的に2200万のアイテムが含まれていることが分かっている場合は、最初から22_000_000/0.75の容量でHashSetを作成してみませんか?それはどんな再ハッシュも防ぎます。 –