Laravel та Elasticsearch: підключення та базове налаштування пошуку

14 Липня 2021

У цій статті ділимося одним з наших кейсів, підключення і використання Elasticsearch разом з Laravel на одному з наших проектів (інформація про переваги в порівнянні з  конкурентами, і що це за новий проект, буде в одному з наступних постів).

Стаття ділиться на дві частини:

1. Підключення Elasticsearch до Laravel і реалізація простого повнотекстового пошуку з урахуванням друкарських помилок. Базове налаштування, мапінг, індексація даних і простий запит, який поверне результати з урахуванням помилок.

2. Агрегація даних або як його називали в 6-й версії Elasticsearch - фасетний пошук. Його часто можна побачити у фільтрах e-commerce проектів, а саме у підрахунку кількості товарів при фільтрації.

Агрегація даних (фасетний пошук)

1. Підключення та базове налаштування Elasticsearch

Технології та версії

Ми завжди використовуємо найактуальніше та найсвіжіше, що є на даний момент, на момент написання статті – це:

  • Laravel 8,
  • PHP 8,
  • Elasticsearch 7,
  • Mysql 8,
  • Apache2.

Вибір пакету

Laravel пропонує просте рішення для реалізації повнотекстового пошуку по Eloquent моделям Scout, який використовує власний обсерватор для автоматичної переіндексації даних при зміні/додаванні/видаленні даних з таблиці. Рішення хороше, однак, Scout не підтримує еластичнийвиробництво з коробки (зараз, у версії 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_Observer

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

elasticsearch3

У методі handle видаляємо індекс якщо він вже є, створюємо новий індекс з налаштуваннями для індексації, і записуємо кожен товар в еластик.  

Налаштування для індексації – важливий момент!

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

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

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

Логіка пошуку

Створимо контролер, який прийматиме запит, передаватиме його на сервіс пошуку, де буде основна логіка, і повертатиме "в'юху" з потрібними нам даними:

Сервіс буде виглядати приблизно так:

Elasticsearch вже повертає результат за релевантністю, у методі buildCollection беремо всі id записів, і сортуємо їх у запиті в тому ж порядку, як повернув еластик.

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

Як видно на скріншоті, в результаті пошуку ми отримали різні варіанти записів, де є слово «вітаміни» з урахуванням помилок та різних закінчень слів.

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

 

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

82 секунди!!! Багато, і ні одна нормальна людина не буде чекати результатів пошуку, ну і сам результат буде без урахування помилок.

PS. Це була реалізація базового пошуку, так би мовити «Elastic для чайників».

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

 

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

Сподобалася стаття ? - Поділіться посиланням ::