Spec-Zone.ru › Elasticsearch 7
›Elasticsearch Guide [7.17] ›Query DSL ›Полные текстовые запросы

Запрос multi-match

Запрос multi_match основан на запросе match и позволяет выполнять запросы по нескольким полям:

GET /_search
{
  "query": {
    "multi_match" : {
      "query":    "this is a test", 
      "fields": [ "subject", "message" ] 
    }
  }
}

Строка запроса.

Поля для поиска.

fields и усиление по полям

Поля можно указывать с подстановочными знаками, например:

GET /_search
{
  "query": {
    "multi_match" : {
      "query":    "Will Smith",
      "fields": [ "title", "*_name" ] 
    }
  }
}

Произвести поиск по полям title, first_name и last_name.

Индивидуальные поля могут быть усилены с помощью символа возвышения (^):

GET /_search
{
  "query": {
    "multi_match" : {
      "query" : "this is a test",
      "fields" : [ "subject^3", "message" ] 
    }
  }
}

Запрос умножает рейтинг поля subject на три, но оставляет рейтинг поля message без изменений.

Если не указаны fields, запрос multi_match по умолчанию использует настройки индекса index.query.default_field, которые, в свою очередь, по умолчанию устанавливают значение *. * извлекает все поля в отображении, которые подходят для запросов по терминам и фильтрует метаданные поля. Все извлечённые поля объединяются для построения запроса.

Предел количества полей

По умолчанию существует ограничение на количество условий, которое может содержать запрос. Это ограничение определяется настройкой indices.query.bool.max_clause_count, которая по умолчанию равна 1024. Для запросов multi-match количество условий вычисляется как произведение количества полей на количество терминов.

Типы запроса multi_match:

Способ выполнения запроса multi_match зависит от параметра type, который можно задать:

best_fields

(По умолчанию) Находит документы, которые соответствуют любому полю, но использует _score от лучшего поля. См. best_fields.

most_fields

Находит документы, которые соответствуют любому полю, и объединяет _score из каждого поля. См. most_fields.

cross_fields

Обрабатывает поля с одинаковым analyzer как одно большое поле. Ищет каждое слово в любом поле. См. cross_fields.

phrase

Выполняет запрос match_phrase для каждого поля и использует _score от лучшего поля. См. phrase и phrase_prefix.

phrase_prefix

Выполняет запрос match_phrase_prefix для каждого поля и использует _score от лучшего поля. См. phrase и phrase_prefix.

bool_prefix

Создаёт запрос match_bool_prefix для каждого поля и объединяет _score из каждого поля. См. bool_prefix.

best_fields

Тип best_fields наиболее полезен, когда вы ищете несколько слов, которые лучше всего находятся в одном поле. Например, «коричневая лиса» в одном поле более значимо, чем «коричневый» в одном поле и «лиса» в другом.

Тип best_fields генерирует запрос match для каждого поля и оборачивает их в запрос dis_max, чтобы найти единственное наилучшее соответствующее поле. Например, этот запрос:

GET /_search
{
  "query": {
    "multi_match" : {
      "query":      "brown fox",
      "type":       "best_fields",
      "fields":     [ "subject", "message" ],
      "tie_breaker": 0.3
    }
  }
}

будет выполнен как:

GET /_search
{
  "query": {
    "dis_max": {
      "queries": [
        { "match": { "subject": "brown fox" }},
        { "match": { "message": "brown fox" }}
      ],
      "tie_breaker": 0.3
    }
  }
}

Обычно тип best_fields использует рейтинг единственного наилучшего соответствующего поля, но если tie_breaker указан, тогда он вычисляет рейтинг следующим образом:

  • рейтинг из лучшего соответствующего поля
  • плюс tie_breaker * _score для всех остальных соответствующих полей

Также принимает analyzer, boost, operator, minimum_should_match, fuzziness, lenient, prefix_length, max_expansions, fuzzy_rewrite, zero_terms_query, cutoff_frequency, auto_generate_synonyms_phrase_query и fuzzy_transpositions, как объяснено в запросе match.

operator и minimum_should_match

Типы best_fields и most_fields являются полеориентированными — они генерируют запрос match для каждого поля. Это означает, что параметры operator и minimum_should_match применяются к каждому полю индивидуально, что, вероятно, не является желаемым результатом.

Например, рассмотрим этот запрос:

GET /_search
{
  "query": {
    "multi_match" : {
      "query":      "Will Smith",
      "type":       "best_fields",
      "fields":     [ "first_name", "last_name" ],
      "operator":   "and" 
    }
  }
}

Все термины должны присутствовать.

Этот запрос выполняется следующим образом:

  (+first_name:will +first_name:smith)
| (+last_name:will  +last_name:smith)

Другими словами, все термины должны присутствовать в одном поле для соответствия документу.

Запрос combined_fields предлагает терминоориентированный подход, который обрабатывает operator и minimum_should_match на основе каждого термина. Другой режим multi-match cross_fields также решает эту проблему.

most_fields

Тип most_fields наиболее полезен при запросе к нескольким полям, содержащим один и тот же текст, анализируемый различными способами. Например, основное поле может содержать синонимы, стеминг и термины без диакритики. Второе поле может содержать исходные термины, а третье поле может содержать шинглы. Объединяя баллы со всех трёх полей, мы можем сопоставить как можно больше документов с основным полем, но использовать второе и третье поля, чтобы вывести наиболее похожие результаты наверх списка.

Этот запрос:

GET /_search
{
  "query": {
    "multi_match" : {
      "query":      "quick brown fox",
      "type":       "most_fields",
      "fields":     [ "title", "title.original", "title.shingles" ]
    }
  }
}

будет выполнен как:

GET /_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "title":          "quick brown fox" }},
        { "match": { "title.original": "quick brown fox" }},
        { "match": { "title.shingles": "quick brown fox" }}
      ]
    }
  }
}

Сумма баллов каждого match условия складывается, а затем делится на количество match условий.

Также принимает analyzer, boost, operator, minimum_should_match, fuzziness, lenient, prefix_length, max_expansions, fuzzy_rewrite, zero_terms_query и cutoff_frequency, как описано в запросе match, но см. operator и minimum_should_match.

phrase и phrase_prefix

Типы phrase и phrase_prefix ведут себя так же, как best_fields, но они используют запрос match_phrase или match_phrase_prefix вместо запроса match.

Этот запрос:

GET /_search
{
  "query": {
    "multi_match" : {
      "query":      "quick brown f",
      "type":       "phrase_prefix",
      "fields":     [ "subject", "message" ]
    }
  }
}

будет выполнен как:

GET /_search
{
  "query": {
    "dis_max": {
      "queries": [
        { "match_phrase_prefix": { "subject": "quick brown f" }},
        { "match_phrase_prefix": { "message": "quick brown f" }}
      ]
    }
  }
}

Также принимает analyzer, boost, lenient и zero_terms_query, как описано в Match, а также slop, что описано в Match phrase. Тип phrase_prefix дополнительно принимает max_expansions.

phrase, phrase_prefix и fuzziness

Параметр fuzziness не может быть использован с типом phrase или phrase_prefix.

cross_fields

Тип cross_fields особенно полезен с структурированными документами, где должны совпадать несколько полей должны. Например, при запросе к полям first_name и last_name для «Уилла Смита», наиболее подходящий результат, вероятно, будет содержать «Уилл» в одном поле и «Смит» в другом.

Это похоже на задачу для most_fields, но есть две проблемы с этим подходом. Первая проблема заключается в том, что operator и minimum_should_match применяются к каждому полю, а не к каждому термину (см. объяснение выше).

Вторая проблема связана с релевантностью: различные частоты терминов в полях first_name и last_name могут привести к неожиданным результатам.

Например, представьте двух человек: «Уилл Смит» и «Смит Джонс». «Смит» как фамилия очень распространён (и поэтому имеет низкую значимость), но «Смит» как имя очень редкое (и поэтому имеет большую значимость).

Если мы выполним поиск по запросу «Уилл Смит», документ «Смит Джонс» , вероятно, отобразится выше, чем более подходящий документ «Уилл Смит», так как рейтинг first_name:smith превзошел объединённые оценки first_name:will плюс last_name:smith.

Один из способов обработки таких запросов — просто индексировать поля first_name и last_name в одно поле full_name. Конечно, это можно сделать только на этапе индексирования.

Тип cross_field пытается решить эти проблемы на этапе запроса, используя подход, ориентированный на термины. Сначала он анализирует строку запроса на отдельные термины, затем ищет каждый термин в любом из полей, как если бы это было одно большое поле.

Запрос, подобный:

GET /_search
{
  "query": {
    "multi_match" : {
      "query":      "Will Smith",
      "type":       "cross_fields",
      "fields":     [ "first_name", "last_name" ],
      "operator":   "and"
    }
  }
}

выполняется как:

+(first_name:will last_name:will)
+(first_name:smith last_name:smith)

Другими словами, все термины должны присутствовать по крайней мере в одном поле, для того чтобы документ соответствовал запросу. (Сравните это с логикой, используемой для best_fields и most_fields.)

Это решает одну из двух проблем. Проблема с разными частотами терминов решается путём смешивания частот терминов для всех полей, чтобы выровнять различия.

На практике first_name:smith будет обрабатываться так, как будто он имеет те же частоты, что и last_name:smith, плюс один. Это позволит результатам поиска по полям first_name и last_name иметь сопоставимые оценки, с небольшим преимуществом для last_name, поскольку это наиболее вероятное поле, которое содержит smith.

Обратите внимание, что cross_fields обычно полезен только для коротких строковых полей, у которых все имеют boost 1. В противном случае повышения, частоты терминов и нормализация длины вносят вклад в оценку таким образом, что смешивание статистических данных терминов больше не имеет смысла.

Если вы запустите вышеуказанный запрос через Validate, он вернёт такое объяснение:

+blended("will",  fields: [first_name, last_name])
+blended("smith", fields: [first_name, last_name])

Также поддерживает analyzer, boost, operator, minimum_should_match, lenient, zero_terms_query и cutoff_frequency, как описано в match query.

Тип cross_fields смешивает статистические данные полей сложным способом, который может быть трудно интерпретировать. Комбинация оценок может быть даже некорректной, особенно когда некоторые документы содержат некоторые поля поиска, но не все. Вы должны рассмотреть запрос combined_fields в качестве альтернативы, который также ориентирован на термины, но объединяет статистические данные по полям более надёжным способом.

cross_field и анализ

Тип cross_field может работать только в режиме, ориентированном на термины, с полями, имеющими одинаковый анализатор. Поля с одинаковым анализатором группируются вместе, как в приведённом выше примере. Если есть несколько групп, запрос использует наилучшую оценку из любой группы.

Например, если у нас есть поля first и last, которые имеют один и тот же анализатор, плюс поля first.edge и last.edge, которые оба используют анализатор edge_ngram, этот запрос:

GET /_search
{
  "query": {
    "multi_match" : {
      "query":      "Jon",
      "type":       "cross_fields",
      "fields":     [
        "first", "first.edge",
        "last",  "last.edge"
      ]
    }
  }
}

будет выполняться как:

    blended("jon", fields: [first, last])
| (
    blended("j",   fields: [first.edge, last.edge])
    blended("jo",  fields: [first.edge, last.edge])
    blended("jon", fields: [first.edge, last.edge])
)

Другими словами, first и last будут сгруппированы вместе и обрабатываться как одно поле, а first.edge и last.edge будут сгруппированы вместе и обрабатываться как одно поле.

Наличие нескольких групп нормально, но при комбинировании с operator или minimum_should_match, это может привести к той же проблеме, что и most_fields или best_fields.

Вы можете легко переписать этот запрос самостоятельно как два отдельных запроса cross_fields, объединённые запросом dis_max, и применить параметр minimum_should_match только к одному из них:

GET /_search
{
  "query": {
    "dis_max": {
      "queries": [
        {
          "multi_match" : {
            "query":      "Will Smith",
            "type":       "cross_fields",
            "fields":     [ "first", "last" ],
            "minimum_should_match": "50%" 
          }
        },
        {
          "multi_match" : {
            "query":      "Will Smith",
            "type":       "cross_fields",
            "fields":     [ "*.edge" ]
          }
        }
      ]
    }
  }
}

Либо will, либо smith должно присутствовать в любом из полей first или last

Вы можете принудительно объединить все поля в одну группу, указав параметр analyzer в запросе.

GET /_search
{
  "query": {
   "multi_match" : {
      "query":      "Jon",
      "type":       "cross_fields",
      "analyzer":   "standard", 
      "fields":     [ "first", "last", "*.edge" ]
    }
  }
}

Используйте анализатор standard для всех полей.

что будет выполняться как:

blended("will",  fields: [first, first.edge, last.edge, last])
blended("smith", fields: [first, first.edge, last.edge, last])

tie_breaker

По умолчанию каждый запрос blended для каждого термина использует наилучшую оценку, возвращённую любым полем в группе. Затем, при объединении оценок по группам, запрос использует наилучшую оценку из любой группы. Параметр tie_breaker может изменить поведение для обоих этих шагов:

0.0

Возьмите единственную лучшую оценку из (например) first_name:will и last_name:will (по умолчанию)

1.0

Сложите оценки (например) first_name:will и last_name:will

0.0 < n < 1.0

Возьмите единственную лучшую оценку плюс tie_breaker, умноженную на каждую оценку из других сопоставимых полей/групп

cross_fields и fuzziness

Параметр fuzziness не может быть использован с типом cross_fields.

bool_prefix

Система оценки типа bool_prefix работает так же, как most_fields, но с использованием match_bool_prefix запроса вместо match запроса.

GET /_search
{
  "query": {
    "multi_match" : {
      "query":      "quick brown f",
      "type":       "bool_prefix",
      "fields":     [ "subject", "message" ]
    }
  }
}

Параметры analyzer, boost, operator, minimum_should_match, lenient, zero_terms_query и auto_generate_synonyms_phrase_query поддерживаются, как объяснено в match query. Параметры fuzziness, prefix_length, max_expansions, fuzzy_rewrite и fuzzy_transpositions поддерживаются для терминов, используемых для построения запросов по терминам, но не влияют на префиксный запрос, построенный из конечного термина.

Параметры slop и cutoff_frequency не поддерживаются этим типом запроса.

© 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/7.17/query-dsl-multi-match-query.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API