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 хост для эластика:

elasticsearch_hosts

Искать будем в таблице products по полю заголовка, поле title в таблице, тип поля varchar. Для этого я создал заранее 1 млн. записей в таблице, специально так много, чтобы показать отличия в скорости поиска с использованием elasticsearch от стандартного mysql like, если в таблице будет большое количество данных.

В AppServiceProvider забиндим класс клиента с Elasticsearch, чтобы можно было легко его использовать в разных классах.

elasticsearch_setup1

Создадим trait Searchable и observer ElasticsearchObserver для модели Product, который будет следить за обновлениями данных и обновлять индекс.

Trait Searchable будет выглядеть примерно так:

elasticsearch_traitsearchable

observer ElasticsearchObserver:

Elasticsearch_ObserverElasticsearch_Observer2

Ну и подключим trait Searchable к классу модели:

elastic_trait_searchable

Создадим еще консольную команду класса ReindexProduct, чтобы проиндексивать все записи из таблицы products, и записать их в Elasticsearch:

elasticsearch3

В методе handle удаляем индекс если он уже есть, создаем новый индекс с настройками для индексации, и записываем каждый товар в эластик.  

Настройки для индексации - важный момент!

Для гибкой настройки поиска под ваши нужды, в них можно описать mappings (это как типы данных в mysql) и analysis, где мы описываем, как именно эластик должен обрабатывать наш запрос. Analysis и Mappings - это отдельная большая тема в эластике, детальнее можно почитать в официальной документации, но для базового примера подойдет и этот вариант настроек.

Все готово, запустим команду индексации:

После того, как проиндексируются все записи, а для индексации 1 млн. записей придется подождать, можно настроить логику кода для поиска.

Логика поиска

Создадим контроллер, который будет принимать запрос, передавать его на сервис поиска, где будет основная логика, и возвращать "вьюху" с нужными нам данными:

Сервис будет выглядеть примерно так:

Elasticsearch уже возвращает результат по релевантности, в методе buildCollection берем все id записей, и сортируем их в запросе в том же порядке, как вернул эластик.

После всего проделанного, страница результата поиска будет выглядеть примерно так:

Как видно на скриншоте, в результате поиска мы получили разные варианты записей, где присутствует слово «витамины» с учетом ошибок и разных окончаний слов.

Скорость выполнения такого запроса будет где-то 80-150 миллисекунд:

 

А теперь заменим в нашем контроле поиск с эластика на классический title like ‘%витамины%’ и посмотрим скорость такого запроса:

82 секунды!!! Многовато, и ни один нормальный человек не будет ждать результатов поиска, ну и сам результат будет без учета ошибок.

P.S. Это была реализация базового поиска, так сказать «Elastic для чайников».

В следующей статье рассмотрим агрегацию данных, что очень важно, для любого e-commerce проекта.

 

Статью подготовил: Артур Щаблевский

Понравилась статья? – Поделитесь ссылкой::