ElasticSearch多字段查询best_fields和most_fields介绍
一 理解bool 和dis_max查询
1.1 bool查询
# 返回的文档必须满足must子句,并且参与计算分值
# 返回的文档必须满足filter子句,不计算分值
# 返回的文档可能满足should子句的条件。如果一个没有must和filter的有一个或者多个should子句,那么只要按满足一个就可以返回,minimum_should_match表示至少满足几个子句
# 返回的文档必须不满足must_not条件
1.2 dis_max查询
dismax查询就是Disjuction Max Query,就是OR的意思,返回匹配了任何查询的文档,并且是产生了最佳匹配的查询所对应的分值。
我们添加2条文档数据:
PUT/ecommerce/product/2
{
"name": "Fender",
"desc": " Fender California Series Kingman SCE CutawayElectric Bass",
"price": 599.99,
"type": "Acoustic",
"reviews": 50,
"tags": [
"Bass",
"Acoustic",
"Gibson Cool"
]
}
PUT/ecommerce/product/3
{
"name": "Gibson",
"desc": "Gibson 2017 Les Paul Studio Gold Series ElectricGuitar",
"price": 599.99,
"type": "Acoustic",
"reviews": 50,
"tags": [
"Bass",
"Acoustic",
"Gibson"
]
}
现在我们进行一个bool查询
POST /ecommerce/_search
{
"query":{
"bool":{
"should":[
{"match":{"desc":"Gibson Cool"}},
{"match":{"tags":"Gibson Cool"}}
]
}
}
}
我们期望如果字段包含Gibson Cool的相关度更高,分值应该更高。这个查询结果是什么呢?
它的结果是doc3 分值比doc2大,为什么?
我们看一下是如何计算分值的吧:
# 执行should中的两个match,每一个match如果匹配到了,就会有一个打分,如果没有匹配我们认为分数为0
# 让这些分数相加,比如1.1 和 1.3 那么相加分数为2.4
# 再由相加的乘以匹配到的文档数,比如这里匹配到的是2个,那么2.4 * 2 = 4.8
# 再将乘以的结果除以查询的数量 ,这儿是2个查询,故
4.8/2 =2.4
二 best_fields 策略:
指的就是搜索结果中应该返回某一个字段匹配到了最多的关键词的文档。我们可以你使用dis_max查询实现。
方案一:使用dis_max查询实现,因为dis_max查询就是返回最高分数的那个文档
POST /ecommerce/glasses/_search
{
"query":{
"dis_max": {
"queries": [
{"match":{"record.desc":"Hadoop Spark"}},
{"match":{"record.content":"HadoopSpark"}}
]
}
}
}
方案二:使用multi_match查询,使用type指定best_fields类型
POST /ecommerce/glasses/_search
{
"query": {
"multi_match": {
"query": "Hadoop Spark",
"type":"best_fields",
"minimum_should_match":"50%",
"fields":["record.desc^3","record.content"]
}
}
}
三 most_fields策略:
指的就是搜索结果应该返回匹配了更多的字段的document优先返回回来。
POST /ecommerce/glasses/_search
{
"query": {
"multi_match": {
"query": "Hadoop Spark",
"type":"most_fields",
"fields": ["record.desc","record.content"]
}
}
}
四 cross_fields策略:
指的是一个唯一标识,跨域了多个字段,比如人的标识是名字,一个建筑的标识是地址,姓名跨域散落在多个field中,比如first_name和last_name,一个地址也可以散落在多个字段中,比如country,province,city中。
跨域多个字段搜索一个标识就是cross_fields搜索。
4.1 首先我们使用most_fileds来实现会有什么问题呢
# 只是尽可能找到匹配的文档,比如我搜索Red Round,我可能搜搜出很多只包含Red或者Round的文档,但是同时满足我跨字段搜索条件的可能很少
# most_fields,没办法用minimum_should_match去掉长尾数据
4.2 使用copy_to,将多个field组合成一个新field,也能实现跨字段搜索的功能
首先,索引映射文件中国使用copy_to,比如:
PUT /ecommerce/_mapping/glasses
{
"properties": {
"first_name": {
"type":"string",
"copy_to":"full_name"
},
"last_name": {
"type":"string",
"copy_to":"full_name"
},
"full_name": {
"type":"string"
}
}
}
POST /ecommerce/glasses/_search
{
"query": {
"match": {"full_name":"Nicky Zhang"}
}
}
4.3 使用multi_match,指定类型为cross_fields
POST /ecommerce/glasses/_search
{
"query": {
"multi_match": {
"query": "Red Round",
"type":"cross_fields",
"operator":"and",
"fields": ["record.color","record.shape"]
}
}
}
为什么使用AND, 因为我要的是两个匹配,而不是其中的任何一个匹配都可以。