我有一个User
表,其中有id
,first_name
,last_name
,street_address
,city
,state
,zip-code
,firm
,user_identifier
,created_at
,update_at
。
此表有很多重复项,例如同一用户已作为新用户多次输入,因此示例
id first_name last_name street_address user_identifier
---------------------------------------------------------
11 Mary Doe 123 Main Ave M2111111
---------------------------------------------------------
21 Mary Doe 123 Main Ave M2344455
---------------------------------------------------------
13 Mary Esq Doe 123 Main Ave M1233444
我想知道是否有一种方法可以对此表进行模糊匹配。
基本上,我想找到所有具有相同名称,相同地址但可能有细微差别的用户,也许该地址相同但具有不同的公寓号,或者具有中间名,而其他重复项
我正在考虑创建一个新的列,该列已将名字,姓氏,街道地址连接起来,并对该列进行模糊匹配。
我尝试将串联的first_name和last_name设置为full_name
的levenshtein距离
但似乎没有赶上具有中间名的名字
select * from users
where levenshtein('Mary Doe', full_name) <=1;
我正在使用Databricks和PostgreSQL。
谢谢!
答案 0 :(得分:2)
在postgres中,您可以使用 fuzzystrmatch 软件包。它提供了levenshtein
函数,该函数返回两个文本之间的距离,然后可以使用以下示例性谓词执行模糊匹配:
where levenshtein(street_address, '123 Main Avex') <= 1
这将匹配所有记录,因为“ 123 Main Ave”和“ 123 Main Avex”之间的距离为1(插入1次)。
当然,这里的值1
仅是一个示例,将非常严格地执行匹配(仅相差一个字符)。您应该使用更大的数字,或者使用@IVO GELOV表示的数字-使用相对距离(距离除以长度)。
答案 1 :(得分:1)
如果您到了Levenshtein(“编辑距离”)不能满足您所有需要的比赛的地步,我强烈建议您检查pg_tgrm。它。是的。太棒了
postgresql.org/docs/current/pgtrgm.html。
作为为什么要使用三字母组合的示例,它们使您可以选择first_name
和last_name
颠倒的情况,这是一个相对常见的错误。 Levenshtein不能很好地与之匹配,因为它所做的只是将一个字符串转换为另一个字符串,并计算所需的移动次数。交换元素后,它们会大大增加距离,并使匹配 less 的可能性降低。例如,假设您有一条记录,其中正确的全名是“ David Adams”。查找姓氏为“ Adam”并查找相反的姓氏是很常见的。因此,这是一个简单名称的三种合理形式。与Postgres trigram实现相比,Levenshtein的性能如何?为此,我将levenshtein(string 1, string 2)
与similarity(string 1, string 2)
进行了比较。如上所述,Levenshtein是一个计数,其中较高的分数表示 less 相似。要将分数归一化为0-1值(其中1 =相同),我按照上面的建议将其除以最大全名长度,然后将其减去1。最后一点是使这些数字与{{1 }} 得分了。 (否则,您会有数字,其中1表示相反的意思。)
这是一些简单的结果,为了清楚起见,将其四舍五入
similarity()
如您所见,即使在这个简单的示例中,Row 1 Row 2 Levenshtein() Levensthein % Similarity %
David Adams Adam David 10 9 77
Adam David Adams David 1 91 77
Adams David David Adams 10 9 100
得分在很多情况下也表现更好。再一次,Levenshtein在一种情况下感觉更好。结合技术并不罕见。如果这样做,请标准化体重秤,以免让您头疼。
但是,如果您一开始就拥有更干净的数据,那么所有这些操作将变得更加容易。如果您的问题之一是缩写和标点不一致,则Levenshtein可能是一个不理想的选择。因此,在重复匹配之前执行地址标准化会很有帮助。
对于它的价值(很多),Postgres中的三字组可以使用索引。在尝试与Levenshtein之类进行更昂贵的比较之前,尝试找到一种通过索引搜索安全地减少候选对象的技术可能是一个不错的选择。嗯,Levenshtein的一个窍门是,如果您有目标/公差,并且存储了字符串的长度,则可以排除存储长度过短或过长的字符串,而无需运行更昂贵的模糊比较。例如,如果您有一个长度为10的起始字符串,并且只希望距离最多2个转换的字符串,那么您就是在浪费时间测试只有7个字符长的字符串,等等。
请注意,您描述的错误数据输入问题通常归结为
一旦清理得井井有条,就值得回顾一下不良数据的输入情况。如果您有一定数量的训练有素的用户,它可以帮助进行每晚(等)扫描,以检测可能的新重复项,然后与生成它们的人进行交谈。也许他们不知道您可以告诉他们什么,也许用户界面中存在您不知道他们可以告诉您的问题。
答案 2 :(得分:0)
有一个类似的运算符。您是否考虑过尝试?
以下SQL语句选择所有以“ a”开头的CustomerName的客户: 例子
SELECT * FROM Customers
WHERE CustomerName LIKE 'a%';