Search by

besnovatyj / yii2-cms-search-manticore

besnovatyj

Ядро сквозного поиска на Manticore Search для Yii2 CMS: настоящая лемматизация русского, поиск с опечатками и с ошибочной раскладкой клавиатуры, подсказки «возможно, вы имели в виду». Подключается к фасаду besnovatyj/yii2-cms-search, требует запущенный демон searchd.

Package info

github.com/besnovatyj/yii2-cms-search-manticore

Type:yii2-extension

pkg:composer/besnovatyj/yii2-cms-search-manticore

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.1.2 2026-09-07 20:05 UTC

This package is auto-updated.

Last update: 2026-09-07 20:05:48 UTC


README

Ядро для фасада besnovatyj/yii2-cms-search: на сервере работает демон searchd, а сайт получает настоящую морфологию русского. Ради чего именно — ниже.

Оформлено модулем, а не пакетом: ядро включают и выключают менеджером модулей, а морфологию, подсказки и допуск опечаток настраивают в админке (раздел настроек «Search»). Выключенный модуль означает «этого ядра в системе нет» — фасад останется на своём.

Что умеет

Возможность Есть Как сделано
Ранжирование да BM25 с учётом близости слов, плюс веса полей (field_weights)
Лемматизация русского да lemmatize_ru_all — словарь, а не отсечение окончаний: «людям» находит «человек»
Поиск с опечатками да OPTION fuzzy=1 силами демона, расстояние Левенштейна по символам
Ошибочная раскладка да layouts='ru,us': «ghbdtn» находит «привет»
Подсветка совпадений да HIGHLIGHT() из хранимых полей, той же морфологией, что и поиск
Подсказка «возможно, вы имели в виду» да CALL QSUGGEST по словарю индекса, когда не нашлось ничего
Вкладки по разделам да группировка по разделу отдельным запросом (см. ниже)
Веса разделов да множитель документа участвует в сортировке: WEIGHT() * boost
Сортировка по дате да дата публикации хранится атрибутом
Обновление по одной записи да REPLACE INTO в таблицу реального времени

Почему лемматизация — это не «то же самое, что стемминг»

Стеммер работает правилами и умеет только отрезать: «ботинки» → «ботинк». Этого хватает на падежи и числа, и именно так работает ядро на TNTSearch. Но правилами нельзя получить «человек» из «людям», «идти» из «шла», «год» из «лет» — там меняется основа. Лемматизатор берёт форму из словаря, поэтому находит то, чего стеммер не найдёт никогда.

Вариант _all индексирует все возможные разборы омонима: «стекло» найдётся и как существительное, и как форма глагола «стечь». Для сайта в тысячу документов полнота важнее экономии места.

Подключение

Демон говорит по протоколу MySQL, поэтому пакет не тянет ни HTTP-клиента, ни нового расширения PHP: подходит тот же pdo_mysql, которым приложение работает с базой. Отдельного компонента приложения ядро не заводит.

Реквизиты приходят вместе с окружением — через SecretReader, то есть из файла /run/secrets/<имя>, а если файла нет, из одноимённой переменной окружения. Ровно так приложение получает реквизиты базы, и ровно поэтому переезд на другой сервер не требует захода в админку:

Имя По умолчанию Смысл
MANTICORE_HOST 127.0.0.1 адрес демона; в docker-сборке — имя сервиса
MANTICORE_PORT 9306 порт SQL-интерфейса
MANTICORE_USER пусто учётная запись; пусто — подключение анонимное, годится только при выключенной авторизации демона
MANTICORE_PASSWORD пусто пароль учётной записи

Пароль не попадает ни в настройки, ни в базу, ни в дамп, ни в резервную копию настроек.

Параметры соединения, которые ядро задаёт само и которые не являются делом вкуса: charset не указывается (иначе Yii отправит демону ненужный SET NAMES), подготовка выражений эмулируется драйвером (демон поддерживает её не полностью), кэш схемы выключен, соединение имеет таймаут — упавший демон не должен превращать страницу поиска в зависший запрос.

Настройки индекса (админка, раздел «Search»)

Настройка По умолчанию Смысл
Имя таблицы индекса пусто пусто — составляется из имени базы проекта
Морфология auto по языку сайта; после смены нужна переиндексация
Подсказки включены требуют словаря подстрок: индекс вырастает в разы. После смены нужна переиндексация
Допуск опечаток 2 сколько букв в слове может не совпасть; 0 — искать без опечаток
Раскладки клавиатуры auto по языку сайта; пусто — не распознавать чужую раскладку
Окно совпадений 5000 глубина листания и точность счётчиков

Таблица индекса

Одна таблица реального времени, имя по умолчанию — bescms_search_<имя базы проекта>. Суффикс появляется сам: один демон нередко обслуживает несколько сайтов на сервере, и индексы не должны мешать друг другу.

Столбец Что это
title, content, keywords полнотекстовые поля: по ним ищут, из них берётся подсвеченный фрагмент
doc_type раздел (blog.post) — фильтр и вкладки
published дата публикации — сортировка по свежести
boost важность документа — множитель к релевантности
stamp метка прогона переиндексации

Столбец назван doc_type, а не type, потому что type — служебное слово в синтаксисе создания таблиц Manticore.

Переиндексация без «слепого» окна

Индекс не пересобирается рядом с рабочим и не подменяется в конце, как это приходится делать ядру на TNTSearch. Таблица реального времени заменяет документы на месте по стабильным идентификаторам каталога, а в конце прогона удаляются строки, которых прогон не подтвердил (stamp меньше текущего). Поэтому:

  • поиск не остаётся без индекса ни на мгновение;
  • прерванная пересборка ничего не ломает: часть документов останется с прошлого прогона до следующего запуска;
  • удалённые и снятые с публикации материалы исчезают из выдачи в конце прогона.

Морфология «запекается» в таблицу, поэтому смена языка сайта требует пересоздания таблицы — ядро делает это само в начале полной пересборки, сверив настройки таблицы с текущими.

Особенности, о которых стоит знать

  • Поиск с опечатками выполняет Manticore Buddy — спутник демона, входящий в штатную поставку. Если его нет (урезанная сборка), демон отвергает запрос: ядро один раз ловит отказ, пишет предупреждение в лог и повторяет запрос без режима опечаток. Поиск продолжает работать.
  • Вкладки считаются отдельным запросом, а не конструкцией FACET: FACET — это мультизапрос, а режим опечаток с мультизапросами несовместим. Отдельный запрос с группировкой даёт те же цифры и работает при любом режиме. Заодно вкладки считаются без учёта выбранного раздела — «Новости» показывают своё число и тогда, когда открыты «Услуги».
  • Счётчики ограничены окном max_matches (по умолчанию 5000 совпадений на запрос, настраивается). До этого числа общее количество найденного точно, дальше — «не меньше».
  • Подсветка безопасна. Демон расставляет в тексте метки, ничего не значащие в HTML; фрагмент экранируется целиком, и только потом метки превращаются в <mark>. Содержимое документа не может внести в страницу разметку.
  • Кириллица работает без настройки: словарь символов по умолчанию (non_cjk) включает русский алфавит.

Авторизация

У Manticore есть встроенная авторизация (пользователи, пароли, права) начиная с версии 27.1.5, по умолчанию выключенная. Ядро её поддерживает: достаточно положить имя пользователя и пароль в секреты окружения. Приложению хватает прав read, write и schema — администрирование и репликация ему не нужны.

Первого администратора демон заводит отдельным режимом запуска searchd --auth-non-interactive, и этот режим обращается к УЖЕ ЗАПУЩЕННОМУ демону: сначала старт, потом создание учёток.

Включённая авторизация не отменяет закрытого порта: индекс содержит тексты всех материалов сайта, включая снятые с публикации, поэтому наружу демон выставлять не следует в любом случае.

Как ядро подключается к фасаду

Module реализует Besnovatyj\Search\contracts\SearchEngineProvider и объявляет один дескриптор: ключ manticore, подпись для настроек и класс движка. Больше фасаду ничего не нужно — он находит ядро обходом модулей и создаёт движок контейнером, а выключенное в менеджере модулей ядро просто исчезает из списка.

Вся DI-проводка пакета живёт в src/config/common.php (секция container.singletons). Bootstrap-класса у пакета нет намеренно: container.singletons применяется раньше любой возможной точки обращения и при этом лениво, поэтому отдельный bootstrap был бы вторым способом сделать то же самое. Соединение объявлено синглтоном не ради экономии: SHOW META (число найденного) читается тем же линком, которым выполнен сам запрос.

Требования

  • установленный и включённый модуль фасада Search;
  • Manticore Search 6.3 или новее — режим опечаток появился в 6.3; лемматизаторы входят в пакет начиная с версии 25.0, встроенная авторизация — с 27.1.5;
  • доступ к порту 9306 (протокол MySQL) с сервера приложения;
  • ext-pdo_mysql, ext-mbstring.

Демон обязан переживать перезагрузку сервера — это единственное, что добавляет ядро в эксплуатацию. Ни отдельной базы, ни репликации, ни JVM ему не нужно; типичный расход памяти на индекс сайта — десятки мегабайт.