计算每个document的(相关度分数)relevance score:每个query的分数,乘以matched query数量,除以总query数量
比如查询语句如下
{
"query": {
"bool": {
"should": [
{ "match": { "title": "java solution" }},
{ "match": { "content": "java solution" }}
]
}
}
}
在查询出的每个文档计算相关度分数流程:
1、针对某个document算出符合每个条件的相关度分数
匹配条件:{ "match": { "title": "java solution" }},如果匹配上会是有一个分数,匹配不上即分数为0,假定分数表示为F1
匹配条件:{ "match": { "content": "java solution" }},如果匹配上会是有一个分数,匹配不上即分数为0,假定分数表示F2
2、计算document相关度分数
matched query数量为M,总query数量为T
最终document相关度分数=(F1+F2)*M/T
例:doc1检索都匹配到了should里的两个match query则M为2 T是match query的总数也是2
doc2检索时只匹配了一个match query则M为1,T还是2
某一个field中匹配到了尽可能多的关键词,被排在前面;而不是尽可能多的field匹配到了少数的关键词,排在了前面。
best fields底层使用dis_max语法,直接取多个query中,分数最高的那一个query的分数即可用上面查询说明,如果F1>F2,则document的相关度分数即为F1
GET /forum/_search
{
"query": {
"dis_max": {
"queries": [
{"match": { "title": "java solution" }},
{ "match": { "content": "java solution" }}
]
}
}
}
注意:
dis_max只取某一个query最大的分数,完全不考虑其他query的分数,此时可以使用tie_breaker将其他query的分数也考虑进去。
除了最高query分数外,将其他query的分数,乘以tie_breaker,然后综合与最高分数的那个query的分数,综合在一起进行计算。所以除了取最高分以外,还会考虑其他的query的分数,tie_breaker的值,在0~1之间
GET /forum/_search
{
"query": {
"dis_max": {
"tie_breaker": 0.7,
"boost": 1.2,
"queries": [
{"match": { "title": "java solution" }},
{ "match": { "content": "java solution" }}
]
}
}
}
上面的写法有点繁琐:es提供了简便写法
GET /forum/_search
{
"query": {
"multi_match": {
"query": "java solution",
"type": "best_fields",
"fields": [ "title", "content" ],
"tie_breaker": 0.3,
"minimum_should_match": "50%"
}
}
}
minimum_should_match:比如你搜索5个关键词,但是很多结果是只匹配1个关键词的,其实跟你想要的结果相差甚远,这些结果就是长尾,minimum_should_match,控制搜索结果的精准度,只有匹配一定数量的关键词的数据,才能返回。
优点:通过best_fields策略,以及综合考虑其他field,还有minimum_should_match支持,可以尽可能精准地将匹配的结果推送到最前面
缺点:除了那些精准匹配的结果,其他差不多大的结果,排序结果不是太均匀,没有什么区分度了
比如:百度之类的搜索引擎,最匹配的到最前面,但是其他的就没什么区分度了
尽可能返回更多field匹配到某个关键词的doc,优先返回回来
综合多个field一起进行搜索,尽可能多地让所有field的query参与到总分数的计算中来,此时就会是个大杂烩,出现类似best_fields案例最开始的那个结果,结果不一定精准,某一个document的一个field包含更多的关键字,但是因为其他document有更多field匹配到了,所以排在了前面;所以需要建立类似sub_title.std这样的field,尽可能让某一个field精准匹配query string,贡献更高的分数,将更精准匹配的数据排到前面。
优点:将尽可能匹配更多field的结果推送到最前面,整个排序结果是比较均匀的
缺点:
(1)可能那些精准匹配的结果,无法推送到最前面
(2)只是找到尽可能多的field匹配的doc,而不是某个field完全匹配的doc
(3)不能用minimum_should_match去掉长尾数据,就是匹配的特别少的结果
比如:wiki,明显的most_fields策略,搜索结果比较均匀,但是的确要翻好几页才能找到最匹配的结果
举例:
POST /forum/_mapping
{
"properties": {
"sub_title": {
"type": "string",
"analyzer": "english",
"fields": {
"std": {
"type": "string",
"analyzer": "standard"
}
}
}
}
}
POST /forum/_bulk
{ "update": { "_id": "1"} }
{ "doc" : {"sub_title" : "learning more courses"} }
{ "update": { "_id": "2"} }
{ "doc" : {"sub_title" : "learned a lot of course"} }
{ "update": { "_id": "3"} }
{ "doc" : {"sub_title" : "we have a lot of fun"} }
{ "update": { "_id": "4"} }
{ "doc" : {"sub_title" : "both of them are good"} }
{ "update": { "_id": "5"} }
{ "doc" : {"sub_title" : "haha, hello world"} }
使用most-fields策略检索
GET /forum/_search
{
"query": {
"multi_match": {
"query": "learning courses",
"type": "most_fields",
"fields": [ "sub_title", "sub_title.std" ]
}
}
}
基于most-fields的检索弊端可以可以使用:copy_to将多个field组合成一个field
比如我们想在author_first_name和author_last_name匹配一个人名的话,
PUT /forum/_mapping/
{
"properties": {
"author_first_name": {
"type": "string",
"copy_to": "new_author_full_name"
},
"author_last_name": {
"type": "string",
"copy_to": "new_author_full_name"
},
"new_author_full_name": {
"type": "string"
}
}
}
因为建了mapping,就可以将多个字段的值拷贝到一个字段中,并建立倒排索引,使用new_author_full_name一个字段使用best fields也可以匹配
检索的关键字在match中多个fields中出现过,且cross-fields支持 minimum_should_match
GET /forum/_search
{
"query": {
"multi_match": {
"query": "Peter Smith",
"type": "cross_fields",
"operator": "and",
"fields": ["author_first_name", "author_last_name"]
}
}
}