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的索引里面存了些什么,如何存放的,也即 ...
随机推荐
- vue学习笔记(一): 建立 vue-cli 初始网站
在安装vue-cli之前,要先安装node.js这个大家百度一下就可以了 1.安装 vue-cli npm install -g @vue/cli-init 2.初始化一个项目,名为 hcmanage ...
- CTF丨Linux Pwn入门教程:针对函数重定位流程的相关测试(下)
Linux Pwn入门教程系列分享已接近尾声,本套课程是作者依据i春秋Pwn入门课程中的技术分类,并结合近几年赛事中出现的题目和文章整理出一份相对完整的Linux Pwn教程. 教程仅针对i386/a ...
- [20190909]完善vim的bccacl插件.txt
[20190909]完善vim的bccacl插件.txt http://blog.itpub.net/267265/viewspace-2140886/http://blog.itpub.net/26 ...
- react中界面跳转 A界面跳B界面,返回A界面,A界面状态保持不变 redux的state方法
在上一篇文章中说过了react中界面A跳到B,返回A,A界面状态保持不变,上篇中使用的是传统的localStorage方法,现在来使用第二种redux的state方法来实现这个功能 现在我刚接触red ...
- Jmeter(二)响应内容乱码解决办法
Jmeter请求编码设置为UTF-8,响应内容依然乱码,可在Jmeter安装路径bin\jmeter.properties中设置默认编码为UTF-8,于是问题得以解决:
- 智能指针类模板(中)——Qt中的智能指针
Qt中的智能指针-QPointer .当其指向的对象被销毁时,它会被自动置空 .析构时不会自动销毁所指向的对象-QSharedPointer .引用计数型智能指针 .可以被自由的拷贝和赋值 .当引用计 ...
- Redis Pipelining
Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务.这意味着通常情况下一个请求会遵循以下步骤: 客户端向服务端发送一个查询请求,并监听Socket返回,通常是以阻塞模式,等待服务端响 ...
- Alpha冲刺(1/4)
队名:天码行空 组长博客连接 作业博客连接 团队燃尽图(共享): GitHub当日代码/文档签入记录展示(共享): 组员情况: 组员1:卢欢(组长) 过去两天完成了哪些任务:SVN管理工具搭建 展示G ...
- 团队Git现场编程实战
团队Git现场编程实战 一.组员职责分工 组员 分工 贡献度 卢欢(组长) 前后端接口设计 8% 严喜 寻找相关资料 8% 张火标 设计并描述界面原型 8% 钟璐英 编写随笔 8% 周华 填写完善文档 ...
- 执行shell脚本遇到错误syntax error: unexpected "then" (expecting "}")
今天执行脚本的时候遇到错误,如下图: root@ApFree:/usr/sbin# ./conntrack_num_graph.sh ./conntrack_num_graph.sh: line : ...