多字段匹配查询编辑

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

$params = [
    'body' => [
        'query' => [
            'multi_match' => [
                'query' => 'this is a test',
                'fields' => [
                    'subject',
                    'message',
                ],
            ],
        ],
    ],
];
$response = $client->search($params);
resp = client.search(
    body={
        "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({
  body: {
    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(
    body={
        "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({
  body: {
    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(
    body={
        "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({
  body: {
    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 字段的得分乘以 3,但保持 message 字段的得分不变。

如果没有提供 fields,则 multi_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(
    body={
        "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({
  body: {
    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(
    body={
        "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({
  body: {
    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,如 匹配查询 中所述。

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(
    body={
        "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({
  body: {
    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 类型最适合查询多个包含相同文本但以不同方式分析的字段。例如,主字段可能包含同义词、词干和不带变音符号的术语。第二个字段可能包含原始术语,而第三个字段可能包含分片。通过组合所有三个字段的得分,我们可以使用主字段匹配尽可能多的文档,但使用第二个和第三个字段将最相似的结果推送到列表的顶部。

此查询

$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(
    body={
        "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({
  body: {
    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(
    body={
        "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({
  body: {
    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" }}
      ]
    }
  }
}

每个 match 子句的得分将加在一起,就像 bool 查询一样。

此外,还接受 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(
    body={
        "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({
  body: {
    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(
    body={
        "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({
  body: {
    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" }}
      ]
    }
  }
}

此外,还接受 analyzerboostlenientzero_terms_query,如 匹配 中所述,以及 slop,如 匹配短语 中所述。类型 phrase_prefix 还接受 max_expansions

phrasephrase_prefixfuzziness

无法将 fuzziness 参数与 phrasephrase_prefix 类型一起使用。

cross_fields编辑

cross_fields 类型特别适合结构化文档,其中多个字段 应该 匹配。例如,当在 first_namelast_name 字段中查询“Will Smith”时,最佳匹配很可能在一个字段中包含“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(
    body={
        "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({
  body: {
    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 具有相同的频率,外加 1。这将使 first_namelast_name 上的匹配具有可比的得分,last_name 稍有优势,因为它是最有可能包含 smith 的字段。

请注意,cross_fields 通常仅对所有都具有 boost1 的短字符串字段有用。否则,boost、词语频率和长度归一化会影响得分,以至于词语统计信息的混合不再有意义。

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

+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 和分析edit

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(
    body={
        "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({
  body: {
    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(
    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"],
                        }
                    },
                ]
            }
        }
    },
)
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
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(
    body={
        "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({
  body: {
    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_breakeredit

默认情况下,每个以词语为中心的 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_prefixedit

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(
    body={
        "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({
  body: {
    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 参数。