在es的查询中,有两个指标非常重要:
一是准确率,查询到的结果集中包含的正确结果数占比;
二是召回率,就是查到的结果集中正确结果在所有正确结果(包含查询到的和未查询到的)中的占比。
在单字符串多字段查询过程中,考虑到正确率,就是要把匹配度最高的放在最前面;考虑到召回率就是就可能多的把相关文档都查出来。
在es中,multi_match就是针对单字符串多字段查询的解决方案,包括三种查询:best_fields,most_fields,cross_fields。
一,best_fields
多字段查询中,单字段匹配度最高的那个文档的算分最高。
插入测试数据:
PUT multi_query_index/_bulk
{"index":{"_id":1}}
{"title":"my bark dogs","body":"cats and dogs"}
{"index":{"_id":2}}
{"title":"my cat mimi","body":"of barking dogs"}
先用bool查询来一波
按照常规理解,第二个文档的body属性中有barking dogs,应该匹配度最高。但结果却是文档1算分最高,排在最前面。
但是考虑到以下几个原因:
一是分词会将barking和dogs还原为bark和dog,这样算起这两个词在文档1一共出现了三次,在文档2中出现了两次,文档1的匹配度最高。
二是,在文本搜索中barking dogs并非整体作为一个关键字去搜索,而是被分词后进行搜索。
三是,bool查询会对每一个match query进行加权平均算分。
GET multi_query_index/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"title": "barking dogs"
}
},
{
"match": {
"body": "barking dogs"
}
}
]
}
}
}
使用multi_query的best_fields来一波
multi_query默认是best_fields模式,即找出匹配度最高的字段的算分作为整个查询的最高算分。这样的话,第二个文档算分就最高了。
GET multi_query_index/_search
{
"explain": true,
"query": {
"multi_match": {
"type": "best_fields",
"query": "barking dogs",
"fields": ["title","body"]
}
}
}
当然,在这个查询中,我们可以指定字段权重,突出某个字段的评分
GET multi_query_index/_search
{
"explain": true,
"query": {
"multi_match": {
"type": "best_fields",
"query": "barking dogs",
"fields": ["title^10","body"]
}
}
}
本质上,multi_match/best_field查询被转换为一个disjunction query。
二,most_fields
most fields字段主要是利用multifields特性,在索引的mapping中对字段设置多个字段,该字段的分词器采用标准分词器,这样的话,分词只会根据空格拆分,而不会对单词进行主干提取。
PUT /multi_query_most_fields
{
"settings": { "number_of_shards": 1 },
"mappings": {
"my_type": {
"properties": {
"title": {
"type": "string",
"analyzer": "english",
"fields": {
"std": {
"type": "string",
"analyzer": "standard"
}
}
}
}
}
}
}
插入2条数据
PUT /multi_query_most_fields/_doc/1
{ "title": "My rabbit jumps" }
PUT /multi_query_most_fields/_doc/2
{ "title": "Jumping jack rabbits" }
针对title单字段来一波multi query查询
这波查询,两个文档的算分一样,但显然第二个文档的算分应该高一些,这就是因为title使用的english分词器会将jumping还原为jump,rabbits还原为rabbit。
GET multi_query_most_fields/_search
{
"query": {
"multi_match": {
"query": "jumping rabbits",
"fields": ["title"],
"type": "most_fields"
}
}
}
针对title及其multifields来一波multi query查询
这波查询,多了对title.std的查询,结果就是第二个文档的算分高,排在最前面,这是因为title.std使用了standard分词器。
GET multi_query_most_fields/_search
{
"query": {
"multi_match": {
"query": "jumping rabbits",
"fields": ["title","title.std"],
"type": "most_fields"
}
}
}
这里,再尝试一次bool查询。
结果发现,bool查询的结果和multi_query/most_fields查询一致。
其实,multi_query/most_fields原理上就是被封装为一个bool查询的。
GET multi_query_most_fields/_search
{
"query": {
"dis_max": {
"boost": 1.2,
"queries": [
{
"match": {
"title": "jumping rabbits"
}
},
{
"match": {
"title.std": "jumping rabbits"
}
}
]
}
}
}