【问题标题】:Get records with similar sounds获取具有相似声音的记录
【发布时间】:2014-04-10 09:56:09
【问题描述】:

我想从联系人表中查找名称与声音匹配的所有重复名称。例如:Rita 或 Reeta、Microsoft 或 Microsift、Mukherjee 或 Mukherji。

我使用了以下查询:

SELECT contacts.id 
FROM contacts 
INNER JOIN (
    SELECT first_name, last_name, count(*) AS rows 
    FROM contacts 
    WHERE deleted = 0 
    GROUP BY SOUNDEX(first_name), SOUNDEX(last_name) 
    HAVING count(rows) > 1
) AS p 
WHERE contacts.deleted = 0 
AND p.first_name SOUNDS LIKE contacts.first_name 
AND p.last_name SOUNDS LIKE contacts.last_name 
ORDER BY contacts.date_entered DESC

上面的查询给出了正确的结果,但是当有很多记录时会花费很多时间。

【问题讨论】:

  • 它会的。您的问题无法快速解决,因为“听起来很相似”的事情无法快速解决。因此,SOUNDEX 很慢,整个查询也很慢
  • 除了使用跑得更快的SOUNDEX,还有其他方法吗?
  • 确定哪些字符串“听起来相似”?不,但如果你可以简化“听起来很相似”这个词 - 可能是

标签: mysql sql


【解决方案1】:

我不知道有比SOUNDEX() 更好的(本地)方法。它缓慢的原因是因为它是一个函数,因此需要处理所有记录以计算值并从那里开始工作。解决此问题的一种方法是将结果直接存储到表中。我在 MySQL 中没有使用这些函数的经验,但根据documentation,您似乎可以将WHERE 子句转换为

[...] AND SOUNDEX(p.first_name) = SOUNDEX(contacts.first_name) [...]

因此,如果您已经预先计算(并编制了索引!)这些值,那么搜索匹配记录的速度应该会快得多!

也就是说,我很难弄清楚您的问题。我认为您不需要那里的HAVING COUNT(*) > 1,即使那样我也对您要如何对联系人进行分组/过滤感到困惑!?

你想要这样的东西吗:

SELECT c1.id as contact_id, 
       c2.id as similar_id
  FROM contacts c1 
  JOIN contacts c2
    ON c2.id <> c1.id
   AND c2.deleted = 0
   AND SOUNDEX(c2.first_name) = SOUNDEX(c1.first_name)
   AND SOUNDEX(c2.last_name) = SOUNDEX(c1.last_name)
 WHERE c1.deleted = 0 
ORDER BY c1.date_entered DESC

然后您可以按照上面的建议进行优化

SELECT c1.id as contact_id, 
       c2.id as similar_id
  FROM contacts c1 
  JOIN contacts c2
    ON c2.id <> c1.id
   AND c2.deleted = 0
   AND c2.first_name_soundex = c1.first_name_soundex
   AND c2.last_name_soundex = c1.last_name_soundex
 WHERE c1.deleted = 0 
ORDER BY c1.date_entered DESC

其中 first_name_soundex 保存 SOUNDEX(first_name) 等的结果。 编制索引时,您可能希望在deletedfirst_name_soundexlast_name_soundex 上有一个覆盖索引。 (AFAIK MySQL 还不支持过滤索引,否则您可以将索引限制为仅deleted = 0)。

【讨论】:

    【解决方案2】:

    SOUNDEX(恕我直言)的效用非常有限。一个极端的例子……

    SELECT SOUNDEX('cholmondley');
    +------------------------+
    | SOUNDEX('cholmondley') |
    +------------------------+
    | C4534                  |
    +------------------------+
    
    SELECT SOUNDEX('chumleigh');
    +----------------------+
    | SOUNDEX('chumleigh') |
    +----------------------+
    | C542                 |
    +----------------------+
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-16
      • 1970-01-01
      • 2013-06-05
      • 2013-01-09
      相关资源
      最近更新 更多