内容简介:Lucene打分公式的推导
lucene 介绍
lucene是一个高效的,基于 Java 的全文检索库,利用lucene可以很方便加入到现有应用中来提供全文检索的功能。比如分布式搜索引擎Elastic Search底层的搜索就是使用lucene。(全文检索是从大量的现有的文档中,搜索出与查询语句最相关的文档集的过程)
为了更高效的完成全文检索的过程,lucene使用倒排索引来完成查询词到文档查找。lucene全文检索的过程主要由创建索引和搜索索引,本文主要介绍文档相关性 排序 部分。
lucene中相关概念:
- document:lucene存储的基本单位,类似于 mysql 数据库中一条记录
- field:document中一个字段,类似于mysql数据库表中一个字段
note:本文分析的lucene版本为5.1.0
倒排索引模型
左边一列是按照一定顺序排列的经过分词处理后的Term,称为字典;每个词都指向的包含该词的文档组成链表称为倒排表。
lucene处理流程
创建索引的过程:
- 准备待索引的原文档,数据来源可能是文件、数据库或网络
- 对文档的内容进行分词组件处理,形成一系列的Term
- 索引组件对文档和Term处理,形成字典和倒排表
搜索索引的过程:
- 对查询语句进行分词处理,形成一系列Term
- 根据倒排索引表查找出包含Term的文档,并进行合并形成符合结果的文档集
- 比对查询语句与各个文档相关性得分,并按照得分高低返回
评分公式推导
空间向量模型
lucene的评分计算模型是基于VSM,即空间向量模型,但实现上稍有不同。
空间向量模型的逻辑就是将每个文档看做是由N个Term组成的向量,文档间相关性就是两个向量的在N维空间内的夹角大小,由于两个向量的之间的夹角越小,相关性就越大,所以就可以将夹角的余弦值作为相关性的得分,夹角越小,余弦值越大,相关性越大。
VSM(空间向量模型) 计算公式:
比如索引中的文档
Document Vector = {Weight1, Weight2, ..., Weight N},查询语句也可以看做是一个文档,查询文档:Query Vector = {Weight1, Weight2, ..., Weight N},Weight是某个Term的权重,N是所有文档包括查询文档在内的所有Term总数,如果文档不包含某个Term,则文档向量中Term的Weight为0。
Term的权重计算
影响一个Term在文档中权重大小的因素主要有两个:
- Term Frequency(tf):即该Term在该文档中出现的次数,tf越大说明越重要;
- Document Frequency(df):即有多少个文档包含了该Term,df越小说明越重要;
计算公式:
以上是Term weight计算的典型实现,Lucene实现于此稍有不同,使用的是tf(t ind ) * idf(t)。
lucene公式推导
我们首先计算余弦公式的分子部分,也即两个向量的点积:
在这里有三点需要指出:
- 由于是点积,则此处的 t1, t2, ..., tn 只有查询语句和文档的并集有非零值,只在查询语句出现的或只在文档中出现的 Term 的项的值为零。
- 在查询的时候,很少有人会在查询语句中输入同样的词,因而可以假设 tf(t, q)都=1
- idf 是指 Term 在多少篇文档中出现过,其中也包括查询语句这篇小文档,因而 idf(t, q)和 idf(t, d)其实是一样的,是索引中的文档总数加一,当索引中的文档总数足够大的时候,查询语句这篇小文档可以忽略,因而可以假设 idf(t, q) = idf(t, d) = idf(t)
下面推导查询语句的长度
由上面的讨论,查询语句中 tf 都为 1,idf 都忽略查询语句这篇小文档,得到如下公式:
接下来推导文档的长度
为什么在打分过程中,需要除以文档的长度呢? 因为在索引中,不同的文档长度不一样,很显然,对于任意一个 term,在长的文档中的 tf 要大的多,因而分数也越高,这样对小的文档不公平,举一个极端的例子,在一篇 1000 万 个词的鸿篇巨著中,“lucene” 这个词出现了 11 次,而在一篇 12 个词的短小文档中,“lucene” 这个词出现了 10 次,如果不考虑长度在内,当然鸿篇巨著应该分数更高,然而显然这篇小文档才是真正关注“lucene” 的。然而如果按照标准的余弦计算公式,完全消除文档长度的影响,则又对长文档不公平(毕竟它是包含更多的信息),偏向于首先返回短小的文档的,这样在实际应用中使得搜索结果 很难看。
在默认状况下,Lucene 采用 DefaultSimilarity,认为在计算文档的向量长度的时候,每个 Term 的权重就不再考虑在内了,而是全部为一。
再加上各种 boost 和 coord,则可得出 Lucene 的计算公式
lucene计算公式
coord(q,d):得分因子,score factor,一个文档中包含越多的查询Term词,则该文档的得分越高,对应lucene类 TFIDFSimilarity.coord(int overlap, int maxOverlap)
;
queryNorm(q):归一化因子,normalizing factor,使得不同查询间的得分具有可比性,但并不会影响文档的排序,对应lucene类 TFIDFSimilarity.queryNorm(float sumOfSquaredWeights)
;
tf(t in d):Term在文档d中出现的次数,对应lucene类 TFIDFSimilarity.tf(float freq)
;
idf(t):Term的逆文档频率,即一个Term在所有文档中出现的次数越多,重要性越小,对应lucene类 TFIDFSimilarity.idf(long docFreq, long numDocs)
;
norm(t,d):封装了文档字段field的权重和field内容长度因子,在index时计算,对应lucene类 TFIDFSimilarity.computeNorm(FieldInvertState state)
;
lengthNorm:field内容长度因子,field字段内容长度越短,则值越大,对应lucene类TFIDFSimilarity.lengthNorm(FieldInvertState state);
q.getBoost():查询的权重(默认值为1.0)
t.getBoost():子查询的权重(默认值为1.0)
f.getBoost():filed字段的权重(认值为1.0)
设置Query权重
BooleanQuery parentQuery=new BooleanQuery(); parentQuery.setBoost(1.0f); TermQuery termQuery=new TermQuery(new Term("search")); termQuery.setBoost(2.0f); parentQuery.add(termQuery,BooleanClause.Occur.SHOULD); termQuery=new TermQuery(new Term("掘金")); termQuery.setBoost(2.0f); parentQuery.add(termQuery,BooleanClause.Occur.SHOULD); reader=DirectoryReader.open(index_directory); IndexSearcher searcher=new IndexSearcher(reader); TopScoreDocCollector collector=TopScoreDocCollector.create(5); searcher.search(parentQuery,collector); ScoreDoc[]hits=collector.topDocs().scoreDocs;
设置Field权重
Document document = new Document(); TextField questionField = new TextField(FieldConstants.QUESTION, question, Field.Store.YES); questionField.setBoost(2.0f); TextField answerField = new TextField(FieldConstants.ANSWER, question, Field.Store.YES); answerField.setBoost(2.0f); document.add(questionField); document.add(answerField); documents.add(document);
note:从lucene4.0之后就不在支持设置document的boost,应该使用filed
以上所述就是小编给大家介绍的《Lucene打分公式的推导》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 四元数公式推导
- 线性模型篇之 SVM 数学公式推导
- 机器学习笔记(七):初识逻辑回归、两种方法推导梯度公式
- 机器学习笔记(七)——初识逻辑回归、两种方法推导梯度公式
- 比欧拉公式更美的公式!
- 完美渲染之数学公式
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。