lucene理论—Lucene的搜索过程(转)
二:Lucene的搜索过程
1:Lucene搜索过程:
大的分为:关键字解析,获取docid(除去删除的docid),获取内容,飘红缩短。
2:关键词解析:
大概原理是:就是把输入的关键词和要搜索的域进行格式化。把应用请求的语义解释成lucene能懂的语法。
1:其实一般的架构就是把这块分离,把应用和搜索分层。
应用层 |
格式化数据 |
获取docid 获取document |
存储 |
Socket/ICE |
1:看看baidu和google,他们的关键字一般都是会分词的
2:但是lucene默认的对搜索关键词不分词
3:主要了解与或非,lucene里面其实做了3层or/and/not处理。一个是关键词组本身自带的逻辑,一个是分词后的逻辑,一个是域逻辑。
实例演示来说明这3个关系。
4:其实要把应用为主要功能的格式化关键词完全放在应用层,存在一个问题,就是分词,一般不把分词剥离,也是为了节约内存,也是为了部署单一分词,比如有的分词按照服务器收费等,所以这是分层的一个主要原因。
5:程序大概过程:MultiFieldQueryParser =〉BooleanQuery =〉 QueryParser(这是个关键的类,也是逻辑复杂类之一)。
ReInit(进行了关键词自身分词)=〉 Query类构造函数(Conjunction方法获取前面分词的or/and/not关系;Modifiers获取field的or/and/not关系;Clause 对前面分次后的每个词进行or/and/not处理;addClause格式化整合处理) =〉格式化分词处理完毕。
Clause =〉 Term =〉 getFieldQuery(分词) =〉 severalTokensAtSamePosition这个设置为true,里面的MultiPhraseQuery换成BooleanQuery;(加上全局的operator值改为and)最终实现搜索框直接输入短语,自动分词,自动and搜索。
6:这块功能值得注意的一个大问题就是分词,分词的缓存是非常的必要,效率影响非常明显。
7:如果优化,可以考虑对这块也是个优化。
3:获取docid:
1:IndexSearcher的search方法;
程序大概过程:返回值是Hits对象。经过构造调用到Hits的构造:在这个构造中weight等计算,我们当时也修改过这个参数,最后结果是效果不大;在这个构造也调用了getMoreDocs,有一个返回100个命中的参数在这里修改。
搜索的信息内容都放在了hits对象中,当然关键的Docid就在里面。
getMoreDocs中主要调用了searcher.search,并且把返回的TopDocs压入hitDocs中
searcher.search通过抽象的实现,在IndexSearcher中实现
2:这里面有几个值得注意的问题就是缓存问题:
1:倒排表以及缓存问题
2:搜索过一次了,是否缓存了已经返回docid对应的内容?因为接下来要取内容啊。Docid里面有没有内容,但是有指针和偏移量,那么缓存了这些吗?缓存了。
4:获取内容:
1:获取内容提供的方法很多,比如有只拿着docid取内容的,还有通过返回的hits对象取内容的,等等很多方法。
2:分析hits取内容过程:
调用hits中的doc方法,里面的hitDoc获取缓存中的document信息
remove中是个典型的双链表结构,删除缓存,addToFront添加缓存
if (hitDoc.doc == null) {一般走这里面,一般没有缓存,为了下面获取内容准备,也就是对field进行缓存。这儿有个很绕,比较复杂的过程。调用了searcher.Doc,它是IndexSearcher里面的reader.document(i); reader又是调用的IndexReader.open,这个过程就和索引的开始过程一摸一样了。这是lucene唯一一个大模块很明显的结构耦合地方。