Lucene主要使用的评分模型是布尔模型 , TF/IDF , 向量空间模型.
布尔模型(Boolean Model) 只是在查询中使用 AND 、 OR 和 NOT (与、或和非)这样的条件来查找匹配的文档 .
GET /my_index/doc/_search
{
"query": {
"match": {
"text": "quick fox"
}
}
}
在内部的实现原理
GET /my_index/doc/_search
{
"query": {
"bool": {
"should": [
{"term": { "text": "quick" }},
{"term": { "text": "fox" }}
]
}
}
}
bool 查询实现了布尔模型 , 只要一个文档与查询匹配,Lucene 就会为查询计算评分,然后合并每个匹配词的评分结果。这里使用的评分计算公式叫做 实用评分函数(practical scoring function) 。
score(q,d) = queryNorm(q) //查询的归一化因子, · coord(q,d) //协调因子 · ∑ ( //词条token相对于document的权重和 tf(t in d) //token在document里面的词频 · idf(t)² //逆向文档频率 · t.getBoost() //是查询中使用的 boost · norm(t,d) // 字段长度归一值 ,与索引时字段层 boost(如果存在)的和 ) (t in q)
查询归一化因子 : 试图将查询 归一化 , 这样就能将两个不同的查询结果相比较。
queryNorm=1sumOfSquaredWeights‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾√sumOfSquaredWeights 是查询里每个词的 IDF 的平方和。
协调因子(coord) : 可以为那些查询词包含度高的文档提供奖励,文档里出现的查询词越多,它越有机会成为好的匹配结果。
举例 : 设想查询 quick brown fox ,每个词的权重都是 1.5 。如果没有协调因子,最终评分会是文档里所有词权重的总和。例如:
- 文档里有 fox → 评分: 1.5
- 文档里有 quick fox → 评分: 3.0
- 文档里有 quick brown fox → 评分: 4.5
协调因子将评分与文档里匹配词的数量相乘,然后除以查询里所有词的数量,如果使用协调因子,评分会变成:
- 文档里有 fox → 评分: 1.5 * 1 / 3 = 0.5
- 文档里有 quick fox → 评分: 3.0 * 2 / 3 = 2.0
- 文档里有 quick brown fox → 评分: 4.5 * 3 / 3 = 4.5
协调因子能使包含所有三个词的文档比只包含两个词的文档评分要高出很多。
bool 查询默认会对所有 should 语句使用协调功能,不过也可以将其禁用。
GET /_search { "query": { "bool": { "disable_coord": true, "should": [ { "term": { "text": "jump" }}, { "term": { "text": "hop" }}, { "term": { "text": "leap" }} ] } } }
索引时权重提升
不建议在建立索引时对字段提升权重,有以下原因:
- 将提升值与字段长度归一值合在单个字节中存储会丢失字段长度归一值的精度,这样会导致 Elasticsearch 不知如何区分包含三个词的字段和包含五个词的字段。
- 要想改变索引时的提升值,就必须重新为所有文档建立索引,与此不同的是,查询时的提升值可以随着每次查询的不同而更改。
- 如果一个索引时权重提升的字段有多个值,提升值会按照每个值来自乘,这会导致该字段的权重急剧上升。
- 查询时赋予权重 是更为简单、清楚、灵活的选择。
GET /_search { "query": { "bool": { "should": [ { "match": { "title": { "query": "quick brown fox", "boost": 2 } } }, { "match": { "content": "quick brown fox" } } ] } } }
提升整个索引的权重
当在多个索引中搜索时, 可以使用参数 indices_boost 来提升整个索引的权重,在下面例子中,当要为最近索引的文档分配更高权重时,可以这么做:
GET /docs_2014_*/_search //这个多索引查询涵盖了所有以字符串 docs_2014_ 开始的索引。 { "indices_boost": { "docs_2014_10": 3, //索引 docs_2014_10 中的所有文件的权重是 3. "docs_2014_09": 2 //索引 docs_2014_09 中是 2 , 其他索引权重为默认值 1. }, "query": { "match": { "text": "quick brown fox" } } }
举例 : 查询quick OR brown OR red OR fox . 这里 Red 和 brown 是同义词,可能只需要保留其中一个,真正的需求是quick OR (brown OR red) OR fox.可以做如下修改:
GET /_search { "query": { "bool": { "should": [ { "term": { "text": "quick" }}, { "term": { "text": "brown" }}, { "term": { "text": "red" }}, { "term": { "text": "fox" }} ] } } } //修改后: GET /_search { "query": { "bool": { "should": [ { "term": { "text": "quick" }}, { "term": { "text": "fox" }}, { "bool": { "should": [ { "term": { "text": "brown" }}, { "term": { "text": "red" }} ] } } ] } } }
在互联网上搜索 “Apple”,返回的结果很可能是一个公司、水果和各种食谱。 我们可以在 bool 查询中用 must_not 语句来排除像 pie 、 tart 、 crumble 和 tree 这样的词,从而将查询结果的范围缩小至只返回与 “Apple” (苹果)公司相关的结果:
GET /_search { "query": { "bool": { "must": { "match": { "text": "apple" } }, "must_not": { "match": { "text": "pie tart fruit crumble tree" } } } } }
有时, must_not 条件会过于严格。
GET /_search { "query": { "boosting": { "positive": { "match": { "text": "apple" } }, "negative": { "match": { "text": "pie tart fruit crumble tree" } }, "negative_boost": 0.5 } } }
为了达到效果, negative_boost 的值必须小于 1.0 。在这个示例中,所有包含负向词的文档评分 _score 都会减半。