
Кратко
В Manticore, начиная с версии 23.0.0, можно настроить поиск так, чтобы запрос xt850 находил xt 850. Для этого используется bigram_delimiter вместе с режимами bigram_index , которые умеют работать с цифрами.
Это помогает в типичной ситуации для товарного поиска: пользователь вводит модель без пробела, а в индексе она лежит как несколько отдельных токенов.
Что стоит учесть в примерах
В примерах ниже мы исходим из таких условий:
RT-таблицы созданы по SQL-примерам без изменений, именно в показанном виде
токенизация остается стандартной, если в конкретном примере явно не задано другое поведение
в названиях моделей используются ASCII‑цифры, потому что
second_numericиsecond_has_digitрассчитаны на цифры из диапазона0-9
Все SQL-примеры и ожидаемые результаты в этой статье мы проверили перед публикацией на реальном сервере Manticore версии 23.0.0, используя новые таблицы, созданные с нуля для каждого сценария.
Проблема не только в xt850
Представьте, что у вас есть каталог с такими товарами:
xt 850 action cameraiphone 5se battery casecanon eos 80d bodythinkpad x1 carbon
А теперь представьте, что пользователи ищут так:
xt850iphone5seeos80dthinkpadx1
С точки зрения пользователя такие запросы, конечно, должны совпадать. Для движка они часто не совпадают, потому что при индексации текст разбивается на отдельные термины.
Обычно поисковые системы решают такое несоответствие одним из четырёх способов:
индексация префиксов или инфиксов
добавление пользовательских правил нормализации
дублирование контента в альтернативные нормализованные поля
индексация соседних пар токенов и при необходимости хранение склеенных вариантов
Новые возможности Manticore для биграмм позволяют сделать четвёртый вариант проще и понятнее, не дублируя поля.
Начнём с простого: почему xt850 не срабатывает по умолчанию
Вот как эта проблема выглядит в самом простом сценарии:
DROP TABLE IF EXISTS bi_default_demo; CREATE TABLE bi_default_demo(title text); INSERT INTO bi_default_demo VALUES (1,'xt 850 action camera'); SELECT id, title FROM bi_default_demo WHERE MATCH('xt850');
Ожидаемый результат:
Empty set
Почему это не работает?
Причина в том, что при индексации документ превращается в два отдельных токена: xt и 850. Запрос же приходит одним токеном — xt850.
По умолчанию Manticore не предполагает, что:
xt850должен быть разбит наxt+850или
xt+850также должно быть доступно для поиска какxt850
То есть это не проблема работы с опечатками и не проблема фразового поиска. Это несоответствие токенизации: индекс видит два токена, а запрос даёт один.
Новые настройки биграмм помогают решить именно эту проблему. С их помощью Manticore может индексировать выбранные соседние пары токенов так, чтобы они совпадали и со склеенными запросами.
Как помогают биграммы
bigram_index может помочь и с ускорением поиска фраз , и с сопоставлением названий моделей, но в этой статье мы фокусируемся на проблеме xt 850 vs xt850.
Ключевая идея проста:
находим соседние пары токенов, похожие на названия моделей
также сохраняем эти пары в склеенной форме
это позволяет запросам вроде
xt850,iphone5seилиthinkpadx1находить текст с пробелами
Именно для этого важен bigram_delimiter .
Что нужно знать о bigram_delimiter
bigram_index отвечает за то, какие соседние пары попадут в обработку.
bigram_delimiter определяет, в каком виде сохраняются подходящие биграммы:
true: только внутренняя форма с разделителемnone: только склеенный токен, напримерgalaxy24both: обе формы
Практическую разницу проще всего понять на конкретных запросах:
при
trueManticore сохраняет только внутреннюю форму биграммы, нужную для оптимизации фраз, но не сохраняет склеенный вариант из пользовательского ввода. Поэтому запросxt850не сработает как соответствие дляxt 850при
noneManticore сохраняет только склеенную форму, поэтомуxt850может найтиxt 850, но для таких пар поиск будет опираться только на это склеенное представлениепри
bothManticore сохраняет оба варианта: внутреннее представление биграммы и склеенную форму. Поэтомуxt850может найтиxt 850, а стандартное поведение фразового поиска остается на месте
В таком сценарии both обычно выглядит самым безопасным дефолтом: он закрывает проблему, заметную пользователю, и при этом меньше затрагивает привычную работу обычных фразовых запросов и смешанных нагрузок.
Режим 1: second_numeric
bigram_index = second_numeric bigram_delimiter = both
Этот режим подходит для названий моделей, где второй токен состоит только из цифр.
Такое часто встречается в товарных каталогах:
xt 850galaxy 24playstation 5pixel 8
Идея проста: пользователи часто ищут такие модели в склеенном виде — xt850, galaxy24 или playstation5, хотя в исходном тексте они записаны с пробелом.
second_numeric сохраняет пару только тогда, когда второй токен состоит исключительно из ASCII‑цифр.
Используйте его, когда:
в каталоге встречаются линейки продуктов с поколениями и нумерованными моделями
пользователи часто вводят такие запросы слитно, без пробелов
второй токен в таких парах чаще всего состоит только из цифр
Пример
DROP TABLE IF EXISTS bi_second_numeric_demo; CREATE TABLE bi_second_numeric_demo(title text) bigram_index='second_numeric' bigram_delimiter='both'; INSERT INTO bi_second_numeric_demo VALUES (1,'xt 850 action camera'), (2,'galaxy 24 ultra'), (3,'playstation 5 slim'), (4,'iphone 5se case'), (5,'canon eos 80d body'), (6,'thinkpad x1 carbon');
Теперь проверим запросы по очереди:
SELECT id, title FROM bi_second_numeric_demo WHERE MATCH('xt850'); +------+----------------------+ | id | title | +------+----------------------+ | 1 | xt 850 action camera | +------+----------------------+
SELECT id, title FROM bi_second_numeric_demo WHERE MATCH('galaxy24'); +------+-----------------+ | id | title | +------+-----------------+ | 2 | galaxy 24 ultra | +------+-----------------+
SELECT id, title FROM bi_second_numeric_demo WHERE MATCH('playstation5'); +------+--------------------+ | id | title | +------+--------------------+ | 3 | playstation 5 slim | +------+--------------------+
SELECT id, title FROM bi_second_numeric_demo WHERE MATCH('iphone5se'); Empty set
SELECT id, title FROM bi_second_numeric_demo WHERE MATCH('eos80d'); Empty set
SELECT id, title FROM bi_second_numeric_demo WHERE MATCH('thinkpadx1'); Empty set
На этом примере хорошо видно, где проходит граница режима:
24и5подходят5se,80dиx1не подходят
Режим 2: second_has_digit
bigram_index = second_has_digit bigram_delimiter = both
Этот режим - более гибкий вариант second_numeric.
Он сохраняет пару, когда второй токен содержит хотя бы одну ASCII‑цифру. Поэтому этот режим намного лучше подходит для реальных каталогов товаров, где идентификаторы моделей часто представляют собой смешанные буквенно-цифровые строки:
xt 850iphone 5seeos 80dthinkpad x1
Используйте его, когда:
в названиях моделей у вас смешаны буквы и цифры
пользователи часто удаляют пробелы в своих запросах
вам нужен удобный для каталога механизм поиска без необходимости индексировать каждую пару в таблице
Пример
DROP TABLE IF EXISTS bi_second_has_digit_demo; CREATE TABLE bi_second_has_digit_demo(title text) bigram_index='second_has_digit' bigram_delimiter='both'; INSERT INTO bi_second_has_digit_demo VALUES (1,'xt 850 action camera'), (2,'galaxy 24 ultra'), (3,'playstation 5 slim'), (4,'iphone 5se case'), (5,'canon eos 80d body'), (6,'thinkpad x1 carbon'), (7,'kindle paperwhite signature');
Затем проверьте запросы один за другим:
SELECT id, title FROM bi_second_has_digit_demo WHERE MATCH('xt850'); +------+----------------------+ | id | title | +------+----------------------+ | 1 | xt 850 action camera | +------+----------------------+
SELECT id, title FROM bi_second_has_digit_demo WHERE MATCH('galaxy24'); +------+-----------------+ | id | title | +------+-----------------+ | 2 | galaxy 24 ultra | +------+-----------------+
SELECT id, title FROM bi_second_has_digit_demo WHERE MATCH('iphone5se'); +------+---------------------+ | id | title | +------+---------------------+ | 4 | iphone 5se case | +------+---------------------+
SELECT id, title FROM bi_second_has_digit_demo WHERE MATCH('eos80d'); +------+---------------------+ | id | title | +------+---------------------+ | 5 | canon eos 80d body | +------+---------------------+
SELECT id, title FROM bi_second_has_digit_demo WHERE MATCH('thinkpadx1'); +------+---------------------+ | id | title | +------+---------------------+ | 6 | thinkpad x1 carbon | +------+---------------------+
SELECT id, title FROM bi_second_has_digit_demo WHERE MATCH('kindlesignature'); Empty set
Часто это более подходящий вариант для смешанных идентификаторов моделей, потому что в реальных каталогах нередко встречаются формы вроде 5se, 80d или x1, а не только чисто цифровые суффиксы вроде 24.
Какой режим выбрать
Если вы хотите, чтобы запрос xt850 находил xt 850, проще всего следовать такому правилу:
используйте
second_numeric, когда второй токен состоит только из цифриспользуйте
second_has_digit, когда второй токен может быть смешанным, например5se,80dилиx1
Есть один практический нюанс: в базовом сценарии это сохраняется и при дополнительных настройках обработки текста. xt 850 все равно совпадает с xt850, если включены morphology='stem_en' и wordforms.
Но это не значит, что эти настройки сами нормализуют склеенный запрос. В тестах iphones 5 совпадал с iphones5, но не с iphone5, даже при стемминге или замене iphones -> iphone через wordforms. Коротко: в простом случае xt 850 и xt850 совместимы с morphology и wordforms, но если они для вас важны, отдельно проверьте нужную форму запроса.
Главное
Проблема xt850 на самом деле не в одном конкретном названии продукта. Речь идёт о более широком несоответствии между тем, как пользователи вводят названия моделей, и тем, как поисковые движки разбивают их на токены.
В Manticore, начиная с версии 23.0.0, для этого есть штатное решение: bigram_delimiter вместе с режимами bigram_index, которые учитывают цифры. Обычно это проще, чем дублировать поля или собирать отдельный пайплайн предобработки.
Если ваша основная проблема — производительность поиска фраз, а не сопоставление склеенных названий моделей, см. Как ускорить поиск фраз с помощью bigram_index .
CitizenOfDreams
Неужели программисты наконец-то задумались над идеей выдавать в результатах поиска то, что ищет пользователь, а не то, что хочет продать владелец магазина?