多字段匹配查询

编辑

multi_match 查询建立在 match 查询 的基础上,允许进行多字段查询。

$params = [
    'body' => [
        'query' => [
            'multi_match' => [
                'query' => 'this is a test',
                'fields' => [
                    'subject',
                    'message',
                ],
            ],
        ],
    ],
];
$response = $client->search($params);
resp = client.search(
    query={
        "multi_match": {
            "query": "this is a test",
            "fields": [
                "subject",
                "message"
            ]
        }
    },
)
print(resp)
response = client.search(
  body: {
    query: {
      multi_match: {
        query: 'this is a test',
        fields: [
          'subject',
          'message'
        ]
      }
    }
  }
)
puts response
res, err := es.Search(
	es.Search.WithBody(strings.NewReader(`{
	  "query": {
	    "multi_match": {
	      "query": "this is a test",
	      "fields": [
	        "subject",
	        "message"
	      ]
	    }
	  }
	}`)),
	es.Search.WithPretty(),
)
fmt.Println(res, err)
const response = await client.search({
  query: {
    multi_match: {
      query: "this is a test",
      fields: ["subject", "message"],
    },
  },
});
console.log(response);
GET /_search
{
  "query": {
    "multi_match" : {
      "query":    "this is a test", 
      "fields": [ "subject", "message" ] 
    }
  }
}

查询字符串。

要查询的字段。

fields 和每个字段的加权

编辑

可以使用通配符指定字段,例如

$params = [
    'body' => [
        'query' => [
            'multi_match' => [
                'query' => 'Will Smith',
                'fields' => [
                    'title',
                    '*_name',
                ],
            ],
        ],
    ],
];
$response = $client->search($params);
resp = client.search(
    query={
        "multi_match": {
            "query": "Will Smith",
            "fields": [
                "title",
                "*_name"
            ]
        }
    },
)
print(resp)
response = client.search(
  body: {
    query: {
      multi_match: {
        query: 'Will Smith',
        fields: [
          'title',
          '*_name'
        ]
      }
    }
  }
)
puts response
res, err := es.Search(
	es.Search.WithBody(strings.NewReader(`{
	  "query": {
	    "multi_match": {
	      "query": "Will Smith",
	      "fields": [
	        "title",
	        "*_name"
	      ]
	    }
	  }
	}`)),
	es.Search.WithPretty(),
)
fmt.Println(res, err)
const response = await client.search({
  query: {
    multi_match: {
      query: "Will Smith",
      fields: ["title", "*_name"],
    },
  },
});
console.log(response);
GET /_search
{
  "query": {
    "multi_match" : {
      "query":    "Will Smith",
      "fields": [ "title", "*_name" ] 
    }
  }
}

查询 titlefirst_namelast_name 字段。

可以使用插入符号 (^) 表示法对单个字段进行加权。

$params = [
    'body' => [
        'query' => [
            'multi_match' => [
                'query' => 'this is a test',
                'fields' => [
                    'subject^3',
                    'message',
                ],
            ],
        ],
    ],
];
$response = $client->search($params);
resp = client.search(
    query={
        "multi_match": {
            "query": "this is a test",
            "fields": [
                "subject^3",
                "message"
            ]
        }
    },
)
print(resp)
response = client.search(
  body: {
    query: {
      multi_match: {
        query: 'this is a test',
        fields: [
          'subject^3',
          'message'
        ]
      }
    }
  }
)
puts response
res, err := es.Search(
	es.Search.WithBody(strings.NewReader(`{
	  "query": {
	    "multi_match": {
	      "query": "this is a test",
	      "fields": [
	        "subject^3",
	        "message"
	      ]
	    }
	  }
	}`)),
	es.Search.WithPretty(),
)
fmt.Println(res, err)
const response = await client.search({
  query: {
    multi_match: {
      query: "this is a test",
      fields: ["subject^3", "message"],
    },
  },
});
console.log(response);
GET /_search
{
  "query": {
    "multi_match" : {
      "query" : "this is a test",
      "fields" : [ "subject^3", "message" ] 
    }
  }
}

该查询将 subject 字段的分数乘以三,但 message 字段的分数保持不变。

如果没有提供 fieldsmulti_match 查询默认使用 index.query.default_field 索引设置,该设置又默认使用 ** 会提取映射中所有符合词项查询条件的字段,并过滤元数据字段。然后将所有提取的字段组合起来构建一个查询。

字段数量限制

默认情况下,查询可以包含的子句数量有限制。此限制由 indices.query.bool.max_clause_count 设置定义,该设置默认为 4096。对于多字段匹配查询,子句的数量计算为字段数量乘以词项数量。

multi_match 查询的类型

编辑

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

best_fields

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

most_fields

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

cross_fields

将具有相同 analyzer 的字段视为一个大字段。在任何字段中查找每个单词。请参阅 cross_fields

phrase

在每个字段上运行 match_phrase 查询,并使用最佳字段的 _score。请参阅 phrasephrase_prefix

phrase_prefix

在每个字段上运行 match_phrase_prefix 查询,并使用最佳字段的 _score。请参阅 phrasephrase_prefix

bool_prefix

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

best_fields

编辑

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

best_fields 类型为每个字段生成一个 match 查询,并将它们包装在一个 dis_max 查询中,以查找单个最佳匹配字段。例如,此查询

$params = [
    'body' => [
        'query' => [
            'multi_match' => [
                'query' => 'brown fox',
                'type' => 'best_fields',
                'fields' => [
                    'subject',
                    'message',
                ],
                'tie_breaker' => 0.3,
            ],
        ],
    ],
];
$response = $client->search($params);
resp = client.search(
    query={
        "multi_match": {
            "query": "brown fox",
            "type": "best_fields",
            "fields": [
                "subject",
                "message"
            ],
            "tie_breaker": 0.3
        }
    },
)
print(resp)
response = client.search(
  body: {
    query: {
      multi_match: {
        query: 'brown fox',
        type: 'best_fields',
        fields: [
          'subject',
          'message'
        ],
        tie_breaker: 0.3
      }
    }
  }
)
puts response
res, err := es.Search(
	es.Search.WithBody(strings.NewReader(`{
	  "query": {
	    "multi_match": {
	      "query": "brown fox",
	      "type": "best_fields",
	      "fields": [
	        "subject",
	        "message"
	      ],
	      "tie_breaker": 0.3
	    }
	  }
	}`)),
	es.Search.WithPretty(),
)
fmt.Println(res, err)
const response = await client.search({
  query: {
    multi_match: {
      query: "brown fox",
      type: "best_fields",
      fields: ["subject", "message"],
      tie_breaker: 0.3,
    },
  },
});
console.log(response);
GET /_search
{
  "query": {
    "multi_match" : {
      "query":      "brown fox",
      "type":       "best_fields",
      "fields":     [ "subject", "message" ],
      "tie_breaker": 0.3
    }
  }
}

将执行为

$params = [
    'body' => [
        'query' => [
            'dis_max' => [
                'queries' => [
                    [
                        'match' => [
                            'subject' => 'brown fox',
                        ],
                    ],
                    [
                        'match' => [
                            'message' => 'brown fox',
                        ],
                    ],
                ],
                'tie_breaker' => 0.3,
            ],
        ],
    ],
];
$response = $client->search($params);
resp = client.search(
    query={
        "dis_max": {
            "queries": [
                {
                    "match": {
                        "subject": "brown fox"
                    }
                },
                {
                    "match": {
                        "message": "brown fox"
                    }
                }
            ],
            "tie_breaker": 0.3
        }
    },
)
print(resp)
response = client.search(
  body: {
    query: {
      dis_max: {
        queries: [
          {
            match: {
              subject: 'brown fox'
            }
          },
          {
            match: {
              message: 'brown fox'
            }
          }
        ],
        tie_breaker: 0.3
      }
    }
  }
)
puts response
res, err := es.Search(
	es.Search.WithBody(strings.NewReader(`{
	  "query": {
	    "dis_max": {
	      "queries": [
	        {
	          "match": {
	            "subject": "brown fox"
	          }
	        },
	        {
	          "match": {
	            "message": "brown fox"
	          }
	        }
	      ],
	      "tie_breaker": 0.3
	    }
	  }
	}`)),
	es.Search.WithPretty(),
)
fmt.Println(res, err)
const response = await client.search({
  query: {
    dis_max: {
      queries: [
        {
          match: {
            subject: "brown fox",
          },
        },
        {
          match: {
            message: "brown fox",
          },
        },
      ],
      tie_breaker: 0.3,
    },
  },
});
console.log(response);
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_expansionsfuzzy_rewritezero_terms_queryauto_generate_synonyms_phrase_queryfuzzy_transpositions,如 match 查询 中所述。

operatorminimum_should_match

best_fieldsmost_fields 类型是以字段为中心的 — 它们为每个字段生成一个 match 查询。这意味着 operatorminimum_should_match 参数分别应用于每个字段,这可能不是您想要的。

以这个查询为例

$params = [
    'body' => [
        'query' => [
            'multi_match' => [
                'query' => 'Will Smith',
                'type' => 'best_fields',
                'fields' => [
                    'first_name',
                    'last_name',
                ],
                'operator' => 'and',
            ],
        ],
    ],
];
$response = $client->search($params);
resp = client.search(
    query={
        "multi_match": {
            "query": "Will Smith",
            "type": "best_fields",
            "fields": [
                "first_name",
                "last_name"
            ],
            "operator": "and"
        }
    },
)
print(resp)
response = client.search(
  body: {
    query: {
      multi_match: {
        query: 'Will Smith',
        type: 'best_fields',
        fields: [
          'first_name',
          'last_name'
        ],
        operator: 'and'
      }
    }
  }
)
puts response
res, err := es.Search(
	es.Search.WithBody(strings.NewReader(`{
	  "query": {
	    "multi_match": {
	      "query": "Will Smith",
	      "type": "best_fields",
	      "fields": [
	        "first_name",
	        "last_name"
	      ],
	      "operator": "and"
	    }
	  }
	}`)),
	es.Search.WithPretty(),
)
fmt.Println(res, err)
const response = await client.search({
  query: {
    multi_match: {
      query: "Will Smith",
      type: "best_fields",
      fields: ["first_name", "last_name"],
      operator: "and",
    },
  },
});
console.log(response);
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 查询提供了一种以词项为中心的方法,可以在每个词项的基础上处理 operatorminimum_should_match。另一种多字段匹配模式 cross_fields 也解决了这个问题。

most_fields

编辑

当查询以不同方式分析的包含相同文本的多个字段时,most_fields 类型最有用。例如,主字段可能包含同义词、词干和不带变音符号的词项。第二个字段可能包含原始词项,而第三个字段可能包含 shingles。通过组合来自所有三个字段的分数,我们可以使用主字段匹配尽可能多的文档,但使用第二个和第三个字段将最相似的结果推到列表的顶部。

此查询

$params = [
    'body' => [
        'query' => [
            'multi_match' => [
                'query' => 'quick brown fox',
                'type' => 'most_fields',
                'fields' => [
                    'title',
                    'title.original',
                    'title.shingles',
                ],
            ],
        ],
    ],
];
$response = $client->search($params);
resp = client.search(
    query={
        "multi_match": {
            "query": "quick brown fox",
            "type": "most_fields",
            "fields": [
                "title",
                "title.original",
                "title.shingles"
            ]
        }
    },
)
print(resp)
response = client.search(
  body: {
    query: {
      multi_match: {
        query: 'quick brown fox',
        type: 'most_fields',
        fields: [
          'title',
          'title.original',
          'title.shingles'
        ]
      }
    }
  }
)
puts response
res, err := es.Search(
	es.Search.WithBody(strings.NewReader(`{
	  "query": {
	    "multi_match": {
	      "query": "quick brown fox",
	      "type": "most_fields",
	      "fields": [
	        "title",
	        "title.original",
	        "title.shingles"
	      ]
	    }
	  }
	}`)),
	es.Search.WithPretty(),
)
fmt.Println(res, err)
const response = await client.search({
  query: {
    multi_match: {
      query: "quick brown fox",
      type: "most_fields",
      fields: ["title", "title.original", "title.shingles"],
    },
  },
});
console.log(response);
GET /_search
{
  "query": {
    "multi_match" : {
      "query":      "quick brown fox",
      "type":       "most_fields",
      "fields":     [ "title", "title.original", "title.shingles" ]
    }
  }
}

将执行为

$params = [
    'body' => [
        'query' => [
            'bool' => [
                'should' => [
                    [
                        'match' => [
                            'title' => 'quick brown fox',
                        ],
                    ],
                    [
                        'match' => [
                            'title.original' => 'quick brown fox',
                        ],
                    ],
                    [
                        'match' => [
                            'title.shingles' => 'quick brown fox',
                        ],
                    ],
                ],
            ],
        ],
    ],
];
$response = $client->search($params);
resp = client.search(
    query={
        "bool": {
            "should": [
                {
                    "match": {
                        "title": "quick brown fox"
                    }
                },
                {
                    "match": {
                        "title.original": "quick brown fox"
                    }
                },
                {
                    "match": {
                        "title.shingles": "quick brown fox"
                    }
                }
            ]
        }
    },
)
print(resp)
response = client.search(
  body: {
    query: {
      bool: {
        should: [
          {
            match: {
              title: 'quick brown fox'
            }
          },
          {
            match: {
              'title.original' => 'quick brown fox'
            }
          },
          {
            match: {
              'title.shingles' => 'quick brown fox'
            }
          }
        ]
      }
    }
  }
)
puts response
res, err := es.Search(
	es.Search.WithBody(strings.NewReader(`{
	  "query": {
	    "bool": {
	      "should": [
	        {
	          "match": {
	            "title": "quick brown fox"
	          }
	        },
	        {
	          "match": {
	            "title.original": "quick brown fox"
	          }
	        },
	        {
	          "match": {
	            "title.shingles": "quick brown fox"
	          }
	        }
	      ]
	    }
	  }
	}`)),
	es.Search.WithPretty(),
)
fmt.Println(res, err)
const response = await client.search({
  query: {
    bool: {
      should: [
        {
          match: {
            title: "quick brown fox",
          },
        },
        {
          match: {
            "title.original": "quick brown fox",
          },
        },
        {
          match: {
            "title.shingles": "quick brown fox",
          },
        },
      ],
    },
  },
});
console.log(response);
GET /_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "title":          "quick brown fox" }},
        { "match": { "title.original": "quick brown fox" }},
        { "match": { "title.shingles": "quick brown fox" }}
      ]
    }
  }
}

就像 bool 查询一样,每个 match 子句的分数会相加在一起。

此外,还接受 analyzerboostoperatorminimum_should_matchfuzzinesslenientprefix_lengthmax_expansionsfuzzy_rewritezero_terms_query

phrasephrase_prefix

编辑

phrasephrase_prefix 类型的行为与 best_fields 类似,但它们使用 match_phrasematch_phrase_prefix 查询而不是 match 查询。

此查询

$params = [
    'body' => [
        'query' => [
            'multi_match' => [
                'query' => 'quick brown f',
                'type' => 'phrase_prefix',
                'fields' => [
                    'subject',
                    'message',
                ],
            ],
        ],
    ],
];
$response = $client->search($params);
resp = client.search(
    query={
        "multi_match": {
            "query": "quick brown f",
            "type": "phrase_prefix",
            "fields": [
                "subject",
                "message"
            ]
        }
    },
)
print(resp)
response = client.search(
  body: {
    query: {
      multi_match: {
        query: 'quick brown f',
        type: 'phrase_prefix',
        fields: [
          'subject',
          'message'
        ]
      }
    }
  }
)
puts response
res, err := es.Search(
	es.Search.WithBody(strings.NewReader(`{
	  "query": {
	    "multi_match": {
	      "query": "quick brown f",
	      "type": "phrase_prefix",
	      "fields": [
	        "subject",
	        "message"
	      ]
	    }
	  }
	}`)),
	es.Search.WithPretty(),
)
fmt.Println(res, err)
const response = await client.search({
  query: {
    multi_match: {
      query: "quick brown f",
      type: "phrase_prefix",
      fields: ["subject", "message"],
    },
  },
});
console.log(response);
GET /_search
{
  "query": {
    "multi_match" : {
      "query":      "quick brown f",
      "type":       "phrase_prefix",
      "fields":     [ "subject", "message" ]
    }
  }
}

将执行为

$params = [
    'body' => [
        'query' => [
            'dis_max' => [
                'queries' => [
                    [
                        'match_phrase_prefix' => [
                            'subject' => 'quick brown f',
                        ],
                    ],
                    [
                        'match_phrase_prefix' => [
                            'message' => 'quick brown f',
                        ],
                    ],
                ],
            ],
        ],
    ],
];
$response = $client->search($params);
resp = client.search(
    query={
        "dis_max": {
            "queries": [
                {
                    "match_phrase_prefix": {
                        "subject": "quick brown f"
                    }
                },
                {
                    "match_phrase_prefix": {
                        "message": "quick brown f"
                    }
                }
            ]
        }
    },
)
print(resp)
response = client.search(
  body: {
    query: {
      dis_max: {
        queries: [
          {
            match_phrase_prefix: {
              subject: 'quick brown f'
            }
          },
          {
            match_phrase_prefix: {
              message: 'quick brown f'
            }
          }
        ]
      }
    }
  }
)
puts response
res, err := es.Search(
	es.Search.WithBody(strings.NewReader(`{
	  "query": {
	    "dis_max": {
	      "queries": [
	        {
	          "match_phrase_prefix": {
	            "subject": "quick brown f"
	          }
	        },
	        {
	          "match_phrase_prefix": {
	            "message": "quick brown f"
	          }
	        }
	      ]
	    }
	  }
	}`)),
	es.Search.WithPretty(),
)
fmt.Println(res, err)
const response = await client.search({
  query: {
    dis_max: {
      queries: [
        {
          match_phrase_prefix: {
            subject: "quick brown f",
          },
        },
        {
          match_phrase_prefix: {
            message: "quick brown f",
          },
        },
      ],
    },
  },
});
console.log(response);
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 中所述的 slop。类型 phrase_prefix 另外接受 max_expansions

phrasephrase_prefixfuzziness

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

cross_fields

编辑

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

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

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

类似这样的查询

$params = [
    'body' => [
        'query' => [
            'multi_match' => [
                'query' => 'Will Smith',
                'type' => 'cross_fields',
                'fields' => [
                    'first_name',
                    'last_name',
                ],
                'operator' => 'and',
            ],
        ],
    ],
];
$response = $client->search($params);
resp = client.search(
    query={
        "multi_match": {
            "query": "Will Smith",
            "type": "cross_fields",
            "fields": [
                "first_name",
                "last_name"
            ],
            "operator": "and"
        }
    },
)
print(resp)
response = client.search(
  body: {
    query: {
      multi_match: {
        query: 'Will Smith',
        type: 'cross_fields',
        fields: [
          'first_name',
          'last_name'
        ],
        operator: 'and'
      }
    }
  }
)
puts response
res, err := es.Search(
	es.Search.WithBody(strings.NewReader(`{
	  "query": {
	    "multi_match": {
	      "query": "Will Smith",
	      "type": "cross_fields",
	      "fields": [
	        "first_name",
	        "last_name"
	      ],
	      "operator": "and"
	    }
	  }
	}`)),
	es.Search.WithPretty(),
)
fmt.Println(res, err)
const response = await client.search({
  query: {
    multi_match: {
      query: "Will Smith",
      type: "cross_fields",
      fields: ["first_name", "last_name"],
      operator: "and",
    },
  },
});
console.log(response);
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 使用的逻辑进行比较。)

这解决了两个问题之一。为了平衡差异,通过混合所有字段的词项频率来解决词项频率不同的问题。

实际上,first_name:smith 将被视为具有与 last_name:smith 相同的频率,加一。这将使 first_namelast_name 上的匹配具有可比较的分数,并且由于 last_name 是最有可能包含 smith 的字段,因此它略有优势。

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

如果您通过 验证 API 运行以上查询,它将返回此解释:

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

此外,还接受 analyzerboostoperatorminimum_should_matchlenientzero_terms_query

cross_fields 类型以一种复杂的、难以解释的方式混合字段统计信息。得分组合甚至可能不正确,尤其是在某些文档包含某些搜索字段,但并非全部搜索字段时。您应该考虑使用 combined_fields 查询作为替代方案,它也是以词项为中心,但以更稳健的方式组合字段统计信息。

cross_field 和分析

编辑

cross_field 类型只能在以词项为中心的模式下工作,且字段必须具有相同的分析器。具有相同分析器的字段会像上面的示例一样被分组在一起。如果存在多个组,则查询将使用任何组中的最佳得分。

例如,如果我们有一个 firstlast 字段,它们具有相同的分析器,以及一个 first.edgelast.edge 字段,它们都使用 edge_ngram 分析器,那么这个查询:

$params = [
    'body' => [
        'query' => [
            'multi_match' => [
                'query' => 'Jon',
                'type' => 'cross_fields',
                'fields' => [
                    'first',
                    'first.edge',
                    'last',
                    'last.edge',
                ],
            ],
        ],
    ],
];
$response = $client->search($params);
resp = client.search(
    query={
        "multi_match": {
            "query": "Jon",
            "type": "cross_fields",
            "fields": [
                "first",
                "first.edge",
                "last",
                "last.edge"
            ]
        }
    },
)
print(resp)
response = client.search(
  body: {
    query: {
      multi_match: {
        query: 'Jon',
        type: 'cross_fields',
        fields: [
          'first',
          'first.edge',
          'last',
          'last.edge'
        ]
      }
    }
  }
)
puts response
res, err := es.Search(
	es.Search.WithBody(strings.NewReader(`{
	  "query": {
	    "multi_match": {
	      "query": "Jon",
	      "type": "cross_fields",
	      "fields": [
	        "first",
	        "first.edge",
	        "last",
	        "last.edge"
	      ]
	    }
	  }
	}`)),
	es.Search.WithPretty(),
)
fmt.Println(res, err)
const response = await client.search({
  query: {
    multi_match: {
      query: "Jon",
      type: "cross_fields",
      fields: ["first", "first.edge", "last", "last.edge"],
    },
  },
});
console.log(response);
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.edgelast.edge 将被分组在一起并被视为单个字段。

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

您可以轻松地将此查询重写为两个单独的 cross_fields 查询,并使用 dis_max 查询组合,并将 minimum_should_match 参数仅应用于其中一个查询。

resp = client.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"
                        ]
                    }
                }
            ]
        }
    },
)
print(resp)
response = client.search(
  body: {
    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'
              ]
            }
          }
        ]
      }
    }
  }
)
puts response
const response = await client.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"],
          },
        },
      ],
    },
  },
});
console.log(response);
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" ]
          }
        }
      ]
    }
  }
}

firstlast 字段中,必须存在 willsmith 中的至少一个。

您可以通过在查询中指定 analyzer 参数来强制将所有字段放入同一组中。

$params = [
    'body' => [
        'query' => [
            'multi_match' => [
                'query' => 'Jon',
                'type' => 'cross_fields',
                'analyzer' => 'standard',
                'fields' => [
                    'first',
                    'last',
                    '*.edge',
                ],
            ],
        ],
    ],
];
$response = $client->search($params);
resp = client.search(
    query={
        "multi_match": {
            "query": "Jon",
            "type": "cross_fields",
            "analyzer": "standard",
            "fields": [
                "first",
                "last",
                "*.edge"
            ]
        }
    },
)
print(resp)
response = client.search(
  body: {
    query: {
      multi_match: {
        query: 'Jon',
        type: 'cross_fields',
        analyzer: 'standard',
        fields: [
          'first',
          'last',
          '*.edge'
        ]
      }
    }
  }
)
puts response
res, err := es.Search(
	es.Search.WithBody(strings.NewReader(`{
	  "query": {
	    "multi_match": {
	      "query": "Jon",
	      "type": "cross_fields",
	      "analyzer": "standard",
	      "fields": [
	        "first",
	        "last",
	        "*.edge"
	      ]
	    }
	  }
	}`)),
	es.Search.WithPretty(),
)
fmt.Println(res, err)
const response = await client.search({
  query: {
    multi_match: {
      query: "Jon",
      type: "cross_fields",
      analyzer: "standard",
      fields: ["first", "last", "*.edge"],
    },
  },
});
console.log(response);
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: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 查询。

$params = [
    'body' => [
        'query' => [
            'multi_match' => [
                'query' => 'quick brown f',
                'type' => 'bool_prefix',
                'fields' => [
                    'subject',
                    'message',
                ],
            ],
        ],
    ],
];
$response = $client->search($params);
resp = client.search(
    query={
        "multi_match": {
            "query": "quick brown f",
            "type": "bool_prefix",
            "fields": [
                "subject",
                "message"
            ]
        }
    },
)
print(resp)
response = client.search(
  body: {
    query: {
      multi_match: {
        query: 'quick brown f',
        type: 'bool_prefix',
        fields: [
          'subject',
          'message'
        ]
      }
    }
  }
)
puts response
res, err := es.Search(
	es.Search.WithBody(strings.NewReader(`{
	  "query": {
	    "multi_match": {
	      "query": "quick brown f",
	      "type": "bool_prefix",
	      "fields": [
	        "subject",
	        "message"
	      ]
	    }
	  }
	}`)),
	es.Search.WithPretty(),
)
fmt.Println(res, err)
const response = await client.search({
  query: {
    multi_match: {
      query: "quick brown f",
      type: "bool_prefix",
      fields: ["subject", "message"],
    },
  },
});
console.log(response);
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 参数。 fuzzinessprefix_lengthmax_expansionsfuzzy_rewritefuzzy_transpositions 参数支持用于构造词项查询的词项,但对从最终词项构造的前缀查询没有影响。

此查询类型不支持 slop 参数。