Как исключить поле из поиска поasticsearch 6.1? - PullRequest
0 голосов
/ 11 октября 2018

У меня есть индекс с несколькими полями в нем.Я хочу отфильтровать на основе наличия строки поиска во всех полях, кроме одного - user_comments .Я выполняю поиск по запросу:

{
    "from": offset,
    "size": limit,
    "_source": [
      "document_title"
    ],
    "query": {
      "function_score": {
        "query": {
          "bool": {
            "must":
            {
              "query_string": {
                "query": "#{query}"
              }
            }
          }
        }
      }
    }
  }

Хотя строка запроса выполняет поиск по всем полям и выдает мне документы с соответствующей строкой в ​​поле user_comments .Но я хочу выполнить запрос ко всем полям, оставляя поле user_comments .Белый список - это очень большой список, а также имена полей являются динамическими, поэтому упоминать список белых списков полей с помощью параметра fields не представляется возможным.

"query_string": {
                    "query": "#{query}",
                    "fields": [
                      "document_title",
                      "field2"
                    ]
                  }

Может кто-нибудь пожалуйстапредложить идею о том, как исключить поле из поиска?

Ответы [ 2 ]

0 голосов
/ 11 октября 2018

Есть способ заставить это работать, это не красиво, но сделает работу.Вы можете достичь своей цели, используя 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": ["*"]

вызывает ошибкупоскольку текстовая строка запроса не может быть применена к числу.


Надеюсь, это поможет!

0 голосов
/ 11 октября 2018

Как вы ищете, ES будет искать совпадения в поле _all.Чтобы исключить одно поле, вы можете отключить поле _all для комментариев пользователей.

Ссылка - https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-all-field.html#enabling-all-field

Для ES 6.x его можно реплицировать с помощью copy_to

https://www.elastic.co/guide/en/elasticsearch/reference/current/copy-to.html

...