Использование Query

Класс yii\elasticsearch\Query в целом совместим со yii\db\Query, который хорошо описан в руководстве.

Перечислим ключевые отличия.

  • Так как сервер Elasticsearch не поддерживает язык SQL, методы join(), groupBy(), having() и union() работать не будут. Сортировка, функции limit(), offset() и where() поддерживаются с некоторыми ограничениями.

  • Метод from() задает не таблицу, а индекс и тип к которым выполняется запрос.

  • Метод select() заменен на метод storedFields(). Он задает, какие из хранимых полей нужно вернуть, аналогично колонкам в SQL.

  • Так как Elasticsearch - это не только база данных, но и поисковая система, поддерживаются дополнительные механизмы запросов и агрегаций. Более подробно это описано в руководстве по языку запросов Elasticsearch.

Выполнение запросов

В классе yii\elasticsearch\Query реализованы привычные методы для выполнения запросов: one() и all(). Эти методы возвращают исключительно результаты запроса (или один результат).

Также существует метод search(), который возвращает как результаты поиска, так и все метаданные, полученные от сервера, в том числе агрегации.

Расширение поддерживает так называемый скролл-режим, который позволяет эффективно принимать от сервера большие многостраничные результаты запросов. Для работы в таком режиме используются методы batch() и each().

Объем результатов запроса и особенности постраничного вывода

Большинство серверов SQL возвращают по умолчанию все результаты запроса, если не задан параметр LIMIT. Если не указано иное, сервер Elasticsearch всегда возвращает лишь первые 10 результатов. Больше результатов можно получить, если указать их количество в методе yii\elasticsearch\Query::limit(). Это особенно важно при объявлении связей в ActiveRecord, где максимальное количество связанных моделей нужно указать явно.

У Elasticsearch есть определенные ограничения, связанные с постраничным выводом результатов поиска. База данных оптимизирована для использования в качестве поисковой системы, где пользователя обычно обычно интересуют только первые несколько страниц результатов. Хотя с помощью методов yii\elasticsearch\Query::limit() и yii\elasticsearch\Query::offset() можно получить все страницы результатов, чем дальше мы отдаляемся от первой страницы, тем сильнее страдает производительность.

Один из вариантов решения такой задачи - это скролл-режим, который работает примерно как курсоры в традиционных базах данных SQL. В таком режиме работают методы batch() и each().

Обработка ошибок в запросах

Elasticsearch - это распределенная БД. Одно из следствий этой распределенности - это отсутствие гарантий, что все без исключения элементы системы успешно отработали.

Представим себе, как выполняется типичный поисковый запрос. Запрос передается всем шардам, где могут храниться нужные данные, результаты собираются вместе, обрабатываются, а затем возвращаются пользователю. Есть вероятность, что какие-то из шардов не смогли выполнить запрос и вернуть результат. Тем не менее, данных может быть достаточно, чтобы результат был приемлемого качества.

В ответе на запрос сервер возвращает определенные метаданные, в том числе сведения о том, какие шарды не смогли выполнить запрос. Стандартные методы Yii2, такие как one() и all(), игнорируют эти метаданные. Даже если какие-то из шардов не смогли выполнить запрос, это не считается ошибкой сервера.

Чтобы получить ответ сервера целиком, включая статистику по шардам, используйте метод search().

Разумеется, запрос может не сработать по многим причинам (проблемы с соединением, синтаксическая ошибка, и т.д.), но это приведет к исключению.

Обработка ошибок в пакетных запросах

В Elasticsearch пакетный режим - это способ выполнить несколько операций за один запрос к серверу. Так снижаются накладные расходы и увеличивается скорость индексирования.

Поскольку операции в пакете выполняются по одной, какие-то могут выполниться успешно, а какие-то нет. Следует отличать ошибку поискового запроса в целом и ошибки при выполнении отдельных операций в этом запросе. Если нужно узнать, какие из операций выполнились с ошибкой, эти данные есть в результатах вызова метода execute().

Если ошибка возникла в самом пакетном запросе, например, из-за проблем с соединением, это приведет к исключению.

Количество найденных документов в ES > 7.0.0

Начиная с версии Elasticsearch 7.0.0, если по запросу находится более 10000 документов, их общее количество (total_hits) указывается примерно. Иными словами, если найдено более 10000 документов, значение total_hits будет 10000, а если менее, то total_hits будет равно точному количеству найденных документов. Таким образом повышается производительность системы.

С помощью опции track_total_hits это поведение можно изменить. Если передать значение 'true', точное количество документов будет возвращаться в любом случае. Также можно изменить пороговое значение, передав другое число.

$query = new Query();
$query->from('customer');

// Обратите внимание, что значение параметра - строка 'true', а не булево значение
$query->addOptions(['track_total_hits' => 'true']);