文章目录
一、前言
上一篇文章介绍如何通过TermsDict定位Term对应的Postings的所在位置并读取,属于Query跟索引(IndexReader)交互部分,我们将它定义为搜索流程的后端。开始之前,先回顾搜索主流程,它包含如下几个步骤,其中被标记为删除的部分表示已经介绍的后端部分内容。其它的则今天要探讨的内容,也是将它们归前端的部分。
- 解析查询条件生成一棵逻辑语法树
- 提取基于Term的原子查询
通过字典信息定位Term的Postings位置读取Posting用于文档匹配- 构建评分器对文档评分
- 按语法树的定义执行逻辑运算
- 通过Collector收集目标文档集合
二、Query
IndexSearch在接到用户的搜索请求之后,首先解析用户查询条件生成语法树。语法树的所有叶子结点都是为这次搜索请求的原子搜索条件,如TermQuery,即需要Query与IndexReader交互,通过IndexReader获取Term对应的Postings信息。非叶子点,即非原子查询,则无须与IndexReader交互,由它的子节点提供的Postings运算所得。
TermQuery属于单Term查询,所以查询得到Posting List。但是近似查询属于多Term查询,那它将得到Posting Lists。
但如果用户提交的查询,原本就是原子查询的话,IndexSearch实际上就没有执行解析成语法树的过程。
2.1. TermQuery
原子查询是最基础、常用的查询类型。TermQuery具有一般原子查询必须经过的流程,同时它又足够简单,因而选择从TermQuery开始剖析Lucene搜索流程以及处理机制。
TermQuery按下面流程得到Postings信息,并构建成可迭代的链表(PostingsEnum),也称它为迭代器。它依然保持按DocID
从小到大有序,并且提供advance(target)
操作实现将迭代器前进到不小于target
的最小DocID
的位置且返回。advance(traget)
是非常重要的操作后续还会用到。这是上一篇博客长篇大论介绍的内容。
Lucene将Postings相关信息打包封装在PostingsEnum对象里,因此在全文中PostingsEnum与Postings可以认为同意。
此步骤在《Lucene Search流程之一》已经详细的介绍过了从Query到获得PostingsEnum的过程,同时也会把Term的相关统计信息(如TTF,TDF等)记得在环境中以便后续评分过程中如必要时可以直接使用。
a. Weight
接着IndexSearch利用Query创建一个Weight
用于计算原子查询类型中的自身权重,也在复合查询中承载着子查询间的逻辑运算。由于Query在上一个步骤获取的PostingsEnum也会交付给它,使得直接能够访问Postings,因此也有为候选文档计算相似度的条件。
实际上Weight并没有真实的计算Query的权重,Weight只是拥有访问Postings的能力,一方面创建一个与它对应的Scorer评分器,由它负责文档的评分方面功能(这部分内容后续还会介绍到)。另一方面,通过matches接口向外部提供访问Term的Postings信息功能,即指定的Term出现在哪些文档上,在其中每个文档出现次数,以及位置和每个位置附带额外信息。
Weight还提供的访问Terms在候选文档上位置信息和Payload信息的matches接口,在Explain时会用到它。当然也可以用它来实现类似
PharseQuery
的功能,虽然PharseQuery没有直接它,不过也是采用雷同的方式。
Weight在搜索流程中,主要负责依据Query的查询条件创建对应Scorer,以及提供对评分结果进行解释的explain的方法。
b. Scorer
Scorer是Lucene在搜索流程用于计算Query与文档相似度计算的外围组件,它实际上并不负责文档得分的计算,这部分工作是委托给Similarity去做的。Similarity才是真正的评分器,而Scorer只是负责评分外围的工作。比如它为文档评分提供必须参数,决定文档是否需要评分,哪部分文档进行评分,哪些文档不用评分。也就说它决定了读取Postings信息的种类和模式,是否启用跳表优化等。
Query与文档的相似度代表文档在这次查询的得分,得分越高,相似度越高。博文出现文档得分与相似度属于相同意思。
虽然Scorer不负责文档得分的计算,但它却是能够给出文档最终得分的组件。关于真正得分计算是Similarity插件完成,Lucene实现了两种常用的计算模型,空间向量模型和BM25概率模型。这两种模型都依赖于TF-IDF
,它是一种统计方法,可以粗略的将二者关系理解为:TF-IDF
用于计算权重,两模型通过权重计算相似度。
Lucene6.0
之前的版本中,Lucene默认使用空间向量模型实现作为评分器,之后改用BM25概率模型作为默认实现。
TF-IDF
用于计算查询词Term
文档或者Query的权重,那么文档与Query的相似度如何用这两种权重来表示呢?以空间向量模型为例,Query中的Term系列
,可以计算得每个Term的文档权重,得到文档权重系列,它也是文档权重的向量。同样的方式也可以得到Query权重的向量,那么Query与文档的最终相似度便可以表示为两向量的距离。
I. Score_Mode
至于如何决定文档是否需要评分,Lucene定义了三种模式分别如下:
- TOP_SCORE,最常用的方式,即按文档得分取查询结果集的TopK
- COMPLETE,则需要为所有候选文档都进行评分
- NOT_COMPLETE,与COMPLETE相反,它表示完全不需要评分
关于评分模式,通常由collector决定的,如在大部分的facet查询的collector便是完全无须评分的。但也有由排序的条件决定,如按字段排序。NOT_COMPLETE表示
在默认情况下,即没有指定Collector和排序条件,此时IndexSearcher采用TOP_SCORE的评分模式,仅给用户返回TopK文档。显然Lucene仅需要对头部分文档进行评分即可,即跳过部分候选文档不用为之计算就可以淘汰的。
Lucene为什么可以直接淘汰跳过部分文档,而不需要为之计算评分,且最终不影响召回的结果集呢?
首先从评分角度看,哪些因素会最终影响了评分呢?下面是对Lucene官方文档给出的TFIDFSimlarity相似度评分公式展开之后得到的式子:
s c o r