大きなテキストファイルがあるとしましょう。各行には、電子メールIDとその他の情報(たとえば、製品ID)が含まれています。ファイルに数百万の行があると仮定します。このデータをデータベースにロードする必要があります。データを効率的に重複排除する(つまり、重複を排除する)にはどうすればよいですか?
6 に答える
非常識な行数
- Map&Reduce フレームワーク (Hadoop など) を使用します。これは本格的な分散コンピューティングであるため、数 TB のデータがない限りやり過ぎです。( j/k :) )
すべての行をメモリに収めることができません
- 結果も収まりません: マージソートを使用して、中間データをディスクに永続化します。マージすると、重複を破棄できます (おそらく、このサンプルが役立ちます)。必要に応じて、これをマルチスレッドにすることができます。
- 結果は収まります: メモリ内のすべてを読み取って HashSet (以下を参照) に入れる代わりに、行反復子または何かを使用して、この HashSet に追加し続けることができます。ConcurrentHashMap を使用し、複数のスレッドを使用してファイルを読み取り、このマップに追加できます。もう 1 つのマルチスレッド オプションは、ConcurrentSkipListSet を使用することです。この場合、 equals()/hashCode() の代わりに compareTo() を実装し (compareTo()==0 は重複を意味します)、この SortedSet に追加し続けます。
メモリに収まる
- データを保持するオブジェクトを設計し、適切な equals()/hashCode() メソッドを実装して、それらすべてを HashSet に入れます。
- または、上記の方法を使用します (ただし、おそらくディスクに保持したくないでしょう)。
ああ、もし私があなただったら、とにかくDBに一意の制約を置きます...
Duke ( https://github.com/larsga/Duke ) を見てみましょう。これは、Java で書かれた高速重複排除およびレコード リンケージ エンジンです。Lucene を使用してインデックスを作成し、比較の数を減らします (容認できないデカルト積の比較を避けるため)。最も一般的なアルゴリズム (編集距離、ジャロ ウィンクラーなど) をサポートし、非常に拡張可能で構成可能です。
私は明白な答えから始めます。ハッシュマップを作成し、メール ID をキーとして入力し、残りの情報を値に入力します (または、すべての情報を保持するオブジェクトを作成します)。新しい行に移動したら、キーが存在するかどうかを確認し、存在する場合は次の行に移動します。最後に、HashMap を使用してすべての SQL ステートメントを書き出します。「無数の」行がある場合、メモリの制約が重要になるというeqbridgesに同意します。
2 つのオプションがあります。
Javaでそれを行う:テスト用のようなものをまとめることができ
HashSet
ます-セットに存在しない場合に、入ってくる各アイテムの電子メールIDを追加します。データベースで実行します。重複がテーブルに追加されないように、テーブルに一意の制約を設定します。これに追加されたボーナスは、プロセスを繰り返して、以前の実行から重複を削除できることです。
メールと製品 ID でテーブルのインデックスを作成できませんか? 次に、インデックスによる読み取りにより、電子メールまたは電子メール + prodId のいずれかの重複が順次読み取りによって容易に識別され、前のレコードと単純に一致する必要があります。
問題は、抽出、変換、読み込み (ETL)アプローチで解決できます。
- インポート スキーマにデータをロードします。
- データに対して必要なすべての変換を行います。
- 次に、それをターゲット データベース スキーマにロードします。
これは手動で行うことも、ETL ツールを使用することもできます。