在本篇文章中,我们讨论如何在特定情况下使用单个 CALL QSUGGEST 来纠正短语。
CALL QSUGGEST 是在 Sphinx 2.x 的最新版本中引入的。该语句允许从启用内部匹配的索引字典中找到输入单词的接近匹配。此功能的最常见用例是实现“您是想说…吗?”的功能。
在引入 QSUGGEST 之前,为了实现“您是想说…吗?”,需要从索引字典中提取单词,并将单词的三元组放入一个单独的索引中。然后,基于输入单词的
trigrams
将在此索引上执行搜索。作为后续,为了提高返回结果的质量,在返回的匹配项上计算了
Levenshtein 距离
。
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 调用,或者如果可以从索引中单独提取术语,应使用三元组搜索。