如何使用 PHP 对 MYSQL 中的公司名称进行模糊匹配以自动完成?

Posted

技术标签:

【中文标题】如何使用 PHP 对 MYSQL 中的公司名称进行模糊匹配以自动完成?【英文标题】:How do I do a fuzzy match of company names in MYSQL with PHP for auto-complete? 【发布时间】:2010-09-27 01:15:58 【问题描述】:

我的用户将通过剪切和粘贴包含公司名称的大字符串来导入。

我有一个现有且不断增长的 mysql 公司名称数据库,每个数据库都有一个唯一的 company_id。

我希望能够解析字符串并为每个用户输入的公司名称分配一个模糊匹配。

现在,直接进行字符串匹配也很慢。 ** Soundex 索引会更快吗?如何在用户键入时为他们提供一些选项? **

例如,有人写道:

微软 -> 微软 基本要素 -> 基本要素 Polycom, Inc. -> 宝利通

我发现了以下与此问题相似的主题,但发布者尚未批准,我不确定它们的用例是否适用:

How to find best fuzzy match for a string in a large string database

Matching inexact company names in Java

【问题讨论】:

抱歉编辑错误,我忽略了第二个链接。 我在下面的回答将消除模糊搜索的需要,并将提供对任何部分名称的索引搜索 - 看看吧! 对我来说是一个谜,为什么一些基本功能没有内置在开源项目中,甚至是因此而诞生的产品/公司(如弹性搜索)。 【参考方案1】:

您可以从使用SOUNDEX() 开始,这可能会满足您的需要(我想象了一个自动建议框,其中包含用户正在输入的现有替代方案)。

SOUNDEX() 的缺点是:

它无法区分较长的字符串。仅考虑前几个字符,最后发散的较长字符串会生成相同的 SOUNDEX 值 第一个字母必须相同,否则您将无法轻松找到匹配项。 SQL Server 有 DIFFERENCE() 函数来告诉你两个 SOUNDEX 值相差多少,但我认为 MySQL 没有内置这种类型。 对于 MySQL,至少根据 the docs,对于 unicode 输入,SOUNDEX 已损坏

例子:

SELECT SOUNDEX('Microsoft')
SELECT SOUNDEX('Microsift')
SELECT SOUNDEX('Microsift Corporation')
SELECT SOUNDEX('Microsift Subsidary')

/* all of these return 'M262' */

对于更高级的需求,我认为您需要查看两个字符串的Levenshtein distance(也称为“编辑距离”)并使用阈值。这是更复杂(=更慢)的解决方案,但它允许更大的灵活性。

主要缺点是,您需要两个字符串来计算它们之间的距离。使用 SOUNDEX,您可以将预先计算的 SOUNDEX 存储在您的表中,并对其进行比较/排序/分组/过滤。使用 Levenshtein 距离,您可能会发现“Microsoft”和“Nzcrosoft”之间的差异只有 2,但要得出这个结果还需要更多时间。

无论如何,可以在codejanitor.com: Levenshtein Distance as a MySQL Stored Function (Feb. 10th, 2007) 找到一个用于 MySQL 的 Levenshtein 距离函数示例。

【讨论】:

同时使用;使用 soundex 选择一组初始结果,然后按 Levenshtein 距离对结果进行排序和选择性过滤。 仍然需要处理“首字母问题”。如果您开始输入错误的字母,SOUNDEX 的结果就会很差。 我预计不需要过滤 - 我预计不会有太多潜在匹配;而不是足够的(或不是正确的)。那么消除其中的一些也无济于事。 上面指向 MySQL Levenshtein Distance 的链接现在已断开。这是当前链接:artfulsoftware.com/infotree/queries.php#552 Levenshtein Distance 是一个很好的算法。但它不容易被任何类型的索引优化,比如 SOUNDEX 或(双)Metaphone 可能是。因此,如果您的公司数据库很大,您的逐个字符匹配建议方案可能会变得非常昂贵。【参考方案2】:

SOUNDEX 是一个很好的算法,但是最近在这个主题上取得了一些进展。创建了另一种称为 Metaphone 的算法,后来将其修改为双 Metaphone 算法。我个人使用过java apache commons的double metaphone实现,可定制且准确。

他们在***页面上也有许多其他语言的实现。这个问题已经得到解答,但是如果您发现任何已识别的 SOUNDEX 问题出现在您的应用程序中,很高兴知道有选项。有时它可以为两个完全不同的单词生成相同的代码。双变音位就是为了帮助解决这个问题而创建的。

从***窃取:http://en.wikipedia.org/wiki/Soundex

作为对不足之处的回应 Soundex 算法,劳伦斯飞利浦 开发了 Metaphone 算法 相同的目的。飞利浦后来 对 Metaphone 进行了改进, 他称之为双重变音。 双变位机包括很多 比它更大的编码规则集 前任,处理一个子集 非拉丁字符,并返回一个 初级和次级编码 解释不同的发音 一个英文单词。

在双变位页面的底部,他们有各种编程语言的实现:http://en.wikipedia.org/wiki/Double-Metaphone

Python 和 MySQL 实现:https://github.com/AtomBoy/double-metaphone

【讨论】:

MySQL Double Metaphone 实现正在移至:atomodo.com/code/double-metaphone 请注意,levenshtein 在数据库上非常重,除非您能够规范化数据,否则对于中等重度使用的网站来说,这不是一个好的选择。 dm 函数给出了准确的结果,例如请看下面两个 WHER 的输出 WHERE dm(first_name) = dm('james') WHERE SOUNDEX(first_name) = SOUNDEX('james') 【参考方案3】:

首先,我想补充一点,在使用任何形式的语音/模糊匹配算法时,您都应该非常小心,因为这种逻辑正是如此,模糊或更简单地说;可能不准确。用于匹配公司名称时尤其如此。

一个好的方法是从其他数据中寻求佐证,例如地址信息、邮政编码、电话号码、地理坐标等。这将有助于确认您的数据被准确匹配的可能性。

有很多与 B2B 数据匹配相关的问题需要在这里解决,我在我的博客(也是一个 updated article)中写了更多关于 Company Name Matching 的内容,但总的来说,关键问题是:

查看整个字符串作为最重要的部分是没有帮助的 公司名称的开头不一定是公司的开头 姓名。即“宝洁公司”或“美国联邦 预留' 缩写在公司名称中很常见,例如 HP、GM、GE、P&G、 邓白氏等。 一些公司故意拼错他们的名字作为 他们的品牌,并与其他公司区分开来。

匹配精确数据很容易,但匹配非精确数据可能会耗费更多时间,我建议您考虑如何验证非精确匹配以确保它们具有可接受的质量。

在我们建立 Match2Lists.com 之前,我们曾经花费大量时间来验证模糊匹配。在 Match2Lists 中,我们集成了一个强大的可视化工具,使我们能够查看非精确匹配,这在匹配验证方面被证明是一个真正的游戏规则改变者,降低了我们的成本,使我们能够更快地交付结果。

祝你好运!!

【讨论】:

【参考方案4】:

Here's a link to the php discussion of the soundex functions 在 mysql 和 php 中。我将从那里开始,然后扩展到您的其他定义不那么明确的要求。

您的参考引用了 Levenshtein 匹配方法。两个问题。 1.更适合测量两个已知单词之间的差异,而不是搜索。 2. 它讨论了一种解决方案,旨在更多地检测校对错误(使用“Levenshtien”作为“Levenshtein”)而不是拼写错误(用户不知道如何拼写,说“Levenshtein”并输入“Levinstein” . 我通常将它与在书中查找短语而不是在数据库中查找键值联系起来。

编辑:回应评论--

    至少可以让用户将公司名称放入多个文本框中吗? 2. 或使用明确的名称分隔符(比如反斜杠); 3. 省略冠词(“The”)和通用缩写(或者您可以过滤这些); 4. 挤出空格并与之匹配(所以微软 => microsoft,Bare Essentials => bareessentials); 5.过滤掉标点符号; 6. 对单词进行“OR”搜索(“bare”或“essentials”)——人们有时会不可避免地忽略其中一个。

疯狂地测试并使用来自用户的反馈循环。

【讨论】:

什么额外的要求会有帮助? +1 表示“Levenshtein 旨在检测校对错误而不是拼写错误”【参考方案5】:

此答案会导致使用 2 或 3 个或更多字符的输入对几乎任何实体进行索引查找。

基本上,创建一个包含 2 列、word 和 key 的新表。在包含要模糊搜索的列的原始表上运行一个进程。此过程将从原始列中提取每个单独的单词,并将这些单词与原始键一起写入单词表。在此过程中,应丢弃经常出现的单词,例如“the”、“and”等。

然后我们在单词表上创建几个索引,如下...

单词+键上的普通小写索引 第 2 到第 5 个字符 + 键的索引

第 3 到第 6 个字符 + 键的索引

或者,在 word 列上创建 SOUNDEX() 索引。

一旦完成,我们将接受任何用户输入并使用普通的 word = input 或 LIKE input% 进行搜索。我们从不执行 LIKE %input,因为我们总是在前 3 个字符中的任何一个上寻找匹配项,这些字符都已编入索引。

如果您的原始表很大,您可以按字母表对单词表进行分区,以确保立即将用户的输入缩小到候选行。

【讨论】:

【参考方案6】:

虽然问题询问如何在 MySQL 中进行模糊搜索,但我建议考虑使用单独的模糊搜索(又名容错)引擎来完成此操作。以下是一些需要考虑的搜索引擎:

ElasticSearch(开源,功能丰富,操作复杂) Algolia(专有,但拥有出色的文档并且超级容易启动和运行) Typesense(开源,提供与 Algolia 相同的模糊搜索功能)

【讨论】:

【参考方案7】:

模糊匹配的最佳函数是 levenshtein。它传统上被拼写检查器使用,所以这可能是要走的路。这里有一个 UDF:http://joshdrew.com/

使用 levenshtein 的缺点是它不能很好地扩展。一个更好的主意可能是将整个表转储到拼写检查器自定义字典文件中,并从您的应用程序层而不是数据库层执行建议。

【讨论】:

【参考方案8】:

检查是否拼写错误在服务器端使用受信任且经过良好测试的拼写检查库进行查询,然后对原始文本和第一个建议的正确拼写进行简单查询(如果拼写检查确定它拼写错误)。

您可以为任何值得使用的拼写检查库创建自定义词典,您可能需要这样做以匹配更晦涩的公司名称。

匹配两个简单的字符串比对整个表格进行 Levenshtein 距离计算要快得多。 MySQL 不太适合这个。

我最近处理了一个类似的问题,浪费了很多时间摆弄算法,所以我真希望有更多的人警告不要在 MySQL 中这样做。

【讨论】:

【参考方案9】:

之前可能有人建议过,但为什么不将数据转储到 Excel 并使用 Fuzzy Match Excel 插件。这将给出从 0 到 1 的分数(1 表示 100%)。

我为保存在数据库中的业务合作伙伴(公司)数据执行此操作。 下载最新的 UK Companies House 数据并以此为依据进行评分。

对于 ROW 数据,它更复杂,因为我们必须进行更多手动处理。

【讨论】:

以上是关于如何使用 PHP 对 MYSQL 中的公司名称进行模糊匹配以自动完成?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用php对mysql数据库中的数据进行加密和解密?

如何在Mysql查询中通过PHP对加密数据进行排序

php和mysql如何加入表[重复]

在 MySQL / PHP 中匹配相似的字符串

如何使用 php 和 mysql 使用纬度和经度进行几何搜索

如何使用 PHP 和 MySQL 有效地对大型数据集进行分页?