【问题标题】:Finding similar objects in 500k records在 500k 条记录中查找相似对象
【发布时间】:2012-08-05 17:13:57
【问题描述】:

编辑解决方案 这是解决方案,感谢@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 脚本,它可以提取所有记录,将它们与带状疱疹进行比较,然后向管理用户展示潜在的重复记录。此脚本在

该方法使用 pygraph 记录数据,并使用 shingles 查找重复项。它仍然停留在图表中 - 所以我假设这意味着它甚至还没有完成查看记录!

我们希望能够比较“相似”匹配项,因此字段的差异(如“St.”和“Street”)不会成为唯一性的依据。我们可能不会处理简单的同义词,因此仅替换同义词不是一种选择。所以我猜我们正在寻找模糊匹配。

我尝试了一些简单的解决方案,但速度不够快。

虽然在这种情况下,哈希构建速度很快(当前的带状疱疹示例没有......它构建了大约 8 个小时并且没有完成),但它的比较速度是可怕的(但这是算法效率低下,而不是解释器速度)

我也在尽可能多地研究选项。我已经被Nearest Neighbor Search 卡住了一段时间了,DNlog(n) 搜索的命中承诺。

最近邻搜索有两个问题,你可能很清楚如何克服,但我一直没能解决:

  1. 并非所有键都是数字键
  2. 我们当前系统的限制是我们只需要一组 [K-Nearest Neighbor] 中的两个匹配项,但前提是它们是非常明确的匹配项(固定半径最近邻)

我也很幸运地找到了某种集群解决方案。我还没有找到一个可用的 python 库,其中包含可变数量的集群。我找到但无法实施的每个解决方案都需要提前了解最终要拥有的集群数量。

  1. 我们应该只在它们实际上相似时才具有匹配项
  2. 我们不知道会有多少,如果有的话。

对于#2,我们当然可以在得到答案后进行过滤,但哪个更好?但这只有在 #1 可以被克服的情况下。

由于我们要比较的数据受到限制,我还不能实现神经网络或聚类解决方案,并且不得不转向普通的旧比较。这样做时,为了删除比较域的数量,我连接了所有记录的值,并对字符串与所有其他字符串进行了 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 来解决我的问题?有没有其他我不考虑的模式可以提供帮助?我是 SOL 吗?

【问题讨论】:

    标签: python mysql algorithm data-mining bigdata


    【解决方案1】:

    我还没有真正尝试过,你可能会发现它不起作用,但无论如何我都会分享,因为如果我遇到同样的问题,我会尝试它。

    我会在表格中添加一个新列。然后我会检查所有记录并这样做:

    1. 将名字、姓氏、地址等连接成一个字符串,我将为其计算类似 Soundex 的字符串(或根据您的需要稍作修改,例如,如果有数字,请保留数字,删除非字母数字字符,添加对长字符串的支持等...)

    2. 然后我会计算 soundex 代码并将其存储在我的新列中

    然后,假设 soundex 完成了它的工作,您可以查询记录,按 soundex 排序,然后应用您已有的比较逻辑。这个想法是只比较排序结果集中彼此相邻的记录。

    所谓 soundex-like,我的意思是不同于普通的 soundex,即一个字母和三个数字。但这不适用于长字符串。可以使用三个以上的数字。

    无论如何,只是想给你另一个探索的途径......

    【讨论】:

    • 这非常有效!谢谢!你把我引向了完美的方向。它从未知的小时数到在 0.62 秒内完成!谢谢!
    • 甜蜜。我喜欢当一个计划一起出现的时候:)
    • 按串联的soundex value 排序会丢失名称/记录中除前几个字符之外的部分相似性。它可能会错过街道地址完全相同但名字明显不同的人,例如:“Richard”vs. null/blank vs.“Richie”,vs.“Dick”vs.“D”。与“R”)
    • 我们可以使用特征提取技术来查找文本之间的相似性,例如 TF-IDF 与 N-gram,而不是使用距离算法来查找相似度,这降低了复杂性并提供了比任何方法都准确的结果距离算法。例如,我在我的双核系统中在不到 20 秒的时间内处理了 60 万条记录
    【解决方案2】:

    据我所知,最快的方法很可能只在 MySQL 中完成。

    我也必须在我的一张大桌子中找到所有重复项,我做过这样的事情:

    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 ...
    

    然后将 ... 替换为您的比较标准。

    如果您在表中添加正确的索引,它应该足够快。

    当我这样做时,我有数百万个字段要检查,但我只寻找直接的“=”。

    不过,我从未见过比循环搜索更慢的简单 Where...

    就像 mprivat 所说,它更多的是给你一种搜索方式,而不是一个实际的解决方案......我希望它会有所帮助。

    【讨论】:

      【解决方案3】:

      我知道您说这可能不切实际,但我认为您最好以某种方式规范化您的数据,以便 St. vs street 不成问题。当然,你选择哪一个取决于你,但同时拥有这两者只会让事情变得过于复杂。

      然后你可以使用布隆过滤器,假设你有很多独特的和相对较少的重复。布隆过滤器是一种概率集合数据结构,可以添加元素并测试成员资格。在测试成员资格时,它可以给出两个答案之一:“这个元素肯定不在集合中”或“这个元素几乎肯定在集合中”。这使您可以丢弃大量唯一性并将输入减少到可以在合理内存量中使用传统算法的位置。该过程的后一阶段使事情恢复到精确性 - 布隆过滤器只是减少了精确算法需要考虑的输入数量。

      我在 http://stromberg.dnsalias.org/~strombrg/drs-bloom-filter/ 有一个 Python 的布隆过滤器实现。当然还有其他的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-16
        相关资源
        最近更新 更多