我正在建立一个用户必须注册的系统。这些用户可能也是更大的客户数据库的一部分,我希望将注册与更大的客户数据库中的用户ID联系起来。
客户数据库有点不完整。有些客户只有一个电话号码,根据输入的人/用户,可能在不同的地方有空格。其他客户只有一个电子邮件地址,由于它是手写的,然后由其他人在以后处理,它可能会有拼写错误。真的是噩梦。
我想找到用户在我正在构建的系统上输入的最接近的记录。该数据非常简单,并将得到验证。那个数据:
我最初的想法是使用Levenshtein距离算法来计算弦距离'对于每个字段,除非它们为空,然后按总分排序。下面的代码中没有显示,以保持良好和可读性,但我显然也会修剪(甚至可能只删除)所有空格。
伪代码:
SELECT c.customerID
FROM customers c
WHERE ( c.first_name IS NULL OR ( Levenshtein(c.first_name, $first_name) < 3 ) )
AND ( c.last_name IS NULL OR ( Levenshtein(c.last_name, $last_name) < 3 ) )
AND ( c.email IS NULL OR ( Levenshtein(c.email, $email) < 3 ) )
AND ( c.telephone IS NULL OR ( Levenshtein(c.telephone, $telephone) < 3 ) )
仅供参考我在这两个数据库中使用PHP(Laravel)和MySQL。
我是在正确的轨道上还是应该使用Levenshtein以外的其他东西?我应该比较所有领域得分的某种组合吗?
答案 0 :(得分:0)
赛道绝对是正确的,但我会添加一些音符。
准备数据
首先,为了匹配,我建议转换数据以消除可能的所有噪音,f.i。将字符串转换为大写,删除空格,删除电话号码中的所有非数字等。
在不完整数据中找到最接近的匹配
其次,设置任意阈值(如&#34;小于3&#34;以上)会使其有点僵硬。虽然对CPU要求更高,但你可能最好按照差异因素排序结果&#34;:
SELECT c.customerID
FROM customers c
ORDER BY
Levenshtein(c.first_name, $first_name)) +
Levenshtein(c.last_name, $last_name) +
Levenshtein(c.email, $email) +
Levenshtein(c.telephone, $telephone) asc
LIMIT 0,1;
显然,你可以添加一些安全性,以便在差异高得离谱时不匹配,但你明白了。如果两个对象都缺少同一字段中的数据(例如,两者都缺少电子邮件),则该方法仍然可以。只有一方缺失时会出现问题 - 然后我们会因为差异而受到重创。我们可能会进一步复杂化查询以避免它:
ORDER BY
(if(c.first_name is null OR c.first_name = '' OR $first_name = '', 0, Levenshtein(c.first_name, $first_name))) +
...
为简洁起见,缩短为一行 - 我们只在有比较数据的情况下计算Lev dist。
<强>缺点强>
对于与diff因子大于X相匹配的所有记录,您可能会想到某种让人类决定的旗帜。经过一段时间的审核后,我确定您会提出更多规则来实现自动化。