Лучший подход к разбиению на страницы Elasticsearch
Мы разработали решение для хранения файлов, которое использует эластичный поиск для хранения метаданных о файлах с использованием клиентского java API остального уровня.
В настоящее время у нас реализована разбивка на страницы с помощью "от" и "размера". Клиент звонит нам, указывая размер, а также может указать номер страницы, мы используем номер страницы для вычисления смещения или "от".
Им также разрешена сортировка по любому полю, которое может именоваться от строк до дат, целых чисел и т. Д., Но мы по умолчанию используем дату создания.
От и размер вызывают проблемы в настоящий момент, например, с глубокой разбивкой на страницы (решение 1)
1. /rest/metadata/search*
1. numberOfHitsPerPage = 5000
2. from(0),size(5000)
2. /rest/metadata/search?pageNumber=2
1. numberOfHitsPerPage=5000
2. from(5000),size(5000)
3. /rest/metadata/search?pageNumber=3
1. from(10000),size(5000)
2. From + size = 15,000, which is over the index.max_result_window of 10,000 and will fail.
Я изучал функцию searchAfter и реализовал ее, поэтому в ответе мы возвращаем последнее значение индекса "сортировки", которое клиент может использовать в последующих вызовах, чтобы избежать вышеуказанной проблемы. Пример. (Решение 2)
1. /rest/metadata/search
1. numberOfHitsPerPage = 5000
2. We return the 5000 hits but also include the sort value of the last hit.
2. /rest/metadata/search?lastIndexValue=1581418484000
1. numberOfHitsPerPage=5000
2. Under the hood we then use search_after to search from 1581418484000, return the next 5000 hits and the new last index.
3. /rest/metadata/search? lastIndexValue=1581418484011
1. numberOfHitsPerPage=5000
2. Under the hood we then use search_after to search from 1581418484011, return the next 5000 hits and return the new last index.
3. There is no exception here because the filter is applied on the search request itself @ 5000 a time.
В некоторых случаях это работает нормально, но дает нам странные результаты еще и потому, что, как я упоминал выше, мы разрешаем сортировку по любому полю, например, у нас есть 100 файлов, сохраненных с полем "extension", установленным в txt, и 100, установленным в pdf, поэтому пользователь один вызов с размером 10 и хочет отсортировать по "расширению", мы возвращаем их вместе с последним индексом "сортировки", который равен "txt", "txt" затем используется в последующих вызовах для поля searchAfter, но это не не дает никаких результатов.
Так что похоже, что searchAfter только хорошо работает с такими полями, как даты и т. Д.
Я думал, что потенциально мы могли бы сохранить значение lastSorted (индекс) внутри, поэтому вернитесь к решению 1, но если от + size > 10,000, используйте последнее значение сортировки, и оно будет скрыто для пользователя клиента. Единственная проблема, которую я вижу в этом, заключается в том, где мы можем хранить последнее значение сортировки, и последнее значение сортировки должно быть уникальным для каждого поиска, я потенциально не хочу, чтобы огромная БД была заполнена всеми этими значениями сортировки исключительно для этого.
Мысли?
Спасибо,
1 ответ
Как вы правильно заметили, from
а также size
техника не позволяет делать глубокую нумерацию страниц. С участиемsearch_after
вы можете искать так глубоко, как хотите.
Но search_after
не позволяет вам случайным образом "прыгать", но вы можете получать удары последовательно. Для каждого последующего запроса вам необходимо предоставить значения параметров сортировки последнего попадания предыдущего запроса. Значения сортировки должны быть уникальными. Поскольку сортировка только по одному значению (например, _score или суффикс), скорее всего, не уникальна, вам необходимо указать второй критерий сортировки (в идеале уникальное значение), чтобы сделать последнее попадание предыдущего запроса однозначно идентифицируемым.
Вы можете использовать _id
-field для этого, но это было бы не очень эффективно, поскольку Elasticsearch не записывает структуру данных doc-values для _id
-поле. Поэтому используйте любое другое уникальное поле типаkeyword
для этой цели (например, uri). Если у вас нет такого поля с уникальным значением для каждого документа, просто скопируйте значение_id
-field в новое поле типа keyword
. Вы можете сделать это, например, в конвейере приема.