Сортировка результатов поиска
Позволяет добавить один или несколько сортировок по определенным полям. Каждая сортировка также может быть обратной. Сортировка определяется на уровне поля, с использованием специальных имён полей для _score сортировки по оценке релевантности и _doc для сортировки по порядку индекса.
Для оптимизации производительности сортировки, избегайте сортировки по полям типа text; вместо этого используйте поля типа keyword или numerical. Кроме того, можно улучшить производительность, включив предварительную сортировку во время индексации, используя сортировку индекса. Хотя это может ускорить сортировку во время запроса, это может снизить производительность индексации и увеличить использование памяти.
Предполагается следующее отображение индекса:
resp = client.indices.create(
index="my-index-000001",
mappings={
"properties": {
"post_date": {
"type": "date"
},
"user": {
"type": "keyword"
},
"name": {
"type": "keyword"
},
"age": {
"type": "integer"
}
}
},
)
print(resp) response = client.indices.create(
index: 'my-index-000001',
body: {
mappings: {
properties: {
post_date: {
type: 'date'
},
user: {
type: 'keyword'
},
name: {
type: 'keyword'
},
age: {
type: 'integer'
}
}
}
}
)
puts response res, err := es.Indices.Create(
"my-index-000001",
es.Indices.Create.WithBody(strings.NewReader(`{
"mappings": {
"properties": {
"post_date": {
"type": "date"
},
"user": {
"type": "keyword"
},
"name": {
"type": "keyword"
},
"age": {
"type": "integer"
}
}
}
}`)),
)
fmt.Println(res, err) const response = await client.indices.create({
index: "my-index-000001",
mappings: {
properties: {
post_date: {
type: "date",
},
user: {
type: "keyword",
},
name: {
type: "keyword",
},
age: {
type: "integer",
},
},
},
});
console.log(response); PUT /my-index-000001
{
"mappings": {
"properties": {
"post_date": { "type": "date" },
"user": {
"type": "keyword"
},
"name": {
"type": "keyword"
},
"age": { "type": "integer" }
}
}
} resp = client.search(
index="my-index-000001",
sort=[
{
"post_date": {
"order": "asc",
"format": "strict_date_optional_time_nanos"
}
},
"user",
{
"name": "desc"
},
{
"age": "desc"
},
"_score"
],
query={
"term": {
"user": "kimchy"
}
},
)
print(resp) response = client.search(
index: 'my-index-000001',
body: {
sort: [
{
post_date: {
order: 'asc',
format: 'strict_date_optional_time_nanos'
}
},
'user',
{
name: 'desc'
},
{
age: 'desc'
},
'_score'
],
query: {
term: {
user: 'kimchy'
}
}
}
)
puts response const response = await client.search({
index: "my-index-000001",
sort: [
{
post_date: {
order: "asc",
format: "strict_date_optional_time_nanos",
},
},
"user",
{
name: "desc",
},
{
age: "desc",
},
"_score",
],
query: {
term: {
user: "kimchy",
},
},
});
console.log(response); 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.
resp = client.search(
index="my-index-000001",
sort=[
{
"post_date": {
"format": "strict_date_optional_time_nanos"
}
}
],
query={
"term": {
"user": "kimchy"
}
},
)
print(resp) response = client.search(
index: 'my-index-000001',
body: {
sort: [
{
post_date: {
format: 'strict_date_optional_time_nanos'
}
}
],
query: {
term: {
user: 'kimchy'
}
}
}
)
puts response const response = await client.search({
index: "my-index-000001",
sort: [
{
post_date: {
format: "strict_date_optional_time_nanos",
},
},
],
query: {
term: {
user: "kimchy",
},
},
});
console.log(response); GET /my-index-000001/_search
{
"sort" : [
{ "post_date" : {"format": "strict_date_optional_time_nanos"}}
],
"query" : {
"term" : { "user" : "kimchy" }
}
} Порядок сортировки
Опция order может иметь следующие значения:
| | Сортировка по возрастанию |
| | Сортировка по убыванию |
По умолчанию порядок сортировки устанавливается в desc при сортировке по _score, и в asc при сортировке по другим полям.
Опция режима сортировки
Elasticsearch поддерживает сортировку по массивам или многозначным полям. Опция mode управляет тем, какое значение массива выбирается для сортировки документа, к которому оно относится. Опция mode может иметь следующие значения:
| | Выбрать наименьшее значение. |
| | Выбрать наибольшее значение. |
| | Использовать сумму всех значений как значение сортировки. Применимо только к числовым массивам. |
| | Использовать среднее всех значений как значение сортировки. Применимо только к числовым массивам. |
| | Использовать медиану всех значений как значение сортировки. Применимо только к числовым массивам. |
По умолчанию режим сортировки при сортировке по возрастанию — min (выбирается наименьшее значение). По умолчанию режим сортировки при сортировке по убыванию — max (выбирается наибольшее значение).
Пример использования режима сортировки
В примере ниже поле price имеет несколько цен на документ. В этом случае результаты будут отсортированы по цене по возрастанию на основе среднего значения цены на документ.
resp = client.index(
index="my-index-000001",
id="1",
refresh=True,
document={
"product": "chocolate",
"price": [
20,
4
]
},
)
print(resp)
resp1 = client.search(
query={
"term": {
"product": "chocolate"
}
},
sort=[
{
"price": {
"order": "asc",
"mode": "avg"
}
}
],
)
print(resp1) response = client.index(
index: 'my-index-000001',
id: 1,
refresh: true,
body: {
product: 'chocolate',
price: [
20,
4
]
}
)
puts response
response = client.search(
body: {
query: {
term: {
product: 'chocolate'
}
},
sort: [
{
price: {
order: 'asc',
mode: 'avg'
}
}
]
}
)
puts response {
res, err := es.Index(
"my-index-000001",
strings.NewReader(`{
"product": "chocolate",
"price": [
20,
4
]
}`),
es.Index.WithDocumentID("1"),
es.Index.WithRefresh("true"),
es.Index.WithPretty(),
)
fmt.Println(res, err)
}
{
res, err := es.Search(
es.Search.WithBody(strings.NewReader(`{
"query": {
"term": {
"product": "chocolate"
}
},
"sort": [
{
"price": {
"order": "asc",
"mode": "avg"
}
}
]
}`)),
es.Search.WithPretty(),
)
fmt.Println(res, err)
} const response = await client.index({
index: "my-index-000001",
id: 1,
refresh: "true",
document: {
product: "chocolate",
price: [20, 4],
},
});
console.log(response);
const response1 = await client.search({
query: {
term: {
product: "chocolate",
},
},
sort: [
{
price: {
order: "asc",
mode: "avg",
},
},
],
});
console.log(response1); 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"] и может быть полезной для запросов по нескольким потокам данных или индексам, где поле сортировки отображено по-разному.
Рассмотрим, например, эти два индекса:
resp = client.indices.create(
index="index_double",
mappings={
"properties": {
"field": {
"type": "double"
}
}
},
)
print(resp) response = client.indices.create(
index: 'index_double',
body: {
mappings: {
properties: {
field: {
type: 'double'
}
}
}
}
)
puts response res, err := es.Indices.Create(
"index_double",
es.Indices.Create.WithBody(strings.NewReader(`{
"mappings": {
"properties": {
"field": {
"type": "double"
}
}
}
}`)),
)
fmt.Println(res, err) const response = await client.indices.create({
index: "index_double",
mappings: {
properties: {
field: {
type: "double",
},
},
},
});
console.log(response); PUT /index_double
{
"mappings": {
"properties": {
"field": { "type": "double" }
}
}
} resp = client.indices.create(
index="index_long",
mappings={
"properties": {
"field": {
"type": "long"
}
}
},
)
print(resp) response = client.indices.create(
index: 'index_long',
body: {
mappings: {
properties: {
field: {
type: 'long'
}
}
}
}
)
puts response res, err := es.Indices.Create(
"index_long",
es.Indices.Create.WithBody(strings.NewReader(`{
"mappings": {
"properties": {
"field": {
"type": "long"
}
}
}
}`)),
)
fmt.Println(res, err) const response = await client.indices.create({
index: "index_long",
mappings: {
properties: {
field: {
type: "long",
},
},
},
});
console.log(response); PUT /index_long
{
"mappings": {
"properties": {
"field": { "type": "long" }
}
}
} Поскольку field отображается как double в первом индексе и как long во втором, по умолчанию невозможно использовать это поле для сортировки запросов, которые запрашивают оба индекса. Однако вы можете принудительно установить тип к одному из них с помощью опции numeric_type, чтобы принудительно установить определённый тип для всех индексов:
$params = [
'index' => 'index_long,index_double',
'body' => [
'sort' => [
[
'field' => [
'numeric_type' => 'double',
],
],
],
],
];
$response = $client->search($params); resp = client.search(
index="index_long,index_double",
sort=[
{
"field": {
"numeric_type": "double"
}
}
],
)
print(resp) response = client.search(
index: 'index_long,index_double',
body: {
sort: [
{
field: {
numeric_type: 'double'
}
}
]
}
)
puts response res, err := es.Search(
es.Search.WithIndex("index_long,index_double"),
es.Search.WithBody(strings.NewReader(`{
"sort": [
{
"field": {
"numeric_type": "double"
}
}
]
}`)),
es.Search.WithPretty(),
)
fmt.Println(res, err) const response = await client.search({
index: "index_long,index_double",
sort: [
{
field: {
numeric_type: "double",
},
},
],
});
console.log(response); POST /index_long,index_double/_search
{
"sort" : [
{
"field" : {
"numeric_type" : "double"
}
}
]
} В примере выше значения для индекса index_long преобразуются в double, чтобы быть совместимыми со значениями, полученными от индекса index_double. Также возможно преобразовать поле с плавающей точкой в целое число, но в этом случае числа с плавающей точкой заменяются наибольшим значением, которое меньше или равно (больше или равно, если значение отрицательное) аргументу и равно целому числу.
Эта опция также может использоваться для преобразования поля date, использующего миллисекундное разрешение, в поле date_nanos с наносекундным разрешением. Рассмотрим, например, эти два индекса:
resp = client.indices.create(
index="index_double",
mappings={
"properties": {
"field": {
"type": "date"
}
}
},
)
print(resp) response = client.indices.create(
index: 'index_double',
body: {
mappings: {
properties: {
field: {
type: 'date'
}
}
}
}
)
puts response res, err := es.Indices.Create(
"index_double",
es.Indices.Create.WithBody(strings.NewReader(`{
"mappings": {
"properties": {
"field": {
"type": "date"
}
}
}
}`)),
)
fmt.Println(res, err) const response = await client.indices.create({
index: "index_double",
mappings: {
properties: {
field: {
type: "date",
},
},
},
});
console.log(response); PUT /index_double
{
"mappings": {
"properties": {
"field": { "type": "date" }
}
}
} resp = client.indices.create(
index="index_long",
mappings={
"properties": {
"field": {
"type": "date_nanos"
}
}
},
)
print(resp) response = client.indices.create(
index: 'index_long',
body: {
mappings: {
properties: {
field: {
type: 'date_nanos'
}
}
}
}
)
puts response res, err := es.Indices.Create(
"index_long",
es.Indices.Create.WithBody(strings.NewReader(`{
"mappings": {
"properties": {
"field": {
"type": "date_nanos"
}
}
}
}`)),
)
fmt.Println(res, err) const response = await client.indices.create({
index: "index_long",
mappings: {
properties: {
field: {
type: "date_nanos",
},
},
},
});
console.log(response); PUT /index_long
{
"mappings": {
"properties": {
"field": { "type": "date_nanos" }
}
}
} Значения в этих индексах хранятся с различными разрешениями, поэтому сортировка по этим полям всегда будет сортировать date перед date_nanos (по возрастанию). С помощью опции типа numeric_type можно установить единое разрешение для сортировки. Установка в date преобразует date_nanos в миллисекундное разрешение, в то время как date_nanos преобразует значения в поле date в наносекундное разрешение:
$params = [
'index' => 'index_long,index_double',
'body' => [
'sort' => [
[
'field' => [
'numeric_type' => 'date_nanos',
],
],
],
],
];
$response = $client->search($params); resp = client.search(
index="index_long,index_double",
sort=[
{
"field": {
"numeric_type": "date_nanos"
}
}
],
)
print(resp) res, err := es.Search(
es.Search.WithIndex("index_long,index_double"),
es.Search.WithBody(strings.NewReader(`{
"sort": [
{
"field": {
"numeric_type": "date_nanos"
}
}
]
}`)),
es.Search.WithPretty(),
)
fmt.Println(res, err) const response = await client.search({
index: "index_long,index_double",
sort: [
{
field: {
numeric_type: "date_nanos",
},
},
],
});
console.log(response); POST /index_long,index_double/_search
{
"sort" : [
{
"field" : {
"numeric_type" : "date_nanos"
}
}
]
} Для предотвращения переполнения, преобразование в date_nanos не может быть применено к датам до 1970 года и после 2262 года, так как наносекунды представлены как целые числа.
Сортировка внутри вложенных объектов
Elasticsearch также поддерживает сортировку по полям, которые находятся внутри одного или нескольких вложенных объектов. Поддержка сортировки по вложенному полю имеет опцию сортировки nested со следующими свойствами:
-
path - Определяет, по какому вложенному объекту выполнять сортировку. Фактическое поле сортировки должно быть прямым полем внутри этого вложенного объекта. При сортировке по вложенному полю это поле является обязательным.
-
filter - Фильтр, которому должны соответствовать внутренние объекты внутри вложенного пути, чтобы значения его полей учитывались при сортировке. Общий случай — повторение запроса/фильтра внутри вложенного фильтра или запроса. По умолчанию никакой
filterне активен. -
max_children - Максимальное количество дочерних элементов для рассмотрения на каждый корневой документ при выборе значения сортировки. По умолчанию неограниченно.
-
nested - То же, что и верхнеуровневый
nested, но применяется к другому вложенному пути внутри текущего вложенного объекта.
Elasticsearch выбросит ошибку, если вложенное поле определено в сортировке без контекста nested.
Примеры сортировки по вложенным данным
В примере ниже offer — поле типа nested. Вложенное поле path необходимо указать; в противном случае Elasticsearch не знает, на каком уровне вложенности нужно собирать значения для сортировки.
$params = [
'body' => [
'query' => [
'term' => [
'product' => 'chocolate',
],
],
'sort' => [
[
'offer.price' => [
'mode' => 'avg',
'order' => 'asc',
'nested' => [
'path' => 'offer',
'filter' => [
'term' => [
'offer.color' => 'blue',
],
],
],
],
],
],
],
];
$response = $client->search($params); resp = client.search(
query={
"term": {
"product": "chocolate"
}
},
sort=[
{
"offer.price": {
"mode": "avg",
"order": "asc",
"nested": {
"path": "offer",
"filter": {
"term": {
"offer.color": "blue"
}
}
}
}
}
],
)
print(resp) response = client.search(
body: {
query: {
term: {
product: 'chocolate'
}
},
sort: [
{
'offer.price' => {
mode: 'avg',
order: 'asc',
nested: {
path: 'offer',
filter: {
term: {
'offer.color' => 'blue'
}
}
}
}
}
]
}
)
puts response res, err := es.Search(
es.Search.WithBody(strings.NewReader(`{
"query": {
"term": {
"product": "chocolate"
}
},
"sort": [
{
"offer.price": {
"mode": "avg",
"order": "asc",
"nested": {
"path": "offer",
"filter": {
"term": {
"offer.color": "blue"
}
}
}
}
}
]
}`)),
es.Search.WithPretty(),
)
fmt.Println(res, err) const response = await client.search({
query: {
term: {
product: "chocolate",
},
},
sort: [
{
"offer.price": {
mode: "avg",
order: "asc",
nested: {
path: "offer",
filter: {
term: {
"offer.color": "blue",
},
},
},
},
},
],
});
console.log(response); 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 не знает, на каком уровне вложенности нужно собирать значения для сортировки.
$params = [
'body' => [
'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',
],
],
],
],
],
],
],
],
];
$response = $client->search($params); resp = client.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"
}
}
}
}
}
}
],
)
print(resp) res, err := es.Search(
es.Search.WithBody(strings.NewReader(`{
"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"
}
}
}
}
}
}
]
}`)),
es.Search.WithPretty(),
)
fmt.Println(res, err) const response = await client.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",
},
},
},
},
},
},
],
});
console.log(response); 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.
Например:
resp = client.search(
sort=[
{
"price": {
"missing": "_last"
}
}
],
query={
"term": {
"product": "chocolate"
}
},
)
print(resp) response = client.search(
body: {
sort: [
{
price: {
missing: '_last'
}
}
],
query: {
term: {
product: 'chocolate'
}
}
}
)
puts response res, err := es.Search(
es.Search.WithBody(strings.NewReader(`{
"sort": [
{
"price": {
"missing": "_last"
}
}
],
"query": {
"term": {
"product": "chocolate"
}
}
}`)),
es.Search.WithPretty(),
)
fmt.Println(res, err) const response = await client.search({
sort: [
{
price: {
missing: "_last",
},
},
],
query: {
term: {
product: "chocolate",
},
},
});
console.log(response); GET /_search
{
"sort" : [
{ "price" : {"missing" : "_last"} }
],
"query" : {
"term" : { "product" : "chocolate" }
}
} Если вложенный внутренний объект не соответствует nested.filter, используется пропущенное значение.
Игнорирование неотображенных полей
По умолчанию запрос поиска завершится ошибкой, если нет сопоставления с полем. Параметр unmapped_type позволяет игнорировать поля без сопоставления и не сортировать по ним. Значение этого параметра используется для определения значений сортировки, которые нужно выводить. Вот пример его использования:
resp = client.search(
sort=[
{
"price": {
"unmapped_type": "long"
}
}
],
query={
"term": {
"product": "chocolate"
}
},
)
print(resp) response = client.search(
body: {
sort: [
{
price: {
unmapped_type: 'long'
}
}
],
query: {
term: {
product: 'chocolate'
}
}
}
)
puts response res, err := es.Search(
es.Search.WithBody(strings.NewReader(`{
"sort": [
{
"price": {
"unmapped_type": "long"
}
}
],
"query": {
"term": {
"product": "chocolate"
}
}
}`)),
es.Search.WithPretty(),
)
fmt.Println(res, err) const response = await client.search({
sort: [
{
price: {
unmapped_type: "long",
},
},
],
query: {
term: {
product: "chocolate",
},
},
});
console.log(response); GET /_search
{
"sort" : [
{ "price" : {"unmapped_type" : "long"} }
],
"query" : {
"term" : { "product" : "chocolate" }
}
} Если какой-либо из индексов, которые запрашиваются, не имеет сопоставления для price, Elasticsearch обработает это так, как если бы было сопоставление типа long, и все документы в этом индексе не имели значения для этого поля.
Сортировка по расстоянию до геообъекта
Возможность сортировки по расстоянию до геообъекта. Вот пример, предполагая, что pin.location — поле типа geo_point:
resp = client.search(
sort=[
{
"_geo_distance": {
"pin.location": [
-70,
40
],
"order": "asc",
"unit": "km",
"mode": "min",
"distance_type": "arc",
"ignore_unmapped": True
}
}
],
query={
"term": {
"user": "kimchy"
}
},
)
print(resp) response = client.search(
body: {
sort: [
{
_geo_distance: {
'pin.location' => [
-70,
40
],
order: 'asc',
unit: 'km',
mode: 'min',
distance_type: 'arc',
ignore_unmapped: true
}
}
],
query: {
term: {
user: 'kimchy'
}
}
}
)
puts response res, err := es.Search(
es.Search.WithBody(strings.NewReader(`{
"sort": [
{
"_geo_distance": {
"pin.location": [
-70,
40
],
"order": "asc",
"unit": "km",
"mode": "min",
"distance_type": "arc",
"ignore_unmapped": true
}
}
],
"query": {
"term": {
"user": "kimchy"
}
}
}`)),
es.Search.WithPretty(),
)
fmt.Println(res, err) const response = await client.search({
sort: [
{
_geo_distance: {
"pin.location": [-70, 40],
order: "asc",
unit: "km",
mode: "min",
distance_type: "arc",
ignore_unmapped: true,
},
},
],
query: {
term: {
user: "kimchy",
},
},
});
console.log(response); 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, если у документа нет значений для поля, используемого для вычисления расстояния.
Ниже приведены поддерживаемые форматы для указания координат:
Широта и долгота как свойства
resp = client.search(
sort=[
{
"_geo_distance": {
"pin.location": {
"lat": 40,
"lon": -70
},
"order": "asc",
"unit": "km"
}
}
],
query={
"term": {
"user": "kimchy"
}
},
)
print(resp) response = client.search(
body: {
sort: [
{
_geo_distance: {
'pin.location' => {
lat: 40,
lon: -70
},
order: 'asc',
unit: 'km'
}
}
],
query: {
term: {
user: 'kimchy'
}
}
}
)
puts response res, err := es.Search(
es.Search.WithBody(strings.NewReader(`{
"sort": [
{
"_geo_distance": {
"pin.location": {
"lat": 40,
"lon": -70
},
"order": "asc",
"unit": "km"
}
}
],
"query": {
"term": {
"user": "kimchy"
}
}
}`)),
es.Search.WithPretty(),
)
fmt.Println(res, err) const response = await client.search({
sort: [
{
_geo_distance: {
"pin.location": {
lat: 40,
lon: -70,
},
order: "asc",
unit: "km",
},
},
],
query: {
term: {
user: "kimchy",
},
},
});
console.log(response); GET /_search
{
"sort" : [
{
"_geo_distance" : {
"pin.location" : {
"lat" : 40,
"lon" : -70
},
"order" : "asc",
"unit" : "km"
}
}
],
"query" : {
"term" : { "user" : "kimchy" }
}
} Широта и долгота как строка WKT
Формат в Well-Known Text.
resp = client.search(
sort=[
{
"_geo_distance": {
"pin.location": "POINT (-70 40)",
"order": "asc",
"unit": "km"
}
}
],
query={
"term": {
"user": "kimchy"
}
},
)
print(resp) response = client.search(
body: {
sort: [
{
_geo_distance: {
'pin.location' => 'POINT (-70 40)',
order: 'asc',
unit: 'km'
}
}
],
query: {
term: {
user: 'kimchy'
}
}
}
)
puts response const response = await client.search({
sort: [
{
_geo_distance: {
"pin.location": "POINT (-70 40)",
order: "asc",
unit: "km",
},
},
],
query: {
term: {
user: "kimchy",
},
},
});
console.log(response); GET /_search
{
"sort": [
{
"_geo_distance": {
"pin.location": "POINT (-70 40)",
"order": "asc",
"unit": "km"
}
}
],
"query": {
"term": { "user": "kimchy" }
}
} Geohash
resp = client.search(
sort=[
{
"_geo_distance": {
"pin.location": "drm3btev3e86",
"order": "asc",
"unit": "km"
}
}
],
query={
"term": {
"user": "kimchy"
}
},
)
print(resp) response = client.search(
body: {
sort: [
{
_geo_distance: {
'pin.location' => 'drm3btev3e86',
order: 'asc',
unit: 'km'
}
}
],
query: {
term: {
user: 'kimchy'
}
}
}
)
puts response res, err := es.Search(
es.Search.WithBody(strings.NewReader(`{
"sort": [
{
"_geo_distance": {
"pin.location": "drm3btev3e86",
"order": "asc",
"unit": "km"
}
}
],
"query": {
"term": {
"user": "kimchy"
}
}
}`)),
es.Search.WithPretty(),
)
fmt.Println(res, err) const response = await client.search({
sort: [
{
_geo_distance: {
"pin.location": "drm3btev3e86",
order: "asc",
unit: "km",
},
},
],
query: {
term: {
user: "kimchy",
},
},
});
console.log(response); GET /_search
{
"sort": [
{
"_geo_distance": {
"pin.location": "drm3btev3e86",
"order": "asc",
"unit": "km"
}
}
],
"query": {
"term": { "user": "kimchy" }
}
} Широта и долгота как массив
Формат в [lon, lat], обратите внимание на порядок lon/lat, чтобы соответствовать GeoJSON.
resp = client.search(
sort=[
{
"_geo_distance": {
"pin.location": [
-70,
40
],
"order": "asc",
"unit": "km"
}
}
],
query={
"term": {
"user": "kimchy"
}
},
)
print(resp) response = client.search(
body: {
sort: [
{
_geo_distance: {
'pin.location' => [
-70,
40
],
order: 'asc',
unit: 'km'
}
}
],
query: {
term: {
user: 'kimchy'
}
}
}
)
puts response res, err := es.Search(
es.Search.WithBody(strings.NewReader(`{
"sort": [
{
"_geo_distance": {
"pin.location": [
-70,
40
],
"order": "asc",
"unit": "km"
}
}
],
"query": {
"term": {
"user": "kimchy"
}
}
}`)),
es.Search.WithPretty(),
)
fmt.Println(res, err) const response = await client.search({
sort: [
{
_geo_distance: {
"pin.location": [-70, 40],
order: "asc",
unit: "km",
},
},
],
query: {
term: {
user: "kimchy",
},
},
});
console.log(response); GET /_search
{
"sort": [
{
"_geo_distance": {
"pin.location": [ -70, 40 ],
"order": "asc",
"unit": "km"
}
}
],
"query": {
"term": { "user": "kimchy" }
}
} Несколько точек отсчета
Несколько геоточек могут передаваться как массив, содержащий любой формат geo_point, например
resp = client.search(
sort=[
{
"_geo_distance": {
"pin.location": [
[
-70,
40
],
[
-71,
42
]
],
"order": "asc",
"unit": "km"
}
}
],
query={
"term": {
"user": "kimchy"
}
},
)
print(resp) response = client.search(
body: {
sort: [
{
_geo_distance: {
'pin.location' => [
[
-70,
40
],
[
-71,
42
]
],
order: 'asc',
unit: 'km'
}
}
],
query: {
term: {
user: 'kimchy'
}
}
}
)
puts response res, err := es.Search(
es.Search.WithBody(strings.NewReader(`{
"sort": [
{
"_geo_distance": {
"pin.location": [
[
-70,
40
],
[
-71,
42
]
],
"order": "asc",
"unit": "km"
}
}
],
"query": {
"term": {
"user": "kimchy"
}
}
}`)),
es.Search.WithPretty(),
)
fmt.Println(res, err) const response = await client.search({
sort: [
{
_geo_distance: {
"pin.location": [
[-70, 40],
[-71, 42],
],
order: "asc",
unit: "km",
},
},
],
query: {
term: {
user: "kimchy",
},
},
});
console.log(response); GET /_search
{
"sort": [
{
"_geo_distance": {
"pin.location": [ [ -70, 40 ], [ -71, 42 ] ],
"order": "asc",
"unit": "km"
}
}
],
"query": {
"term": { "user": "kimchy" }
}
} и так далее.
Конечное расстояние для документа будет min/max/avg (определенное через mode) расстоянием всех точек, содержащихся в документе, до всех точек, указанных в запросе сортировки.
Сортировка на основе скрипта
Возможность сортировки на основе пользовательских скриптов, вот пример:
resp = client.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"
}
},
)
print(resp) response = client.search(
body: {
query: {
term: {
user: 'kimchy'
}
},
sort: {
_script: {
type: 'number',
script: {
lang: 'painless',
source: "doc['field_name'].value * params.factor",
params: {
factor: 1.1
}
},
order: 'asc'
}
}
}
)
puts response res, err := es.Search(
es.Search.WithBody(strings.NewReader(`{
"query": {
"term": {
"user": "kimchy"
}
},
"sort": {
"_script": {
"type": "number",
"script": {
"lang": "painless",
"source": "doc['field_name'].value * params.factor",
"params": {
"factor": 1.1
}
},
"order": "asc"
}
}
}`)),
es.Search.WithPretty(),
)
fmt.Println(res, err) const response = await client.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",
},
},
});
console.log(response); 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, баллы будут все равно вычисляться и отслеживаться.
resp = client.search(
track_scores=True,
sort=[
{
"post_date": {
"order": "desc"
}
},
{
"name": "desc"
},
{
"age": "desc"
}
],
query={
"term": {
"user": "kimchy"
}
},
)
print(resp) response = client.search(
body: {
track_scores: true,
sort: [
{
post_date: {
order: 'desc'
}
},
{
name: 'desc'
},
{
age: 'desc'
}
],
query: {
term: {
user: 'kimchy'
}
}
}
)
puts response res, err := es.Search(
es.Search.WithBody(strings.NewReader(`{
"track_scores": true,
"sort": [
{
"post_date": {
"order": "desc"
}
},
{
"name": "desc"
},
{
"age": "desc"
}
],
"query": {
"term": {
"user": "kimchy"
}
}
}`)),
es.Search.WithPretty(),
)
fmt.Println(res, err) const response = await client.search({
track_scores: true,
sort: [
{
post_date: {
order: "desc",
},
},
{
name: "desc",
},
{
age: "desc",
},
],
query: {
term: {
user: "kimchy",
},
},
});
console.log(response); 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/8.17/sort-search-results.html