Lucene搜索/索引过程笔记
lucene索引文档过程:
> 初始化IndexWriter
> 构建Document
> 调用IndexWriter.addDocument执行写入
> 初始化DocumentWriter。参数指定写出位置为内存
> 生成自增段ID
> 调用DocumentWriter.addDocument(); 执行写入
> 写出FieldInfos到内存
> 写出FieldValues到内存
> 计算词元列表
> 排序词元列表
> 写出词元到内存文件
> 写出归一化变量到内存文件
> 全局变量segmentInfos添加新增段
> 增量合并段
> 调用IndexWriter.optimize()优化索引
> 合并内存中的段并将合并后的段写出到磁盘
> 如果当前索引里有多个索引,则合并这些索引
> 调用IndexWriter.close()关闭索引 归一化变量是什么? 干什么用的? 为什么要在searchable接口上放一个rewrite方法? 为什么Weight的创建要用query的createWeight,而不是直接new Weight();
为什么search接口不返回一个包含查询结果的list,而是把查询过程包含在返回对象的构造方法里面?
searcher可以执行多次Query,query和result是绑定的,如果search接口只返回一个list,那同一个查询后面页数查询的时候又待重新parse等一些过程,把查询过程包含在返回对象中实现了一个query的自治,可以在返回对象中做一些优化,比如缓存啥的
为什么searcher不能带pageNo pageSize?
打分是在内存里做的,肯定需要把所有符合的文档全都查出来
为什么要把搜索任务放在query头上?不同的query搜索逻辑有什么不一样?
如果要把搜索逻辑放在searcher上,则在搜索的时候需要判断是哪类搜索然后从里面取出来参数,与其这样判断,不如直接把搜索逻辑放在query上,以后加新的query逻辑也不需要修改已有的代码 Term搜索过程: > 初始化IndexSearcher
> 根据查询语句和解析器解析出Query
> 调用IndexSearcher.search(query); 执行搜索
> 执行搜索,获取前100条
> 重写query
> 创建Weight
> 计算Weight的平方和(?)
> 计算权重归一化因子(?)
> 执行weight的归一化操作
> 创建Scorer
> 通过reader获取命中的文档列表
> 获取搜索term所属field的归一化因子
> 获取当前Query的相似性算法
> 返回TermScorer
> 通过Scorer对命中的文档打分,并获取得分前100条文档
> 计算得分归一化值
> 将命中的100条文档得分乘上归一化因子,然后添加到hitDocs缓存中
> 遍历hitDocs获取最终命中的文档列表数据
> 如果当前遍历的文档没有文档内容数据,则通过searcher获取该文档内容
> 如果遍历超过100条,则重新执行搜索获取当前遍历的位置数据 lucene文档得分是如何计算的? 计算公式是什么? Query是如何简单化的? BoolQuery执行步骤?
由QueryParser生成BoolQuery, 每添加一个子句都会给这个子句添加required和prohibited参数,required表示这个子句必须满足,prohibited表示这个子句一定不能满足
当所有的子句都必须满足,且所有的子句已经是最基础子句了,则使用ConjunctionScorer打分器,该打分器里会通过一个算法来获取多个子句都包含的文档。具体代码如下:
while (more && first().doc() < last().doc()) { // find doc w/ all clauses
more = first().skipTo(last().doc()); // skip first upto last
scorers.addLast(scorers.removeFirst()); // move first to last
}
注: 所有Scorer的doc都是按照从小到大排序的,这个在写索引的时候就确定下来了(termQuery),在ConjunctionScorer里第一次执行next时,会对所有的子Scorer按照第一个文档编号从小到大排序,
每当执行next寻找下一个文档时,先看排在第一位的Scorer当前文档号是否小于排在最后一位的Scorer的当前文档号,如果小于,则表明排在第一位的Scorer当前文档并不是所有Scorer都具备的,所以
排在第一位的Scorer会跳到排在最后一位Scorer当前文档编号的位置,一直找到排在第一位的Scorer和排在最后一位Scorer都具备的一个文档,这样的文档满足AND的关系,可以返回。
对于子句不满足所有子句都是required的情况,使用BooleanScorer,BooleanScorer的逻辑是,每往该打分器里添加一个子Scorer,这个子Scorer都带rquired和prohibited属性,至于这两个属性是从哪里得来的,
目前我猜测应该是从QueryParser中已经计算好的。每调用BooleanScorer的next时,都会按顺序从添加进来的子Scorer中取命中的文档(批量取),然后判断取的这个文档是否应该排除掉(所属的子Scorerprohibited属性值为true),
如果应该排除掉,则直接丢弃,再取下一个,直到找到一个文档符合所有子打分器要求,然后返回。重要的代码片段如下:
while (bucketTable.first != null) { // more queued
current = bucketTable.first;
bucketTable.first = current.next; // pop the queue // check prohibited & required
if ((current.bits & prohibitedMask) == 0 && // prohibitedMask里每一位代表一个子打分器的prohibited属性,1表示决定不能匹配
(current.bits & requiredMask) == requiredMask) { // requierdMask里每一位代表一个子打分器required属性,1表示必须匹配
return true;
}
}
在取命中的文档ID的时候,是批量取的,内存里会缓存在一个叫BucketTable的数据结构里面,按照文档ID分组缓存。 比如第一批缓存的文档ID为 0 ~ 1024。 第二组为 1024 ~ 2048 ... 为什么要这样取,而不是先取100个,再取一百个?
我理解应该是为了防止一直遍历一个必须排除掉的子打分器命中的文档,这样可能会大大增加搜索的延迟,通过文档ID,可以将缓存的文档均匀的分散在多个打分器上,增加命中文档的比率。那为啥不先遍历required=true的打分器命中的文档呢?
如果先遍历这样的打分器,命中率不是更高么?我理解是应该可以这样来优化的,先遍历requrired=true的子打分器,然后再遍历prohibited=true的打分器,增加文档命中率。不知道作者这样写是不是有什么其他的考虑,关键代码如下:
// refill the queue
more = false;
end += BucketTable.SIZE;
for (SubScorer sub = scorers; sub != null; sub = sub.next) { // 按照子打分器add的顺序遍历
Scorer scorer = sub.scorer;
while (!sub.done && scorer.doc() < end) { // 每一个文档都取文档ID在固定范围内的命中文档
sub.collector.collect(scorer.doc(), scorer.score());
sub.done = !scorer.next();
}
if (!sub.done) {
more = true;
}
}
} while (bucketTable.first != null | more); queryParser是如何解析查询脚本的? 是不是索引都会加载到内存里?
这不是的,在根据Term搜索的时候,只会把tii文件内容加载到内存里,tii文件是词元字典的索引,在初始化tisReader的时候就会把所有tii文件中的内容给加载到内存里 SkipInterval是干什么用的?
frq文件中存储了某个词元命中的文档列表,skipInterval记录了隔几个文档记录一下该词元命中的文档列表索引
TermVector干啥用的? 可以实现从文档到属性到词元的映射 段合并是如何维护合并后文档ID的?
1. 在写合并文档数据(.fdt)数据时,是按照SegmentInfos里的顺序按顺序写入的。
2. 在合并时写出合并的词元数据时,会修改每个词元下的文档ID,会把当前词元所属段的base documentid加上写出的文档ID
如果在查询时写入的文档导致同一个查询结果不一样lucene是如何处理的?
先前查询的不会变化,但是新页的数据是按照新查询的结果分页得到。因为ES用了一个缓存,先前查询的不会再更新。
每一次查询都会把所有符合的文档和相应的打分加载到内存里,然后在内存里做排序、过滤、分页
Lucene搜索/索引过程笔记的更多相关文章
- Lucene学习笔记: 五,Lucene搜索过程解析
一.Lucene搜索过程总论 搜索的过程总的来说就是将词典及倒排表信息从索引中读出来,根据用户输入的查询语句合并倒排表,得到结果文档集并对文档进行打分的过程. 其可用如下图示: 总共包括以下几个过程: ...
- lucene学习笔记:三,Lucene的索引文件格式
Lucene的索引里面存了些什么,如何存放的,也即Lucene的索引文件格式,是读懂Lucene源代码的一把钥匙. 当我们真正进入到Lucene源代码之中的时候,我们会发现: Lucene的索引过程, ...
- Lucene学习总结之七:Lucene搜索过程解析
一.Lucene搜索过程总论 搜索的过程总的来说就是将词典及倒排表信息从索引中读出来,根据用户输入的查询语句合并倒排表,得到结果文档集并对文档进行打分的过程. 其可用如下图示: 总共包括以下几个过程: ...
- Lucene构建索引时的一些概念和索引构建的过程
在搜索文档内容之前要做的事情就是对从各种不同来源(网页,数据库,电子邮件等)的文档进行索引,索引的过程就是对内容进行提取,规范化(通过对内容进行建模来实现),然后存储. 在索引的过程中有几个基本的概念 ...
- Lucene建立索引搜索入门实例
第一部分:Lucene建立索引 Lucene建立索引主要有以下两步:第一步:建立索引器第二步:添加索引文件准备在f盘建立lucene文件夹,然后 ...
- Lucene学习总结之七:Lucene搜索过程解析 2014-06-25 14:23 863人阅读 评论(1) 收藏
一.Lucene搜索过程总论 搜索的过程总的来说就是将词典及倒排表信息从索引中读出来,根据用户输入的查询语句合并倒排表,得到结果文档集并对文档进行打分的过程. 其可用如下图示: 总共包括以下几个过程: ...
- Lucene学习总结之三:Lucene的索引文件格式(1)
Lucene的索引里面存了些什么,如何存放的,也即Lucene的索引文件格式,是读懂Lucene源代码的一把钥匙. 当我们真正进入到Lucene源代码之中的时候,我们会发现: Lucene的索引过程, ...
- ElasticSearch优化系列六:索引过程
大家可能会遇到索引数据比较慢的过程.其实明白索引的原理就可以有针对性的进行优化.ES索引的过程到相对Lucene的索引过程多了分布式数据的扩展,而这ES主要是用tranlog进行各节点之间的数据平衡. ...
- Lucene学习之四:Lucene的索引文件格式(1)
本文转载自:http://www.cnblogs.com/forfuture1978/archive/2009/12/14/1623597.html Lucene的索引里面存了些什么,如何存放的,也即 ...
随机推荐
- JavaScript中break、continue和return的区别
break function myBreak() { for(var i = 0; i < 5; i++) { if(i == 3) { break; } console.log(i); } } ...
- 通过重复运行的Microsoft Flow由OAuth认证后获取Access Token并将其更新到实体记录
我是微软Dynamcis 365 & Power Platform方面的工程师罗勇,也是2015年7月到2018年6月连续三年Dynamics CRM/Business Solutions方面 ...
- 堆与栈(heap and stack)在c/c++的应用(概念)
在学习c/c++时,我们经常会遇到 堆与栈 的问题,今天就来讲一下各类情况下的heap,stack的应用. 程序内存布局场景下,堆与栈表示两种内存管理方式: 1.内部分配时,堆和栈表示两种不同的内存管 ...
- 【cf915】E. Physical Education Lessons(线段树)
传送门 简单的线段树区间修改区间查询,但是因为数据范围过大,所以采用动态开点的方法(注意一下空间问题). 也可以直接对询问区间的端点离散化然后建树,这种方法时间复杂度和空间复杂度都比较优秀. 给出动态 ...
- 初学JavaScript正则表达式(十二)
text / exec方法 text() var reg1 = /\w/; var reg2 = /\w/g; reg1.test('a') === true reg2.test('a') === t ...
- Sqlserver 2014 下载
ed2k://|file|cn_sql_server_2014_enterprise_edition_x64_dvd_3932882.iso|2898847744|A33CE10CD989083D1A ...
- python session保持登录,新增地址,并删除,由观察可知,address_id决定删除的内容;
import requests,reheaders={"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) Ap ...
- 分析-flag被盗
用wireshark打开数据包 寻找http协议的数据 找一个post包进行TCP追踪流 寻找flag
- read_sql_query, def read_sql_table
read_sql_query, read_sql_table def read_sql_query(sql, con, index_col=None, coerce_float=True, param ...
- lua 6 函数
定义: function max(num1, num2) local result = 0 if (num1 > num2) then result = num1; else result = ...