Lucene Search流程之二

本文深入探讨Lucene搜索流程,重点分析TermQuery和BooleanQuery。TermQuery通过PostingsEnum获取信息,构建Scorer进行评分,使用SkipList优化查找效率。BooleanQuery涉及Conjunction和Disjunction操作,实现布尔逻辑运算。搜索流程包括Query解析、文档匹配、评分和Collector收集目标文档。
摘要由CSDN通过智能技术生成

一、前言

上一篇文章介绍如何通过TermsDict定位Term对应的Postings的所在位置并读取,属于Query跟索引(IndexReader)交互部分,我们将它定义为搜索流程的后端。开始之前,先回顾搜索主流程,它包含如下几个步骤,其中被标记为删除的部分表示已经介绍的后端部分内容。其它的则今天要探讨的内容,也是将它们归前端的部分。

  1. 解析查询条件生成一棵逻辑语法树
  2. 提取基于Term的原子查询
  3. 通过字典信息定位Term的Postings位置
  4. 读取Posting用于文档匹配
  5. 构建评分器对文档评分
  6. 按语法树的定义执行逻辑运算
  7. 通过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定义了三种模式分别如下:

  1. TOP_SCORE,最常用的方式,即按文档得分取查询结果集的TopK
  2. COMPLETE,则需要为所有候选文档都进行评分
  3. NOT_COMPLETE,与COMPLETE相反,它表示完全不需要评分

关于评分模式,通常由collector决定的,如在大部分的facet查询的collector便是完全无须评分的。但也有由排序的条件决定,如按字段排序。NOT_COMPLETE表示

在默认情况下,即没有指定Collector和排序条件,此时IndexSearcher采用TOP_SCORE的评分模式,仅给用户返回TopK文档。显然Lucene仅需要对头部分文档进行评分即可,即跳过部分候选文档不用为之计算就可以淘汰的。

Lucene为什么可以直接淘汰跳过部分文档,而不需要为之计算评分,且最终不影响召回的结果集呢?

首先从评分角度看,哪些因素会最终影响了评分呢?下面是对Lucene官方文档给出的TFIDFSimlarity相似度评分公式展开之后得到的式子:

s c o r

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值