Есть способ заставить это работать, это не красиво, но сделает работу.Вы можете достичь своей цели, используя boost и multifield параметры запроса query_string
, bool
, чтобы объединить оценки и настройки min_score
:
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 результаты поиска сортируются по релевантности _score
, чем большезабей лучше.
Итак, давайте попробуем повысить вниз по полю "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 (название: "Бристоль", текст: "Бристоль", комментарии: "Бристоль") - комментарии: "Бристоль"
Документ 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"
в любом поле, были выбраны.Оценка релевантности для comments:"Bristol"
была исключена, и только документы, соответствующие title:"Bristol"
или text:"Bristol"
, получили _score
> 0.
Можем ли мы отфильтровать эти результаты с нежелательной оценкой?
Да, мы можем, используя min_score
:
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": ["*"]
вызывает ошибкупоскольку текстовая строка запроса не может быть применена к числу.
Надеюсь, это поможет!