Files
ave-cms/help/modules/search.md
T
2026-07-27 12:58:44 +03:00

26 KiB
Raw Permalink Blame History

Поиск по сайту

Назад к разделу «Модули»

Модуль search предоставляет собственный полнотекстовый индекс, страницу результатов, поисковые подсказки и API. Поиск не нужно собирать PHP-кодом в системном блоке. Модуль сам обновляет индекс при сохранении и удалении документа, а внешний вид выдачи можно получить из готового запроса AVE.cms.

Возможности

  • поиск по заголовку, alias, анонсу и разрешённым полям документов;
  • отдельные области: новости, статьи, товары или любые наборы рубрик;
  • четыре штатных алгоритма и регистрация собственных стратегий;
  • встроенный вывод или карточки из существующего запроса;
  • поисковые подсказки;
  • живое обновление результатов и пагинации без перезагрузки страницы;
  • JSON API с явно выбранным набором полей;
  • HTML API для готовой выдачи и режим both для JSON вместе с HTML;
  • хуки до поиска, после поиска, перед выводом и после проекции API.

Быстрый запуск

  1. Откройте Модули → Управление и установите Поиск по сайту.
  2. Перейдите в Модули → Поиск по сайту.
  3. На вкладке Основные задайте URL, шаблон страницы и лимиты.
  4. Выберите рубрики либо оставьте пустой выбор для поиска по всем рубрикам.
  5. Выберите встроенный вывод или запрос с готовыми карточками.
  6. На вкладке Индекс нажмите Переиндексировать.
  7. Добавьте [mod_search] в шаблон, блок или содержимое документа, если нужна отдельная поисковая форма.
  8. Откройте /search?q=установка и проверьте выдачу.

Переиндексация выполняется порциями через панель и не требует командной строки. После первого построения штатное сохранение и удаление документов поддерживает индекс автоматически.

Основные настройки

Публичная страница

Настройка Назначение
URL поиска Адрес страницы результатов. По умолчанию /search.
Шаблон страницы Обычный шаблон сайта, в [tag:maincontent] которого модуль помещает выдачу.
На странице Число результатов, от 5 до 100.
Подсказок Максимальное число вариантов под поисковой строкой.
Минимум символов Запрос короче этого значения не выполняется.

Модуль резервирует URL страницы и адрес подсказок. Документ не сможет получить занятый alias. Адрес /api/v1/search зарезервирован для поискового API и не может быть назначен странице поиска.

Если документ со старым alias search существовал до установки модуля, панель покажет предупреждение. Пока модуль включён, его маршрут имеет приоритет.

Что попадает в индекс

Документ участвует в поиске, когда он:

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

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

После изменения признака поиска у поля или после импорта напрямую в БД запустите полную переиндексацию. Обычное сохранение через AVE.cms делает это само.

Настройка вывода

Поисковый алгоритм только выбирает ID документов и определяет их порядок. Отображение настраивается отдельно.

Встроенный шаблон

Режим Встроенный шаблон поиска выводит универсальный список: дата, название, анонс и ссылка. Это готовый вариант для простого сайта и проверка того, что индекс настроен правильно.

Это осознанное исключение из общего правила AVE.cms: модуль поиска предоставляет собственную резервную разметку, чтобы выдача работала сразу после установки. Движок не навязывает эту разметку остальным подсистемам. На рабочем сайте внешний вид поиска лучше передать обычному запросу AVE.cms или собственному обработчику хука.

Файлы публичного представления находятся в:

modules/search/app/view/
modules/search/app/assets/

В файлах находятся функциональная оболочка страницы, форма и штатные assets. Разметка самих результатов хранится в настройках модуля. Для разных карточек по разделам удобнее использовать запросы.

В Модули → Поиск по сайту → Шаблоны вывода встроенную разметку можно менять без правки файлов. Доступны четыре шаблона:

  • сводка найденного;
  • один результат;
  • обёртка списка;
  • пустая выдача.

Основные теги элемента: [tag:docid], [tag:url], [tag:title], [tag:excerpt], [tag:date], [tag:datetime], [tag:score]. В обёртке работают [tag:summary], [tag:items], [tag:pagination], [tag:query] и [tag:total]. Если убрать [tag:pagination], штатная пагинация будет добавлена после обёртки. Кнопка восстановления возвращает шаблоны поставки после последующего сохранения настроек.

В этих шаблонах PHP не выполняется. Для условий, полей рубрик и полностью проектной карточки используйте существующий запрос или хук вывода.

Карточки из существующего запроса

Режим Шаблоны существующего запроса позволяет использовать уже готовую карточку новости, статьи или товара.

Важно: модуль не выполняет SQL-условия выбранного запроса. Он использует только:

  • Основной шаблон запроса как обёртку списка;
  • Шаблон элемента как карточку каждого найденного документа;
  • настройки кеширования элементов и доступные теги запроса.

ID и их порядок приходят из поискового индекса. Поэтому условия, сортировка, рубрика и лимит самого запроса не меняют состав поисковой выдачи.

Как подготовить запрос

  1. Откройте Контент → Запросы и создайте запрос, например Карточка результата поиска.
  2. Условия можно не задавать: для поиска они не используются.
  3. В Основной шаблон поместите контейнер и [tag:content].
  4. В Шаблон элемента вставьте нужную разметку и теги документа или полей.
  5. При необходимости поместите [tag:pages] в основной шаблон.
  6. Сохраните запрос.
  7. Вернитесь в Модули → Поиск по сайту, выберите способ вывода Шаблоны существующего запроса и созданный запрос.

Минимальный основной шаблон:

<div class="search-grid">
  [tag:content]
</div>
<div class="search-pages">[tag:pages]</div>

Пример элемента:

<article class="search-card">
  <a href="[tag:link]">
    <img src="[tag:rfld:image][img]" alt="[tag:doctitle]">
    <h2>[tag:doctitle]</h2>
    <div class="search-card-price">[tag:rfld:price][more]</div>
  </a>
</article>

В элементе работают штатные теги запросов, в том числе [tag:docid], [tag:link], [tag:doctitle], [tag:excerpt], [tag:rfld:alias][more] и условные конструкции. Это позволяет использовать ту же карточку, что уже применяется в каталоге или новостной ленте.

В основном шаблоне доступны:

Тег Значение
[tag:content] Готовые элементы в порядке релевантности.
[tag:pages] Пагинация поиска.
[tag:doctotal] Общее число совпадений, а не только текущая страница.
[tag:doconpage] Число выведенных элементов.
[tag:pages:curent] Номер текущей страницы. Написание сохранено для совместимости.
[tag:pages:total] Общее число страниц.

Если [tag:pages] отсутствует, модуль добавит свою пагинацию после результата запроса. Если тег есть, пагинацией полностью управляет основной шаблон запроса.

PHP, разрешённый в административно управляемом шаблоне запроса, обрабатывается тем же StoredPhpRuntime, что и на обычных страницах сайта.

Области поиска

Область задаёт собственные рубрики, алгоритм, вывод и поля API. Например:

Название Код Рубрики Вывод
Новости news Новости, Пресс-центр Запрос с карточкой новости
Статьи articles Блог, Инструкции Запрос с карточкой статьи
Товары products Товарные рубрики Запрос с карточкой товара

Пустой набор рубрик означает все рубрики. Область может наследовать основной запрос и набор полей API либо переопределить их.

Публичная страница показывает области как переключатели. Прямые ссылки:

/search?q=кресло
/search?q=кресло&scope=products
/search?q=обзор&scope=articles&page=2

Поисковая форма и подсказки

Доступны теги:

[mod_search]
[mod_search:compact]
[mod_search:news]
  • [mod_search] выводит обычную форму;
  • [mod_search:compact] выводит компактный вариант;
  • [mod_search:news] закрепляет форму за областью news.

У формы включены подсказки. Они обращаются к адресу <URL поиска>/suggest?q=...&scope=.... Базовый модуль возвращает ID, подпись и URL. Установленные модули могут дополнить ответ через хук search.suggestions.projected. Товарный модуль в области products добавляет название, артикул, изображение, текущую и старую цену, поэтому из того же API можно собрать поиск с карточками.

На самой странице поиска JavaScript перехватывает отправку формы, смену области и пагинацию. Результат заменяется через HTML API, URL браузера обновляется через History API. Без JavaScript остаётся обычная GET-форма и серверная пагинация.

JSON и HTML API

Постоянный endpoint:

GET /api/v1/search

Параметры:

Параметр Значение
q Поисковая строка.
scope Код области, необязательно.
page Страница, начиная с 1.
per_page Размер страницы от 5 до 100.
format json, html или both. По умолчанию json.

Пример:

/api/v1/search?q=массажный+стол&scope=products&page=1&per_page=12

Ответ JSON:

{
  "success": true,
  "query": "массажный стол",
  "scope": "products",
  "algorithm": "balanced",
  "pagination": {
    "page": 1,
    "pages": 3,
    "per_page": 12,
    "total": 31
  },
  "items": [
    {
      "id": 145,
      "title": "Массажный стол",
      "url": "/catalog/massazhnyj-stol",
      "price": 125000,
      "image": {
        "url": "/uploads/catalog/145/main.webp",
        "description": "Массажный стол"
      }
    }
  ]
}

format=html возвращает готовый фрагмент результатов с выбранным обработчиком вывода. format=both добавляет этот фрагмент в ключ html JSON-ответа.

API публичный и ограничен rate limiter. Не добавляйте в проекцию служебные или конфиденциальные поля: выбранные значения сможет прочитать посетитель сайта.

Выбор полей API

В Основные → Вывод и API → Поля JSON API выбираются источники ответа. Для каждого источника задаются:

  • ключ в JSON, например title, price, image;
  • формат, в котором поле попадёт в ответ.

Системные источники:

  • ID, название, URL, анонс;
  • дата публикации и изменения;
  • ID рубрики;
  • вычисленная релевантность.

Ниже выводятся реальные поля рубрик по их alias. Если одинаковый alias есть в нескольких рубриках, он представлен одним источником и берёт значение текущего документа.

Форматы:

Формат Результат
Автоматически Нативное значение типа поля: строка, число, массив или объект.
Текст HTML очищается; массив сериализуется в JSON-строку.
Число Числовое значение без оформления.
Да/нет JSON true или false.
Медиа Нормализованный объект изображения/файла либо массив объектов.
Как хранится Исходное значение поля из БД. Используйте только для совместимости.

Чтобы вывести название, цену и изображение:

  1. Выберите Название, назначьте ключ title, формат Текст.
  2. Выберите поле рубрики с alias price, назначьте ключ price, формат Число.
  3. Выберите поле с alias image, назначьте ключ image, формат Медиа.
  4. Добавьте ID или URL, если они нужны клиентскому коду.
  5. Сохраните настройки и проверьте endpoint.

Область может иметь собственную проекцию. Например, news возвращает дату и анонс, а products — цену, наличие и изображения. Пустая проекция области означает наследование основного набора.

Собственный живой поиск

Для выпадающего списка с ценой и изображением используйте JSON API:

fetch('/api/v1/search?q=' + encodeURIComponent(query) +
  '&scope=products&per_page=8', {
  credentials: 'same-origin',
  headers: { Accept: 'application/json' }
})
  .then(function (response) { return response.json(); })
  .then(function (payload) {
    if (!payload.success) return;
    renderItems(payload.items);
  });

Если клиенту нужна уже готовая карточка, используйте format=html. Для одновременного получения структурированных данных и готовой разметки используйте format=both.

Алгоритмы и веса

Штатные стратегии:

  • Сбалансированный — слова объединяются через «ИЛИ», точные совпадения и заголовки получают больший вес;
  • Строгий — каждое слово должно присутствовать;
  • Широкий — полнотекстовый вес MySQL и совпадение любого слова;
  • Только заголовки — поиск по названию и alias.

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

Собственная стратегия

Другой модуль может зарегистрировать алгоритм в своём services.php:

use App\Modules\Search\AlgorithmRegistry;

AlgorithmRegistry::register(
    'editorial',
    'Редакционный',
    function (array $tokens, $query) {
        return array(
            'tokens' => $tokens,
            'operator' => 'and',
            'natural' => false,
        );
    },
    'Все слова обязательны; веса задаются настройками поиска.'
);

Обработчик возвращает план, а не SQL. Допустимые ключи: tokens, operator (and или or), natural, title_only. SQL и параметры по-прежнему формирует репозиторий поиска.

Хуки поиска

Модуль регистрирует стабильные события:

Хук Назначение
search.query.preparing Изменение строки, области, страницы или лимита до SQL.
search.results.resolved Изменение полного результата после поиска.
search.output.rendering Смена режима/запроса или полная подмена HTML до вывода.
search.output.rendered Изменение готового descriptor вывода.
search.results.projected Изменение элементов после проекции JSON.

Подписка другого модуля:

'hooks' => array(
    array(
        'name' => 'search.query.preparing',
        'handler' => array(SearchSubscriber::class, 'prepare'),
        'priority' => 20,
    ),
),

Пример обработчика:

public static function prepare($event)
{
    $query = trim((string) $event->value('query', ''));
    $event->setValue('query', str_replace('ё', 'е', $query));
    return $event;
}

Для полной подмены HTML обработчик search.output.rendering может вызвать $event->cancel() и передать строку через $event->setResult($html). Для добавления вычисляемых ключей JSON измените массив $event->result() в search.results.projected и верните событие.

Производительность и кеш

  • индекс отделён от рабочих таблиц документов;
  • значения полей для API загружаются одним пакетным запросом на текущую страницу;
  • результаты поиска кешируются на 30 секунд;
  • сохранение, удаление и переиндексация сбрасывают тег кеша search;
  • запрос с карточками получает ID уже в порядке релевантности и не повторяет поисковое SQL-условие;
  • массовая переиндексация сбрасывает кеш один раз на порцию, а не на документ.

При установке модуль пытается добавить InnoDB FULLTEXT-индекс. Если сервер MySQL не разрешает такой индекс из-за своих параметров, установка всё равно завершается, а поиск автоматически использует совместимое сравнение LIKE. Функциональность сохраняется, но на большой базе такой режим будет медленнее.

Диагностика

Ничего не найдено после установки. Запустите переиндексацию и проверьте признак поиска у документа и его полей.

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

Карточка пустая или выглядит не так. Проверьте основной шаблон и шаблон элемента выбранного запроса. Условия запроса на поиск не влияют.

Пагинация повторяется дважды. Оставьте [tag:pages] только в основном шаблоне запроса либо удалите его и используйте пагинацию модуля.

В JSON нет цены или изображения. Добавьте соответствующий alias поля в проекцию API нужной области. Настройка индексирования определяет поиск по полю, а проекция API — его присутствие в ответе; это разные настройки.

Область ничего не находит. Проверьте код в scope, выбранные рубрики и алгоритм. Строгий алгоритм требует присутствия каждого слова.

API отвечает 422. Строка короче настроенного минимального размера.

API отвечает 429. Клиент превысил лимит запросов. Для живого поиска используйте задержку после ввода и отменяйте предыдущий fetch.

Отключение и удаление

Отключение убирает публичные маршруты и обработчики, но сохраняет индекс и настройки. Деинсталляция удаляет таблицу индекса и все настройки search.*. Документы, рубрики, шаблоны и выбранный запрос не удаляются.