Lucene的搜索过程:
- IndexReader 打开索引文件,读取并打开指向索引文件的流。
- 用户输入查询语句。
- 将查询语句转换为查询对象Query对象树。
- 构造Weight对象树,用于计算词的权重(仅计算搜索语句相关的部分)。
- 构造Scorer对象树,用于计算打分。
- 在构造Scorer对象树的过程中,其叶子节点的 TermScorer 会将词典和倒排表从索引中读出来。
- 构造 SumScorer 对象树,为了方便合并倒排表对Scorer对象树的重新组织,得到结果文档集。
- 将收集的结果集合打分返回给用户。
IndexReader
|
|
- 段元数据信息已经被读入到内存中。
因而索引文件夹中因为新添加文档而新增加的段对已经打开的reader是不可见的。 - .del文件已经读入内存。
因而其他的reader或者writer删除的文档对打开的reader也是不可见的。 - 打开的reader已经有inputstream指向cfs文件。
一个段文件从生成起就不会改变,新添加的文档都在新的段中,删除的文档都在.del中。段之间的合并是生成新的段,而不会改变旧的段,只不过在段的合并过程中,会将旧的段文件删除。
以上三点保证了 IndexReader 的 snapshot 的性质,也即一个IndexReader打开一个索引,就好像对此索引照了一张像,无论背后索引如何改变,此IndexReader在被重新打开之前,看到的信息总是相同的。
严格的来讲,Lucene的文档号仅仅对打开的某个reader有效,当索引发生了变化,再打开另外一个reader的时候,前面reader的文档0就不一定是后面reader的文档0了,因而我们进行查询的时候,从结果中得到文档号的时候,一定要在reader关闭之前应用,一旦reader关闭了,则文档号已经无意义,如果用其他的reader查询这些文档号,得到的可能是不期望的文档。
IndexSearcher
|
|
IndexSearcher 提供了两个重要的函数:
- setSimilarity()
可以自定义 Similarity 对象,从而影响搜索过程的打分。 - search()
负责打分的计算和倒排表的合并。
search()
|
|
搜索查询对象包括以下过程:
- 创建 Weight 树,计算 term weight。
- 创建 scorer 及 SumScorer 树,为合并到排表做准备。
- 用 SumScorer 进行倒排表合并。
- 收集文档结果集和计算打分。
创建 Weight 树,计算 Term Weight
|
|
包括以下过程:
- 重写 Query 对象树
- 创建 Term Weight 对象树
- 计算 Term Weight 得分
重写 rewrite 主要涉及TermQuery
和MultiTermQuery
,真正需要重写的是MultiTermQuery
,也即一个 Query 代表多个 Term 参与查询,例如 PrefixQuery 和 FuzzyQuery。
对于此类Query,Lucene不能直接进行查询,必须进行重写处理,有两种方式:
- 方式一,将MultiTermQuery对应的所有 Term 看成一个 Term,将包含它们的文档号取出来组成一个 docId Set。
无论多少 Term,都只有一个倒排表参与合并,不会产生 TooManyClauses异常,性能得到提高。 - 方式二,将多个 Term 组成一个 BooleanQuery,组成 OR 关系。
涉及的多个 Term 需要根据索引中的tf、idf参与打分计算。
创建 Scorer 和 SumScorer 树
|
|
除了创建 Scorer 对象树之外,还会创建 SumScorer 树来表示各个语句之间的关系,为合并倒排表做准备。
合并倒排表
- 交集 ConjunctionScorer,多个must
- 并集 DisjunctionSumScorer,多个should
- 差集 ReqExclScorer,must + must_not
- ReqOptSumScorer,must + should
收集文档结果集和计算打分
文档收集器 TopScoreDocCollector,主要作用是先计算文档的得分,然后将 文档放入优先队列中,最后取出前 n 篇文档(得分相同,文档号小的优先)。
QueryParser
|
|
对查询进行解析成Query的过程,涉及到 JavaCC、QueryParser、分词器、查询语法等,从而生成一个 Query 树。
感谢:
http://www.cnblogs.com/forfuture1978/archive/2010/04/04/1704282.html