多字段匹配(multi_match)查询

multi_match 查询建立在 match 查询的基础上,以允许 多字段(multi-field) 查询:

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

要查询的字符串。

要查询的字段。

fields 和 字段增强(per-field boosting)

可以使用通配符指定字段名称,比如:

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

查询titlefirst_namelast_name 字段。

单个字段可以用脱字符号(^)来增强:

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

字段 subject 的重要性是 message3 倍。

如果未指定 fields,则 multi_match 查询默认使用 index.query.default_field 索引设置,该设置又默认为 ** 提取映射中符合条件查询的所有字段,并过滤元数据字段。 然后将所有提取的字段组合起来构建一个查询。

一次可以查询的字段数量是有限制的。 它由 indices.query.bool.max_clause_count 搜索设置 定义的,默认为 1024。

multi_match查询的类型:

multi_match 查询在内部执行的方式取决于参数 type,该参数可设置为:

best_fields

(默认) 查找与任何字段匹配的文档,但使用最佳字段的 _score。参见 best_fields

most_fields

查找与任何字段匹配的文档,并合并每个字段的 _score。参见 most_fields

cross_fields

用相同的 analyzer 处理字段,就好像它们是一个大字段。 在 任何 字段中查找每个单词。 参见 cross_fields

phrase

对每个字段运行 match_phrase 查询,并使用最佳字段(best field)的 _score。 参见 phrasephrase_prefix

phrase_prefix

对每个字段运行 match_phrase_prefix 查询,并使用最佳字段(best field)的 _score。 参见 phrasephrase_prefix

bool_prefix

在每个字段上创建 match_bool_prefix 查询,并组合每个字段的 _score。 参见 bool_prefix

best_fields

best_fields 类型在搜索同一字段中最容易找到的多个单词时最有用。 例如,一个字段里的“brown fox”比一个字段里的“brown”和另一个字段里的“fox”更有意义。

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

此外,接受 analyzerboostoperatorminimum_should_matchfuzzinesslenientprefix_lengthmax_expansionsrewritezero_terms_querycutoff_frequencyauto_generate_synonyms_phrase_queryfuzzy_transpositions,如 match 查询 中所述。

operatorminimum_should_match

best_fieldsmost_fields 类型是以字段为中心(field-centric)的,它们为每个字段生成一个 match 查询。 这意味着 operatorminimum_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)

换句话说,所有词项必须出现在一个字段中,文档才能匹配。

更好的解决方案请参考 cross_fields

most_fields

当查询包含以不同方式分析的相同文本的多个字段时,most_fields 类型最有用。 例如,主字段可能包含同义词(synonyms)、词干(stemming)和不带发音符号(diacritics)的词项。 第二个字段可能包含原始的(original)词项(term),第三个字段可能包含 shingles(不知道该怎么翻译)。 通过组合所有三个字段的分数,我们可以将尽可能多的文档与主字段匹配,但使用第二个和第三个字段将最相似的结果推到列表的顶部。

下面这个查询

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 子句的数量。

此外,接受analyzerboostoperatorminimum_should_matchfuzzinesslenientprefix_lengthmax_expansionsrewritezero_terms_querycutoff_frequency,如 match 查询 中所述,但是 请参见 operatorminimum_should_match

phrasephrase_prefix

phrasephrase_prefix 类型的行为类似于best_fields,但是它们使用 match_phrasematch_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" }}
      ]
    }
  }
}

此外,还接受 match 中所述的 analyzerboostlenientzero_terms_query,以及 match phrase 中介绍的 slopphrase_prefix 类型还接受 max_expansions

phrase, phrase_prefixfuzziness

参数 fuzziness 不能与 phrasephrase_prefix 一起使用。

cross_fields

cross_fields 类型对于多个字段should(应该)匹配的结构化文档特别有用。 例如,当在 first_namelast_name字段查询“Will Smith”时,最佳匹配可能是一个字段中有“Will ”,另一个字段中有“Smith”。

处理这些类型的查询的一种方法是简单地将 first_namelast_name 字段索引到单个full_name字段中。当然,这只能在索引时完成。

cross_field 类型试图通过采用以词项为中心(term-centric)的方法在查询时解决这些问题。 它首先将查询字符串分析成单个词项,然后在任何字段中查找每个词项,就好像它们是一个大字段一样。

像下面这样的一个查询

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_fieldsmost_fields 的逻辑 进行比较。)

这解决了两个问题中的一个。 不同词频的问题通过混合(blending)所有字段的词频以消除差异来解决。

实际上,first_name:smith 将被视为与last_name:smith + 1 具有相同的频率。 这将使 first_namelast_name 的匹配项具有可比较的分数,last_name 有一点优势,因为它是最有可能包含smith的字段。

请注意,cross_fields 通常只对 boost 都为 1 的短字符串字段有用。 否则 boost、词频和长度归一化会以这样的一种方式影响分数,以至于词项统计数据的混合不再有意义。

如果你通过 Validate API 运行上述查询,它将返回如下解释:

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

此外,还接受 analyzerboostoperatorminimum_should_matchlenientzero_terms_querycutoff_frequency,如 match 查询 中所述。

cross_field 和分析(analysis)

cross_field 类型只能在具有相同分析器的字段上以词项为中心(term-centric)的模式下工作。 如上例所示,具有相同分析器的字段被分组在一起。 如果有多个组,它们将与一个 bool 查询组合在一起。

例如,如果字段 firstlast 具有相同的分析器,加上 first.edgelast.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])
)

换句话说,firstlast 将被分组在一起并被视为单个字段,first.edge and last.edge 将被分组在一起并被视为单个字段。

拥有多个组是可以的,但是当与 operatorminimum_should_match 结合使用时,它可能会遇到与most_fieldsbest_fields 相同的问题

可以很容易地将该查询重写为两个单独的 cross_fields 查询与一个 bool 查询的组合,并将 minimum_should_match 参数应用于其中一个查询:

GET /_search
{
  "query": {
    "bool": {
      "should": [
        {
          "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" ]
          }
        }
      ]
    }
  }
}

willsmith 必须出现在 firstlast 字段中

通过在查询中指定 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 可以更改按词项 blended(混合的) 查询的默认行为。 它接受:

0.0

取单个最佳分数(默认)。(比如从first_name:willlast_name:will中取最佳分数)

1.0

将分数相加。(比如把first_name:willlast_name:will的分数相加)

0.0 < n < 1.0

将单个最佳分数加上 tie_breaker 乘以其他匹配字段中的每个分数。

cross_fieldsfuzziness

参数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" ]
    }
  }
}

支持 match 查询 中所述的参数 analyzerboostoperatorminimum_should_matchlenientzero_terms_queryauto_generate_synonyms_phrase_query。 用于构建词项(term, "条件"??)查询的词项支持fuzzinessprefix_lengthmax_expansionsrewritefuzzy_transpositions 参数,但这些参数对从最终的词项构建的前缀查询没有作用。

该查询类型不支持slopcutoff_frequency 参数。