Стрёбление результатов поиска
По умолчанию запросы возвращают 10 совпадающих результатов. Для просмотра большего набора результатов можно использовать параметры API поиска from и size. Параметр from определяет количество результатов для пропуска, по умолчанию он равен 0. Параметр size — максимальное количество возвращаемых результатов. Вместе эти два параметра определяют страницу результатов.
GET /_search
{
"from": 5,
"size": 20,
"query": {
"match": {
"user.id": "kimchy"
}
}
} Избегайте глубокого стрёбления с помощью параметров from и size или запроса слишком большого количества результатов сразу. Запросы поиска обычно охватывают несколько фрагментов. Каждый фрагмент должен загрузить запрошенные результаты и результаты любых предыдущих страниц в память. Для глубоких страниц или больших наборов результатов эти операции могут значительно увеличить использование памяти и ЦП, что приведет к ухудшению производительности или сбоям узла.
По умолчанию нельзя использовать from и size для стрёбления более чем 10 000 результатов. Это ограничение устанавливается настройкой индекса index.max_result_window. Если вам нужно стрёблить больше чем 10 000 результатов, используйте параметр search_after вместо этого.
Elasticsearch использует внутренние идентификаторы документов Lucene в качестве разделителей. Эти внутренние идентификаторы документов могут быть совершенно разными на репликах одних и тех же данных. При стрёблении результатов поиска иногда может наблюдаться, что документы с одинаковыми значениями сортировки не упорядочены последовательно.
Стрёбление по значениям сортировки
Можно использовать параметр search_after, чтобы получить следующую страницу результатов, используя набор значений сортировки с предыдущей страницы.
Использование search_after требует нескольких запросов поиска с одинаковыми значениями параметров query и sort. Если произойдёт обновление POST /my-index-000001/_pit?keep_alive=1m
между этими запросами, порядок результатов может измениться, что приведёт к несогласованным результатам на разных страницах. Для предотвращения этого можно создать момент во времени (PIT) для сохранения текущего состояния индекса при выполнении запросов.
POST /my-index-000001/_pit?keep_alive=1m
API возвращает идентификатор PIT.
{
"id": "46ToAwMDaWR5BXV1aWQyKwZub2RlXzMAAAAAAAAAACoBYwADaWR4BXV1aWQxAgZub2RlXzEAAAAAAAAAAAEBYQADaWR5BXV1aWQyKgZub2RlXzIAAAAAAAAAAAwBYgACBXV1aWQyAAAFdXVpZDEAAQltYXRjaF9hbGw_gAAAAA=="
} Для получения первой страницы результатов отправьте запрос поиска с аргументом sort. Если используется PIT, укажите идентификатор PIT в параметре pit.id и опустите целевой поток данных или индекс из пути запроса.
Все запросы поиска с PIT добавляют неявное поле разделителя сортировки, называемое _shard_doc, которое также можно указать явно. Если вы не можете использовать PIT, рекомендуется включать поле разделителя сортировки в запросе sort. Это поле разделителя сортировки должно содержать уникальное значение для каждого документа. Если вы не включаете поле разделителя сортировки, запрошенные результаты могут пропускать или дублировать результаты.
Запросы с стрёблированием по значениям сортировки имеют оптимизации, которые делают их быстрее, когда порядок сортировки _shard_doc, и общее количество результатов не отслеживается. Если вы хотите перебрать все документы независимо от порядка, это наиболее эффективный вариант.
Если поле sort является date в некоторых целевых потоках данных или индексах, но является полем date_nanos в других целевых объектах, используйте параметр numeric_type для преобразования значений в одно разрешение и параметр format для указания формата даты для поля sort. В противном случае Elasticsearch не правильно интерпретирует параметр стрёбления в каждом запросе.
GET /_search
{
"size": 10000,
"query": {
"match" : {
"user.id" : "elkbee"
}
},
"pit": {
"id": "46ToAwMDaWR5BXV1aWQyKwZub2RlXzMAAAAAAAAAACoBYwADaWR4BXV1aWQxAgZub2RlXzEAAAAAAAAAAAEBYQADaWR5BXV1aWQyKgZub2RlXzIAAAAAAAAAAAwBYgACBXV1aWQyAAAFdXVpZDEAAQltYXRjaF9hbGw_gAAAAA==",
"keep_alive": "1m"
},
"sort": [
{"@timestamp": {"order": "asc", "format": "strict_date_optional_time_nanos", "numeric_type" : "date_nanos" }}
]
} | Идентификатор PIT для поиска. | |
| Сортирует результаты поиска с неявным разделителем сортировки по полю |
Ответ поиска включает массив значений sort для каждого результата. Если вы использовали PIT, разделитель сортировки включается как последнее sort значение для каждого результата. Этот разделитель сортировки, называемый _shard_doc, добавляется автоматически во все запросы поиска, использующие PIT. Значение _shard_doc — это сочетание индекса фрагмента в рамках PIT и внутреннего идентификатора документа Lucene, оно уникально для каждого документа и постоянно в рамках PIT. Вы также можете явно добавить разделитель сортировки в запрос поиска для настройки порядка:
GET /_search
{
"size": 10000,
"query": {
"match" : {
"user.id" : "elkbee"
}
},
"pit": {
"id": "46ToAwMDaWR5BXV1aWQyKwZub2RlXzMAAAAAAAAAACoBYwADaWR4BXV1aWQxAgZub2RlXzEAAAAAAAAAAAEBYQADaWR5BXV1aWQyKgZub2RlXzIAAAAAAAAAAAwBYgACBXV1aWQyAAAFdXVpZDEAAQltYXRjaF9hbGw_gAAAAA==",
"keep_alive": "1m"
},
"sort": [
{"@timestamp": {"order": "asc", "format": "strict_date_optional_time_nanos"}},
{"_shard_doc": "desc"}
]
} | Идентификатор PIT для поиска. | |
| Сортирует результаты поиска с явным разделителем сортировки по полю |
{
"pit_id" : "46ToAwMDaWR5BXV1aWQyKwZub2RlXzMAAAAAAAAAACoBYwADaWR4BXV1aWQxAgZub2RlXzEAAAAAAAAAAAEBYQADaWR5BXV1aWQyKgZub2RlXzIAAAAAAAAAAAwBYgACBXV1aWQyAAAFdXVpZDEAAQltYXRjaF9hbGw_gAAAAA==",
"took" : 17,
"timed_out" : false,
"_shards" : ...,
"hits" : {
"total" : ...,
"max_score" : null,
"hits" : [
...
{
"_index" : "my-index-000001",
"_id" : "FaslK3QBySSL_rrj9zM5",
"_score" : null,
"_source" : ...,
"sort" : [
"2021-05-20T05:30:04.832Z",
4294967298
]
}
]
}
} | Обновлённые | |
| Значения сортировки для последнего возвращённого результата. | |
| Значение разделителя сортировки, уникальное для каждого документа в пределах |
Для получения следующей страницы результатов повторно запустите предыдущий поиск, используя значения сортировки последнего результата (включая разделитель сортировки) в качестве аргумента search_after. Если используется PIT, используйте последний идентификатор PIT в параметре pit.id. Аргументы query и sort поиска должны оставаться неизменными. Если указан, аргумент from должен быть 0 (по умолчанию) или -1.
GET /_search
{
"size": 10000,
"query": {
"match" : {
"user.id" : "elkbee"
}
},
"pit": {
"id": "46ToAwMDaWR5BXV1aWQyKwZub2RlXzMAAAAAAAAAACoBYwADaWR4BXV1aWQxAgZub2RlXzEAAAAAAAAAAAEBYQADaWR5BXV1aWQyKgZub2RlXzIAAAAAAAAAAAwBYgACBXV1aWQyAAAFdXVpZDEAAQltYXRjaF9hbGw_gAAAAA==",
"keep_alive": "1m"
},
"sort": [
{"@timestamp": {"order": "asc", "format": "strict_date_optional_time_nanos"}}
],
"search_after": [
"2021-05-20T05:30:04.832Z",
4294967298
],
"track_total_hits": false
} | Идентификатор PIT, возвращённый предыдущим поиском. | |
| Значения сортировки с последнего результата предыдущего поиска. | |
| Отключить отслеживание общего количества результатов для ускорения стрёбления. |
Этот процесс можно повторить для получения дополнительных страниц результатов. При использовании PIT вы можете продлить срок хранения PIT, используя параметр keep_alive каждого запроса.
По завершении необходимо удалить PIT.
DELETE /_pit
{
"id" : "46ToAwMDaWR5BXV1aWQyKwZub2RlXzMAAAAAAAAAACoBYwADaWR4BXV1aWQxAgZub2RlXzEAAAAAAAAAAAEBYQADaWR5BXV1aWQyKgZub2RlXzIAAAAAAAAAAAwBYgACBXV1aWQyAAAFdXVpZDEAAQltYXRjaF9hbGw_gAAAAA=="
} Стрёбление результатов поиска
Мы больше не рекомендуем использовать API стрёбления для глубокого стрёбления. Если вам нужно сохранить состояние индекса при стрёблении более 10 000 результатов, используйте параметр search_after с моментом во времени (PIT).
В то время как запрос search возвращает одну «страницу» результатов, API scroll можно использовать для получения большого количества результатов (или даже всех результатов) из одного запроса поиска, так же, как вы бы использовали курсор в традиционной базе данных.
Стрёбление не предназначено для запросов в реальном времени от пользователя, а скорее для обработки больших объёмов данных, например, для переиндексации содержимого одного потока данных или индекса в новый поток данных или индекс с другой конфигурацией.
Результаты, возвращаемые запросом стрёбления, отражают состояние потока данных или индекса на момент отправки исходного запроса search, как снимок во времени. Последующие изменения в документах (индексирование, обновление или удаление) повлияют только на последующие запросы.
Для использования стрёбления исходный запрос поиска должен указывать параметр scroll в строке запроса, который сообщает Elasticsearch, как долго следует сохранять «контекст поиска» (см. Сохранение контекста поиска), например, ?scroll=1m.
POST /my-index-000001/_search?scroll=1m
{
"size": 100,
"query": {
"match": {
"message": "foo"
}
}
} Результат вышеуказанного запроса включает _scroll_id, который должен быть передан в API scroll для получения следующей партии результатов.
POST /_search/scroll
{
"scroll" : "1m",
"scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ=="
} |
| |
| Параметр | |
| Параметр |
Параметр size позволяет настроить максимальное количество совпадений, возвращаемых с каждой партией результатов. Каждый вызов API scroll возвращает следующую партию результатов до тех пор, пока не останется больше результатов, т.е. массив hits пуст.
Изначальный запрос поиска и каждый последующий запрос прокрутки возвращают _scroll_id. Хотя _scroll_id может меняться между запросами, это не всегда происходит — в любом случае, следует использовать только последний полученный _scroll_id.
Если запрос указывает агрегации, только начальный ответ поиска будет содержать результаты агрегаций.
Запросы прокрутки имеют оптимизации, которые делают их быстрее, когда порядок сортировки является _doc. Если вы хотите перебрать все документы независимо от порядка, это наиболее эффективный вариант:
GET /_search?scroll=1m
{
"sort": [
"_doc"
]
} Сохранение контекста поиска
Прокрутка возвращает все документы, которые соответствуют поиску на момент первоначального запроса поиска. Она игнорирует любые последующие изменения этих документов. scroll_id идентифицирует контекст поиска, который отслеживает всё, что Elasticsearch нужно для возвращения правильных документов. Контекст поиска создаётся начальным запросом и сохраняется последующими запросами.
Параметр scroll (передаваемый в запрос search и в каждый последующий запрос scroll) сообщает Elasticsearch, как долго необходимо сохранять контекст поиска. Его значение (например, 1m, см. Единицы времени) не должно быть слишком длинным, чтобы обработать все данные — оно должно быть достаточно длинным, чтобы обработать предыдущую партию результатов. Каждый запрос прокрутки scroll (с параметром scroll) устанавливает новое время истечения срока действия. Если запрос прокрутки scroll не передаёт параметр scroll, тогда контекст поиска будет освобожден в рамках этого запроса scroll.
Обычно процесс фоновой слияния оптимизирует индекс, объединяя меньшие сегменты для создания новых, более крупных сегментов. Как только меньшие сегменты больше не нужны, они удаляются. Этот процесс продолжается во время прокрутки, но открытый контекст поиска предотвращает удаление старых сегментов, так как они всё ещё используются.
Сохранение старых сегментов означает, что требуется больше дискового пространства и файловых дескрипторов. Убедитесь, что ваши узлы настроены на достаточное количество свободных файловых дескрипторов. См. Файловые дескрипторы.
Кроме того, если сегмент содержит удалённые или обновлённые документы, то контекст поиска должен отслеживать, был ли каждый документ активен на момент первоначального запроса поиска. Убедитесь, что ваши узлы имеют достаточный объём оперативной памяти, если у вас много открытых прокруток на индексе, который подвержен текущим удалениям или обновлениям.
Чтобы предотвратить проблемы, вызванные слишком большим количеством открытых прокруток, пользователю запрещено открывать прокрутки сверх определённого предела. По умолчанию максимальное количество открытых прокруток составляет 500. Этот предел можно обновить с помощью настройки кластера search.max_open_scroll_context.
Вы можете проверить, сколько контекстов поиска открыто, с помощью API статистики узлов:
GET /_nodes/stats/indices/search
Очистка прокрутки
Контексты поиска автоматически удаляются, когда время ожидания scroll истекло. Однако удерживание прокруток имеет свои издержки, как обсуждалось в предыдущем разделе, поэтому прокрутки следует явно очищать, как только они больше не используются, используя API clear-scroll:
DELETE /_search/scroll
{
"scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ=="
} Несколько идентификаторов прокрутки можно передать как массив:
DELETE /_search/scroll
{
"scroll_id" : [
"DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ==",
"DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAABFmtSWWRRWUJrU2o2ZExpSGJCVmQxYUEAAAAAAAAAAxZrUllkUVlCa1NqNmRMaUhiQlZkMWFBAAAAAAAAAAIWa1JZZFFZQmtTajZkTGlIYkJWZDFhQQAAAAAAAAAFFmtSWWRRWUJrU2o2ZExpSGJCVmQxYUEAAAAAAAAABBZrUllkUVlCa1NqNmRMaUhiQlZkMWFB"
]
} Все контексты поиска можно очистить с помощью параметра _all:
DELETE /_search/scroll/_all
scroll_id также можно передать как параметр строки запроса или в теле запроса. Несколько идентификаторов прокрутки могут быть переданы через запятую:
DELETE /_search/scroll/DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ==,DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAABFmtSWWRRWUJrU2o2ZExpSGJCVmQxYUEAAAAAAAAAAxZrUllkUVlCa1NqNmRMaUhiQlZkMWFBAAAAAAAAAAIWa1JZZFFZQmtTajZkTGlIYkJWZDFhQQAAAAAAAAAFFmtSWWRRWUJrU2o2ZExpSGJCVmQxYUEAAAAAAAAABBZrUllkUVlCa1NqNmRMaUhiQlZkMWFB
Прокрутка с нарезкой
При просмотре большого количества документов полезно разделить поиск на несколько нарезки для их независимого потребления:
GET /my-index-000001/_search?scroll=1m
{
"slice": {
"id": 0,
"max": 2
},
"query": {
"match": {
"message": "foo"
}
}
}
GET /my-index-000001/_search?scroll=1m
{
"slice": {
"id": 1,
"max": 2
},
"query": {
"match": {
"message": "foo"
}
}
} | Идентификатор нарезки | |
| Максимальное количество нарезки |
Результат первого запроса возвращает документы, принадлежащие первой нарезке (id: 0), а результат второго запроса — документы, принадлежащие второй нарезке. Поскольку максимальное количество нарезки установлено в 2, объединение результатов двух запросов эквивалентно результатам запроса прокрутки без нарезки. По умолчанию разделение выполняется сначала по фрагментам, а затем локально на каждом фрагменте, используя поле _id. Локальное разделение следует формуле slice(doc) = floorMod(hashCode(doc._id), max)).
Каждая прокрутка независима и может обрабатываться параллельно, как любой запрос прокрутки.
Если количество нарезки больше количества фрагментов, фильтр нарезки очень медленный при первых вызовах, он имеет сложность O(N) и затраты памяти, равные N битам на нарезку, где N — общее количество документов во фрагменте. После нескольких вызовов фильтр должен быть кэширован, и последующие вызовы должны быть быстрее, но вы должны ограничить количество параллельных запросов с нарезкой, чтобы избежать взрыва памяти.
API точек во времени поддерживает более эффективную стратегию разделения и не страдает этой проблемой. В возможности, рекомендуется использовать поиск с точками во времени с нарезкой вместо прокрутки.
Ещё один способ избежать этих высоких затрат — использовать doc_values другого поля для нарезки. Поле должно иметь следующие свойства:
- Поле является числовым.
-
doc_valuesвключены для этого поля - Каждый документ должен содержать одно значение. Если документ имеет несколько значений для указанного поля, используется первое значение.
- Значение для каждого документа должно быть установлено один раз при создании документа и не должно обновляться. Это гарантирует, что каждая нарезка получает детерминированные результаты.
- Мощность поля должна быть высокой. Это гарантирует, что каждая нарезка получает примерно одинаковое количество документов.
GET /my-index-000001/_search?scroll=1m
{
"slice": {
"field": "@timestamp",
"id": 0,
"max": 10
},
"query": {
"match": {
"message": "foo"
}
}
} Для индексов, основанных на времени с добавлением данных, поле timestamp можно безопасно использовать.
© 2023-2025 Elasticsearch
As of September 2024, Elasticsearch is available under a choice of three licenses: the Server Side Public License (SSPL), the Elastic License, or the AGPLv3 (OSI approved).
Elasticsearch and the Elasticsearch logo are trademarks of Elasticsearch B.V., registered in the U.S. and in other countries.
https://www.elastic.co/guide/en/elasticsearch/reference/7.17/paginate-search-results.html