“我正在尝试寻找一种可靠的方法来匹配重复的人
数据库中的记录。”
唉,没有这样的事情。您最多可以期望的是一个具有合理怀疑因素的系统。
SQL> select n1
, n2
, soundex(n1) as sdx_n1
, soundex(n2) as sdx_n2
, utl_match.edit_distance_similarity(n1, n2) as ed
, utl_match.jaro_winkler_similarity(n1, n2) as jw
from t94
order by n1, n2
/
2 3 4 5 6 7 8 9
N1 N2 SDX_ SDX_ ED JW
-------------------- -------------------- ---- ---- ---------- ----------
MARK MARKIE M620 M620 67 93
MARK MARKS M620 M620 80 96
MARK MARKUS M620 M622 67 93
MARKY MARKIE M620 M620 67 89
MARSK MARKS M620 M620 60 95
MARX AMRX M620 A562 50 91
MARX M4RX M620 M620 75 85
MARX MARKS M620 M620 60 84
MARX MARSK M620 M620 60 84
MARX MAX M620 M200 75 93
MARX MRX M620 M620 75 92
11 rows selected.
SQL> SQL> SQL>
SOUNDEX 的一大优点是它对字符串进行标记。这意味着它给了你一些东西可以被索引:当涉及大量数据时,这非常有价值。另一方面,它又旧又简陋。还有更新的算法,例如 Metaphone 和 Double Metaphone。您应该能够通过 Google 找到它们的 PL/SQL 实现。
评分的优点是允许一定程度的模糊性。这样你就可以找到所有行where name_score >= 90%
。最大的缺点是分数是相对的,因此您无法对它们进行索引。这种比较会让你在大量数据的情况下丧命。
这意味着:
- 您需要多种策略的组合。没有任何单一算法可以解决您的问题。
- 数据清理很有用。比较 MARX 与 MRX 和 M4RX 的分数:从名称中删除数字可以提高命中率。
- 你无法即时获得大量名字。如果可以的话,使用标记化和预评分。如果您的流失率不高,请使用缓存。如果可以的话,请使用分区。
- 使用 Oracle Text(或类似的)构建昵称和变体的同义词库。
- Oracle 11g 向 Oracle Text 引入了特定的名称搜索功能。了解更多。
- 构建用于评分的规范名称表,并将实际数据记录链接到该表。
- 使用其他数据值,尤其是可索引的数据值(例如出生日期)来预先过滤大量姓名或增加对建议匹配的置信度。
- 请注意,其他数据值也有其自身的问题:出生于 2011 年 1 月 31 日的人是十一个月还是八十岁?
- 请记住,名字很棘手,尤其是当您必须考虑已罗马化的名字时:Moammar Khadaffi(罗马字母表)有四百多种不同的拼写方式 - 甚至谷歌也无法就哪种变体最规范达成一致。
根据我的经验,连接标记(名字、姓氏)是一件喜忧参半的事情。它解决了某些问题(例如道路名称是否出现在地址行 1 或地址行 2 中),但会导致其他问题:考虑对 GRAHAM OLIVER 与 OLIVER GRAHAM 进行评分,与对 OLIVER 与 OLIVER、GRAHAM 与 GRAHAM、OLIVER 与 GRAHAM 以及 GRAHAM 与 OLIVER 进行评分。
无论您做什么,您仍然会出现误报和错过命中的情况。没有算法可以防止拼写错误(尽管 Jaro Winkler 在 MARX 与 AMRX 方面做得相当不错)。