lucene搜索过程详解

原创 2013年12月04日 10:12:07

查询以最简单的TermQuery为例,从searcher.search()方法为入口:


1.为各个查询的term计算权重。createNormalizedWeight(Query query);具体是在new TermWeight()完成权重计算

2.从索引文件中加载terms到内存,并且缓存,方法是loadTerms()。比如我这里用的codec是SimpleTextCodec(不同的codec生成的索引文件的后缀格式不一样),那么这里将会读取以.pst结尾的倒排表文件,读取的过程是:


,如果你在看下倒排表文件就更清楚了:

这个是倒排表的一小部分,但是是完整的结构。对照上面的代码,估计应该一目了然了吧!

那么保存这些索引的数据结构是什么呢?没错,就是一个叫做org.apache.lucene.util.fst.FST的数据结构,如果你使用以下方式把这种数据结构输出:

PrintWriter pw = new PrintWriter("e://out.dot"); //输出文件

Util.toDot(fst, pw, true, true); //输出FST格式保存的索引

pw.close();

然后,用一个叫做Graphviz的软件(http://www.graphviz.org/)将上面e://out.dot(使用你自己输出的文件)的文件生成图片格式,命令行代码类似于

dot -Tpng -o out.png out.dot
,打开刚刚生成的图片你就会看见:


,我这里实际分词后的term是:git、it、hit,对应上面的图片,你就会看出一些端倪,参考我的另外一篇文章Lucene索引在文件和内存中的数据结构


3.计算TF-IDF模型中的IDF值。new TermWeight(); 在这里就会调用similarity.computeWeight方法,即,计算搜索所用的这个term在整个语料库中的权重,代码如下:


对于同一个term的搜索,各个文档的IDF值是一样的,只有多个term才会显现出IDF的重要性

4.生成collector,循环搜索每一个索引段(不是多线程条件下),如图代码所示:


5。生成Scorer实例,预先计算TF值。在生成这个实例时会调用

org.apache.lucene.search.similarities.TFIDFSimilarity.ExactTFIDFDocScorer.ExactTFIDFDocScorer(IDFStats stats, DocValues norms)方法,


在这个方法中:

a)获得满足查询条件的各个文档的norm值,比如我用的是SimpleTextCodec,则这些值保存在.len后缀的文件中
b)预先计算TF值,这里可能你会有疑问,还没有查询怎么会知道给个文档的TF值呢?其实再看看TF的定义:term在某一个文档中出现的频率,想想出现次数不就是0、1、2、3......32次等等;到时候根据具体的文档如果你出现一次我就返回事先计算好的TF(1)的值,5次就返回TF(5)的值不就可以了吗?

c)计算TF-IDF的值


6。获取文档ID,计算评分,并且排序。scorer.nextDoc()方法循环获得满足条件的文档ID(读取方式和loadTerms类似),然后collector.collect(docID)方法(比如我这里具体的实例是TopFieldCollector.collect(docID))来收集这个文档,代码如下:


具体工作是:

a)命中文档数加一

b)计算文档得分,具体代码在:

org.apache.lucene.search.similarities.TFIDFSimilarity.ExactTFIDFDocScorer.score(int doc, int freq)

用之前的TF-IDF值,乘以解码后的normValue,即:decodeNormValue(norms[docID]),代码如下:


c)和收集文档的队列的最小得分(bottom)的文档对比,如果比小于等于这个bottom则直接丢弃,否则就和队列中的其他文档对比,排序,直到放到正确的位置上,之前的bottom被当前队列中最小的文档取代



7。返回命中的TopFieldDocs,collector.topDocs()


总结:

从搜索流程可以知道:

1。评分算法只能改变文档返回的顺序和与查询的相关度,如果想优化评分公式来优化查询速度是徒劳的(也不敢说绝对)。

2。不管定义返回结果数是多少,都会收集(遍历)所有满足查询的文档,并且为他们排序,因此减少低权重的term会大大提高搜索速度。比如,对于一个垂直的公司搜索引擎来说,由于每个公司名称都几乎会有个“有限公司”的后缀,因此在这个搜索引擎中,“有限”、“公司”、“有限公司”这类型的term搜索是比较慢的,因为几乎每个文档都命中,都需要被collector.collect(docID)。


本文只是对搜索流程的大致描述,很多细节是没有关注的,比如评分方法中的其他因素也没有列出来;同时再次说明这只是最简单的TermQuery的过程,其他类型的Query肯定比这个复杂的多,但是,大致流程会是一样的。

本文中难免会有一些错误和纰漏之处,也希望大家能指出,修正。



Lucene搜索过程解析(6)

以下转自:http://forfuture1978.iteye.com/blog/632859 2.4、搜索查询对象   2.4.3、进行倒排表合并 在得到了Scorer对象树以及SumSco...

搜索引擎----以lucene为例进行简单的搜索过程描述

Lucene使用的是倒排文件索引结构。这种结构组织值得学习 过程主要为几步: 一, 3个文件 词典索引文件----由word找出对应的docid 的映射文件 而为了更高效的准...

Lucene搜索过程解析(3)

2.3、QueryParser解析查询语句生成查询对象 代码为: QueryParser parser = new QueryParser(Version.LUCENE_CURRENT, "con...

lucene搜索源码过程简析

转载请务必注明,原创地址,谢谢配合!  http://qindongliang1922.iteye.com/blog/2013702  今天来谈下有关在Lucene中,如何完成一个搜索的过程,...

Lucene搜索过程解析

本系列文章将详细描述几乎最新版本的Lucene的基本原理和代码分析。 其中总体架构和索引文件格式是Lucene 2.9的,索引过程分析是Lucene 3.0的。 鉴于索引文件格式没有太大变...

Lucene教程(三)- 理解搜索过程的核心类

上一篇博客,我们学习了索引过程的核心类,并且重构了IndexFiles, 在这一篇博客,我们学习一下搜索过程的核心类,并重构一下SearchFiles类。...

Lucene搜索过程解析(5)

以下转自:http://forfuture1978.iteye.com/blog/632840 2.4、搜索查询对象   2.4.2、创建Scorer及SumScorer对象树 当创建完Wei...

Lucene学习总结之七:Lucene搜索过程解析(3)

2.3、QueryParser解析查询语句生成查询对象 代码为: QueryParser parser = new QueryParser(Version.LUCENE_CURRE...

Lucene学习总结之七:Lucene搜索过程解析(2)

二、Lucene搜索详细过程为了解析Lucene对索引文件搜索的过程,预先写入索引了如下几个文件:file01.txt: apple apples cat dogfile02.txt: apple b...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:lucene搜索过程详解
举报原因:
原因补充:

(最多只允许输入30个字)