Если ваш сайт на PHP когда-нибудь тормозил из-за поиска по базе данных, вы знаете, как это больно. Elasticsearch решает эту проблему, но интеграция с PHP может показаться сложной. На самом деле всё проще, чем кажется: достаточно знать несколько приёмов и использовать правильную библиотеку.

Digital-студия WNDER

Почему Elasticsearch, а не обычный SQL LIKE

Представьте, что у вас интернет-магазин с миллионом товаров. Пользователь вводит "красные кроссовки Nike". Если вы делаете запрос WHERE name LIKE '%красные%', база данных перебирает все записи. Это медленно и неточно.

Elasticsearch — это поисковый движок, который хранит данные в виде документов и умеет искать по ним с невероятной скоростью. Он анализирует текст, разбивает на слова, учитывает опечатки, синонимы и релевантность. Для PHP-разработчика это означает, что можно забыть о тормозах и сложных SQL-запросах.

Установка и подключение клиента

Для работы с Elasticsearch из PHP есть официальная библиотека elasticsearch-php. Устанавливается через Composer:

composer require elasticsearch/elasticsearch

После установки создаём клиент. По умолчанию Elasticsearch слушает порт 9200 на localhost.

<?php
require 'vendor/autoload.php';

use Elasticsearch\ClientBuilder;

$client = ClientBuilder::create()
    ->setHosts(['localhost:9200'])
    ->build();

// Проверка соединения
$info = $client->info();
echo 'Elasticsearch версия: ' . $info['version']['number'];

Если всё сделано правильно, вы увидите номер версии. Если нет — проверьте, запущен ли Elasticsearch и доступен ли порт.

Индексация данных: первый шаг к поиску

Прежде чем искать, нужно создать индекс (аналог таблицы в SQL) и добавить документы. Допустим, у нас есть таблица products в MySQL. Мы хотим перенести товары в Elasticsearch.

<?php
// Создаём индекс с настройками
$params = [
    'index' => 'products',
    'body' => [
        'settings' => [
            'number_of_shards' => 1,
            'number_of_replicas' => 0
        ],
        'mappings' => [
            'properties' => [
                'name' => ['type' => 'text'],
                'price' => ['type' => 'float'],
                'description' => ['type' => 'text']
            ]
        ]
    ]
];

$client->indices()->create($params);

Теперь добавим документ. Можно вручную, но лучше использовать bulk-запросы для пакетной вставки.

<?php
$params = [
    'index' => 'products',
    'id' => 1,
    'body' => [
        'name' => 'Кроссовки Nike Air',
        'price' => 8990,
        'description' => 'Удобные красные кроссовки для бега'
    ]
];

$response = $client->index($params);

Для массовой загрузки из MySQL используйте цикл и bulk():

<?php
$bulkParams = ['body' => []];
$stmt = $pdo->query('SELECT id, name, price, description FROM products');
while ($row = $stmt->fetch()) {
    $bulkParams['body'][] = [
        'index' => [
            '_index' => 'products',
            '_id' => $row['id']
        ]
    ];
    $bulkParams['body'][] = [
        'name' => $row['name'],
        'price' => (float)$row['price'],
        'description' => $row['description']
    ];
}
$client->bulk($bulkParams);
Правило: Никогда не индексируйте данные по одному документу в цикле — это убивает производительность. Используйте bulk-запросы пакетами по 500–1000 документов.

Поиск: от простого к сложному

Самый простой поиск — match-запрос. Он ищет по указанному полю с учётом анализа текста.

<?php
$params = [
    'index' => 'products',
    'body' => [
        'query' => [
            'match' => [
                'name' => 'красные кроссовки'
            ]
        ]
    ]
];

$response = $client->search($params);
foreach ($response['hits']['hits'] as $hit) {
    echo $hit['_source']['name'] . ' - ' . $hit['_source']['price'] . ' руб.' . PHP_EOL;
}

Elasticsearch вернёт документы, отсортированные по релевантности. Если нужно искать по нескольким полям, используйте multi_match:

<?php
'query' => [
    'multi_match' => [
        'query' => 'красные кроссовки',
        'fields' => ['name^2', 'description']
    ]
]

Символ ^2 означает, что поле name важнее в два раза.

Практические советы и лайфхаки

  • Используйте фильтры для точных значений. Если нужно отфильтровать по цене или категории, применяйте filter внутри bool — это быстрее и не влияет на релевантность.
  • Настройте анализатор для русского языка. По умолчанию Elasticsearch не понимает морфологию. Установите плагин analysis-icu или используйте встроенный russian анализатор.
  • Пагинация через from и size. Но помните: глубокий from (более 10000) может тормозить. Для больших выборок используйте search_after.
  • Обрабатывайте ошибки. Elasticsearch может быть недоступен. Оборачивайте вызовы в try-catch и логируйте.
Лайфхак: Если вы часто меняете данные, используйте алиасы индексов. Создайте новый индекс, проиндексируйте данные, а затем переключите алиас на него. Это позволит обновлять поиск без простоя.

Сравнение основных методов поиска:

Метод Когда использовать Пример
match Полнотекстовый поиск по одному полю Поиск по названию товара
multi_match Поиск по нескольким полям Название + описание
term Точное совпадение (без анализа) Фильтр по статусу заказа
bool Комбинация условий (must, should, filter) Сложные запросы с фильтрацией

Что в итоге

Elasticsearch и PHP — отличный тандем для создания быстрого и умного поиска. Главное — правильно настроить индекс, использовать bulk-индексацию и не забывать про анализаторы. Начните с простых запросов, постепенно усложняя их. И помните: поиск должен помогать пользователю, а не заставлять его ждать.

Если вы только начинаете, попробуйте интегрировать Elasticsearch в небольшой проект — например, для поиска по статьям блога. Уверен, результат вас приятно удивит.

Студия WNDER