Полнотекстовый поиск — это как поиск иголки в стоге сена, только стог огромный, а иголка может быть где угодно. Если ваш сайт на Yii страдает от медленных запросов и неточных результатов, Elasticsearch придёт на помощь. В этой статье мы разберём, как подружить Yii с Elasticsearch и настроить поиск, который работает быстро и релевантно.

Digital-студия WNDER

Что такое Elasticsearch и зачем он нужен в Yii

Elasticsearch — это поисковый движок на основе Lucene. Он хранит данные в виде JSON-документов и умеет искать по ним с высокой скоростью. В Yii мы привыкли использовать базы данных вроде MySQL, но для полнотекстового поиска они не всегда эффективны. Elasticsearch же индексирует текст, разбивает его на токены, применяет стемминг (приведение слов к основе) и ранжирует результаты по релевантности.

Представьте, что у вас интернет-магазин с миллионом товаров. Пользователь вводит «красные кроссовки Nike». MySQL с LIKE будет перебирать все записи и тормозить. Elasticsearch найдёт нужное за миллисекунды, даже если в названии товара написано «кроссовки Nike красного цвета».

Установка и настройка Elasticsearch

Сначала установим Elasticsearch. Скачайте дистрибутив с официального сайта и распакуйте. Для Linux/macOS запустите:

./bin/elasticsearch

Для Windows — bin\elasticsearch.bat. По умолчанию Elasticsearch слушает порт 9200. Проверьте работу:

curl http://localhost:9200

Вы должны увидеть JSON с информацией о кластере. Если всё ок, переходим к Yii.

Подключаем Elasticsearch к Yii

Для интеграции используем официальное расширение yiisoft/yii2-elasticsearch. Установим через Composer:

composer require --prefer-dist yiisoft/yii2-elasticsearch

Теперь настроим компонент в конфиге приложения (например, config/web.php):

return [
    'components' => [
        'elasticsearch' => [
            'class' => 'yii\elasticsearch\Connection',
            'nodes' => [
                ['http_address' => '127.0.0.1:9200'],
            ],
        ],
    ],
];

Всё, соединение готово. Теперь можно выполнять запросы через Yii::$app->elasticsearch.

Правило: Всегда указывайте несколько узлов (nodes) в конфиге, даже если у вас один сервер. Это поможет избежать простоя при перезагрузке Elasticsearch.

Индексация данных в Elasticsearch

Elasticsearch хранит данные в индексах. Индекс — это аналог таблицы в базе данных. Создадим индекс для товаров. В Yii это делается через компонент:

$index = Yii::$app->elasticsearch->createCommand()->index('products');
$index->create([
    'settings' => [
        'number_of_shards' => 1,
        'number_of_replicas' => 0,
    ],
    'mappings' => [
        'properties' => [
            'name' => ['type' => 'text'],
            'description' => ['type' => 'text'],
            'price' => ['type' => 'float'],
        ],
    ],
]);

Теперь заполним индекс данными из базы. Например, возьмём все товары и отправим их в Elasticsearch:

$products = Product::find()->all();
foreach ($products as $product) {
    Yii::$app->elasticsearch->createCommand()->index('products')->add($product->id, [
        'name' => $product->name,
        'description' => $product->description,
        'price' => $product->price,
    ]);
}

Для больших объёмов данных используйте пакетную индексацию (bulk). Это значительно быстрее.

Поиск с помощью Elasticsearch в Yii

Теперь самое интересное — поиск. Допустим, пользователь ищет «кроссовки». Выполним запрос:

$query = Yii::$app->elasticsearch->createCommand()->search('products');
$query->query([
    'multi_match' => [
        'query' => 'кроссовки',
        'fields' => ['name', 'description'],
    ],
]);
$results = $query->all();

В $results будет массив документов с полем _source, где лежат исходные данные. Можно вывести их в представлении.

Чтобы поиск был умнее, используйте анализаторы. Например, русский анализатор умеет учитывать морфологию. Добавим его в настройки индекса:

'settings' => [
    'analysis' => [
        'analyzer' => [
            'my_analyzer' => [
                'type' => 'custom',
                'tokenizer' => 'standard',
                'filter' => ['lowercase', 'russian_morphology', 'english_morphology'],
            ],
        ],
    ],
],

И применим его к полям:

'name' => [
    'type' => 'text',
    'analyzer' => 'my_analyzer',
],

Теперь запрос «кроссовки» найдёт и «кроссовок», и «кроссовочный».

Лайфхак: Используйте fuzziness в запросе, чтобы находить слова с опечатками. Например, 'fuzziness' => 'AUTO' позволит найти «кросовки» вместо «кроссовки».

Сравнение возможностей Elasticsearch и MySQL

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

Критерий MySQL (LIKE) Elasticsearch
Скорость поиска Медленно на больших данных Очень быстро
Релевантность Нет Высокая (ранжирование)
Морфология Нет Есть анализаторы
Опечатки Нет Fuzzy-поиск

Практические советы по интеграции

  • Синхронизация данных. При изменении записи в базе обновляйте документ в Elasticsearch. Можно использовать поведение (behavior) в Yii.
  • Обработка ошибок. Elasticsearch может быть недоступен. Оборачивайте запросы в try-catch и предусмотрите fallback на обычный поиск по базе.
  • Мониторинг. Следите за состоянием кластера через _cluster/health.
  • Безопасность. Не оставляйте Elasticsearch открытым в интернет без аутентификации. Используйте X-Pack или обратный прокси.
Совет: Для автоматической синхронизации используйте события ActiveRecord (afterSave, afterDelete) и отправляйте изменения в Elasticsearch через очередь (например, RabbitMQ или Redis), чтобы не тормозить основной поток.

Заключение

Интеграция Yii с Elasticsearch — это не так сложно, как кажется. Вы получаете мощный полнотекстовый поиск, который работает быстро и умеет прощать опечатки. Главное — правильно настроить анализаторы и не забывать синхронизировать данные. Попробуйте на небольшом проекте, и вы оцените разницу.

Что в итоге: Elasticsearch + Yii = быстрый и релевантный поиск, который порадует пользователей. Дерзайте!

Студия WNDER