1

ソリューションの編集 @mprivatのおかげで、これがソリューションでした。

from mysql_wrapper2 import Mysql
import Levenshtein
import time

db = Mysql()
fields = [...]

 records = db.query('SELECT *, CONCAT(%s) as `string`, SOUNDEX(CONCAT(%s)) as `soundsLike` FROM records ORDER BY `soundsLike`' % (','.join(fields), ','.join(fields)))

print len(records)

matches = []


start = time.clock()
for k,v in enumerate(records):
        if k+1 == len(records):
                break

        if Levenshtein.ratio(records[k]['string'],records[k+1]['string']) >= .98:
                matches.append((records[k],records[k+1]))

print time.clock() - start
print len(matches)

エンドソリューション

重複するレコードがある(またはない)Webアプリケーション用のMySQLデータベースがあります。これらのレコードは、人物(名前、住所など)を表します。

現在、すべてのレコードをプルし、それらを帯状疱疹と比較して、管理ユーザーに重複の可能性を提示するPythonスクリプトがあります。このスクリプトは、1000レコード未満でうまく機能しました。現在、実際のデータ(89kレコード)でテストしているため、持続不可能になっています。16GBのメモリ使用量でスクリプトを停止しましたが、まだ終了したかどうかわかりません。[私はメモリを大切にしていますが、約30GBのメモリまでは速度がはるかに重要です-500kレコードを処理する場合]

その方法では、データを文書化するためにpygraphを使用し、重複を見つけるために帯状疱疹を使用しました。それはまだグラフに残っていたので、それはレコードを見終わってさえいないことを意味していると思います!

「類似した」一致を比較できるようにすることを目指しているため、フィールドの違い(「St.」や「Street」など)が一意性の根拠になることはありません。単純な同義語を扱っていない可能性があるため、同義語の置換だけを選択することはできません。ですから、あいまい一致を探していると思います。

私はいくつかの簡単な解決策を試しましたが、それらは十分に速くありません。

この場合、ハッシュは迅速に構築されますが(帯状疱疹を使用した現在の例では構築されません...約8時間構築され、終了しませんでした)、比較時の速度は恐ろしいものです(ただし、これはアルゴリズムの非効率性であり、インタープリターの速度ではありません)

私はまた、可能な限り多くのオプションを研究してきました。DNlog(n)検索のヒットの約束で、私はしばらくの間最近傍検索で立ち往生しています。

最近傍探索には2つの問題があります。それは、克服する方法をよく知っているかもしれませんが、私はできませんでした。

  1. すべてのキーが数値ではありません
  2. 現在のシステムの制約は、セット[K-Nearest Neighbor]で2つの一致のみが必要であるということですが、それらがかなり明確な一致である場合に限ります(Fixed radius Nearest Neighbor)

私はまた、ある種のクラスタリングソリューションに幸運をもたらしてきました。クラスターの数が可変である、動作するPythonライブラリをまだ見つけていません。私が見つけた、そして実装できなかったすべてのソリューションは、最終的に持つクラスターの数についての事前の知識を必要とします。

  1. 実際に類似している場合にのみ一致する必要があります
  2. いくつあるかはわかりません。

#2の場合、答えが得られたら確かにフィルタリングできますが、どちらが良いでしょうか?しかし、それは#1を克服できる場合にのみです。

比較しているデータに制約があるため、NNまたはクラスタリングソリューションのいずれかを暗示することができず、単純な古い比較に移行する必要がありました。そうすることで、比較ドメインの数を削除するために、すべてのレコードの値を連結し、文字列に対して他のすべての文字列に対してレーベンシュタイン比較を実行しました。このソリューションも、単に十分な速度ではありません。約20分で1つのレコードを終了しません(その時点でタイミングを停止しました)。

簡単な例として私が思いついたもの:

from mysql_wrapper2 import Mysql
import Levenshtein

db = Mysql()
# Get 89k records from the database
records = db.query(""""
    SELECT *
    FROM records 
""")

# Build a dictionary where the keys are our records, and their IDs are our data
# Only passing ID, we only use about 3GB of memory, instead of 
#  > 16GB with the actual dictionaries

records_hash = {}
for i in records:
    key = []
    for k in i.values():
        key.append(str(i))
        records_hash['-'.join(key)] = i['id']

# Compare every key to every key with the Levenshtein ratio

for i in records_hash.keys():
    print 'once...'
    for j in records_hash.keys():
        if Levenshtein.ratio(i,j) >= .75:
            pass

繰り返しになりますが、これは簡単な例であり、実際に実装された場合、2つのレコードが2回チェックされていないことを確認します。

解決策はありますか?問題に合うようにNNまたはクラスタリングのいずれかを暗示する方法はありますか?私が考えていない他のパターンが役立つ可能性はありますか?私はSOLですか?

4

3 に答える 3

4

私は実際に試したことがなく、うまくいかないかもしれませんが、同じ問題に直面した場合に試すことになるので、とにかく共有します。

テーブルに新しい列を追加します。次に、すべてのレコードを調べて、これを実行します。

  1. 名、姓、住所などを文字列に連結して、Soundexのような文字列を計算します(または、必要に応じて少し変更します。たとえば、数字がある場合はそのままにし、英数字以外の文字を削除して、追加します。長い文字列などのサポート...)

  2. 次に、soundexコードを計算して、新しい列に保存します

次に、soundexがその役割を果たしていると仮定すると、レコードをクエリし、soundexで並べ替えてから、既存の比較ロジックを適用できます。アイデアは、ソートされた結果セットで互いに近くにあるレコードのみを比較することです。

サウンデックスのように、私は1文字と3つの数字である通常のサウンデックスとは異なることを意味します。しかし、それは長い文字列ではうまく機能しません。3つ以上の数字を使用できます。

とにかく、探索するための別の道をあなたに与えたかっただけです...

于 2012-08-08T14:59:00.953 に答える
0

私の知る限り、最速の方法は、MySQLでのみすべてを実行することです。

私は自分の大きなテーブルの1つでもすべての重複を見つけなければなりませんでした、私は次のようなことをしました:

DELETE FROM t1 
where t1.id in (SELECT clonet1.id from t1 origine, t1 clone 
    WHERE clone.id != origine.id AND clone.id > origine.id AND ...

次に、...を比較の基準に置き換えます。

テーブルに正しいインデックスを追加すると、十分に高速になるはずです。

私がこれをしたとき、私はチェックするために何百万ものフィールドを持っていました、しかし私はまっすぐな「=」だけを探しました。

それでも、ループ検索よりも遅い単純な場所を見たことがありません...

そして、mprivatが言ったように、実際の解決策よりも検索する方法を提供することが重要です...それがあなたの助けになることを願っています。

于 2012-08-08T15:06:46.307 に答える
0

これはおそらく実用的ではないとおっしゃっていたと思いますが、St。vs streetが問題にならないように、データを正規化したほうがよいと思います。もちろんどちらを選ぶかはあなた次第ですが、両方を持っていると問題が複雑になりすぎます。

次に、一意性が多く、重複が比較的少ないと仮定して、ブルームフィルターを使用できます。ブルームフィルターは、要素を追加してメンバーシップをテストできる確率的なセットデータ構造です。メンバーシップをテストすると、「この要素は間違いなくセットに含まれていません」または「この要素はほぼ確実にセットに含まれています」という2つの答えのいずれかが得られます。これにより、多数の一意のアルゴリズムを使用して、妥当な量のメモリで従来のアルゴリズムを使用できる場所に入力を絞り込むことができます。プロセスのこの後半の段階では、物事が正確に戻ります。ブルームフィルターは、正確なアルゴリズムが考慮する必要のある入力の数を減らすだけです。

私はhttp://stromberg.dnsalias.org/~strombrg/drs-bloom-filter/にPython用のブルームフィルターの実装を持っています。もちろん、他にもあります。

于 2012-08-08T15:56:45.057 に答える