在文章 Elasticsearch 入门学习 中介绍了 Elasticsearch 的基础概念以及一些常用的 API。这篇文章是继续对 Elasticsearch 中一些高级的搜索功能的学习和总结:
搜索的相关性以及算分机制
是什么是相关性算分?
- 相关性算分描述了一个文档和查询语句的匹配程度,ES 会对查询到的每个文档进行打分,打分的本质就是排序
- ES5 之前默认的相关性打分采用 TF-IDF 算法,TF-IDF 是信息检索领域最重要的发明,现代搜索引擎都对 TF-IDF 做了大量细微的优化
- ES6 之后开始采用 BM25 算法(对 TF-IDF 的改进),当 TF 无限增加时, BM 25 算法会使之趋于一个稳定的数值
- 在 ES 中查询加上 explain=true 可以查看当前查询是如何打分的
- 影响相关性算分的几个因子:
1. 词频-TF(Term Frequency):检索词在一篇文档中出现的频率,频率越高,权重越大
2. 文档频率-DF(Document Frequency)- 检索词出现的文档数量占总文档数量的比重,DF 越大,出现的文档数越多,说明对应用意义越小,该词的相关性也就越小,
比如 "and", "is" 这些词出现非常频繁,用户反而不关心
3. 逆向文档频率-IDF(Inverse document frequency)- 因为 DF 的值算出来结果范围会非常大,为了减少 DF 对打分的影响,引入了 IDF,其实就是对 DF 取对数来减少打分影响
4. 字段长度(Field-length)- 搜索的字段越短,相关性越高
如何人为干预相关性算分?
- 使用 boost 属性来控制 query 权重值:
//第一个 match 查询的权重值是 2,第二个默认是 1
//最终得分并不是在系统得分的基础上乘以 2,这里的权重只是重要性 2 倍的概念,最终结果会被规范化
GET /_search
{
"query": {
"bool": {
"should": [
{
"match": {
"title": {
"query": "quick brown fox",
"boost": 2
}
}
},
{
"match": {
"content": "quick brown fox"
}
}
]
}
}
}
- 使用 boost 提升索引权重值:
GET /docs_2014_*/_search
{
//分别控制 docs_2014_10,docs_2014_09 两个索引的权重值为 3, 2
"indices_boost": {
"docs_2014_10": 3,
"docs_2014_09": 2
},
"query": {
"match": {
"text": "quick brown fox"
}
}
}
- Boosting Query:将查询的 query 与人为干预影响算分权重的 query 解耦:
POST testscore/_search
{
"query": {
"boosting" : {
//指定用于查询的 query,最后返回结果必须满足 positive 对应的条件
"positive" : {
"term" : {
"content" : "elasticsearch"
}
},
//指定影响相关性算分的 query,如果查询出来的文档同时满足 negative query,那么最终得分 = positive query 得分 * negative_boost
"negative" : {
"term" : {
"content" : "like"
}
},
"negative_boost" : 0.2 (范围是 0 到 1.0)
}
}
}
- constant_score:
// 可以通过 Constant Score 将查询转换成一个 Filtering 查询,这样避免进行相关性算分,并且可以提高查询性能
// filter 可以利用缓存,此时返回的相关性算分是恒定的,都为 1.0
// Constant Score 一般用于结构化的查询
POST /products/_search
{
"explain": true,
"query": {
"constant_score": {
"filter": {
"term": {
"productID.keyword": "XHDK-A-1293-#fJ3"
}
}
}
}
}
Function Score Query
如果对我们前面介绍到的算分结果不满意,ES 还提供了 Function Score Query 在查询结束后,对每一个匹配到的文档在原先算分的基础上进行一系列算分,然后重新排序,是用来控制评分过程的终极武器。ES 提供了下面几种默认的计算分值的函数:
- Weight:和上面查询时设置 boost 权重类似,区别在于该权重不会被规范化,当某个文档的 weight 为 2 时,最终结果就是 2 * _score
- Field Value Factor:允许你使用文档中某些字段参与相关性算分,例如可以将字段“热度” 和“点赞数”作为算分的参考因素来修改 _score
POST /blogs/_search
{
"query": {
"function_score": {
"query": { // Multi Match Query
"multi_match": {
"query": "popularity",
"fields": [ "title", "content" ]
}
},
// 新的算分 = _score * log(1 + votes值 * factor)
"field_value_factor": {
"field": "votes", //字段 votes 来影响算分
//计算函数,可以是 none,log,log1p,log2p,相关请参考(https://www.elastic.co/guide/en/