Spec-Zone.ru › Elasticsearch 7
›Руководство по Elasticsearch [7.17] ›Поиск данных

Сортировка результатов поиска

Позволяет добавить один или несколько сортировок по определённым полям. Каждая сортировка также может быть обращена. Сортировка определяется на уровне поля, с использованием специального имени поля для _score, чтобы сортировать по оценке, и _doc для сортировки по порядку индекса.

Предположим следующую карту индекса:

PUT /my-index-000001
{
  "mappings": {
    "properties": {
      "post_date": { "type": "date" },
      "user": {
        "type": "keyword"
      },
      "name": {
        "type": "keyword"
      },
      "age": { "type": "integer" }
    }
  }
}
GET /my-index-000001/_search
{
  "sort" : [
    { "post_date" : {"order" : "asc", "format": "strict_date_optional_time_nanos"}},
    "user",
    { "name" : "desc" },
    { "age" : "desc" },
    "_score"
  ],
  "query" : {
    "term" : { "user" : "kimchy" }
  }
}

_doc не имеет реального практического применения, кроме того, что это наиболее эффективный порядок сортировки. Поэтому, если вам не важен порядок возвращаемых документов, следует сортировать по _doc. Это особенно полезно при прокрутке.

Значения сортировки

Ответ поиска включает sort значения для каждого документа. Используйте параметр format, чтобы указать формат даты для sort значений полей date и date_nanos. Следующий запрос возвращает sort значения для поля post_date в формате strict_date_optional_time_nanos.

GET /my-index-000001/_search
{
  "sort" : [
    { "post_date" : {"format": "strict_date_optional_time_nanos"}}
  ],
  "query" : {
    "term" : { "user" : "kimchy" }
  }
}

Порядок сортировки

Параметр order может принимать следующие значения:

asc

Сортировка по возрастанию

desc

Сортировка по убыванию

Порядок по умолчанию — desc при сортировке по полю _score, и asc — во всех остальных случаях.

Параметр режима сортировки

Elasticsearch поддерживает сортировку по массивам или многозначным полям. Параметр mode управляет выбором значения массива для сортировки документа, к которому оно относится. Параметр mode может принимать следующие значения:

min

Выбор наименьшего значения.

max

Выбор наибольшего значения.

sum

Использование суммы всех значений в качестве значения сортировки. Применимо только для числовых массивов.

avg

Использование среднего арифметического всех значений в качестве значения сортировки. Применимо только для числовых массивов.

median

Использование медианы всех значений в качестве значения сортировки. Применимо только для числовых массивов.

По умолчанию в порядке возрастания сортировки используется режим min — выбирается наименьшее значение. В порядке убывания — max — выбирается наибольшее значение.

Пример использования режима сортировки

В примере ниже поле price содержит несколько цен на документ. В этом случае результаты будут отсортированы по цене по возрастанию, основываясь на среднем значении цены за документ.

PUT /my-index-000001/_doc/1?refresh
{
   "product": "chocolate",
   "price": [20, 4]
}

POST /_search
{
   "query" : {
      "term" : { "product" : "chocolate" }
   },
   "sort" : [
      {"price" : {"order" : "asc", "mode" : "avg"}}
   ]
}

Сортировка числовых полей

Для числовых полей также можно преобразовать значения из одного типа в другой, используя параметр numeric_type. Этот параметр принимает следующие значения: ["double", "long", "date", "date_nanos"] и может быть полезен для запросов по нескольким потокам данных или индексам, где поле сортировки отображено по-разному.

Рассмотрим, например, эти два индекса:

PUT /index_double
{
  "mappings": {
    "properties": {
      "field": { "type": "double" }
    }
  }
}
PUT /index_long
{
  "mappings": {
    "properties": {
      "field": { "type": "long" }
    }
  }
}

Поскольку field отображено как double в первом индексе и как long во втором, по умолчанию нельзя использовать это поле для сортировки запросов, которые обращаются к обоим индексам. Однако вы можете принудительно установить тип для одного или другого с помощью параметра numeric_type, чтобы принудительно установить определённый тип для всех индексов:

POST /index_long,index_double/_search
{
   "sort" : [
      {
        "field" : {
            "numeric_type" : "double"
        }
      }
   ]
}

В приведённом примере значения для индекса index_long преобразуются в double для совместимости со значениями, полученными от индекса index_double. Также возможно преобразовать поле с плавающей точкой в long, но обратите внимание, что в этом случае значения с плавающей точкой заменяются наибольшим значением, которое меньше или равно (больше или равно, если значение отрицательное) аргументу и равно целому математическому числу.

Этот параметр также можно использовать для преобразования поля date с разрешением миллисекунд в поле date_nanos с разрешением наносекунд. Рассмотрим, например, эти два индекса:

PUT /index_double
{
  "mappings": {
    "properties": {
      "field": { "type": "date" }
    }
  }
}
PUT /index_long
{
  "mappings": {
    "properties": {
      "field": { "type": "date_nanos" }
    }
  }
}

Значения в этих индексах хранятся с разным разрешением, поэтому сортировка по этим полям всегда будет сортировать date перед date_nanos (по возрастанию). С помощью параметра типа numeric_type можно установить единое разрешение для сортировки. Установка в date преобразует значения date_nanos в разрешение миллисекунд, в то время как date_nanos преобразует значения в поле date в разрешение наносекунд:

POST /index_long,index_double/_search
{
   "sort" : [
      {
        "field" : {
            "numeric_type" : "date_nanos"
        }
      }
   ]
}

Для предотвращения переполнения, преобразование в date_nanos не может быть применено к датам до 1970 и после 2262 года, поскольку наносекунды представлены в виде длинных целых чисел.

Сортировка внутри вложенных объектов

Elasticsearch также поддерживает сортировку по полям, которые находятся внутри одного или нескольких вложенных объектов. Поддержка сортировки по вложенным полям имеет параметр сортировки nested со следующими свойствами:

path
Определяет, по какому вложенному объекту производить сортировку. Фактическое поле сортировки должно быть прямым полем внутри этого вложенного объекта. При сортировке по вложенному полю это поле обязательно.
filter
Фильтр, которому должны соответствовать внутренние объекты внутри вложенного пути, чтобы их значения поля учитывались при сортировке. Часто используется повторный запрос/фильтр внутри вложенного фильтра или запроса. По умолчанию никакой nested_filter не активен.
max_children
Максимальное количество дочерних элементов, которое необходимо рассмотреть для каждого корневого документа при выборе значения сортировки. По умолчанию неограниченно.
nested
Аналогично верхнему уровню nested, но применяется к другому вложенному пути внутри текущего вложенного объекта.

Параметры вложенной сортировки до Elasticsearch 6.1

Параметры nested_path и nested_filter устарели и заменены вышеуказанными параметрами.

Примеры сортировки вложенных объектов

В примере ниже offer — поле типа nested. Необходимо указать вложенное поле path; в противном случае Elasticsearch не знает, на каком уровне вложенности необходимо получать значения сортировки.

POST /_search
{
   "query" : {
      "term" : { "product" : "chocolate" }
   },
   "sort" : [
       {
          "offer.price" : {
             "mode" :  "avg",
             "order" : "asc",
             "nested": {
                "path": "offer",
                "filter": {
                   "term" : { "offer.color" : "blue" }
                }
             }
          }
       }
    ]
}

В следующем примере поля parent и child имеют тип nested. Необходимо указать nested_path на каждом уровне; в противном случае Elasticsearch не знает, на каком уровне вложенности необходимо получать значения сортировки.

POST /_search
{
   "query": {
      "nested": {
         "path": "parent",
         "query": {
            "bool": {
                "must": {"range": {"parent.age": {"gte": 21}}},
                "filter": {
                    "nested": {
                        "path": "parent.child",
                        "query": {"match": {"parent.child.name": "matt"}}
                    }
                }
            }
         }
      }
   },
   "sort" : [
      {
         "parent.child.age" : {
            "mode" :  "min",
            "order" : "asc",
            "nested": {
               "path": "parent",
               "filter": {
                  "range": {"parent.age": {"gte": 21}}
               },
               "nested": {
                  "path": "parent.child",
                  "filter": {
                     "match": {"parent.child.name": "matt"}
                  }
               }
            }
         }
      }
   ]
}

Вложенная сортировка также поддерживается при сортировке по скриптам и сортировке по расстоянию.

Пропущенные значения

Параметр missing указывает, как должны обрабатываться документы, в которых отсутствует поле сортировки: Значение missing может быть установлено в _last, _first или пользовательское значение (которое будет использоваться для отсутствующих документов как значение сортировки). По умолчанию значение _last.

Например:

GET /_search
{
  "sort" : [
    { "price" : {"missing" : "_last"} }
  ],
  "query" : {
    "term" : { "product" : "chocolate" }
  }
}

Если вложенный внутренний объект не соответствует nested_filter, то используется пропущенное значение.

Игнорирование неотображённых полей

По умолчанию запрос поиска завершится ошибкой, если полю нет соответствия в карте. Параметр unmapped_type позволяет игнорировать поля, которым не соответствует карта, и не сортировать по ним. Значение этого параметра используется для определения, какие значения сортировки следует выводить. Вот пример его использования:

GET /_search
{
  "sort" : [
    { "price" : {"unmapped_type" : "long"} }
  ],
  "query" : {
    "term" : { "product" : "chocolate" }
  }
}

Если ни один из запрошенных индексов не имеет карты для price, Elasticsearch обработает это так, как будто карта была типа long, и у всех документов в этом индексе не будет значения для этого поля.

Сортировка по географическому расстоянию

Позволяет сортировать по _geo_distance. Вот пример, предполагая, что pin.location — поле типа geo_point:

GET /_search
{
  "sort" : [
    {
      "_geo_distance" : {
          "pin.location" : [-70, 40],
          "order" : "asc",
          "unit" : "km",
          "mode" : "min",
          "distance_type" : "arc",
          "ignore_unmapped": true
      }
    }
  ],
  "query" : {
    "term" : { "user" : "kimchy" }
  }
}
distance_type
Способ вычисления расстояния. Может быть arc (по умолчанию) или plane (быстрее, но неточно для больших расстояний и близко к полюсам).
mode
Действия в случае, если поле содержит несколько гео-точек. По умолчанию, при сортировке по возрастанию учитывается кратчайшее расстояние, а при сортировке по убыванию — наибольшее. Поддерживаемые значения — min, max, median и avg.
unit
Единица измерения при вычислении значений сортировки. По умолчанию — m (метры).
ignore_unmapped
Указывает, следует ли рассматривать неотображённое поле как пропущенное значение. Установка в значение true эквивалентна указанию unmapped_type в сортировке по полю. По умолчанию — false (неотображённое поле приводит к сбою поиска).

Сортировка по гео-расстоянию не поддерживает настраиваемые пропущенные значения: расстояние всегда считается равным Infinity, если документ не содержит значений для поля, используемого для вычисления расстояния.

Ниже приведены поддерживаемые форматы для указания координат:

Lat Lon как свойства

GET /_search
{
  "sort" : [
    {
      "_geo_distance" : {
        "pin.location" : {
          "lat" : 40,
          "lon" : -70
        },
        "order" : "asc",
        "unit" : "km"
      }
    }
  ],
  "query" : {
    "term" : { "user" : "kimchy" }
  }
}

Lat Lon как строка

Формат в lat,lon.

GET /_search
{
  "sort": [
    {
      "_geo_distance": {
        "pin.location": "40,-70",
        "order": "asc",
        "unit": "km"
      }
    }
  ],
  "query": {
    "term": { "user": "kimchy" }
  }
}

Geohash

GET /_search
{
  "sort": [
    {
      "_geo_distance": {
        "pin.location": "drm3btev3e86",
        "order": "asc",
        "unit": "km"
      }
    }
  ],
  "query": {
    "term": { "user": "kimchy" }
  }
}

Lat Lon как массив

Формат в [lon, lat], обратите внимание, порядок lon/lat здесь согласуется с GeoJSON.

GET /_search
{
  "sort": [
    {
      "_geo_distance": {
        "pin.location": [ -70, 40 ],
        "order": "asc",
        "unit": "km"
      }
    }
  ],
  "query": {
    "term": { "user": "kimchy" }
  }
}

Несколько точек отсчета

Несколько гео-точек можно передать как массив, содержащий любой geo_point формат, например

GET /_search
{
  "sort": [
    {
      "_geo_distance": {
        "pin.location": [ [ -70, 40 ], [ -71, 42 ] ],
        "order": "asc",
        "unit": "km"
      }
    }
  ],
  "query": {
    "term": { "user": "kimchy" }
  }
}

и так далее.

Конечное расстояние для документа будет равно min/max/avg (определяется через mode) расстоянием всех точек, содержащихся в документе, до всех точек, заданных в запросе сортировки.

Сортировка на основе скриптов

Разрешает сортировку на основе пользовательских скриптов, вот пример:

GET /_search
{
  "query": {
    "term": { "user": "kimchy" }
  },
  "sort": {
    "_script": {
      "type": "number",
      "script": {
        "lang": "painless",
        "source": "doc['field_name'].value * params.factor",
        "params": {
          "factor": 1.1
        }
      },
      "order": "asc"
    }
  }
}

Отслеживание баллов

При сортировке по полю баллы не вычисляются. Установив track_scores в true, баллы всё ещё будут вычисляться и отслеживаться.

GET /_search
{
  "track_scores": true,
  "sort" : [
    { "post_date" : {"order" : "desc"} },
    { "name" : "desc" },
    { "age" : "desc" }
  ],
  "query" : {
    "term" : { "user" : "kimchy" }
  }
}

Учёт памяти

При сортировке соответствующие отсортированные значения поля загружаются в память. Это означает, что на каждый фрагмент должно быть достаточно оперативной памяти для их хранения. Для строковых типов поле, по которому осуществляется сортировка, не должно быть проанализировано/разбито на токены. Для числовых типов, по возможности, рекомендуется явно установить тип на более узкие типы (например, short, integer и float).

© 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/sort-search-results.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API