Есть способ заставить его работать, это некрасиво, но сработает. Вы можете достичь своей цели, используя boost и многополевые параметры query_string
, _ 2_ запрос для объединения оценок и настройки _ 3_:
POST my-query-string/doc/_search
{
"query": {
"bool": {
"should": [
{
"query_string": {
"query": "#{query}",
"type": "most_fields",
"boost": 1
}
},
{
"query_string": {
"fields": [
"comments"
],
"query": "#{query}",
"boost": -1
}
}
]
}
},
"min_score": 0.00001
}
Так что же происходит под капотом?
Предположим, у вас есть следующий набор документов:
PUT my-query-string/doc/1
{
"title": "Prodigy in Bristol",
"text": "Prodigy in Bristol",
"comments": "Prodigy in Bristol"
}
PUT my-query-string/doc/2
{
"title": "Prodigy in Birmigham",
"text": "Prodigy in Birmigham",
"comments": "And also in Bristol"
}
PUT my-query-string/doc/3
{
"title": "Prodigy in Birmigham",
"text": "Prodigy in Birmigham and Bristol",
"comments": "And also in Cardiff"
}
PUT my-query-string/doc/4
{
"title": "Prodigy in Birmigham",
"text": "Prodigy in Birmigham",
"comments": "And also in Cardiff"
}
В вашем поисковом запросе вы хотели бы видеть только документы 1 и 3, но ваш исходный запрос вернет 1, 2 и 3.
В Elasticsearch результаты поиска сортируются по релевантности _6 _, чем больше балл, тем лучше.
Итак, давайте попробуем сдвиньте вниз поле "comments"
, чтобы не повлиять на оценку релевантности. Мы можем сделать это, объединив два запроса с should
и используя отрицательный boost
:
POST my-query-string/doc/_search
{
"query": {
"bool": {
"should": [
{
"query_string": {
"query": "Bristol"
}
},
{
"query_string": {
"fields": [
"comments"
],
"query": "Bristol",
"boost": -1
}
}
]
}
}
}
Это даст нам следующий результат:
{
"hits": {
"total": 3,
"max_score": 0.2876821,
"hits": [
{
"_index": "my-query-string",
"_type": "doc",
"_id": "3",
"_score": 0.2876821,
"_source": {
"title": "Prodigy in Birmigham",
"text": "Prodigy in Birmigham and Bristol",
"comments": "And also in Cardiff"
}
},
{
"_index": "my-query-string",
"_type": "doc",
"_id": "2",
"_score": 0,
"_source": {
"title": "Prodigy in Birmigham",
"text": "Prodigy in Birmigham",
"comments": "And also in Bristol"
}
},
{
"_index": "my-query-string",
"_type": "doc",
"_id": "1",
"_score": 0,
"_source": {
"title": "Prodigy in Bristol",
"text": "Prodigy in Bristol",
"comments": "Prodigy in Bristol",
"discount_percent": 10
}
}
]
}
}
Документ 2 был оштрафован, но также и документ 1, хотя для нас это желаемое совпадение. Почему так случилось?
Вот как Elasticsearch вычислил _score
в этом случае:
_score = max (название: Bristol, текст: Bristol, комментарии: Bristol) - комментарии: Bristol
Документ 1 соответствует части comments:"Bristol"
и также является лучшим результатом. По нашей формуле результат равен 0.
На самом деле мы хотели бы усилить первое предложение (со всеми полями) больше, если совпало больше полей.
Можем ли мы увеличить query_string
соответствие большему количеству полей?
Мы можем query_string
в многополевой режим имеет параметр type
, который делает именно это. Запрос будет выглядеть так:
POST my-query-string/doc/_search
{
"query": {
"bool": {
"should": [
{
"query_string": {
"type": "most_fields",
"query": "Bristol"
}
},
{
"query_string": {
"fields": [
"comments"
],
"query": "Bristol",
"boost": -1
}
}
]
}
}
}
Это даст нам следующий результат:
{
"hits": {
"total": 3,
"max_score": 0.57536423,
"hits": [
{
"_index": "my-query-string",
"_type": "doc",
"_id": "1",
"_score": 0.57536423,
"_source": {
"title": "Prodigy in Bristol",
"text": "Prodigy in Bristol",
"comments": "Prodigy in Bristol",
"discount_percent": 10
}
},
{
"_index": "my-query-string",
"_type": "doc",
"_id": "3",
"_score": 0.2876821,
"_source": {
"title": "Prodigy in Birmigham",
"text": "Prodigy in Birmigham and Bristol",
"comments": "And also in Cardiff"
}
},
{
"_index": "my-query-string",
"_type": "doc",
"_id": "2",
"_score": 0,
"_source": {
"title": "Prodigy in Birmigham",
"text": "Prodigy in Birmigham",
"comments": "And also in Bristol"
}
}
]
}
}
Как видите, нежелательный документ 2 находится внизу и имеет оценку 0. На этот раз оценка была рассчитана следующим образом:
_score = sum (название: Bristol, текст: Bristol, комментарии: Bristol) - комментарии: Bristol
Итак, были выбраны документы, соответствующие "Bristol"
в любом поле. Оценка релевантности для comments:"Bristol"
была исключена, и только документы, соответствующие title:"Bristol"
или text:"Bristol"
, получили _score
›0.
Можем ли мы отфильтровать эти результаты с нежелательной оценкой?
Да, мы можем, используя _ 24_:
POST my-query-string/doc/_search
{
"query": {
"bool": {
"should": [
{
"query_string": {
"query": "Bristol",
"type": "most_fields",
"boost": 1
}
},
{
"query_string": {
"fields": [
"comments"
],
"query": "Bristol",
"boost": -1
}
}
]
}
},
"min_score": 0.00001
}
Это будет работать (в нашем случае), поскольку оценка документов будет равна 0 тогда и только тогда, когда "Bristol"
был сопоставлен только с полем "comments"
и не соответствовал никакому другому полю.
Результатом будет:
{
"hits": {
"total": 2,
"max_score": 0.57536423,
"hits": [
{
"_index": "my-query-string",
"_type": "doc",
"_id": "1",
"_score": 0.57536423,
"_source": {
"title": "Prodigy in Bristol",
"text": "Prodigy in Bristol",
"comments": "Prodigy in Bristol",
"discount_percent": 10
}
},
{
"_index": "my-query-string",
"_type": "doc",
"_id": "3",
"_score": 0.2876821,
"_source": {
"title": "Prodigy in Birmigham",
"text": "Prodigy in Birmigham and Bristol",
"comments": "And also in Cardiff"
}
}
]
}
}
Можно ли это сделать по-другому?
Конечно. Я бы не советовал заниматься _score
настройкой, поскольку это довольно сложный вопрос.
Я бы посоветовал сделать выборку существующего сопоставления и заранее составить список полей для запуска запроса, это сделает код намного проще и понятнее.
Оригинальное решение, предложенное в ответе (сохранено для истории)
Первоначально предлагалось использовать этот тип запроса с той же целью, что и в приведенном выше решении:
POST my-query-string/doc/_search
{
"query": {
"function_score": {
"query": {
"bool": {
"must": {
"query_string": {
"fields" : ["*", "comments^0"],
"query": "#{query}"
}
}
}
}
}
},
"min_score": 0.00001
}
Единственная проблема в том, что если индекс содержит какие-либо числовые значения, эта часть:
"fields": ["*"]
вызывает ошибку, поскольку текстовую строку запроса нельзя применить к числу.
person
Nikolay Vasiliev
schedule
11.10.2018