Elasticsearch 7.10 Как придать больший вес терминам, которые появляются ранее в документе

#elasticsearch #lucene

#elasticsearch #lucene

Вопрос:

Допустим, мы отправляем запрос (точный тип не имеет значения) для термина: «cosmopolitan» в определенном поле, и давайте предположим, что результирующий набор содержит несколько документов, каждый из которых содержит ровно «k» экземпляров «cosmopolitan».

Каким бы ни был применимый механизм (повышение, взвешивание, сортировка и т. Д.), Я бы хотел, Чтобы результирующий набор возвращался таким образом, чтобы учитывались позиции «cosmopolitan» в документах, т.Е. Если средняя позиция cosmopolitan ниже (ближе к началу документа), то его ранг/ оценка выше.

Я изучил различные типы запросов и сценариев, но, похоже, не могу найти что-то, что применимо к этому, что кажется странным, поскольку для многих доменов термин position может быть действительно важным.

Ответ №1:

Если мы говорим о точных подстроках произвольного myfield , мы можем использовать скрипт сортировки, который вычитает индекс первого вхождения из всей длины строки, тем самым увеличивая более ранние вхождения:

 {
  "query": { ... },
  "sort": [
    {
      "_script": {
        "script": {
          "params": {
            "substr_value": "cosmopolitan"
          },
          "source": """
            def fieldval = doc['myfield.keyword'].value;
            def indexof = fieldval.indexOf(params.substr_value);
            return indexof == -1 ? _score : _score   (fieldval.length() - indexof)
          """
        },
        "type": "number",
        "order": "desc"
      }
    }
  ]
}
 

.keyword Сопоставление не требуется — поле тоже могло иметь fielddata: true настройку — в любом случае, нам понадобится доступ к исходному значению myfield , чтобы этот скрипт работал.


В качестве альтернативы, здесь отлично подходит запрос оценки функции:

 {
  "query": {
    "function_score": {
      "query": {
        "match": {
          "myfield": "cosmopolitan"
        }
      },
      "script_score": {
        
        "script": {
          "params": {
            "substr_value": "cosmopolitan"
          },
          "source": """
            def fieldval = doc['myfield.keyword'].value;
            def indexof = fieldval.indexOf(params.substr_value);
            return indexof == -1 ? _score : (fieldval.length() - indexof)
          """
        }
      },
      "boost_mode": "sum"
    }
  }
}
 

Вы можете настроить его параметры, такие как boost_mode , weight и т.д., в соответствии с вашими потребностями.

Кроме того, вы, вероятно, захотите выполнить взвешенное среднее значение всех вхождений подстроки, и вы можете сделать это в этих сценариях.

Комментарии:

1. Спасибо, это было очень полезно. Я действительно ценю это.

2. Приятно, рад это слышать! Привет, я пишу руководство по Elasticsearch и хотел бы услышать ваш вклад . Приветствия!

3. ПРИМЕЧАНИЕ: если для track_sores не установлено значение true на верхнем уровне запроса, _score всегда будет равен 0 для сценария контекста сортировки, поскольку ES не будет утруждать себя вычислением оценки (это дорого, и ES предполагает, что вы все равно переопределяете его).