В этой статье мы обсуждаем, как один вызов CALL QSUGGEST можно использовать для исправления фраз в определенных случаях.
CALL QSUGGEST был введен в последней версии Sphinx 2.x. Эта команда позволяет находить близкие совпадения вводимого слова из словаря индекса с включенной вставкой. Наиболее распространенный случай использования этой функции - реализация функции “Не подскажете …?”.
Перед введением QSUGGEST, чтобы достичь “Не подскажете …?”, нужно было извлечь слова из словаря индекса и поместить триграмы слов в отдельный индекс. Поиск на основе
триграм
вводимого слова затем выполнялся против этого индекса. В качестве дополнения, для улучшения качества результатов,
расстояния Левенштейна
рассчитывались для возвращаемых совпадений.
CALL QSUGGEST избавляет от этого, так как не требует отдельного индекса и также предоставляет расчет Левенштейна, что исключает необходимость в другом индексе (который также требовал бы обновления время от времени), но также и дополнительный код, необходимый для реализации этой функции.
Хотя CALL QSUGGEST позволяет получать более одного слова на вход, он будет искать предложения только для последнего слова и игнорировать остальные. Его антагонист - CALL SUGGEST - использует вместо этого первое слово и игнорирует остальные. Если мы хотим выполнять предложения по нескольким словам, первым вариантом будет выполнить несколько вызовов QSUGGEST. Однако могут быть случаи, когда наш ввод является конкретным термином или таксономией (например, артикулы или теги продуктов), состоящими из более чем одного слова или слова, разделенного на отдельные слова (из-за ошибки пользователя). В этих случаях можно использовать один 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 применяет расстояния Левенштейна, порядок слов имеет значение, и проверка терминов в обратном порядке не даст ожидаемых результатов, например:
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 для каждого слова или, если термины могут быть извлечены отдельно из индекса, следует использовать поиск триграмм.