ElasticSearch 之 _score

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: ElasticSearch 之 _score

1. 什么是_score

搜索排序是搜索引擎的核心工作之一,搜索排序的好坏影响着搜索质量的好坏。诸如ES、Solr等开源的搜索引擎,它们在默认情况下使用的都是相关性排序。

那么什么是相关性呢?相关性指的是搜索结果和查询条件的相关程度,它是搜索质量的重要指标之一。

就ES来说,搜索结果中的每个结果都有一个_score字段,ES默认按照相关性算法计算每个命中的文档的_score字段值,命中的文档按照该字段的值进行降序排列。

Lucene(或 Elasticsearch)使用布尔模型(Boolean model)查找匹配文档,并用一个名为实用评分函数(practical scoring function)的公式来计算相关度。这个公式借鉴了词频/逆向文档频率(term frequency/inverse document frequency)和向量空间模型(vector space model),同时也加入了一些现代的新特性,如协调因子(coordination factor),字段长度归一化(field length normalization),以及词或查询语句权重提升。


2. 布尔模型

  1. 布尔模型(Boolean Model)只是在查询中使用 ANDORNOT (与、或和非)这样的条件来查找匹配的文档,以下查询:
full AND text AND search AND (elasticsearch OR lucene)

  1. 会将所有包括词 fulltextsearch ,以及 elasticsearchlucene 的文档作为结果集。
  2. 这个过程简单且快速,它将所有可能不匹配的文档排除在外。

3. 词频/逆向文档频率(TF/IDF

当匹配到一组文档后,需要根据相关度排序这些文档,不是所有的文档都包含所有词,有些词比其他的词更重要。一个文档的相关度评分部分取决于每个查询词在文档中的权重,由以下三个因素决定。

3.1. 词频

  1. t 在文档 d 的词频( tf )为:该词在文档中出现次数的平方根。
tf(t in d) = √frequency
  1. 如果不在意词在某个字段中出现的频次,而只在意是否出现过,则可以在字段映射中禁用词频统计:
PUT /my_index
{
 "mappings": {
   "doc": {
     "properties": {
       "text": {
         "type": "string",
         "index_options": "docs" 
       }
     }
   }
 }
}
  1. 将参数 index_options 设置为 docs 可以禁用词频统计及词频位置,这个映射的字段不会计算词的出现次数,对于短语或近似查询也不可用。要求精确查询的 not_analyzed 字符串字段会默认使用该设置。


3.2. 逆向文档频率

  1. t 的逆向文档频率( idf )是:索引中文档数量除以所有包含该词的文档数,然后求其对数。
idf(t) = 1 + log ( numDocs / (docFreq + 1)) 


  1. 一个词在文档中出现的频次越高,逆向文档频率就越低。常用词如 andthe 对相关度贡献很少,因为它们在多数文档中都会出现,一些不常见词如 elastichippopotamus 可以帮助我们快速缩小范围找到感兴趣的文档。

3.3. 字段长度归一值

  1. 字段长度归一值( norm )是字段中词数平方根的倒数。
norm(d) = 1 / √numTerms
  1. 字段越短,字段长度归一值就越高。如果词出现在类似标题 title 这样的字段,要比它出现在内容 body 这样的字段中的相关度更高。
  2. 字段长度的归一值对全文搜索非常重要,许多其他字段不需要有归一值。
  3. 无论文档是否包括这个字段,索引中每个文档的每个 string 字段都大约占用 1 个 byte 的空间。对于 not_analyzed 字符串字段的归一值默认是禁用的,而对于 analyzed 字段也可以通过修改字段映射禁用归一值:
PUT /my_index
{
 "mappings": {
   "doc": {
     "properties": {
       "text": {
         "type": "string",
         "norms": { "enabled": false } 
       }
     }
   }
 }
}
  1. "enabled": false使得这个字段不会将字段长度归一值考虑在内,长字段和短字段会以相同长度计算评分。
  2. 对于有些应用场景如日志,归一值不是很有用,要关心的只是字段是否包含特殊的错误码或者特定的浏览器唯一标识符。字段的长度对结果没有影响,禁用归一值可以节省大量内存空间。


3.4. 结合使用

  1. 以下三个因素——词频(term frequency)、逆向文档频率(inverse document frequency)和字段长度归一值(field-length norm)——是在索引时计算并存储的。最后将它们结合在一起计算单个词在特定文档中的权重。
  2. 前面公式中提到的 文档 实际上是指文档里的某个字段,每个字段都有它自己的倒排索引,因此字段的 TF/IDF 值就是文档的 TF/IDF 值。
  3. 当用 explain 查看一个简单的 term 查询时(参见 explain ),可以发现与计算相关度评分的因子就是前面章节介绍的这些:
PUT /my_index/doc/1
{ "text" : "quick brown fox" }
GET /my_index/doc/_search?explain
{
 "query": {
   "term": {
     "text": "fox"
   }
 }
}

  1. 以上请求(简化)的 explanation 解释如下:
weight(text:fox in 0) [PerFieldSimilarity]:  0.15342641 
result of:
   fieldWeight in 0                         0.15342641
   product of:
       tf(freq=1.0), with freq of 1:        1.0 
       idf(docFreq=1, maxDocs=1):           0.30685282 
       fieldNorm(doc=0):                    0.5 

  1. 词 fox 在文档的内部 Lucene doc ID 为 0 ,字段是 text 里的最终评分为0.15342641。
  2. 词 fox 在该文档 text 字段中只出现了1.0次。
  3. fox 在所有文档 text 字段索引的逆向文档频率为0.30685282。
  4. 该字段的字段长度归一值为0.5。

5.当然,查询通常不止一个词,所以需要一种合并多词权重的方式——向量空间模型(vector space model)。

4. 向量空间模型

  1. 向量空间模型(vector space model)提供一种比较多词查询的方式,单个评分代表文档与查询的匹配程度,为了做到这点,这个模型将文档和查询都以向量(vectors)的形式表示:向量实际上就是包含多个数的一维数组,例如:
[1,2,5,22,3,8]
  1. 在向量空间模型里,向量空间模型里的每个数字都代表一个词的 权重 ,与词频/逆向文档频率(term frequency/inverse document frequency) 计算方式类似。
  2. 尽管 TF/IDF 是向量空间模型计算词权重的默认方式,但不是唯一方式。Elasticsearch 还有其他模型如 Okapi-BM25 。TF/IDF 是默认的因为它是个经检验过的简单又高效的算法,可以提供高质量的搜索结果。
  3. 设想如果查询 “happy hippopotamus” ,常见词 happy 的权重较低,不常见词 hippopotamus 权重较高,假设 happy 的权重是 2, hippopotamus 的权重是 5 ,可以将这个二维向量—— [2,5] ——在坐标系下作条直线,线的起点是 (0,0) 终点是 (2,5) ,如图:



  1. 现在,设想我们有三个文档:
  1. I am happy in summer 。
  2. After Christmas I’m a hippopotamus
  3. The happy hippopotamus helped Harry 。


6.可以为每个文档都创建包括每个查询词—— happy 和 hippopotamus ——权重的向量,然后将这些向量置入同一个坐标系中,如图:

  • 文档 1: (happy,____________) —— [2,0]
  • 文档 2: ( ___ ,hippopotamus) —— [0,5]
  • 文档 3: (happy,hippopotamus) —— [2,5]

7.向量之间是可以比较的,只要测量查询向量和文档向量之间的角度就可以得到每个文档的相关度,文档 1 与查询之间的角度最大,所以相关度低;文档 2 与查询间的角度较小,所以更相关;文档 3 与查询的角度正好吻合,完全匹配。

8.在实际中,只有二维向量(两个词的查询)可以在平面上表示,幸运的是, 线性代数——作为数学中处理向量的一个分支——为我们提供了计算两个多维向量间角度工具,这意味着可以使用如上同样的方式来解释多个词的查询。

9.关于比较两个向量的更多信息可以参考 余弦近似度(cosine similarity)。


5. Lucene的实用评分函数

  1. 对于多词查询, Lucene 使用布尔模型(Boolean model)、TF/IDF 以及向量空间模型(vector space model),然后将它们组合到单个高效的包里以收集匹配文档并进行评分计算。
  2. 一个多词查询
GET /my_index/doc/_search
{
 "query": {
   "match": {
     "text": "quick fox"
   }
 }
}

会在内部被重写为:

GET /my_index/doc/_search
{
 "query": {
   "bool": {
     "should": [
       {"term": { "text": "quick" }},
       {"term": { "text": "fox"   }}
     ]
   }
 }
}

3.bool 查询实现了布尔模型,在这个例子中,它会将包括词 quick 和 fox 或两者兼有的文档作为查询结果。

4.只要一个文档与查询匹配,Lucene 就会为查询计算评分,然后合并每个匹配词的评分结果。这里使用的评分计算公式叫做实用评分函数(practical scoring function)。

score(q,d)  =  //文档 d 与查询 q 的相关度评分
           queryNorm(q)  //查询归一化因子
         · coord(q,d)    //协调因子
         · ∑ (           //查询 q 中每个词 t 对于文档 d 的权重和。
               tf(t in d)   //词 t 在文档 d 中的词频 
             · idf(t)²      //词 t 的逆向文档频率 
             · t.getBoost() //查询中使用的 boost
             · norm(t,d)    //字段长度归一值,与索引时字段层 boost (如果存在)的和
           ) (t in q)    

5.1. 查询归一因子

  1. 查询归一因子( queryNorm )试图将查询归一化,这样就能将两个不同的查询结果相比较。
  2. 尽管查询归一值的目的是为了使查询结果之间能够相互比较,但是它并不十分有效,因为相关度评分 _score 的目的是为了将当前查询的结果进行排序,比较不同查询结果的相关度评分没有太大意义。
  3. 这个因子是在查询过程的最前面计算的,具体的计算依赖于具体查询,一个典型的实现如下:
queryNorm = 1 / √sumOfSquaredWeights

  1. sumOfSquaredWeights 是查询里每个词的 IDF 的平方和。
  2. 相同查询归一化因子会被应用到每个文档,不能被更改,总而言之,可以被忽略。


5.2. 协调因子

1.协调因子( coord )可以为那些查询词包含度高的文档提供奖励,文档里出现的查询词越多,它越有机会成为好的匹配结果。

2.设想查询 quick brown fox ,每个词的权重都是 1.5 。如果没有协调因子,最终评分会是文档里所有词权重的总和。例如:

文档里有 fox → 评分: 1.5

文档里有 quick fox → 评分: 3.0

文档里有 quick brown fox → 评分: 4.5

3.协调因子将评分与文档里匹配词的数量相乘,然后除以查询里所有词的数量,如果使用协调因子,评分会变成:

文档里有 fox → 评分: 1.5 * 1 / 3 = 0.5

文档里有 quick fox → 评分: 3.0 * 2 / 3 = 2.0

文档里有 quick brown fox → 评分: 4.5 * 3 / 3 = 4.5

4.协调因子能使包含所有三个词的文档比只包含两个词的文档评分要高出很多。

5.回想将查询 quick brown fox 重写成 bool 查询的形式:

GET /_search
{
 "query": {
   "bool": {
     "should": [
       { "term": { "text": "quick" }},
       { "term": { "text": "brown" }},
       { "term": { "text": "fox"   }}
     ]
   }
 }
}


6.bool 查询默认会对所有 should 语句使用协调功能,不过也可以将其禁用。为什么要这样做?通常的回答是——无须这样。查询协调通常是件好事,当使用 bool 查询将多个高级查询如 match 查询包裹的时候,让协调功能开启是有意义的,匹配的语句越多,查询请求与返回文档间的重叠度就越高。

7.但在某些高级应用中,将协调功能关闭可能更好。设想正在查找同义词 jump 、 leap 和 hop 时,并不关心会出现多少个同义词,因为它们都表示相同的意思,实际上,只有其中一个同义词会出现,这是不使用协调因子的一个好例子:

GET /_search
{
"query": {
  "bool": {
    "disable_coord": true,
    "should": [
      { "term": { "text": "jump" }},
      { "term": { "text": "hop"  }},
      { "term": { "text": "leap" }}
    ]
  }
}
}
  1. 当使用同义词的时候(参照: 同义词 ),Lucene 内部是这样的:重写的查询会禁用同义词的协调功能。大多数禁用操作的应用场景是自动处理的,无须为此担心。

6. 官方文档

更多详细资料,请参考官方文档:Elasticsearch: 权威指南


相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
目录
相关文章
|
索引
带你读《Elastic Stack 实战手册》之74:——4.1.6.优化Elasticsearch中的打分(_score)(上)
带你读《Elastic Stack 实战手册》之74:——4.1.6.优化Elasticsearch中的打分(_score)(上)
117 0
|
算法 搜索推荐 API
带你读《Elastic Stack 实战手册》之74:——4.1.6.优化Elasticsearch中的打分(_score)(中)
带你读《Elastic Stack 实战手册》之74:——4.1.6.优化Elasticsearch中的打分(_score)(中)
174 0
|
缓存 算法 UED
带你读《Elastic Stack 实战手册》之74:——4.1.6.优化Elasticsearch中的打分(_score)(下)
带你读《Elastic Stack 实战手册》之74:——4.1.6.优化Elasticsearch中的打分(_score)(下)
112 0
elasticsearch的score相关资料(整理)
核心概念理解:elastcsearch整个过程包括匹配+打分,其中匹配根据查询条件进行查询,打分根据查询回来的字段进行打分。 通过Function Score Query优化Elasticsearch搜索结果:http://blog.
1239 0
|
搜索推荐 Java API
Spring Boot 整合 Elasticsearch,实现 function score query 权重分查询
运行环境:JDK 7 或 8,Maven 3.0+技术栈:SpringBoot 1.5+,ElasticSearch 2.3.2 本文提纲一、ES 的使用场景二、运行 springboot-elasticsearch 工程三、springboot-elasticsearch 工程代码详解 一、ES 的使用场景 简单说,ElasticSearch(简称 ES)是搜索引擎,是结构化数据的分布式搜索引擎。
3387 0
|
搜索推荐 Java API
Spring Boot 整合 Elasticsearch,实现 function score query 权重分查询
摘要: 原创出处 www.bysocket.com 「泥瓦匠BYSocket 」欢迎转载,保留摘要,谢谢! 『 预见未来最好的方式就是亲手创造未来 - 《史蒂夫·乔布斯传》 』 运行环境:JDK 7 或 8,Maven 3.
8080 0
|
1月前
|
存储 安全 数据管理
如何在 Rocky Linux 8 上安装和配置 Elasticsearch
本文详细介绍了在 Rocky Linux 8 上安装和配置 Elasticsearch 的步骤,包括添加仓库、安装 Elasticsearch、配置文件修改、设置内存和文件描述符、启动和验证 Elasticsearch,以及常见问题的解决方法。通过这些步骤,你可以快速搭建起这个强大的分布式搜索和分析引擎。
41 5
|
2月前
|
存储 JSON Java
elasticsearch学习一:了解 ES,版本之间的对应。安装elasticsearch,kibana,head插件、elasticsearch-ik分词器。
这篇文章是关于Elasticsearch的学习指南,包括了解Elasticsearch、版本对应、安装运行Elasticsearch和Kibana、安装head插件和elasticsearch-ik分词器的步骤。
208 0
elasticsearch学习一:了解 ES,版本之间的对应。安装elasticsearch,kibana,head插件、elasticsearch-ik分词器。
|
3月前
|
NoSQL 关系型数据库 Redis
mall在linux环境下的部署(基于Docker容器),Docker安装mysql、redis、nginx、rabbitmq、elasticsearch、logstash、kibana、mongo
mall在linux环境下的部署(基于Docker容器),docker安装mysql、redis、nginx、rabbitmq、elasticsearch、logstash、kibana、mongodb、minio详细教程,拉取镜像、运行容器
mall在linux环境下的部署(基于Docker容器),Docker安装mysql、redis、nginx、rabbitmq、elasticsearch、logstash、kibana、mongo
|
4月前
|
数据可视化 Docker 容器
一文教会你如何通过Docker安装elasticsearch和kibana 【详细过程+图解】
这篇文章提供了通过Docker安装Elasticsearch和Kibana的详细过程和图解,包括下载镜像、创建和启动容器、处理可能遇到的启动失败情况(如权限不足和配置文件错误)、测试Elasticsearch和Kibana的连接,以及解决空间不足的问题。文章还特别指出了配置文件中空格的重要性以及环境变量中字母大小写的问题。
一文教会你如何通过Docker安装elasticsearch和kibana 【详细过程+图解】