Свои данные в поиске по сайту - индексация, адреса, права
Добавляем записи своего модуля в общий поиск по сайту: запись в индекс, адреса результатов, права на показ и поддержание индекса в актуальном виде.
Что нужно знать заранее
Поиск хранит собственный индекс, а не ищет по таблицам проекта. Пока запись не положили в этот индекс, её не найдёт ни один поисковый запрос посетителя.
Каждая запись индекса привязана к модулю и к своему идентификатору. Эта пара служит ключом: повторная запись с тем же ключом обновляет запись, а не заводит вторую.
Права на показ хранятся в самой записи индекса. Поиск не спрашивает ваш модуль, можно ли показать результат, а сравнивает группы посетителя с группами, которые записаны рядом с текстом.
Шаги
- Решить, какие поля записи имеет смысл искать: заголовок и основной текст.
- Класть запись в индекс при создании и при каждом изменении данных.
- Задать адрес результата отдельно для каждой витрины мультисайта.
- Записать в индекс группы, которым эта запись должна быть видна.
- Убирать записи из индекса при удалении данных и при потере доступа.
Решение
Кладём запись в индекс:
\Bitrix\Main\Loader::includeModule('search');\CSearch::Index('vendor.module', 'ITEM_' . $id, [ 'LAST_MODIFIED' => \ConvertTimeStamp(time(), 'FULL'), 'TITLE' => $item['NAME'], 'BODY' => strip_tags($item['TEXT']), // разметка в индексе не нужна 'SITE_ID' => ['s1' => '/registry/item/' . $id . '/'], // адрес результата 'PARAM1' => 'registry', // свой признак для отбора выдачи 'PERMISSIONS' => [2, 7], // кому виден результат], true);Ключом записи служит пара из имени модуля и своего идентификатора. Повторный вызов с той же парой обновляет запись, поэтому отдельный код на создание и на правку писать не нужно.
Обновляем индекс на событии правки:
\Bitrix\Main\EventManager::getInstance()->addEventHandler('vendor.module', 'OnItemSave', [Indexer::class, 'onSave']);// индексация на событии избавляет от расхождения данных и выдачиИндексация из одного места - половина успеха. Если запись в индекс раскидана по контроллерам и скриптам, часть правок рано или поздно пройдёт мимо поиска.
Убираем запись при удалении:
\CSearch::DeleteIndex('vendor.module', 'ITEM_' . $id);// без этого удалённая запись остаётся в выдаче и ведёт на несуществующую страницуМусор в индексе выглядит хуже пустой выдачи. Посетитель находит результат, переходит по нему и получает страницу с ошибкой, а виноват в его глазах сайт целиком.
Отбираем свою выдачу в компоненте поиска:
$APPLICATION->IncludeComponent('bitrix:search.page', '', [ 'arrWHERE' => ['MODULE_ID' => 'vendor.module', 'PARAM1' => 'registry'], 'CHECK_DATES' => 'Y',]);// тот же признак разделяет выдачу на вкладки по типам содержимогоПроверяем, что попало в индекс:
$rs = \CSearch::GetList([], ['MODULE_ID' => 'vendor.module'], ['MODULE_ID', 'ITEM_ID', 'TITLE', 'URL']);while ($row = $rs->Fetch()) { printf("%s %s\n", $row['ITEM_ID'], $row['URL']); }Типичные проблемы
Результат поиска ведёт на несуществующую страницу.
В записи индекса записан старый адрес или адрес не той витрины мультисайта. Адрес задают отдельно для каждого сайта и обновляют вместе с самими данными.
Записи видны всем посетителям, включая закрытые.
В записи индекса не заданы группы, которым результат должен быть виден. Права хранятся в самой записи, а не спрашиваются у модуля при показе.
Поиск находит удалённые записи.
При удалении данных запись из поискового индекса не удаляется. Удаление из индекса делают тем же обработчиком, что и удаление самих данных.
Изменения появляются в поиске только после переиндексации.
Индекс обновляется вручную, а не на событии сохранения данных. Запись в индекс вешают на событие правки, тогда выдача не отстаёт от данных.
Полная переиндексация не видит данных модуля.
У модуля нет обработчика, который отдаёт свои записи механизму переиндексации. Без него в индекс попадает только то, что вы положили туда сами.
Частые вопросы
Можно ли искать по своей таблице без индекса?
Можно своим запросом, но тогда результаты не попадут в общую выдачу сайта. Общий поиск работает только с собственным индексом и его форматом записи.
Что класть в текст записи?
Чистый текст без разметки: заголовок отдельно, тело отдельно. Разметка раздувает индекс и мешает подсветке найденного фрагмента.
Как разделить выдачу по типам содержимого?
Своими признаками записи: по ним компонент поиска отбирает результаты. Обычно первый признак означает тип, второй - раздел или категорию.
Нужна ли переиндексация после правки кода?
Нужна, если менялся состав индексируемых полей или адреса результатов. Точечные правки данных доезжают сами, если индексация висит на событии.
Сколько записей выдержит индекс?
Сотни тысяч записей - обычное дело для штатного поиска. Дальше разумнее внешний поисковый движок с морфологией и подсказками.
Смежное
- Релевантность выдачи: правила сортировки, стоп-слова, вес - как поднять свои документы в выдаче
- Поиск по сайту - оглавление подтемы
- Настройка поиска по сайту: что индексировать, морфология, подсказки - настройки самого поиска
- Поиск не находит товары: индекс, переиндексация, выдача - разбор пустой выдачи
- Живой поиск с подсказками: выдача, доступность, подстроки - подсказки по тому же индексу
- Внешний поисковый движок: индекс, запрос, синхронизация - когда штатного индекса мало
- Свой модуль: структура, установка, автозагрузка классов - где живёт код индексации
- Обработчик события: регистрация, аргументы, отмена действия - как повесить индексацию на событие
- Поиск по сайту - устройство индекса и морфологии целиком