YetiSearch Pro¶
Важно
Продуктам Premium нужен бесплатный плагин License Manager. Установите его и добавьте лицензию продукта перед установкой этого продукта.
Установка¶
Сначала убедитесь, что у вас последняя версия Grav 1.7 (-f принудительно обновляет индекс GPM).
Установите YetiSearch Pro через GPM:
Плагин также можно установить через раздел Plugins в плагине админки.
После установки запустите первую индексацию, чтобы заполнить базу поиска:
Требования¶
- PHP 7.4 или выше
- SQLite 3.24.0 или выше (для лучшей производительности рекомендуется 3.35.0+)
- Включённое расширение SQLite FTS5 — YetiSearch использует виртуальные таблицы FTS5 для полнотекстового поиска и ранжирования BM25. Ваша сборка PHP должна быть связана с библиотекой SQLite, скомпилированной с FTS5 (
ENABLE_FTS5). - Расширение PHP PDO SQLite
- Расширение PHP Mbstring
- Расширение PHP JSON
- Индексация PDF (необязательно, 2.2.0+) требует PHP 8.3 или выше и расширения PHP zlib. На более старых версиях PHP всё остальное работает, а PDF пропускаются.
Проверить версию SQLite и поддержку FTS5 можно встроенным скриптом из корня Grav:
Или посмотреть версию SQLite напрямую:
На macOS PHP из Homebrew обычно включает свежий SQLite с FTS5. Некоторые дистрибутивы Linux и хостинги с общим доступом могут поставлять старые версии SQLite — см. Устранение неполадок ниже.
Фичи¶
- 100% локальный поиск — поиск по файлам без внешних зависимостей (необязательный семантический поиск использует API эмбеддингов)
- Два дизайна модального окна — выберите «simple» (лёгкое автодополнение) или «full» (две панели с предпросмотром)
- Vanilla JS — без зависимостей от фреймворков, работает с любой темой
- CSS-переменные — простое оформление через пользовательские свойства CSS
- Умная индексация — обнаружение изменений по отпечатку для эффективных обновлений
- Очистка осиротевших записей — автоматически удаляет устаревшие документы удалённых страниц
- Обновления в реальном времени — обновление индекса при сохранении или удалении страницы (необязательно)
- Многоязычность — стратегии на язык или единого индекса
- Нечёткий поиск — находит результаты, несмотря на опечатки
- Стемминг — необязательно. Поиск также находит другие формы слова (
runsнаходит «running») в английском, французском, немецком и испанском (2.3.0+) - Индексация фрагментами — точные результаты поиска внутри длинного содержимого
- Аналитика — отслеживание поисков, переходов и популярных запросов
- Геопоиск — задайте страницам местоположение и ищите по расстоянию: радиус, сначала ближайшие и кнопка «Near me» в полном модальном окне (2.3.0+)
- Права — детальные права администратора (просмотр, изменение, администрирование)
- Планировщик — автоматическая переиндексация и обслуживание через планировщик Grav
- Команды CLI — полный интерфейс командной строки для индексации, запросов и обслуживания
- Индексация PDF — необязательный поиск внутри PDF с результатами, ведущими на нужную страницу PDF (2.2.0+)
- Семантический поиск — необязательный поиск по смыслу, а не только по ключевым словам, через OpenAI, OpenRouter, Ollama или любой совместимый с OpenAI API эмбеддингов (2.1.0+)
Конфигурация¶
YetiSearch Pro настраивается через user/plugins/yetisearch-pro/yetisearch-pro.yaml или в интерфейсе плагина админки.
Базовая конфигурация¶
enabled: true
engine:
storage_dir: 'user://data/yetisearch-pro'
index_prefix: 'grav_'
timeout: 5
max_batch_size: 10
search:
snippet_length: 75 # длина окна фрагмента по умолчанию
stem_weight: 0.5 # при включённом стемминге: насколько учитывается совпадение со стеммом слова (от 0 до 1)
indexes:
pages:
strategy: single # или 'per_language'
languages: [] # пусто: определить по языкам и версиям Grav
stemming: false # также находить другие формы слова; см. раздел «Стемминг» ниже
geo: # откуда берётся местоположение страницы (точечные пути в заголовке страницы)
lat: geo.lat
lng: geo.lng
options:
fuzzy: true
query_defaults:
per_page: 10
geo:
units: km # km | mi | m для радиуса и расстояний, если запрос их не задаёт
- Пакетная обработка управляется
engine.max_batch_size. - Длина фрагмента по умолчанию — 75. Задайте её через
engine.search.snippet_lengthили параметр CLI--highlight-length. stemmingописан в разделе Стемминг, аgeo— в разделе Геопоиск.- Настройки поиска (
engine.searchи блокsearchверхнего уровня, который побеждает, если оба задают один ключ) применяются к каждому индексу. Настройки индексатора берутся изengine.indexerи могут быть переопределены для индекса черезindexes.<key>.options.indexer. Переопределения поиска для отдельного индекса нет.
Примечание
В более ранних версиях перечислялись настройки индекса для индексируемых полей, фасетов, географических полей и допуска опечаток. Их никто не читал, поэтому в 2.3.0 они удалены. Значения, оставшиеся в вашей конфигурации, игнорируются, как и раньше.
Стратегии индекса¶
YetiSearch Pro поддерживает две стратегии индексации:
single(по умолчанию) — одна база для всех языков. Язык хранится в каждом документе.- Файл:
user/data/yetisearch-pro/<prefix><index>.db(например,grav_pages.db) -
Запрос с
--index pages --lang fr, чтобы использовать обработку с учётом языка. -
per_language— отдельный файл базы для каждого языка/версии. - Файл:
user/data/yetisearch-pro/<prefix><index>_<lang>.db(например,grav_pages_17.db) - Запрос с
--index pages_17или--index pages --lang 17.
Значения запроса по умолчанию и усиление полей¶
Настройте поля поиска по умолчанию и веса усиления для каждого индекса:
indexes:
pages:
query_defaults:
per_page: 10
fields: [title, headers_h1, headers_h2, headers_h3, headers, content, excerpt, tags]
boost:
title: 5.0
headers_h1: 4.0
headers_h2: 3.0
headers_h3: 2.0
headers: 1.5
tags: 2.5
excerpt: 2.0
content: 1.0
rerank:
title_exact: 10.0 # бонус за точное совпадение слова в заголовке
title_prefix: 8.0 # бонус за совпадение с началом заголовка
title_word: 5.0 # бонус за совпадение слова в заголовке
headers_exact: 7.0 # бонус за точное совпадение слова в заголовках
headers_prefix: 6.0 # бонус за совпадение с началом в заголовках
headers_word: 3.0 # бонус за совпадение слова в заголовках
chunk: 1.0 # небольшое предпочтение совпадениям во фрагментах
fuzzy_factor: 1.2 # масштабировать бонусы переранжирования при включённом нечётком поиске
demote_prefixes: ['/api']
demote_penalty: 10.0
Настройки rerank позволяют переранжировать результаты на стороне клиента после оценки движком, давая точный контроль над порядком.
Режимы окружения¶
Плагин поддерживает конфигурацию с учётом окружения, чтобы индексы не конфликтовали:
environment:
mode: auto # auto | production | staging | development
append_environment_to_index: true # добавлять имя окружения к префиксу индекса
realtime_in_development: true # включить индексацию в реальном времени в режиме разработки
Когда mode равен auto, плагин следует определению окружения Grav. Параметр append_environment_to_index не даёт индексам staging и development конфликтовать с production.
Стемминг¶
Доступен с YetiSearch Pro 2.3.0. Необязателен и по умолчанию выключен.
Стемминг позволяет поиску находить другие формы слова: runs находит «running», configured находит «configuration», utilisateur находит «utilisateurs».
Включение¶
Включите его для индекса параметром Stemming (Pages) в настройках плагина или в конфигурации:
Языки¶
Для английского, французского, немецкого и испанского есть стеммеры. Индекс на любом другом языке не проходит стемминг, и его слова совпадают так, как введены. Выбор языка зависит от стратегии индекса:
per_language— каждый индекс проходит стемминг на своём языке, поэтомуpages_frиспользует французский, аpages_de— немецкий. Поиск по нему тоже проходит стемминг на этом языке.single— каждая страница проходит стемминг на языке, на котором была проиндексирована, поэтому французская страница использует французский. Собственный язык индекса — язык сайта по умолчанию: язык Grav по умолчанию илиsite.default_langна сайте без языков. Эндпоинт/ysищет по всем языкам и не передаёт ни одного, поэтому его поиски используют стемминг языка сайта по умолчанию, а каждая страница сохраняет стеммы своего языка.
На многоязычном сайте per_language даёт максимальную пользу от стемминга.
Ранжирование и подсветка¶
Совпадение со словом в том виде, как оно введено, ранжируется выше совпадения со стеммом. stem_weight (от 0 до 1, по умолчанию 0.5) задаёт, насколько учитывается совпадение со стеммом: меньшее значение оставляет точные совпадения впереди, а 0 всё ещё находит стеммы, но ставит их в конце. Задайте его в engine.search или в блоке search верхнего уровня, который побеждает, если задано и там, и там. Подсветка включает совпадения со стеммами, поэтому поиск runs отмечает «running».
Стоимость¶
Каждая страница проходит стемминг при индексации, поэтому индексация занимает больше времени, а индекс растёт. На демо-сайте Helios (507 документов) запись индекса заняла 0,15 с со стеммингом против 0,09 с без него, а база была примерно на треть больше. Измерения библиотеки на 32 000 документов: индексация примерно в 2,5 раза медленнее, база примерно на 50% больше, а медиана поиска — 1,7 мс против 0,9 мс.
Включение и выключение для существующего индекса¶
Изменение настройки один раз перестраивает полнотекстовый индекс каждого существующего индекса по хранящимся в нём документам, без повторной индексации страниц.
- Когда это происходит. При сохранении настроек плагина в любой админке с настройками, с которыми сайт работает после сохранения (включая переопределения окружения). Иначе — при следующем запуске индексации (
bin/plugin yetisearch-pro index, переиндексации из админки или планировщика), сохранении или удалении страницы. - Настройки другого окружения. Сохранение настроек другого окружения (например,
user/env/staging/config/plugins/yetisearch-pro.yamlс production-сайта) здесь ничего не меняет. Это окружение переключится при своём следующем запуске индексации или сохранении страницы. - Переменные
GRAV_CONFIG__. Сохранение также ничего не меняет, пока задана любая переменная окруженияGRAV_CONFIG__(например,GRAV_CONFIG__plugins__yetisearch-pro__engine__storage_dir), для каких бы настроек она ни была. Такая переменная может переопределить настройки плагина, а сохранённые файлы не содержат этого значения. Следующий запуск индексации, сохранение или удаление страницы переключат индексы с настройками, с которыми работает сайт. - Что вы увидите.
bin/plugin yetisearch-pro indexпечатает строку для каждого перестроенного индекса, и это записывается в журнал Grav. - Сколько времени занимает. Несколько сотых секунды на индекс на демо Helios. Библиотека измерила 1,7 с на 32 000 документов.
- С
--flush. Переиндексация с--flushсоздаёт индексы с этой настройкой.
Семантический поиск¶
Доступен с YetiSearch Pro 2.1.0. Необязателен и по умолчанию выключен.
Поиск по ключевым словам находит страницы, содержащие введённые посетителем слова. Семантический поиск также находит страницы, которые означают то же самое. Кто-то вводит «can't log in» и получает вашу страницу сброса пароля. «Hire an advisor» находит вашу страницу консультаций, даже если ни одного из этих слов на ней нет. YetiSearch Pro выполняет оба поиска и объединяет результаты, поэтому страница, совпавшая и по ключевым словам, и по смыслу, оказывается первой, а страница, найденная только по смыслу, всё равно попадает в список.
Чтобы понимать смысл, YetiSearch Pro превращает каждую страницу в список чисел, называемый эмбеддингом, с помощью модели эмбеддингов. Страницы со схожим смыслом получают похожие числа. Эмбеддинги хранятся в существующем файле индекса, а при поиске запрос посетителя обрабатывается так же и сравнивается с ними.
Модель должна где-то работать. Запускать её внутри PHP непрактично на обычном хостинге, поэтому YetiSearch Pro обращается к API эмбеддингов. Это может быть размещённый сервис вроде OpenAI или OpenRouter либо ваш собственный сервер Ollama, если хотите держать всё у себя. Поиск по ключевым словам в любом случае остаётся на 100% локальным и продолжает работать, если API медленный или недоступен.
Настройка¶
Откройте настройки плагина, разверните Semantic Search, включите его и заполните данные подключения к вашему сервису:
| Сервис | Базовый URL API | Модель эмбеддингов | Размерность |
|---|---|---|---|
| OpenAI | https://api.openai.com/v1 |
text-embedding-3-small |
512 |
| OpenRouter | https://openrouter.ai/api/v1 |
openai/text-embedding-3-small |
512 |
| Ollama | http://localhost:11434/v1 |
nomic-embed-text |
0 |
Подойдёт и любой другой сервис с API эмбеддингов OpenAI (Voyage, Mistral, Together, LM Studio). Оставьте API Key пустым для локального сервера вроде Ollama. Если не хотите хранить ключ в конфигурации, введите env:OPENAI_API_KEY (или любое имя переменной), и YetiSearch Pro прочитает его из окружения.
Для Ollama с nomic-embed-text также задайте Query Prefix как search_query:, а Document Prefix как search_document:. Эта модель этого ожидает.
Затем проверьте подключение:
Та же проверка доступна кнопкой Test connection на странице YetiSearch Pro в Admin Next.
Эмбеддинг содержимого¶
После включения страницы нужно один раз превратить в эмбеддинги. Либо переиндексируйте, либо выполните:
В API отправляются только страницы, новые или изменённые с момента последнего эмбеддинга. Повторная индексация неизменённого содержимого ничего не стоит, а редактирование одной страницы отправляет только её. После этого изменённые страницы подхватываются автоматически:
- После сохранения страницы или переиндексации — когда ответ уже ушёл в браузер, поэтому медленный API никогда не задерживает сохранение
- Заданием планировщика Semantic Search Embedding, по умолчанию каждые 15 минут, которое добирает всё оставшееся
- Кнопкой Embed на странице YetiSearch Pro в Admin Next, которая показывает, какая часть сайта уже обработана, и полосу выполнения во время работы
Страницы, ещё не получившие эмбеддинги, всё равно находятся поиском по ключевым словам. Просто они не ранжируются по смыслу, пока обработка не завершится.
С text-embedding-3-small от OpenAI эмбеддинг стоит пару центов за миллион слов, поэтому типичный сайт обходится значительно меньше доллара за полную обработку. Каждый новый поисковый запрос стоит одного небольшого вызова API, а повторные запросы кэшируются и ничего не стоят.
Как ведут себя поиски¶
- Модальное окно поиска остаётся мгновенным. Результаты по ключевым словам появляются по мере ввода. Когда посетитель делает паузу, второй запрос ранжирует по смыслу и заменяет результаты. Ни одно нажатие клавиши не ждёт API.
- Короткие запросы (меньше Minimum Query Length, по умолчанию 3 символа) используют только ключевые слова.
- Бессмыслица не совпадает. Запрос вроде «asdf» возвращает ничего, а не случайную ближайшую страницу. С версии 2.1.1 YetiSearch Pro измеряет, где должен быть этот порог, для вашего содержимого: после каждого полного прохода эмбеддингов он превращает несколько бессмысленных тестовых фраз в эмбеддинги, смотрит, насколько близко они совпадают с вашими страницами, и ставит порог чуть выше этого. Страница YetiSearch Pro в Admin Next и
embed --statusпоказывают текущий порог. - Если API не работает или отвечает дольше Search Timeout (5 секунд), поиск возвращается к ключевым словам.
- JSON-эндпоинт принимает
semantic=0, чтобы запросить только ранжирование по ключевым словам, и сообщает"semantic": true, когда смысл участвовал в ранжировании.
Тонкая настройка¶
| Настройка | По умолчанию | Что делает |
|---|---|---|
| Meaning vs Keywords | 0.5 |
Какая доля ранжирования приходится на смысл. 0 — только ключевые слова, 1 — только смысл. |
| Minimum Similarity | 0.25 |
Страницы с меньшим сходством никогда не появляются только по смыслу. Повысьте, если показываются не связанные страницы. |
| Noise Calibration | Automatic | Измеряет порог бессмыслицы для каждого индекса после эмбеддинга. Off использует фиксированное значение по умолчанию. |
| Calibration Strictness | 2.0 |
Насколько порог выше типичной бессмыслицы. Понизьте (например, до 1.5), если хорошие совпадения теряются; повысьте, если бессмыслица проходит. Действует сразу, без повторного эмбеддинга. |
| Minimum Query Length | 3 |
Более короткие запросы используют только ключевые слова. |
| Search Timeout | 5 |
Сколько секунд поиск ждёт API, прежде чем вернуться к ключевым словам. |
| Embed After Indexing | On | Превращать изменённые страницы в эмбеддинги после сохранений и переиндексаций. |
| Documents per Run | 200 |
Сколько документов обрабатывает каждый фоновый запуск. |
| Dimensions | 512 |
Размер каждого эмбеддинга. Меньше — поиск быстрее. Значение принимают только модели text-embedding-3 от OpenAI; для остальных используйте 0. |
У каждого индекса также есть собственный переключатель Semantic Search в разделе Index Definitions, поэтому его можно оставить выключенным для индекса, где он не помогает.
Примечание
Изменение модели, её размерности или префиксов означает, что каждую страницу нужно снова превратить в эмбеддинги. Пока это не сделано, поиски по этому индексу используют только ключевые слова. Re-embed all в Admin Next (или embed --reset) начинает заново с нуля.
Ограничения¶
Семантический поиск сравнивает запрос с каждым фрагментом содержимого, имеющим эмбеддинг. На современном сервере это занимает около 0,1 секунды для 10 000 фрагментов размерности 512 и растёт вместе с объёмом содержимого. Этого достаточно для большинства сайтов. Для очень большого сайта используйте размерность 256 или держите семантический поиск выключенным для самого большого индекса.
Индексация PDF¶
Примечание
Индексация PDF добавлена в YetiSearch Pro 2.2.0 и требует PHP 8.3 или выше.
Включите PDF Indexing в настройках плагина (или задайте pdf.enabled: true) и переиндексируйте. Каждый PDF в папке индексируемой страницы становится отдельным результатом поиска с заголовком из собственного названия PDF или имени файла. Каждая страница PDF индексируется отдельно, поэтому результат ведёт на file.pdf#page=12, и браузер открывает PDF на странице, где найдены слова.
pdf:
enabled: true
max_file_size: 50 # МБ; более крупные PDF пропускаются, 0 = без ограничения
max_pages: 1000 # страниц индексируется на PDF, 0 = все
Требования¶
PHP 8.3 или новее с расширением zlib. Извлечение текста выполняется в PHP встроенной библиотекой YetiPDF, поэтому на сервере ничего устанавливать не нужно. На PHP 8.2 и старше настройка игнорируется, в журнал Grav пишется уведомление, а страницы индексируются как обычно.
Что индексируется¶
PDF, лежащие в папке страницы, которая сама индексируется. PDF наследует язык, таксономию и версию своей страницы, поэтому фильтры и фасеты применяются и к нему. Страница, исключённая из индекса, забирает с собой и свои PDF.
Чтобы оставить страницу в индексе, но исключить её PDF, выключите Index this page's PDFs на вкладке YetiSearch страницы или добавьте в её frontmatter:
Поддержание актуальности¶
Извлечённый текст кэшируется в cache/yetisearch-pro/pdf с привязкой к размеру и времени изменения каждого файла, поэтому переиндексация читает только изменённые PDF. Удалите эту папку, чтобы все PDF были прочитаны заново. При включённой индексации в реальном времени загрузка или удаление PDF в админке сразу обновляет индекс, как и сохранение страницы.
Что пропускается¶
Сканированные PDF без текстового слоя (OCR нет), PDF, для открытия которых нужен пароль, и PDF больше лимита размера. Каждый случай отмечается в журнале Grav. PDF, который не удалось прочитать, будет повторён при следующем запуске индексации.
В шаблонах¶
У результата по PDF есть doc_type: pdf в метаданных (result._meta в Twig и в JSON /ys), а также pdf_file, pdf_page, pdf_pages, page_route и page_title (страница, к которой прикреплён PDF). Его route — путь, по которому отдаётся файл, а url добавляет #page=N.
Геопоиск¶
Примечание
Геопоиск добавлен в YetiSearch Pro 2.3.0.
Задайте страницам местоположение, и поиск сможет перечислять их по расстоянию, оставлять только попавшие в радиус и показывать, насколько далеко находится каждый результат. Поиски и модальные окна работают как раньше для страниц без местоположения, а страница без него никогда не появляется в поиске по местоположению.
Это работает без модуля R-Tree в SQLite. С YetiSearch 2.5.4 библиотека переходит на обычную таблицу с теми же результатами, а с 2.5.5 это верно и без математических функций SQLite. См. Without R-Tree в README библиотеки, чтобы узнать отличия.
Задание местоположения страницы¶
Добавьте geo во frontmatter страницы или заполните группу Location на вкладке YetiSearch редактора страницы, которая записывает те же два ключа:
Широта должна быть от -90 до 90, а долгота — от -180 до 180. Местоположение задаётся странице, только когда оба значения — числа в допустимом диапазоне. Отсутствующее, пустое или недопустимое значение никогда не превращается в 0,0: страница индексируется без местоположения. PDF в папке страницы находятся по местоположению своей страницы, как и фрагменты страницы. Изменение местоположения перезаписывает документ при следующей индексации, а удаление убирает страницу из поиска по местоположению. В Admin Next числовое поле нельзя очистить, если в нём есть значение, поэтому удалите местоположение из frontmatter страницы (режим Expert).
Собственные пути¶
Если ваши страницы уже хранят координаты под другими ключами, укажите на них индекс через точечные пути в заголовке страницы:
Те же настройки есть в конфигурации плагина как Page Latitude Field и Page Longitude Field. Задайте geo: false, чтобы не использовать frontmatter страницы. Поле Location в редакторе страницы всегда записывает geo.lat и geo.lng, поэтому оно подходит только для путей по умолчанию. После изменения путей переиндексируйте.
Местоположения из другого источника, например из базы данных или значения в другом формате, задаются слушателем события (см. Задание местоположения из слушателя события).
Поиск¶
Эндпоинт query_route (по умолчанию /ys), функция Twig yetisearch() и options события onYetisearchProBeforeSearch принимают следующее:
| Параметр | Что делает |
|---|---|
lat, lng |
Точка, вокруг которой искать. Нужны оба. Значения, не являющиеся допустимыми координатами, игнорируются, и поиск выполняется как обычный. |
radius |
Необязательно. С ним возвращаются только документы в пределах этого расстояния. Без него возвращается каждый документ, у которого есть местоположение. Значение, не являющееся положительным числом, игнорируется. |
units |
km, mi или m — для радиуса и расстояний. По умолчанию берётся из query_defaults.geo.units индекса, затем km. |
sort |
distance перечисляет ближайшие первыми, в том числе с запросом. Поиск с запросом без него сохраняет порядок релевантности. |
С местоположением и пустым q поиск перечисляет ближайшие документы, как если бы был задан sort=distance. Пустой q без допустимого местоположения всё равно возвращает пустой результат. Это правило применяется после события onYetisearchProBeforeSearch, поэтому слушатель может задать geo в options события для пустого запроса, а слушатель, который его удаляет, завершает поиск пустым результатом. То же в CLI: query с --lat и --lng без текста перечисляет ближайшие первыми.
/ys?lat=51.5074&lng=-0.1278&radius=5&units=km&sort=distance&ajax=1
/ys?q=coffee&lat=51.5074&lng=-0.1278&radius=25&ajax=1
У каждого результата поиска по местоположению есть distance (в метрах) и distance_text — расстояние в единицах поиска, например 1.3 km или 0.8 mi. Строки берутся из PLUGIN_YETISEARCH_PRO.DISTANCE_KM, DISTANCE_MI и DISTANCE_M, поэтому их можно переводить. В конверте результата есть запись geo с местоположением, которое использовал поиск (lat, lng, radius, units, sort), чтобы страница могла понять, что результаты содержат расстояния.
В Twig:
{% set results = yetisearch('coffee', {'lat': 51.5074, 'lng': -0.1278, 'radius': 5, 'units': 'mi', 'sort': 'distance'}) %}
{% for hit in results.results %}
{{ hit.title }}, {{ hit.distance_text }}
{% endfor %}
Простое модальное окно показывает distance_text для каждого результата, когда его запросы содержат местоположение. Передайте его через data-ys-extra-params (см. Extra Query Parameters в разделе Настройка шаблонов модальных окон), например data-ys-extra-params="lat=51.5074&lng=-0.1278&units=km".
Near Me¶
Задайте modal.near_me: true, чтобы добавить кнопку Near me в полное модальное окно. По умолчанию она выключена. Когда посетитель её включает, браузер спрашивает его местоположение. Затем модальное окно добавляет lat, lng, radius, units и sort=distance к своим запросам, перечисляет ближайшие результаты даже при пустом поле поиска и предлагает меню радиуса. Если в местоположении отказано или его не удаётся определить, модальное окно сообщает об этом.
modal:
type: full
near_me: true
near_me_radii: [1, 5, 10, 25, 50] # варианты радиуса в единицах query_defaults.geo.units индекса
near_me_radius: 10 # радиус, выбранный первым; 0 = любое расстояние. Добавляется в меню, если отсутствует в near_me_radii
Кнопка находится в собственном блоке near_me шаблона полного модального окна, поэтому тема может её переместить или заменить. Собственный filters.html.twig темы не затрагивается.
Конфиденциальность¶
Координаты, которыми делится посетитель, остаются в браузере, пока открыта страница. Они отправляются только как параметры поискового запроса, никогда не сохраняются в браузере, и плагин их не хранит: аналитика записывает текст поиска, как и раньше, плюс то, использовалось ли местоположение, и никогда сами координаты. Поиски с пустым q вообще не записываются.
Поиск по местоположению в CLI¶
bin/plugin yetisearch-pro query "coffee" --lat=51.5074 --lng=-0.1278 --radius=5 --units=km --sort=distance
bin/plugin yetisearch-pro query --lat=51.5074 --lng=-0.1278 --radius=25
Нужны и --lat, и --lng; отрицательное число пишите как --lng=-0.1278, со знаком равенства. --sort distance требует местоположения. Запрос можно не указывать, когда есть местоположение. В таблице результатов появляется столбец расстояния. Все параметры см. в разделе Команда Query.
Задание местоположения из слушателя события¶
onYetisearchBuildDocument может задать местоположение документа из любого источника. Присвойте документ обратно событию: изменение $event['doc']['geo'] на месте не доходит до индексатора, поэтому слушатель должен прочитать $event['doc'], изменить его копию и присвоить копию обратно в $event['doc']. Этот пример, проверенный с bin/plugin yetisearch-pro index и с сохранением страницы в админке, читает ключ заголовка location: "48.8584, 2.2945":
use Grav\Common\Plugin;
use RocketTheme\Toolbox\Event\Event;
class MyPlugin extends Plugin
{
public static function getSubscribedEvents(): array
{
return ['onYetisearchBuildDocument' => ['onYetisearchBuildDocument', 0]];
}
public function onYetisearchBuildDocument(Event $event): void
{
$location = (string)($event['subject']->header()->location ?? '');
if (strpos($location, ',') === false) {
return;
}
[$lat, $lng] = array_map('trim', explode(',', $location, 2));
$doc = $event['doc'];
$doc['geo'] = ['lat' => $lat, 'lng' => $lng];
$event['doc'] = $doc;
}
}
Индексатор проверяет местоположение и превращает два значения в числа; значение, не являющееся допустимой координатой, оставляет документ без местоположения. Документ также может нести geo_bounds (north, south, east, west) вместо точки. Событие срабатывает и для PDF страницы, с самой страницей в subject, поэтому тот же код задаёт местоположение и им.
Настройка модального окна¶
YetiSearch Pro включает два дизайна модального окна, которые могут использовать темы.
Типы модальных окон¶
-
full— двухпанельное модальное окно с результатами слева и живым предпросмотром справа. Включает пагинацию, элементы фильтрации, хлебные крошки и разделы «On This Page». Лучше всего подходит для сайтов документации с длинным содержимым. -
simple(по умолчанию) — лёгкое модальное окно автодополнения со сгруппированными результатами. Одна панель, без предпросмотра. Лучше всего подходит для обычных сайтов, которым нужен чистый и быстрый поиск.
Конфигурация¶
modal:
type: simple # 'full' или 'simple'
branding: true # показывать «Powered by YetiSearch» в подвале
near_me: false # только полное модальное окно (2.3.0+): добавить кнопку «Near me»
near_me_radii: [1, 5, 10, 25, 50] # варианты радиуса в единицах query_defaults.geo.units индекса
near_me_radius: 10 # радиус, выбранный первым; 0 = любое расстояние
near_me добавляет кнопку, которая ищет вокруг местоположения посетителя. По умолчанию она выключена. near_me_radii перечисляет варианты радиуса, а near_me_radius — выбранный первым; он добавляется в меню, если его нет в списке. Как это работает, см. в разделе Near Me.
Интеграция с темой¶
Добавление модального окна поиска¶
Включите модальное окно в базовый шаблон темы:
{# В partials/base.html.twig вашей темы или похожем файле #}
{% if config.plugins['yetisearch-pro'].enabled %}
{% include 'partials/yetisearch-pro/modal.html.twig' %}
{% endif %}
Модальное окно автоматически выбирает правильный тип по вашей конфигурации.
Модальные окна отправляют запросы на query_route (по умолчанию /ys) с базовым URL сайта впереди, поэтому достаточно изменить query_route. Темы, которые строят собственное модальное окно, должны сами читать query_route.
Чтобы включить конкретное модальное окно напрямую:
{% include 'partials/yetisearch-pro/modal-simple.html.twig' %}
{# или #}
{% include 'partials/yetisearch-pro/modal-full.html.twig' %}
Кнопка запуска поиска¶
Включите готовую кнопку поиска:
{% include 'partials/yetisearch-pro/search-trigger.html.twig' %}
{# С пользовательскими параметрами #}
{% include 'partials/yetisearch-pro/search-trigger.html.twig' with {
placeholder: 'Search docs...',
show_shortcut: true,
class: 'my-custom-class'
} %}
Программное открытие модального окна¶
Добавьте data-ys-open любому элементу, чтобы он открывал модальное окно поиска:
Горячие клавиши: Cmd/Ctrl+K или / (когда фокус не в текстовом поле).
Настройка через CSS-переменные¶
Оба модальных окна используют CSS-переменные для простого оформления:
/* Переменные простого модального окна */
:root {
--ys-simple-dialog-bg: #ffffff;
--ys-simple-text: #111827;
--ys-simple-accent: #3b82f6;
--ys-simple-highlight-bg: #fef08a;
}
/* Переменные полноэкранного модального окна */
:root {
--ys-panel-bg: #181a1f;
--ys-text: #d3d7df;
--ys-accent: #4ea1ff;
}
Переменные Twig¶
Плагин передаёт тип модального окна в Twig:
Встроенная страница поиска¶
Примечание
Встроенная страница поиска работает с YetiSearch Pro 2.3.0. В более ранних версиях её шаблон вызывал функции Twig, которые никогда не регистрировались, поэтому страница не отрисовывалась.
Задайте built_in_search_page: true, чтобы отдавать готовую страницу результатов по адресу search_route (по умолчанию /search). Она использует partials/base.html.twig темы. Если на сайте уже есть страница по этому маршруту, даже неопубликованная, используется она, а встроенная не добавляется.
Страница строится из двух функций Twig, которые может использовать любой шаблон:
yetisearch(query, options)выполняет тот же поиск, что и эндпоинтquery_route, включая обработку языков, событиеonYetisearchProBeforeSearchи аналитику, и возвращает тот же конверт результата:results,total,page,pages,limit,timeиtime_ms(в миллисекундах),suggestionиsemantic. Вoptionsмогут бытьpage,per_page,type(content,apiилиboth),filter(см. DSL фильтров),version,fuzzy,semantic,unique_by_route,max_results, а такжеlat,lng,radius,unitsиsortдля поиска по местоположению (см. Геопоиск).yetisearch_form(options)возвращает форму поиска, которая отправляетqна страницу поиска. Вoptionsмогут бытьplaceholder,button_text,action,valueиclass.
У каждого результата есть title, url, route, excerpt, tags (строка через запятую) и _highlights, а в _meta — date, anchor и heading. В поиске по местоположению у него также есть distance (в метрах) и distance_text.
Подсветка содержит теги <mark> вокруг совпадений, и ничего в ней не экранируется: заголовки хранятся так, как введены, а текст страницы сохраняет сущности вроде <. Прежде чем выводить её как HTML, превратите каждый <, который не начинает <mark> или </mark>, в <, как это делает templates/search.html.twig через {{ text|regex_replace('~<(?!/?mark>)~i', '<')|raw }}, или выводите только обычные поля. Не экранируйте весь текст снова, иначе примеры кода на ваших страницах покажутся как <img вместо <img.
Встроенная страница превращается в поиск по местоположению, когда в её URL есть lat и lng, например /search?q=coffee&lat=51.5074&lng=-0.1278&radius=5&units=km&sort=distance. Тогда каждый результат показывает расстояние, а пустой q перечисляет ближайшие страницы. Местоположение остаётся в ссылках страницы, поэтому пагинация его сохраняет.
Настройка шаблонов модальных окон¶
Оба модальных окна используют шаблон базовый шаблон + extends, который позволяет темам переопределять отдельные части, не переписывая всё модальное окно.
Наследование шаблонов¶
Plugin: partials/yetisearch-pro/base/modal-simple.html.twig ← canonical ({% block %} tags)
Plugin: partials/yetisearch-pro/modal-simple.html.twig ← thin {% extends %} wrapper
Theme: partials/yetisearch-pro/modal-simple.html.twig ← theme override (extends base)
Файл темы затеняет обёртку плагина через разрешение шаблонов Grav. Путь в {% extends %} указывает на base/..., который есть только в плагине, поэтому циклического поиска нет.
Тот же шаблон применяется к modal-full.html.twig.
Доступные блоки — простое модальное окно¶
| Блок | Описание |
|---|---|
modal |
Весь контейнер модального окна |
modal_data_attrs |
Пустой слот для дополнительных атрибутов data-* на корневом <div> |
backdrop |
Затемняющая подложка |
search_input |
Обёртка поля ввода (значок + поле + бейдж ESC) |
results |
Весь раздел результатов |
results_header |
Заголовок с числом результатов |
loading |
Индикатор загрузки |
empty |
Сообщение о пустом состоянии |
type_more |
Подсказка «Type more characters» |
results_list |
Контейнер сгруппированных результатов |
footer |
Раздел подвала |
keyboard_hints |
Подсказки о горячих клавишах |
branding |
Ссылка «Powered by YetiSearch» |
Доступные блоки — полное модальное окно¶
| Блок | Описание |
|---|---|
config_script |
Встроенный <script> для определения эндпоинта и темы |
modal |
Весь контейнер модального окна |
modal_data_attrs |
Пустой слот для дополнительных атрибутов data-* на корневом <div> |
backdrop |
Затемняющая подложка |
search_input |
Строка ввода (значок + поле + фильтры + кнопка отмены) |
near_me |
Строка Near me под полем ввода (пуста, если modal.near_me выключен) |
body |
Контейнер тела (левая и правая панели) |
results_panel |
Левая панель (метаданные + список + пагинация) |
preview_panel |
Правая панель (хлебные крошки + заголовок + фрагмент) |
item_template |
Элемент <template> для клонирования результата |
Пример: переопределение темы¶
Минимальное переопределение темы, добавляющее собственный атрибут данных:
{# themes/my-theme/templates/partials/yetisearch-pro/modal-full.html.twig #}
{% extends 'partials/yetisearch-pro/base/modal-full.html.twig' %}
{% block modal_data_attrs %}
data-ys-extra-params="filter[version][eqor]={{ some_version|url_encode }}"
{% endblock %}
Это передаёт дополнительные параметры запроса эндпоинту поиска, не затрагивая другие части модального окна.
Дополнительные параметры запроса (data-ys-extra-params)¶
Добавьте атрибут data-ys-extra-params корневому элементу модального окна, чтобы добавлять произвольные параметры к каждому поисковому запросу. Значение добавляется как есть к URL запроса:
JS плагина читает этот атрибут при инициализации и добавляет его к каждому URL поиска:
Блок modal_data_attrs — рекомендуемый способ задать это из Twig.
Пример: замена панели предпросмотра¶
{% extends 'partials/yetisearch-pro/base/modal-full.html.twig' %}
{% block preview_panel %}
<div class="ys-right custom-preview">
{# Ваш собственный макет предпросмотра #}
</div>
{% endblock %}
Пример: добавление содержимого после результатов¶
{% extends 'partials/yetisearch-pro/base/modal-simple.html.twig' %}
{% block footer %}
<div class="my-custom-footer">
Custom footer content
</div>
{{ parent() }}
{% endblock %}
Используйте {{ parent() }}, чтобы включить исходное содержимое блока вместе с вашими дополнениями.
Управление на уровне страницы¶
Параметры frontmatter¶
Управляйте индексацией каждой страницы через frontmatter или те же настройки на вкладке YetiSearch редактора страницы:
yetisearch-pro:
index-page: false # исключить эту страницу из индекса
ignore: true # то же, что index-page: false
index-children: false # исключить дочерние страницы из индекса
index-pdfs: false # оставить страницу, но исключить её PDF (2.2.0+)
fields: # дополнительные поля frontmatter для индексации вместе со страницей
- seo.description
Примечание
До 2.2.0 читался только старый ключ yetisearch:, поэтому настройки на вкладке YetiSearch редактора страницы (которые сохраняются под yetisearch-pro:) не действовали. С 2.2.0 читаются оба ключа. Использовать нужно yetisearch-pro:, и он побеждает, если страница задаёт один параметр под обоими ключами.
Шорткод игнорирования¶
Исключите определённые блоки содержимого из индексации, оставив их видимыми на странице:
Поля документов по умолчанию¶
Каждый индексируемый документ содержит:
- Поля содержимого:
title,content,excerpt,url,route,tagsиcategory, полученные из таксономии - Метаданные:
taxonomy,meta,breadcrumbs,date,updated_at - Язык:
language(задаётся для каждой страницы при стратегии единого индекса) - Местоположение:
geoсlatиlng, только для страниц с местоположением (2.3.0+) - Стабильный ID:
<lang>:<route>
Панель управления¶
YetiSearch Pro включает полноценную панель управления, доступную из бокового меню плагина админки.
Панель индекса¶
Следите за состоянием индекса и запускайте обслуживание:
- Просмотр общего числа документов, размеров индексов и времени последнего обновления
- Переиндексация всего содержимого с отслеживанием хода
- Очистка и сброс индексов
Аналитика поиска¶
Отслеживайте вовлечённость в поиск и производительность:
- Общее число и число уникальных запросов
- Переходы по результатам и поиски без результатов
- Среднее время ответа
- Популярные поиски и самые часто открываемые результаты
- Частые запросы без результатов (чтобы находить пробелы в содержимом)
Браузер индекса¶
Просматривайте и управляйте индексируемыми документами:
- Просмотр всех документов с пагинацией
- Поиск внутри индекса
- Просмотр отдельного документа с полным JSON
- Прямое редактирование данных документа
- Отладка статистики индекса и частых терминов
- Оптимизация индексов
Права¶
YetiSearch Pro регистрирует детальные права администратора:
yetisearch-pro.view— просмотр панели поиска и статистикиyetisearch-pro.modify— запуск переиндексации и управление индексамиyetisearch-pro.admin— полный доступ, включая изменение конфигурации
Команды CLI¶
Все команды выполняются из корня сайта Grav.
Команда Index¶
bin/plugin yetisearch-pro index [options]
Options:
-x, --index=INDEX Index key (e.g., pages) [default: pages]
-l, --lang=LANG Language/Version (e.g., 17)
-f, --flush Drop and recreate the target index before indexing
-q, --quiet Minimal output
-r, --raw Raw JSON status
--no-embed Skip embedding for semantic search afterwards
Примеры:
# полная перестройка для одного языка
bin/plugin yetisearch-pro index --index pages --lang 17 --flush
# полная перестройка для всех языков (per_language)
bin/plugin yetisearch-pro index --index pages --flush
# индексация конкретного индекса с суффиксом
bin/plugin yetisearch-pro index --index pages_17 --flush
Когда индекс даёт сбой или запуск не смог удалить устаревший документ (тот, чья страница исчезла), команда называет индекс и причину и завершается со статусом 1, в том числе с --raw, чей JSON тогда содержит "success": false. Устаревший документ, который не удалось удалить, остаётся записанным, поэтому следующий запуск его удалит. Переиндексация в любой админке, API и планировщик также сообщают о таком сбое (2.3.0+).
Команда Query¶
bin/plugin yetisearch-pro query [QUERY] [options]
Core:
-x, --index=INDEX Index key or suffixed key
-l, --lang=LANG Language/Version
-p, --page=PAGE Page number (default: 1)
--per-page=N Results per page (default: 10)
--compact Compact output
-r, --raw Raw JSON output
Location (2.3.0+, see Geo Search):
--lat=LAT Latitude of the search location (needs --lng)
--lng=LNG Longitude of the search location (needs --lat)
--radius=R Only documents within R of the location, in --units
--units=km|mi|m Units for the radius and distances (default: the index's setting, else km)
-s, --sort=distance Nearest first (needs a location)
Search behavior:
--fuzzy Enable fuzzy search
--fuzziness=F Fuzziness score (0..1, default: 0.8)
--fields=LIST Comma-separated fields to search
-s, --sort=SPEC Sort spec, e.g. "title:asc,updated_at:desc"
-F, --filter=EXPR Repeatable filter: field<op>value, e.g. type=content or price>=10 (op: =,!=,>,>=,<,<=)
--no-highlight Disable highlight markup
--highlight-length=N Snippet window length (default: 75)
-d, --distinct[=BOOL] Distinct per route (default: true)
--suggestions Show suggestions after results
--suggestions-limit=N Suggestion count (default: 10)
Текст запроса необязателен, когда есть местоположение: query с --lat и --lng без текста перечисляет ближайшие документы первыми. Нужны и --lat, и --lng, а отрицательное число пишется со знаком равенства, как в --lng=-0.1278. --sort distance требует местоположения. С местоположением в таблице результатов появляется столбец расстояния.
Фильтр пишется без скобок: type=content, price>=10, taxonomy.category=plugins. Поле состоит из букв, цифр, _ и . и начинается с буквы или _. С 2.3.0 фильтр, который команда не может прочитать, например type[=]content, печатает предупреждение с его именем в stderr (чтобы JSON --raw в stdout оставался допустимым) и исключается из поиска.
Примеры:
# нечёткий поиск в индексе для отдельного языка
bin/plugin yetisearch-pro query "install theme" --index pages_17 --fuzzy
# поиск с языком при стратегии единого индекса
bin/plugin yetisearch-pro query "installer" --index pages --lang fr
# с фильтрами и сортировкой
bin/plugin yetisearch-pro query "config" -x pages_17 -F "taxonomy.category=plugins" -s "title:asc"
# ближайшие места в пределах 5 км, без текста запроса
bin/plugin yetisearch-pro query --lat=51.5074 --lng=-0.1278 --radius=5 --sort=distance
Команда Schedule¶
bin/plugin yetisearch-pro schedule [options]
Options:
-l, --list Display configured schedule summary
-t, --task=TASK Task to run: reindex, maintenance, embed, or all (default: all)
-f, --force Run even if the task is disabled
Команда Embed¶
Превращает новые и изменённые документы в эмбеддинги для семантического поиска. Требует включённого семантического поиска.
bin/plugin yetisearch-pro embed [options]
Options:
-x, --index=INDEX Index key (e.g., pages); all semantic indexes by default
-l, --limit=LIMIT Documents per API round [default: 100]
-s, --status Show embedding coverage and exit
-t, --test Check the provider settings with one short request
--reset Forget stored embeddings and embed everything again
--status также показывает порог бессмыслицы каждого индекса и то, измерен ли он на вашем содержимом или является значением по умолчанию. После обновления до 2.1.1 запустите embed один раз: он измеряет порог, даже если каждая страница уже имеет эмбеддинг.
Команда Cache¶
bin/plugin yetisearch-pro cache [ACTION] [options]
Actions:
stats Display cache statistics (default)
monitor Monitor cache activity in real-time
purge Clear all cache entries
warm Pre-populate cache with common queries
Options:
-i, --index=INDEX Index name (auto-detected if omitted)
-d, --details Show detailed cache entries
Эндпоинт запросов и фильтры¶
JSON-эндпоинт запросов (query_route, по умолчанию /ys) обрабатывается во время onPluginsInitialized, когда запрос явно просит JSON (Accept: application/json, ?ajax=1 или .json). Это сокращает инициализацию страницы для быстрого автодополнения и ответов API.
DSL фильтров¶
Передавайте фильтры параметром filter в одной из двух форм.
Форма массива, по одному filter[field][operator]=value на условие. Оператор — имя: eq, eqor (равно или пусто), neq или ne, gt, gte, lt, lte, in, nin, like, contains или exists. filter[field]=value сам по себе означает равно:
Строковая форма, field:operator:value, несколько условий соединяются через AND (пробел с каждой стороны, в URL кодируется как %20 или +). Оператор — один из =, =?, !=, >, >=, <, <=, in, like, contains или exists. Для in разделяйте значения запятыми:
/ys?q=search+terms&filter=version:=?:v3
/ys?q=search+terms&filter=version:=?:v3%20AND%20category:=:plugins
/ys?q=search+terms&filter=version:in:v2,v3
=? совпадает со значением или пустым полем, что подходит страницам, действующим для всех версий. Условие, которое парсер не может прочитать, например version[=]v3, пропускается без ошибки, и поиск выполняется без фильтра. Передача filter дважды (filter=a&filter=b) оставляет только последний, поэтому для нескольких условий используйте AND или форму массива. Старый параметр version=v3 всё ещё принимается и ведёт себя как filter=version:=?:v3.
Флаги включения и выключения в запросе (unique_by_route, semantic, fuzzy) принимают 1, true, yes и on либо 0, false, no и off. unique_by_route=0 возвращает каждый подходящий документ вместо одного на маршрут.
Поиск по местоположению добавляет в запрос lat, lng, radius, units и sort=distance. Что делает каждый из них, см. в разделе Геопоиск.
При включённом семантическом поиске добавьте semantic=0 к запросу, чтобы получить только ранжирование по ключевым словам. Ответ содержит "semantic": true, когда смысл участвовал в ранжировании.
Эндпоинт подсказок¶
Лёгкий эндпоинт подсказок доступен по адресу <query_route>/suggest (например, /ys/suggest):
- Параметры:
termилиq(вводимая строка),limit(по умолчанию 10) - Возвращает JSON-массив
{ text, score, count }с минимальными накладными расходами Grav
События (расширяемость)¶
Эти события Grav позволяют настраивать индексацию и изменять документ перед индексацией:
onYetisearchCollectObjects(index, lang, &documents)— добавить или изменить документы, не являющиеся страницами, для индексацииonYetisearchBuildDocument(subject, lang, index, &doc)— изменить документ перед индексацией (например, добавить собственные поля frontmatter или местоположение). С 2.2.0 событие также срабатывает для каждого PDF-документа, с владеющей страницей вsubject; проверяйтеdoc['doc_type'] === 'pdf', чтобы их различить. Присваивайте изменённый документ обратно через$event['doc'] = $doc; изменение$event['doc']['key']на месте не сохраняется. Другой пример см. в разделе Геопоиск.onYetisearchProBeforeSearch(query, lang, &filters, &options)— добавить собственные фильтры или изменить параметры поиска перед выполнением запроса. В поиске по местоположению проверенное местоположение находится вoptions['geo'](lat,lng,radius,units,sort)onYetisearchPageSkip(page, config)— решить, пропускать ли страницу при индексации.config— определение строящегося индекса. Задайтеskipкакtrueв событии, чтобы исключить страницу
Событие передаёт слушателю значения копией. Прочитайте значение из события, измените его и присвойте обратно ($event['options'] = $options). Изменение на месте, например $event['options']['geo'] = ... или $doc = &$event['doc'], теряется.
Пример: добавление собственных полей¶
public function onYetisearchBuildDocument(Event $event)
{
$page = $event['subject'];
$doc = $event['doc'];
// добавить собственное поле из заголовков страницы
$doc['author'] = $page->header()->author ?? '';
// присвоить изменённый документ обратно, иначе изменение не сохранится
$event['doc'] = $doc;
}
Пример: индексация FlexObjects¶
public function onYetisearchCollectObjects(Event $event)
{
$documents = $event['documents'];
// добавить FlexObjects или другой собственный контент
$flex = $this->grav['flex'];
$collection = $flex->getCollection('my-objects');
foreach ($collection as $object) {
$documents[] = [
'id' => 'flex:' . $object->getKey(),
'title' => $object->getProperty('title'),
'content' => $object->getProperty('description'),
'url' => $object->url(),
];
}
$event['documents'] = $documents;
}
Интеграция с темой Helios¶
YetiSearch Pro и тема документации Helios созданы для совместной работы. Helios включает встроенную поддержку YetiSearch Pro с предварительно настроенной комбинацией Cmd+K / Ctrl+K.
Чтобы включить YetiSearch Pro в Helios, задайте провайдера поиска в конфигурации Helios:
Советы и лучшие практики¶
Индексация¶
- Запускайте
--flushдля первой индексации или после крупной перестройки содержимого - Используйте планировщик Grav для автоматической переиндексации на production-сайтах
- Включайте обновления в реальном времени для сайтов, где содержимое часто меняется в админке
Настройка поиска¶
- Настраивайте веса
boost, чтобы отдавать приоритет совпадениям в заголовках и заголовках разделов перед текстом страницы - Используйте
rerank.demote_prefixes, чтобы опустить менее релевантные разделы (например, справочники API) ниже в результатах - Включайте нечёткий поиск (
options.fuzzy, по умолчанию включён), чтобы находить результаты, несмотря на опечатки. Если он пропускает слишком много ложных совпадений, повысьтеsearch.trigram_threshold(0.45в конфигурации плагина по умолчанию; больше — строже) или задайтеoptions.fuzzy: falseдля индекса. Запрос может отключить его черезfuzzy=0 - При включённом стемминге понижайте
stem_weight, чтобы точные совпадения оставались впереди совпадений с другими формами слова - При включённом семантическом поиске повышайте Minimum Similarity, если показываются слабо связанные страницы, или понижайте Meaning vs Keywords, если точные совпадения по ключевым словам должны побеждать чаще
Производительность¶
- Стратегия индекса
singleпроще и хорошо работает для большинства сайтов - Используйте стратегию
per_languageдля больших многоязычных сайтов, где важен размер индекса - Настраивайте
max_batch_sizeс учётом ограничений памяти сервера - Используйте команду прогрева кэша, чтобы заранее заполнить частые поисковые запросы
Устранение неполадок¶
General error: 1 near "RETURNING": syntax error¶
Эта ошибка означает, что ваша версия SQLite старше 3.35.0. Предложение RETURNING появилось в SQLite 3.35.0 (март 2021). Обновитесь до YetiSearch Pro 1.1.0+ (где используется библиотека YetiSearch 2.3.1+) — эта версия автоматически переходит на совместимый метод запроса на старых версиях SQLite. Минимальная поддерживаемая версия SQLite теперь 3.24.0.
Если обновить плагин нельзя, придётся обновить SQLite:
- Ubuntu/Debian:
sudo apt update && sudo apt install --only-upgrade libsqlite3-0(Ubuntu 22.04+ поставляет 3.37+) - CentOS/RHEL: рассмотрите репозиторий Remi для более новых сборок PHP со свежим SQLite
- Общий хостинг: попросите провайдера обновить SQLite или убедитесь, что PHP скомпилирован с SQLite 3.24.0+
no such module: fts5¶
SQLite в вашем PHP не скомпилирован с поддержкой FTS5. Решения:
- Ubuntu/Debian: установите
php-sqlite3из стандартных репозиториев — большинство современных пакетов включают FTS5 - macOS: используйте PHP из Homebrew (
brew install php), который включает FTS5 по умолчанию - Сборка из исходников: убедитесь, что при сборке SQLite задан
-DSQLITE_ENABLE_FTS5
Как проверить версию SQLite?¶
Выполните из командной строки:
Или используйте встроенный диагностический скрипт:
Он сообщает вашу версию SQLite и доступность модулей FTS5 и R-tree.
Обновление до 2.3.0: полнотекстовый индекс перестраивается один раз¶
В этом выпуске встроенная библиотека YetiSearch обновлена до 2.6.1. В версиях библиотеки 2.5.x удаление страницы с фрагментами или PDF либо сохранение страницы, исключённой из поиска (например, неопубликованной), добавляло имена полей хранимых документов (title, route, content, url и так далее) в индекс как слова. После этого поиск по title или route возвращал каждый документ, пока следующее сохранение страницы не перестраивало индекс.
YetiSearch Pro один раз перестраивает полнотекстовый индекс каждого существующего индекса после обновления, прежде чем что-либо в него записать или удалить из него. Это происходит при первом запуске индексации, сохранении страницы, удалении страницы, изменении PDF или сохранении настроек и записывается в индекс, чтобы больше никогда не выполняться. Это важно, потому что с библиотекой 2.6.0 удаление из индекса, где всё ещё есть такие слова, ломает все последующие поиски по одному из них (2.6.1 также сама перестраивает такой индекс при первой записи). На демо-сайтах Helios это заняло около сотой секунды на индекс, и вручную переиндексировать ничего не нужно.
Если перестройка не удалась, журнал Grav сообщает об этом, и в этот индекс ничего не записывается, пока его не перестроит более поздний запрос.