相关性介绍

搜索的相关性算分,描述了一个文档和查询语句匹配的程度。ES 会对每个匹配查询条件的结果进行算分_score。打分的本质是排序,需要把最符合用户需求的文档排在前面。

如下例子:显而易见,查询JAVA多线程设计模式,文档id为2,3的文档的算分更高

如何衡量相关性:

  • Precision(查准率)―尽可能返回较少的无关文档
  • Recall(查全率)–尽量返回较多的相关文档
  • Ranking -是否能够按照相关度进行排序

相关性算法

在 es5 之前默认的相关性算分采用TF-IDF,现在采用BM 25。

TF-IDF

TF-IDF(term frequency–inverse document frequency)是一种用于信息检索与数据挖掘的常用加权技术。

  • TF-IDF被公认为是信息检索领域最重要的发明,除了在信息检索,在文献分类和其他相关领域有着非常广泛的应用。
  • IDF的概念,最早是剑桥大学的“斯巴克.琼斯”提出
    • 1972年——“关键词特殊性的统计解释和它在文献检索中的应用”,但是没有从理论上解释IDF应该是用log(全部文档数/检索词出现过的文档总数),而不是其他函数,也没有做进一步的研究
    • 1970,1980年代萨尔顿和罗宾逊,进行了进一步的证明和研究,并用香农信息论做了证明http://www.staff.city.ac.uk/~sb317/papers/foundations_bm25_review.pdf
  • 现代搜索引擎,对TF-IDF进行了大量细微的优化

Lucene中的TF-IDF评分公式:

ES 相关性详解-LMLPHP

  • TF是词频(Term Frequency)

检索词在文档中出现的频率越高,相关性也越高。

词频(TF) = 某个词在文档中出现的次数 / 文档的总词数

  • IDF是逆向文本频率(Inverse Document Frequency)

每个检索词在索引中出现的频率,频率越高,相关性越低。总文档中有些词比如“是”、“的” 、“在” 在所有文档中出现频率都很高,并不重要,可以减少多个文档中都频繁出现的词的权重。

逆向文本频率(IDF)= log (语料库的文档总数 / (包含该词的文档数+1))

  • 字段长度归一值( field-length norm)

检索词出现在一个内容短的 title 要比同样的词出现在一个内容长的 content 字段权重更大。

以上三个因素——词频(term frequency)、逆向文本频率(inverse document frequency)和字段长度归一值(field-length norm)——是在索引时计算并存储的,最后将它们结合在一起计算单个词在特定文档中的权重。

BM25

BM25 就是对 TF-IDF 算法的改进,对于 TF-IDF 算法,TF(t) 部分的值越大,整个公式返回的值就会越大。BM25 就针对这点进行来优化,随着TF(t) 的逐步加大,该算法的返回值会趋于一个数值。

  • 从ES 5开始,默认算法改为BM 25
  • 和经典的TF-IDF相比,当TF无限增加时,BM 25算分会趋于一个数值

ES 相关性详解-LMLPHP

  • BM 25的公式

ES 相关性详解-LMLPHP

通过Explain API查看TF-IDF

示例:

ES 相关性详解-LMLPHP

PUT /test_score/_bulk
{"index":{"_id":1}}
{"content":"we use Elasticsearch to power the search"}
{"index":{"_id":2}}
{"content":"we like elasticsearch"}
{"index":{"_id":3}}
{"content":"Thre scoring of documents is caculated by the scoring formula"}
{"index":{"_id":4}}
{"content":"you know,for search"}

GET /test_score/_search
{
  "explain": true, 
  "query": {
    "match": {
      "content": "elasticsearch"
    }
  }
}

GET /test_score/_explain/2
{
  "query": {
    "match": {
      "content": "elasticsearch"
    }
  }
}

Boosting Query

Boosting是控制相关度的一种手段。可以通过指定字段的boost值影响查询结果

参数boost的含义:

  • 当boost > 1时,打分的权重相对性提升
  • 当0 < boost
  • 当boost

应用场景:希望包含了某项内容的结果不是不出现,而是排序靠后。

下面示例可以看到,设置 content 的权重高一些,查询的结果根据 content 匹配度高一些

ES 相关性详解-LMLPHP

#批量插入数据
POST /blogs/_bulk
{"index": {"_id": 1}}
{"title":"Apple iPad", "content": "Apple iPad,Apple iPad"}
{"index": {"_id": 2}}
{"title": "Apple iPad,Apple iPad", "content": "Apple iPad"}
#使用 boost 控制权重
GET /blogs/_search
{
  "query": {
    "bool": {
      "should": [
        {"match": {
          "title": {
            "query": "apple,ipad",
            "boost": 4
          }
        }},
        {
          "match": {
            "content": {
              "query": "apple,ipad",
              "boost": 1
            }
          }
        }
      ]
    }
  }
}

案例:要求苹果公司的产品信息优先展示

示例数据

#批量插入数据
POST /news/_bulk
{"ineex": {"_id": 1}}
{"content": "Apple Mac"}
{"index": {"_id": 2}}
{"content": "Apple Phone"}
{"index": {"_id": 3}}
{"content": "Apple employee like Apple Pie and Apple Juice"}

普通查询都是 id 为 3 的数据排名靠前,但是我希望另外两个 排名靠前

ES 相关性详解-LMLPHP

方式一:

使用 must not 排除不是苹果公司产品的文档

下面示例,可以看到排除了第三条数据。

ES 相关性详解-LMLPHP

GET /news/_search
{
  "query": {
    "bool": {
      "must": [
        {"match": {
          "content": "apple"
        }}
      ],
      "must_not": [
        {"match": {
          "content": "pie"
        }}
      ]
    }
  }
}

方式二

方式一这种方式是直接排除了,我希望的是不排除,只是排名靠后。

可以利用negative_boost降低相关性

对某些返回结果不满意,但又不想排除掉( must_not),可以考虑boosting query的negative_boost。

  • negative_boost 对 negative部分query生效
  • 计算评分时,boosting部分评分不修改,negative部分query乘以negative_boost值
  • negative_boost取值:0-1.0,举例:0.3

可以看到,此时再次查询,第三条数据算分就比较低了,满足我们的需求

ES 相关性详解-LMLPHP

GET /news/_search
{
  "query": {
    "boosting": {
      "positive": {
        "match": {
          "content": "apple"
        }
      },
      "negative": {
        "match": {
          "content": "pie"
        }
      },
      "negative_boost": 0.2
    }
  }
}

感谢观看!!!感兴趣的小伙伴可以关注收藏,持续更新中~~~

03-15 20:39