Запрос Percolate
Запрос percolate может использоваться для сопоставления запросов, хранящихся в индексе. Сам запрос percolate содержит документ, который будет использоваться в качестве запроса для сопоставления с сохранёнными запросами.
Пример использования
Для простоты примера, в этом руководстве используется один индекс, my-index-000001, для хранения как запросов percolate, так и документов. Такое решение подходит для небольшого количества запросов percolate. Для более интенсивного использования рекомендуется хранить запросы и документы в отдельных индексах. Для получения более подробной информации см. Как это работает под капотом.
Создайте индекс с двумя полями:
resp = client.indices.create(
index="my-index-000001",
mappings={
"properties": {
"message": {
"type": "text"
},
"query": {
"type": "percolator"
}
}
},
)
print(resp) response = client.indices.create(
index: 'my-index-000001',
body: {
mappings: {
properties: {
message: {
type: 'text'
},
query: {
type: 'percolator'
}
}
}
}
)
puts response const response = await client.indices.create({
index: "my-index-000001",
mappings: {
properties: {
message: {
type: "text",
},
query: {
type: "percolator",
},
},
},
});
console.log(response); PUT /my-index-000001
{
"mappings": {
"properties": {
"message": {
"type": "text"
},
"query": {
"type": "percolator"
}
}
}
} Поле message используется для предварительной обработки документа, определённого в запросе percolator, перед его индексированием в временный индекс.
Поле query используется для индексирования документов запроса. Оно будет содержать JSON-объект, представляющий фактический запрос Elasticsearch. Поле query настроено для использования типа поля percolator. Этот тип поля понимает язык запросов DSL и хранит запрос таким образом, чтобы его можно было использовать для сопоставления с документами, определёнными в запросе percolate.
Зарегистрируйте запрос в percolator:
resp = client.index(
index="my-index-000001",
id="1",
refresh=True,
document={
"query": {
"match": {
"message": "bonsai tree"
}
}
},
)
print(resp) response = client.index(
index: 'my-index-000001',
id: 1,
refresh: true,
body: {
query: {
match: {
message: 'bonsai tree'
}
}
}
)
puts response const response = await client.index({
index: "my-index-000001",
id: 1,
refresh: "true",
document: {
query: {
match: {
message: "bonsai tree",
},
},
},
});
console.log(response); PUT /my-index-000001/_doc/1?refresh
{
"query": {
"match": {
"message": "bonsai tree"
}
}
} Сопоставьте документ с зарегистрированными запросами percolator:
resp = client.search(
index="my-index-000001",
query={
"percolate": {
"field": "query",
"document": {
"message": "A new bonsai tree in the office"
}
}
},
)
print(resp) const response = await client.search({
index: "my-index-000001",
query: {
percolate: {
field: "query",
document: {
message: "A new bonsai tree in the office",
},
},
},
});
console.log(response); GET /my-index-000001/_search
{
"query": {
"percolate": {
"field": "query",
"document": {
"message": "A new bonsai tree in the office"
}
}
}
} Вышеуказанный запрос вернёт следующий ответ:
{
"took": 13,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped" : 0,
"failed": 0
},
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": 0.26152915,
"hits": [
{
"_index": "my-index-000001",
"_id": "1",
"_score": 0.26152915,
"_source": {
"query": {
"match": {
"message": "bonsai tree"
}
}
},
"fields" : {
"_percolator_document_slot" : [0]
}
}
]
}
} | Запрос с идентификатором | |
| Поле |
Параметры
Следующие параметры необходимы при применении percolator к документу:
| | Поле типа |
| | Суффикс, используемый для поля |
| | Источник документа, к которому применяется percolator. |
| | Аналогично параметру |
Вместо указания источника документа, к которому применяется percolator, источник также может быть получен из уже сохранённого документа. Запрос percolate тогда будет внутренне выполнять запрос GET для извлечения этого документа.
В этом случае параметр document может быть заменён следующими параметрами:
| | Индекс, в котором находится документ. Требуемый параметр. |
| | Идентификатор документа для извлечения. Требуемый параметр. |
| | Необязательно, маршрутизация для извлечения документа для применения percolator. |
| | Необязательно, предпочтение для извлечения документа для применения percolator. |
| | Необязательно, ожидаемая версия документа для извлечения. |
Применение percolator в контексте фильтра
В случае, если вы не заинтересованы в оценке, можно ожидать лучшей производительности, обернув запрос percolator в условие фильтра запроса bool или в запрос constant_score:
resp = client.search(
index="my-index-000001",
query={
"constant_score": {
"filter": {
"percolate": {
"field": "query",
"document": {
"message": "A new bonsai tree in the office"
}
}
}
}
},
)
print(resp) const response = await client.search({
index: "my-index-000001",
query: {
constant_score: {
filter: {
percolate: {
field: "query",
document: {
message: "A new bonsai tree in the office",
},
},
},
},
},
});
console.log(response); GET /my-index-000001/_search
{
"query": {
"constant_score": {
"filter": {
"percolate": {
"field": "query",
"document": {
"message": "A new bonsai tree in the office"
}
}
}
}
}
} При индексировании термины из запроса percolator извлекаются, и percolator часто может определить, соответствует ли запрос, просто посмотрев на эти извлеченные термины. Однако вычисление оценок требует десериализации каждого соответствующего запроса и его выполнения по отношению к документу, к которому применяется percolator, что является гораздо более дорогостоящей операцией. Поэтому, если вычисление оценок не требуется, запрос percolate должен быть обернут в запрос constant_score или условие фильтра запроса bool.
Обратите внимание, что запрос percolate никогда не кешируется кэшем запросов.
Применение percolator к нескольким документам
Запрос percolate может одновременно сопоставлять несколько документов с индексированными запросами percolator. Применение percolator к нескольким документам в одном запросе может улучшить производительность, поскольку запросы необходимо анализировать и сопоставлять только один раз вместо нескольких.
Поле _percolator_document_slot, возвращаемое с каждым соответствующим запросом percolator, имеет значение при одновременном применении percolator к нескольким документам. Оно указывает, какие документы соответствуют определенному запросу percolator. Номера соответствуют позиции в массиве documents, указанном в запросе percolate.
resp = client.search(
index="my-index-000001",
query={
"percolate": {
"field": "query",
"documents": [
{
"message": "bonsai tree"
},
{
"message": "new tree"
},
{
"message": "the office"
},
{
"message": "office tree"
}
]
}
},
)
print(resp) const response = await client.search({
index: "my-index-000001",
query: {
percolate: {
field: "query",
documents: [
{
message: "bonsai tree",
},
{
message: "new tree",
},
{
message: "the office",
},
{
message: "office tree",
},
],
},
},
});
console.log(response); GET /my-index-000001/_search
{
"query": {
"percolate": {
"field": "query",
"documents": [
{
"message": "bonsai tree"
},
{
"message": "new tree"
},
{
"message": "the office"
},
{
"message": "office tree"
}
]
}
}
} | Массив документов содержит 4 документа, которые будут обработаны percolator одновременно. |
{
"took": 13,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped" : 0,
"failed": 0
},
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": 0.7093853,
"hits": [
{
"_index": "my-index-000001",
"_id": "1",
"_score": 0.7093853,
"_source": {
"query": {
"match": {
"message": "bonsai tree"
}
}
},
"fields" : {
"_percolator_document_slot" : [0, 1, 3]
}
}
]
}
} |
|
Применение percolator к существующему документу
Для применения percolator к вновь индексированному документу можно использовать запрос percolate. Основываясь на ответе от запроса индексирования, можно сразу применить percolator к только что добавленному документу, используя _id и другую метаинформацию.
Пример
Основываясь на предыдущем примере.
Индексируем документ, к которому хотим применить percolator:
resp = client.index(
index="my-index-000001",
id="2",
document={
"message": "A new bonsai tree in the office"
},
)
print(resp) response = client.index(
index: 'my-index-000001',
id: 2,
body: {
message: 'A new bonsai tree in the office'
}
)
puts response const response = await client.index({
index: "my-index-000001",
id: 2,
document: {
message: "A new bonsai tree in the office",
},
});
console.log(response); PUT /my-index-000001/_doc/2
{
"message" : "A new bonsai tree in the office"
} Ответ индекса:
{
"_index": "my-index-000001",
"_id": "2",
"_version": 1,
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"result": "created",
"_seq_no" : 1,
"_primary_term" : 1
} Применение percolator к существующему документу, используя ответ индекса в качестве основы для нового запроса:
resp = client.search(
index="my-index-000001",
query={
"percolate": {
"field": "query",
"index": "my-index-000001",
"id": "2",
"version": 1
}
},
)
print(resp) const response = await client.search({
index: "my-index-000001",
query: {
percolate: {
field: "query",
index: "my-index-000001",
id: "2",
version: 1,
},
},
});
console.log(response); GET /my-index-000001/_search
{
"query": {
"percolate": {
"field": "query",
"index": "my-index-000001",
"id": "2",
"version": 1
}
}
} | Версия необязательна, но полезна в некоторых случаях. Мы можем гарантировать, что пытаемся применить percolator к документу, который мы только что индексировали. Изменения могут быть внесены после индексирования, и в этом случае запрос будет завершён с ошибкой конфликта версий. |
Результат поиска идентичен предыдущему примеру.
Запрос перколяции и выделение ключевых слов
Запрос percolate обрабатывается особым образом при выделении ключевых слов. Для выделения используются результаты поиска по запросу, предоставленному в запросе percolate. В то время как при обычном выделении ключевых слов используется запрос в запросе поиска.
Пример
Этот пример основан на сопоставлении первого примера.
Сохраните запрос:
resp = client.index(
index="my-index-000001",
id="3",
refresh=True,
document={
"query": {
"match": {
"message": "brown fox"
}
}
},
)
print(resp) response = client.index(
index: 'my-index-000001',
id: 3,
refresh: true,
body: {
query: {
match: {
message: 'brown fox'
}
}
}
)
puts response const response = await client.index({
index: "my-index-000001",
id: 3,
refresh: "true",
document: {
query: {
match: {
message: "brown fox",
},
},
},
});
console.log(response); PUT /my-index-000001/_doc/3?refresh
{
"query": {
"match": {
"message": "brown fox"
}
}
} Сохраните другой запрос:
resp = client.index(
index="my-index-000001",
id="4",
refresh=True,
document={
"query": {
"match": {
"message": "lazy dog"
}
}
},
)
print(resp) response = client.index(
index: 'my-index-000001',
id: 4,
refresh: true,
body: {
query: {
match: {
message: 'lazy dog'
}
}
}
)
puts response const response = await client.index({
index: "my-index-000001",
id: 4,
refresh: "true",
document: {
query: {
match: {
message: "lazy dog",
},
},
},
});
console.log(response); PUT /my-index-000001/_doc/4?refresh
{
"query": {
"match": {
"message": "lazy dog"
}
}
} Выполните запрос поиска с запросом percolate и включённым выделением ключевых слов:
resp = client.search(
index="my-index-000001",
query={
"percolate": {
"field": "query",
"document": {
"message": "The quick brown fox jumps over the lazy dog"
}
}
},
highlight={
"fields": {
"message": {}
}
},
)
print(resp) const response = await client.search({
index: "my-index-000001",
query: {
percolate: {
field: "query",
document: {
message: "The quick brown fox jumps over the lazy dog",
},
},
},
highlight: {
fields: {
message: {},
},
},
});
console.log(response); GET /my-index-000001/_search
{
"query": {
"percolate": {
"field": "query",
"document": {
"message": "The quick brown fox jumps over the lazy dog"
}
}
},
"highlight": {
"fields": {
"message": {}
}
}
} Это даст следующий ответ.
{
"took": 7,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped" : 0,
"failed": 0
},
"hits": {
"total" : {
"value": 2,
"relation": "eq"
},
"max_score": 0.26152915,
"hits": [
{
"_index": "my-index-000001",
"_id": "3",
"_score": 0.26152915,
"_source": {
"query": {
"match": {
"message": "brown fox"
}
}
},
"highlight": {
"message": [
"The quick <em>brown</em> <em>fox</em> jumps over the lazy dog"
]
},
"fields" : {
"_percolator_document_slot" : [0]
}
},
{
"_index": "my-index-000001",
"_id": "4",
"_score": 0.26152915,
"_source": {
"query": {
"match": {
"message": "lazy dog"
}
}
},
"highlight": {
"message": [
"The quick brown fox jumps over the <em>lazy</em> <em>dog</em>"
]
},
"fields" : {
"_percolator_document_slot" : [0]
}
}
]
}
} | Термины из каждого запроса были выделены в документе. |
Вместо выделения ключевых слов запроса в запросе поиска, запросы перколяции выделяют документ, определённый в запросе percolate.
При перколяции нескольких документов одновременно, как в запросе ниже, ответ об выделении ключевых слов отличается:
resp = client.search(
index="my-index-000001",
query={
"percolate": {
"field": "query",
"documents": [
{
"message": "bonsai tree"
},
{
"message": "new tree"
},
{
"message": "the office"
},
{
"message": "office tree"
}
]
}
},
highlight={
"fields": {
"message": {}
}
},
)
print(resp) const response = await client.search({
index: "my-index-000001",
query: {
percolate: {
field: "query",
documents: [
{
message: "bonsai tree",
},
{
message: "new tree",
},
{
message: "the office",
},
{
message: "office tree",
},
],
},
},
highlight: {
fields: {
message: {},
},
},
});
console.log(response); GET /my-index-000001/_search
{
"query": {
"percolate": {
"field": "query",
"documents": [
{
"message": "bonsai tree"
},
{
"message": "new tree"
},
{
"message": "the office"
},
{
"message": "office tree"
}
]
}
},
"highlight": {
"fields": {
"message": {}
}
}
} Несколько отличающийся ответ:
{
"took": 13,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped" : 0,
"failed": 0
},
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": 0.7093853,
"hits": [
{
"_index": "my-index-000001",
"_id": "1",
"_score": 0.7093853,
"_source": {
"query": {
"match": {
"message": "bonsai tree"
}
}
},
"fields" : {
"_percolator_document_slot" : [0, 1, 3]
},
"highlight" : {
"0_message" : [
"<em>bonsai</em> <em>tree</em>"
],
"3_message" : [
"office <em>tree</em>"
],
"1_message" : [
"new <em>tree</em>"
]
}
}
]
}
} | Поля выделения ключевых слов были префиксрованы с обозначением слота документа, чтобы знать, к какому документу относится каждое поле выделения. |
Имена запросов в запросах перколяции
Если сохранённый запрос перколяции является сложным запросом, и вы хотите отслеживать, какие его подзапросы соответствовали перколированному документу, то вы можете использовать параметр \_name для его подзапросов. В этом случае в ответе каждый результат вместе с полем _percolator_document_slot содержит поля _percolator_document_slot_<slotNumber>_matched_queries, которые показывают, какие подзапросы соответствовали каждому перколированному документу.
Например:
resp = client.index(
index="my-index-000001",
id="5",
refresh=True,
document={
"query": {
"bool": {
"should": [
{
"match": {
"message": {
"query": "Japanese art",
"_name": "query1"
}
}
},
{
"match": {
"message": {
"query": "Holand culture",
"_name": "query2"
}
}
}
]
}
}
},
)
print(resp) response = client.index(
index: 'my-index-000001',
id: 5,
refresh: true,
body: {
query: {
bool: {
should: [
{
match: {
message: {
query: 'Japanese art',
_name: 'query1'
}
}
},
{
match: {
message: {
query: 'Holand culture',
_name: 'query2'
}
}
}
]
}
}
}
)
puts response const response = await client.index({
index: "my-index-000001",
id: 5,
refresh: "true",
document: {
query: {
bool: {
should: [
{
match: {
message: {
query: "Japanese art",
_name: "query1",
},
},
},
{
match: {
message: {
query: "Holand culture",
_name: "query2",
},
},
},
],
},
},
},
});
console.log(response); PUT /my-index-000001/_doc/5?refresh
{
"query": {
"bool": {
"should": [
{
"match": {
"message": {
"query": "Japanese art",
"_name": "query1"
}
}
},
{
"match": {
"message": {
"query": "Holand culture",
"_name": "query2"
}
}
}
]
}
}
} resp = client.search(
index="my-index-000001",
query={
"percolate": {
"field": "query",
"documents": [
{
"message": "Japanse art"
},
{
"message": "Holand culture"
},
{
"message": "Japanese art and Holand culture"
},
{
"message": "no-match"
}
]
}
},
)
print(resp) const response = await client.search({
index: "my-index-000001",
query: {
percolate: {
field: "query",
documents: [
{
message: "Japanse art",
},
{
message: "Holand culture",
},
{
message: "Japanese art and Holand culture",
},
{
message: "no-match",
},
],
},
},
});
console.log(response); GET /my-index-000001/_search
{
"query": {
"percolate": {
"field": "query",
"documents": [
{
"message": "Japanse art"
},
{
"message": "Holand culture"
},
{
"message": "Japanese art and Holand culture"
},
{
"message": "no-match"
}
]
}
}
} {
"took": 55,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped" : 0,
"failed": 0
},
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": 1.1181908,
"hits": [
{
"_index": "my-index-000001",
"_id": "5",
"_score": 1.1181908,
"_source": {
"query": {
"bool": {
"should": [
{
"match": {
"message": {
"query": "Japanese art",
"_name": "query1"
}
}
},
{
"match": {
"message": {
"query": "Holand culture",
"_name": "query2"
}
}
}
]
}
}
},
"fields" : {
"_percolator_document_slot" : [0, 1, 2],
"_percolator_document_slot_0_matched_queries" : ["query1"],
"_percolator_document_slot_1_matched_queries" : ["query2"],
"_percolator_document_slot_2_matched_queries" : ["query1", "query2"]
}
}
]
}
} | Первый документ соответствовал только первому подзапросу. | |
| Второй документ соответствовал только второму подзапросу. | |
| Третий документ соответствовал обоим подзапросам. |
Указание нескольких запросов перколяции
Можно указать несколько запросов percolate в одном запросе поиска:
resp = client.search(
index="my-index-000001",
query={
"bool": {
"should": [
{
"percolate": {
"field": "query",
"document": {
"message": "bonsai tree"
},
"name": "query1"
}
},
{
"percolate": {
"field": "query",
"document": {
"message": "tulip flower"
},
"name": "query2"
}
}
]
}
},
)
print(resp) const response = await client.search({
index: "my-index-000001",
query: {
bool: {
should: [
{
percolate: {
field: "query",
document: {
message: "bonsai tree",
},
name: "query1",
},
},
{
percolate: {
field: "query",
document: {
message: "tulip flower",
},
name: "query2",
},
},
],
},
},
});
console.log(response); GET /my-index-000001/_search
{
"query": {
"bool": {
"should": [
{
"percolate": {
"field": "query",
"document": {
"message": "bonsai tree"
},
"name": "query1"
}
},
{
"percolate": {
"field": "query",
"document": {
"message": "tulip flower"
},
"name": "query2"
}
}
]
}
}
} | Параметр |
Имя поля _percolator_document_slot будет дополнено тем, что указано в параметре _name. Если это не указано, используется параметр field, что в данном случае приведёт к неоднозначности.
Вышеупомянутый запрос поиска возвращает ответ, аналогичный этому:
{
"took": 13,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped" : 0,
"failed": 0
},
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": 0.26152915,
"hits": [
{
"_index": "my-index-000001",
"_id": "1",
"_score": 0.26152915,
"_source": {
"query": {
"match": {
"message": "bonsai tree"
}
}
},
"fields" : {
"_percolator_document_slot_query1" : [0]
}
}
]
}
} | Поле слота перколяции |
Как это работает «под капотом»
При индексировании документа в индекс, в котором настроено отображение типа поля «перколатор», часть запроса документа анализируется в запрос Lucene и хранится в индексе Lucene. Бинарное представление запроса хранится, а также термины запроса анализируются и сохраняются в индексированном поле.
Во время поиска документ, указанный в запросе, анализируется в документ Lucene и хранится в временном индексе Lucene в оперативной памяти. Этот индекс в оперативной памяти может содержать только один документ и оптимизирован для этого. После этого создаётся специальный запрос, основанный на терминах в индексе оперативной памяти, который выбирает кандидатов среди запросов перколяции, основываясь на их индексированных терминах запроса. Затем эти запросы оцениваются индексом оперативной памяти на предмет соответствия.
Выбор кандидатных запросов перколяции — важная оптимизация производительности во время выполнения запроса percolate, поскольку он может значительно сократить количество кандидатов, которые индекс оперативной памяти должен оценить. Причина, по которой запрос percolate может это сделать, заключается в том, что при индексировании запросов перколяции термины запроса извлекаются и индексируются вместе с запросом перколяции. К сожалению, перколатор не может извлечь термины из всех запросов (например, запрос wildcard или geo_shape), и в результате в некоторых случаях перколатор не может выполнить оптимизацию выбора (например, если недопустимый запрос определён в необходимом условии булевого запроса или недопустимый запрос является единственным запросом в документе перколяции). Эти запросы помечаются перколатором, и их можно найти, выполнив следующий поиск:
resp = client.search(
query={
"term": {
"query.extraction_result": "failed"
}
},
)
print(resp) response = client.search(
body: {
query: {
term: {
'query.extraction_result' => 'failed'
}
}
}
)
puts response const response = await client.search({
query: {
term: {
"query.extraction_result": "failed",
},
},
});
console.log(response); GET /_search
{
"query": {
"term" : {
"query.extraction_result" : "failed"
}
}
} В примере выше предполагается, что существует поле query типа percolator в отображениях.
Учитывая дизайн перколяции, зачастую имеет смысл использовать отдельные индексы для запросов перколяции и документов, которые перколируются, вместо одного индекса, как мы делаем в примерах. Этот подход имеет несколько преимуществ:
- Поскольку запросы перколяции содержат набор полей, отличающийся от полей перколируемых документов, использование двух отдельных индексов позволяет хранить поля более плотно и эффективно.
- Запросы перколяции не масштабируются так же, как и другие запросы, поэтому производительность перколяции может выиграть от использования другой конфигурации индекса, например, от количества первичных фрагментов.
Примечания
Разрешить дорогостоящие запросы
Запросы перколяции не будут выполняться, если search.allow_expensive_queries установлено в значение false.
Использование настраиваемых функций подобия
Запросы перколяции не будут учитывать никакие настроенные настраиваемые функции подобия. Они всегда используют стандартное подобие Lucene.
© 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/query-dsl-percolate-query.html