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

Digital-студия WNDER

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

Elasticsearch — это поисковый сервер, который хранит данные в виде JSON-документов и умеет быстро их искать. Представьте, что у вас есть огромная библиотека, а библиотекарь — это Elasticsearch. Вы говорите ему: «Найди все книги про космос», — и он мгновенно приносит нужные тома. При этом он не просто ищет точные совпадения, а понимает, что «космос» и «звёзды» связаны.

В PHP мы общаемся с Elasticsearch через HTTP-запросы. Можно использовать официальный клиент, а можно просто отправлять JSON-запросы через cURL. Второй вариант проще для понимания, поэтому начнём с него.

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

Сначала нужно установить Elasticsearch. Это можно сделать локально или на сервере. Для разработки достаточно скачать архив с официального сайта и запустить. После этого убедимся, что он работает, открыв в браузере http://localhost:9200. Если видите JSON с информацией о версии — всё отлично.

Теперь напишем простой PHP-скрипт, который проверит подключение:

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://localhost:9200');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

$data = json_decode($response, true);
echo 'Версия Elasticsearch: ' . $data['version']['number'];

Этот код отправляет GET-запрос к серверу и выводит версию. Если всё работает, вы увидите что-то вроде «Версия Elasticsearch: 8.11.0».

Создаём индекс и добавляем данные

В Elasticsearch данные хранятся в индексах. Индекс — это как таблица в MySQL, только умнее. Создадим индекс для статей блога:

$indexName = 'articles';
$mapping = [
    'mappings' => [
        'properties' => [
            'title' => ['type' => 'text'],
            'content' => ['type' => 'text'],
            'author' => ['type' => 'keyword'],
            'views' => ['type' => 'integer']
        ]
    ]
];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://localhost:9200/' . $indexName);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($mapping));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

var_dump($response);

Здесь мы создали индекс articles с полями: title (текст), content (текст), author (ключевое слово) и views (целое число). Тип text означает, что поле будет полнотекстово искать, а keyword — для точного совпадения.

Теперь добавим несколько документов:

$documents = [
    [
        'title' => 'Как выучить PHP',
        'content' => 'PHP — это просто, если практиковаться каждый день.',
        'author' => 'Иван Петров',
        'views' => 1200
    ],
    [
        'title' => 'Основы Elasticsearch',
        'content' => 'Elasticsearch — это поисковый движок на базе Lucene.',
        'author' => 'Мария Сидорова',
        'views' => 850
    ]
];

foreach ($documents as $doc) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, 'http://localhost:9200/articles/_doc/');
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($doc));
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $response = curl_exec($ch);
    curl_close($ch);
    echo $response;
}

Каждый документ получает уникальный ID автоматически. Если нужно свой ID, укажите его в URL: /articles/_doc/my_id.

Поиск по индексу

Теперь самое интересное — поиск. Допустим, пользователь хочет найти статьи про PHP. Отправляем поисковый запрос:

$query = [
    'query' => [
        'match' => [
            'title' => 'PHP'
        ]
    ]
];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://localhost:9200/articles/_search');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($query));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response, true);
foreach ($result['hits']['hits'] as $hit) {
    echo 'Найдено: ' . $hit['_source']['title'] . ', автор: ' . $hit['_source']['author'] . PHP_EOL;
}

Запрос match ищет слово «PHP» в поле title. Elasticsearch возвращает документы, отсортированные по релевантности. Можно усложнить запрос, добавив фильтры, сортировку или агрегации.

Фильтры и сортировка

Часто нужно искать с условиями. Например, показать статьи автора «Иван Петров» с числом просмотров больше 1000. Используем bool запрос:

$query = [
    'query' => [
        'bool' => [
            'must' => [
                ['match' => ['content' => 'PHP']]
            ],
            'filter' => [
                ['term' => ['author' => 'Иван Петров']],
                ['range' => ['views' => ['gte' => 1000]]]
            ]
        ]
    ],
    'sort' => [
        'views' => ['order' => 'desc']
    ]
];

Здесь must — обязательное условие, filter — фильтры, которые не влияют на релевантность, а sort — сортировка по убыванию просмотров.

Правило: Если вам нужно точное совпадение (например, автор или категория), используйте term вместо match. match разбивает текст на слова и ищет каждое, а term ищет точную фразу без изменений.

Работа с официальным клиентом PHP

Хотя cURL — это просто, для больших проектов лучше использовать официальный клиент elasticsearch/elasticsearch. Установите его через Composer:

composer require elasticsearch/elasticsearch

Теперь подключение и операции выглядят более элегантно:

require 'vendor/autoload.php';

$client = \Elastic\Elasticsearch\ClientBuilder::create()
    ->setHosts(['http://localhost:9200'])
    ->build();

// Создание индекса
$params = [
    'index' => 'articles',
    'body' => [
        'mappings' => [
            'properties' => [
                'title' => ['type' => 'text'],
                'content' => ['type' => 'text']
            ]
        ]
    ]
];

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

// Добавление документа
$params = [
    'index' => 'articles',
    'id' => '1',
    'body' => [
        'title' => 'Новая статья',
        'content' => 'Содержимое статьи'
    ]
];
$response = $client->index($params);

// Поиск
$params = [
    'index' => 'articles',
    'body' => [
        'query' => [
            'match' => ['title' => 'новая']
        ]
    ]
];
$response = $client->search($params);

foreach ($response['hits']['hits'] as $hit) {
    echo $hit['_source']['title'];
}

Клиент берёт на себя много рутины: обработку ошибок, переподключение, сериализацию. Это удобно и надёжно.

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

Вот несколько вещей, которые сэкономят вам нервы при работе с Elasticsearch:

  • Не храните в индексе большие тексты целиком. Лучше хранить только ключевые поля, а остальное брать из основной базы данных.
  • Используйте алиасы для индексов. Это позволяет менять структуру индекса без простоя.
  • Настройте анализаторы для русского языка. По умолчанию Elasticsearch не понимает морфологию, но есть плагины, которые это исправляют.
  • Следите за размером индекса. Если он разрастается, используйте шардирование (разбиение на части).
Лайфхак: Для тестирования запросов используйте Kibana — визуальный интерфейс, который идёт в комплекте с Elasticsearch. Там можно писать запросы и сразу видеть результат, а потом переносить их в PHP-код.

Сравнение cURL и официального клиента

Критерий cURL Официальный клиент
Сложность подключения Низкая Средняя (нужен Composer)
Возможности Все, но вручную Все + удобные методы
Обработка ошибок Вручную Автоматическая
Производительность Хорошая Отличная (пул соединений)

Что в итоге

Elasticsearch — это мощный инструмент, который легко интегрируется с PHP. Вы можете начать с простых cURL-запросов, а позже перейти на официальный клиент. Главное — понимать базовые принципы: индексы, документы, запросы. С ними вы сможете построить быстрый и гибкий поиск для любого проекта.

Не бойтесь экспериментировать. Создайте тестовый индекс, добавьте данные, поиграйте с запросами. Через час практики вы почувствуете себя уверенно, а ваш сайт станет заметно шустрее.

Удачи в кодинге!

Студия WNDER