编辑解决方案 这是解决方案,感谢@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来记录数据,并使用 shingles 来查找重复项。它仍然停留在图表中——所以我假设这意味着它甚至还没有完成查看记录!
我们希望能够比较“相似”匹配,因此字段(如“St.”和“Street”)的差异不会成为唯一性的理由。我们可能不会处理简单的同义词,因此仅替换同义词不是一种选择。所以我想我们正在寻找模糊匹配。
我尝试了一些简单的解决方案,但速度不够快。
尽管在这种情况下哈希构建速度很快(当前的带状疱疹示例没有......它构建了大约 8 个小时并且没有完成),但它的比较速度是可怕的(但这是算法效率低下,而不是解释器速度)
我也一直在研究尽可能多的选择。一段时间以来,我一直坚持使用最近邻搜索,并承诺 DNlog(n) 搜索。
最近邻搜索有两个问题,你可能很清楚如何克服,但我一直没能做到:
- 并非所有键都是数字的
- 我们当前系统的限制是我们只需要一组 [K-Nearest Neighbor] 中的两个匹配项,但前提是它们是非常明确的匹配项(固定半径最近邻)
我也很幸运地使用了某种集群解决方案。我还没有找到一个可用的 python 库,其中包含可变数量的集群。我发现并且无法实施的每个解决方案都需要预先了解最终要拥有的集群数量。
- 我们应该只在它们实际上相似时才匹配
- 我们不知道会有多少,如果有的话。
对于#2,一旦我们有答案,我们当然可以过滤,但哪个更好?但这只有在#1可以被克服的情况下。
由于我们正在比较的数据受到限制,我还没有能够实现 NN 或聚类解决方案,并且不得不转向普通的旧比较。这样做时,为了删除比较域的数量,我连接了所有记录的值,并对字符串与所有其他字符串进行了 Levenshtein 比较。这个解决方案也不够快。它不会在大约 20 分钟内完成一条记录(我当时停止计时)。
我想出了一个简单的例子:
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
再一次,这是一个微不足道的例子,如果实际实施,将确保没有两条记录被检查两次,等等。
有什么解决办法吗?有没有一种方法可以实现 NN 或 Clustering 来解决我的问题?有没有其他我不考虑的模式可以提供帮助?我是索尔吗?