在本文中,我们讨论如何在特定情况下使用单个 CALL QSUGGEST 来纠正短语。
CALL QSUGGEST 是在 Sphinx 2.x 的最新版本中引入的。该语句允许从启用内嵌的索引字典中查找输入单词的近似匹配。此功能的最常见用例是实现“您是想说 ... 吗?”的功能。
在引入 QSUGGEST 之前,要实现“您是想说 ... 吗?”,需要从索引字典中提取单词,并将单词的三元组放入一个单独的索引中。然后,将基于输入单词的
trigrams
在该索引中执行搜索。作为后续,为了提高返回结果的质量,计算了返回匹配项的
Levenshtein distances
。
CALL QSUGGEST 消除了这一点,因为它不需要单独的索引,并且还提供 Levenshtein 计算,不仅消除了对另一个索引的需求(该索引也需要不时刷新),还消除了实现该功能所需的额外代码。
尽管 CALL QSUGGEST 允许输入多个单词,但它只会查看最后一个单词并忽略其余部分。相对的 - CALL SUGGEST - 则使用第一个单词并忽略其余部分。如果我们想对多个单词进行建议,首选是执行多个 QSUGGEST 调用。但是,可能会有一些情况,我们的输入是由多个单词组成的特定术语或分类(想想产品 SKU 或标签),或者是由于用户错误而将一个单词拆分成多个单词。在这些情况下,可以使用单个 SQUGGEST。
正如我们上面所说,CALL QSUGGEST 是基于三元组的。如果我们试图匹配由多个单词组成的术语,我们可以将现有的空格视为可索引字符,这将给我们一个 QSUGGEST 可以处理的单个“单词”。例如,我们可以用下划线替换空格,而下划线包含在默认的 charset_table 中。为了使其工作,我们需要在索引中添加这些术语的额外版本,其中空格(或其他不可索引字符)将被可索引字符替换。另一种选择是直接删除空格,但我们可能会得到不同术语的相同标记。
在这个快速示例中,我们使用了维基百科文章的转储,其中我们索引了文章标题的单独版本,空格被替换为下划线。
在第一个示例中,我们将拼错 Manticore Search 主要支持者之一 - Craigslist 的名字。错误的术语来自实际搜索,这些搜索命中了我们的网站:
mysql> CALL QSUGGEST('craig_list','wikititles', 1 as non_char);
+--------------+----------+------+
| suggest | distance | docs |
+--------------+----------+------+
| craigslist | 1 | 1 |
| craig_first | 2 | 1 |
| craig_zisk | 2 | 1 |
| craig_ellis | 3 | 1 |
| craig_ellis_ | 3 | 1 |
+--------------+----------+------+
5 rows in set (0.09 sec)
mysql> CALL QSUGGEST('crages_list','wikititles', 1 as non_char);
+--------------+----------+------+
| suggest | distance | docs |
+--------------+----------+------+
| craigslist | 3 | 1 |
| swadesh_list | 4 | 2 |
| danger_list | 4 | 1 |
| dean_s_list | 4 | 1 |
| lrus_list | 4 | 1 |
+--------------+----------+------+
5 rows in set (0.13 sec)
mysql> CALL QSUGGEST('crag_list','wikititles', 1 as non_char);
+------------+----------+------+
| suggest | distance | docs |
+------------+----------+------+
| craigslist | 2 | 1 |
| craig_zisk | 3 | 1 |
| brad_listi | 3 | 1 |
| army_list | 3 | 1 |
| cratylism | 3 | 1 |
+------------+----------+------+
5 rows in set (0.03 sec)
一种相反的情况是用户没有在单词之间输入空格,最终得到一个单词而不是两个。
mysql> CALL QSUGGEST('starwars','wikititles', 1 as non_char);
+------------+----------+------+
| suggest | distance | docs |
+------------+----------+------+
| star_wars | 1 | 108 |
| starways | 1 | 1 |
| star_wars_ | 2 | 8 |
| stakkars | 2 | 1 |
| stalwart | 2 | 1 |
+------------+----------+------+
5 rows in set (0.01 sec)
我们也可以将两个单词都拼错:
mysql> CALL QSUGGEST('abaham_lincol','wikititles', 1 as non_char);
+-----------------+----------+------+
| suggest | distance | docs |
+-----------------+----------+------+
| abraham_lincoln | 2 | 1 |
| abraham_sinkov | 4 | 1 |
+-----------------+----------+------+
2 rows in set (0.14 sec)
因为 QSUGGEST 应用 Levenshtein 距离,单词的顺序很重要,反向检查术语不会带来预期的结果,例如:
mysql> CALL QSUGGEST('lincol_abaham','wikititles', 1 as non_char);
+---------------+----------+------+
| suggest | distance | docs |
+---------------+----------+------+
| lincoln_isham | 4 | 1 |
+---------------+----------+------+
1 row in set (0.14 sec)
对于这种情况,应该对每个单词使用 QSUGGEST 调用,或者如果可以从索引中提取术语,则应使用三元组搜索。