Laravel и Elasticsearch: подключение и базовая настройка поиска
14 Июля 2021
В этой статье делимся одним из наших кейсов, подключение и использование Elasticsearch вместе с Laravel на одном из наших проектов (информация о преимуществах по сравнению с конкурентами, и что это за новый проект, будет в одном из следующих постов).
Статья делится на 2 части:
1. Подключение Elasticsearch к Laravel и реализация простого полнотекстового поиска с учетом опечаток. Базовая настройка, маппинг, индексация данных и простой запрос, который вернет результаты с учетом ошибок.
2. Агрегация данных или как его называли в 6-й версии Elasticsearch - фасетный поиск. Его часто можно увидеть в фильтрах e-commerce проектов, а именно, в подсчете количества товаров при фильтрации.
1. Подключение и базовая настройка Elasticsearch
Технологии и версии
Мы всегда используем самое актуальное и свежее, что есть на данный момент, на момент написания статьи - это:
- Laravel 8,
- PHP 8,
- Elasticsearch 7,
- Mysql 8,
- Apache2.
Выбор пакета
Laravel предлагает простое решение для реализации полнотекстового поиска по Eloquent моделям Scout, который использует собственный observer для автоматической переиндексации данных при изменении /добавлении/удалении данных из таблицы. Решение хорошее, но, Scout не поддерживает elasticsearch из коробки (сейчас, в версии laravel8, поддерживается только Algolia и MeiliSearch) и он не дает такой гибкости, которая нужна для более сложных решений, например, как агрегация данных в фильтрах. Ну и «магия» Laravel со Scout не дает полного понимания, как работать с поиском и настраивать его.
Поэтому, исходя из вышеперечисленного, выбор пал на пакет, который предоставляет сам же эластик: «elasticsearch/elasticsearch»
Индексация данных
Процесс настройки сервера, установки Laravel, Elasticsearch на сервер, настройки БД и заполнения таблицы тестовыми данными, по которой будем настраивать поиск, упущу, думаю это не должно быть проблемой.
Пропишем для начала в конфиге services хост для эластика:
Искать будем в таблице products по полю заголовка, поле title в таблице, тип поля varchar. Для этого я создал заранее 1 млн. записей в таблице, специально так много, чтобы показать отличия в скорости поиска с использованием elasticsearch от стандартного mysql like, если в таблице будет большое количество данных.
В AppServiceProvider забиндим класс клиента с Elasticsearch, чтобы можно было легко его использовать в разных классах.
Создадим trait Searchable и observer ElasticsearchObserver для модели Product, который будет следить за обновлениями данных и обновлять индекс.
Trait Searchable будет выглядеть примерно так:
observer ElasticsearchObserver:
Ну и подключим trait Searchable к классу модели:
Создадим еще консольную команду класса ReindexProduct, чтобы проиндексивать все записи из таблицы products, и записать их в Elasticsearch:
В методе handle удаляем индекс если он уже есть, создаем новый индекс с настройками для индексации, и записываем каждый товар в эластик.
Настройки для индексации - важный момент!
Для гибкой настройки поиска под ваши нужды, в них можно описать mappings (это как типы данных в mysql) и analysis, где мы описываем, как именно эластик должен обрабатывать наш запрос. Analysis и Mappings - это отдельная большая тема в эластике, детальнее можно почитать в официальной документации, но для базового примера подойдет и этот вариант настроек.
Все готово, запустим команду индексации:
После того, как проиндексируются все записи, а для индексации 1 млн. записей придется подождать, можно настроить логику кода для поиска.
Логика поиска
Создадим контроллер, который будет принимать запрос, передавать его на сервис поиска, где будет основная логика, и возвращать "вьюху" с нужными нам данными:
Сервис будет выглядеть примерно так:
Elasticsearch уже возвращает результат по релевантности, в методе buildCollection берем все id записей, и сортируем их в запросе в том же порядке, как вернул эластик.
После всего проделанного, страница результата поиска будет выглядеть примерно так:
Как видно на скриншоте, в результате поиска мы получили разные варианты записей, где присутствует слово «витамины» с учетом ошибок и разных окончаний слов.
Скорость выполнения такого запроса будет где-то 80-150 миллисекунд:
А теперь заменим в нашем контроле поиск с эластика на классический title like ‘%витамины%’ и посмотрим скорость такого запроса:
82 секунды!!! Многовато, и ни один нормальный человек не будет ждать результатов поиска, ну и сам результат будет без учета ошибок.
P.S. Это была реализация базового поиска, так сказать «Elastic для чайников».
В следующей статье рассмотрим агрегацию данных, что очень важно, для любого e-commerce проекта.
Статью подготовил: Артур Щаблевский
Понравилась статья? – Поделитесь ссылкой::