Lucene的IndexSearcher提供一个explain方法,能够解释Document的Score是怎么得来的,具体每一部分的得分都可以详细地打印出来。这里用一个中文实例来纯手工验算一遍Lucene的评分算法,并且结合Lucene的源码做一个解释。

首先是测试用例,我使用“北京东路”来检索一个含有address域的文档。

然后是是输出,注意它有缩进,代表一个个的层级,下面以测试环境数据作为举例:

{
"value" : 0.7271681,
"description" : "max of:",
"details" : [ {
"value" : 0.7271681,
"description" : "sum of:",
"details" : [ {
"value" : 0.43069553,
"description" : "weight(address:北京 in 787) [PerFieldSimilarity], result of:",
"details" : [ {
"value" : 0.43069553,
"description" : "score(doc=787,freq=1.0), product of:",
"details" : [ {
"value" : 0.34374008,
"description" : "queryWeight, product of:",
"details" : [ {
"value" : 5.0118747,
"description" : "idf(docFreq=2104, maxDocs=116302)"
}, {
"value" : 0.06858513,
"description" : "queryNorm"
} ]
}, {
"value" : 1.2529687,
"description" : "fieldWeight in 787, product of:",
"details" : [ {
"value" : 1.0,
"description" : "tf(freq=1.0), with freq of:",
"details" : [ {
"value" : 1.0,
"description" : "termFreq=1.0"
} ]
}, {
"value" : 5.0118747,
"description" : "idf(docFreq=2104, maxDocs=116302)"
}, {
"value" : 0.25,
"description" : "fieldNorm(doc=787)"
} ]
} ]
} ]
}, {
"value" : 0.29647252,
"description" : "weight(address:东路 in 787) [PerFieldSimilarity], result of:",
"details" : [ {
"value" : 0.29647252,
"description" : "score(doc=787,freq=1.0), product of:",
"details" : [ {
"value" : 0.2851919,
"description" : "queryWeight, product of:",
"details" : [ {
"value" : 4.158218,
"description" : "idf(docFreq=4942, maxDocs=116302)"
}, {
"value" : 0.06858513,
"description" : "queryNorm"
} ]
}, {
"value" : 1.0395545,
"description" : "fieldWeight in 787, product of:",
"details" : [ {
"value" : 1.0,
"description" : "tf(freq=1.0), with freq of:",
"details" : [ {
"value" : 1.0,
"description" : "termFreq=1.0"
} ]
}, {
"value" : 4.158218,
"description" : "idf(docFreq=4942, maxDocs=116302)"
}, {
"value" : 0.25,
"description" : "fieldNorm(doc=787)"
} ]
} ]
} ]
} ]
} ]
}

这个看起来可真是头疼,尝试解释一下:

首先,需要学习Lucene的评分计算公式——

分值计算方式为查询语句q中每个项t与文档d的匹配分值之和,当然还有权重的因素。其中每一项的意思如下表所示:

表3.5

评分公式中的因子

评分因子

描 述

tf(t in d)

项频率因子——文档(d)中出现项(t)的频率

idf(t)

项在倒排文档中出现的频率:它被用来衡量项的“唯一”性.出现频率较高的term具有较低的idf,出现较少的term具有较高的idf

boost(t.field in d)

域和文档的加权,在索引期间设置.你可以用该方法 对某个域或文档进行静态单独加权

lengthNorm(t.field in d)

域的归一化(Normalization)值,表示域中包含的项数量.该值在索引期间计算,并保存在索引norm中.对于该因子,更短的域(或更少的语汇单元)能获得更大的加权

coord(q,d)

协调因子(Coordination factor),基于文档中包含查询的项个数.该因子会对包含更多搜索项的文档进行类似AND的加权

queryNorm(q)

每个査询的归一化值,指毎个查询项权重的平方和

总匹配分值的计算

具体到上面的测试来讲,地址字段address匹配了二个词条,先分别计算每个词条对应的分值,然后相加,最后结果= ("北京") 0.43069553+ (“东路”)0.29647252=0.7271681 (结果舍入)。

查询语句在某个field匹配分值计算

这个0.43069553是如何来的呢?这是词条“北京”在field中的分值=查询权重queryWeight * 域权重fieldWeight  即   0.34374008*1.2529687=0.43069553。

同埋“东路”这个词条在field中的分值=查询权重queryWeight * 域权重fieldWeight  即   0.2851919*1.0395545=0.29647252

queryWeight的计算

queryWeight的计算可以在TermQuery$TermWeight.normalize(float)方法中看到计算的实现:

public void normalize(float queryNorm) {

              this.queryNorm = queryNorm;

             //原来queryWeight 为idf*t.getBoost(),现在为queryNorm*idf*t.getBoost()。

            queryWeight *= queryNorm;

            value = queryWeight * idf;

}

其实默认情况下,queryWeight = idf * queryNorm,因为Lucene中默认的boost = 1.0。

以“北京”这个词条为例,查询权重queryWeight = idf * queryNorm,即 0.34374008 = 5.0118747*0.06858513。

idf的计算

idf是项在倒排文档中出现的频率,计算方式为

/** Implemented as <code>log(numDocs/(docFreq+1)) + 1</code>. */

@Overrid

public float idf(long docFreq, long numDocs) {

return (float)(Math.log(numDocs/(double)(docFreq+1)) + 1.0);

docFreq是根据指定关键字进行检索,检索到的Document的数量,我们测试“北京”词条的docFreq=2104;

numDocs是指索引文件中总共的Document的数量,对应explain结果中的maxDocs,我们测试的maxDocs=116302。

用计算器验证一下,没有错误,这里就不啰嗦了。

fieldWeight的计算

fieldWeight = tf * idf * fieldNorm

tf和idf的计算参考前面的,fieldNorm的计算在索引的时候确定了,此时直接从索引文件中读取,这个方法并没有给出直接的计算。

如果使用DefaultSimilarity的话,它实际上就是lengthNorm,域越长的话Norm越小,在org/apache/lucene/search/similarities/DefaultSimilarity.java里面有关于它的计算:

public float lengthNorm(FieldInvertState state) {

final int numTerms;

if (discountOverlaps)

numTerms = state.getLength() - state.getNumOverlap();

else

numTerms = state.getLength();

return state.getBoost() * ((float) (1.0 / Math.sqrt(numTerms)));

}

这个我就不再验算了,每个域的Terms数量开方求倒数乘以该域的boost得出最终的结果。

Elasticsearch搜索之explain评分分析的更多相关文章

  1. ElasticSearch评分分析 explian 解释和一些查询理解

    ElasticSearch评分分析 explian 解释和一些查询理解 按照es-ik分析器安装了ik分词器.创建索引:PUT /index_ik_test.索引包含2个字段:content和nick ...

  2. Elasticsearch系列---常见搜索方式与聚合分析

    概要 本篇主要介绍常见的6种搜索方式.聚合分析语法,基本是上机实战,可以和关系型数据库作对比,如果之前了解关系型数据库,那本篇只需要了解搜索和聚合的语法规则就可以了. 搜索响应报文 以上篇建立的mus ...

  3. wukong引擎源码分析之索引——part 3 文档评分 无非就是将docid对应的fields信息存储起来,为搜索结果rank评分用

    之前的文章分析过,接受索引请求处理的代码在segmenter_worker.go里: func (engine *Engine) segmenterWorker() { for { request : ...

  4. 看完这篇还不会 Elasticsearch 搜索,那我就哭了!

    本文主要介绍 ElasticSearch 搜索相关的知识,首先会介绍下 URI Search 和 Request Body Search,同时也会学习什么是搜索的相关性,如何衡量相关性. Search ...

  5. ElasticSearch搜索介绍四

    ElasticSearch搜索 最基础的搜索: curl -XGET http://localhost:9200/_search 返回的结果为: { "took": 2, &quo ...

  6. Elasticsearch搜索资料汇总

    Elasticsearch 简介 Elasticsearch(ES)是一个基于Lucene 构建的开源分布式搜索分析引擎,可以近实时的索引.检索数据.具备高可靠.易使用.社区活跃等特点,在全文检索.日 ...

  7. 一次 ElasticSearch 搜索优化

    一次 ElasticSearch 搜索优化 1. 环境 ES6.3.2,索引名称 user_v1,5个主分片,每个分片一个副本.分片基本都在11GB左右,GET _cat/shards/user 一共 ...

  8. Elasticsearch搜索结果返回不一致问题

    一.背景 这周在使用Elasticsearch搜索的时候遇到一个,对于同一个搜索请求,会出现top50返回结果和排序不一致的问题.那么为什么会出现这样的问题? 后来通过百度和google,发现这是因为 ...

  9. ElasticStack学习(六):ElasticSearch搜索初探

    一.ElasticSearch搜索介绍 1.ElasticSearch搜索方式主要分为以下两种: 1).URI Search:此种查询主要是使用Http的Get方法,在URL中使用查询参数进行查询: ...

随机推荐

  1. ERP小型集团化——运行集团配置向导

    概述 集团配置向导作用为修改集团配置相关的dll文件信息,并按照集团同步设置里的记录对相应的表做数据同步. 一般在集团辅助资料.集团同步设置.子公司自定义业务里的任何记录的新增.编辑.关闭,都需要执行 ...

  2. Spring框架(3)---IOC装配Bean(注解方式)

    IOC装配Bean(注解方式) 上面一遍文章讲了通过xml来装配Bean,那么这篇来讲注解方式来讲装配Bean对象 注解方式需要在原先的基础上重新配置环境: (1)Component标签举例 1:导入 ...

  3. (五)CSS和JavaScript基础

    DHTML :制作动态HTML页面的技术 DHTML=HTML+层叠样式表CSS+脚本语言javascript 一.CSS 1.1 CSS样式的分类: 行内样式:只影响一行,其他相同标签也不影响.如下 ...

  4. wemall app商城源码android开发MD5加密工具类

    wemall-mobile是基于WeMall的android app商城,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可定制修改.本文分享android开发MD5加密工具类主要代码,供 ...

  5. KoaHub平台基于Node.js开发的Koa EJS渲染插件代码信息详情

    koa-ejs ejs render middleware for koa koa-ejs Koa ejs view render middleware. support all feature of ...

  6. HttpURLConnection实现两个服务端的对接

    在企业开发中,很多时候需要用到两个服务端的对接,在java类中进行连接并传递参数,其中的HttpURLConnection是一种轻量化,并且简单的方法! package httptest; impor ...

  7. ubuntu14.04下安装有道词典

    1.打开官方下载链接:http://cidian.youdao.com/index-linux.html 2.下载相应版本的安装包 3.直接双击安装包进行安装 可能会存在软件打不开的情况,更新下系统, ...

  8. ZJOI2017 Day3 滚粗记

    私のZJOI Day3 2017-3-21 07:52:53 今天,考了人生当中的第一次省选(虽然只是普及组三等奖但仍然有幸能体会一下).据胡老师说,这就是来体验一下被大神虐--真的是这样,听课听不懂 ...

  9. webstorm入手笔记

    一.webstorm学习前小记 webstorm是一款现在前端用的比较多的IDE,其优势也比较多,这个大家在网上随便搜搜就可以找到了.但是本人大部分的时间都是使用sublime text工作,最近由于 ...

  10. MVC学习笔记2 - Razor语法

    Razor 同时支持 C# (C sharp) 和 VB (Visual Basic). C# 的主要 Razor 语法规则 Razor 代码封装于 @{ ... } 中 行内表达式(变量和函数)以 ...