关闭

lucene搜索过程详解

822人阅读 评论(0) 收藏 举报
分类:

查询以最简单的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肯定比这个复杂的多,但是,大致流程会是一样的。

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



0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:7051次
    • 积分:129
    • 等级:
    • 排名:千里之外
    • 原创:7篇
    • 转载:0篇
    • 译文:0篇
    • 评论:1条
    文章分类
    最新评论