简单说搜索个过程,Lucene 在搜索的程序简单分成两部分,搜索与排序。高手请忽略下面我的讲解。
搜索:
通过倒排的索引找到对应的 docId 集,拿出来,通过 Collector 类的实现类中的 collect(int docId )
就可以拿到了。
排序:
因为拿出来后,还有一个排序的过程,现在我们只讨论按某一个数字字段进行排序,Collector 的实现类都会从一个叫 FieldCache 类中,加载了需要排序的字段的一个 数组的值,数组下标为docId, 然后通过 FieldValueHitQueue 这一个类进行排序了。
象一般来讲,做搜索应用都会按时间从远到近,一段一段地把数据存入到索引中,完成后,如有新增的数据,只需要把新增那部分存入索引则可,这是很普遍的做法。
完成后似乎一切很顺利,哦,对了,还有一个事情就是其实很多的业务应用中,都是把搜索结果按一个或者多个字段排序了,比如:把搜索出来的结果,按发布时间倒排,或者按评论数倒排,又或者一个比较常用的业务就是,出报表,把最新的前 1000 条记录按发布时间倒排出来,甚至还要按页数一页一页出来结果。这里暂不讨论按匹配度等排序的情况。
问题的来源:
因为我们入索引是从远到近的,可以简单地认为,如:发布时间(time)在索引里面都是一种升序的形式存入索引,而搜索出来后排序则是一种倒序的形式,问题就是这样子,按排序算法来说这就是最差的一种情况了,把一个升序排序成倒序,但通过研究Lucene 的索引发现,一旦达到某个数据量,索引里面的并非完全按 时间正序入索引的,而是把document 分成了几段,我想这样子就是为了避免我刚才说的排序最坏的情况出现吧...但只能是治标不治本的做法,仅是折衷的做法。
解决思路:
现在公司的搜索业务方面的速度不快,估计数据量比较大的原因,整一个集群的速度我个人并不满意。
在 lucene 的排序中,其实仅仅搜索的速度是挺快的,主要的性能瓶颈在排序那里,然后我深入再发现了解到,公司的搜索业务中很多都使用发布时间倒序完成的,这自然让我产生一种想法,为什么不预先让他们排序好?因为既然是按发布时间倒序完成的,那说明只要命中docId ,则它的排序已经固定下来了。
1. 在加载索引的时候,通过 termEum 先把某一个时间段排序后,得到一个已经排序好的数组了。
2. 自己另外再写一个 Collector 的实现类,里面只需要记录命中的 docId,
3. 完成后,再遍历那个已经排序好的数组,拿出 docId ,看是不是已经命中的,拿够了前 20 条再 break 出来就完成整一个搜索与排序的过程了,
从上面看到,都已经没有排序的过程,因为已经第一步实现了排序。代码我不再演示了,思路已经写在那里了,代码估计对于各路大神也不是什么难事。
下面给出测试的条件与结果:
索引的结构给一下,只需要留意红框里面的字段就可以了
我分了三次测试条件, 1000万,3000万, 总数,其中 is 字段是为了可以均匀地把数据划分成 10 份。都没有使用分词器,只对数字进行索引。
第一次测试
1000W 数据,按 is 字段,搜索 10 平均得出每一次搜索结果约 300W.按 time 字段倒序,同样条件,对比预排序与lucene 自身排序的速度比较
从结果可以看出,使用预排序的方式后只需要用Lucene 自带排序的 30% 的时间 , 平均每一次搜索结果约 100W 数据,(上面的预排序那里是 44.922 's 我是整理时错误了, sorry .... )
第二次测试
3000W 数据,按 is 字段,搜索 10 平均得出每一次搜索结果约 300W.按 time 字段倒序,同样条件,对比预排序与lucene 自身排序的速度比较
从图上可以看出,同样道理搜索出来的结果,平均每次300W,而且搜索结果数完全一致,排除加载缓存及其他因素,预排序也只需要Lucene 普通排序的 30% 的时间就完成了
第三次测试
这次比较极端,使用MatchAllQuery 进行排序,就是 1000W 结果参与排序,对于Lucene自带的那种排序方式最致命,而对于预先排序这种方式则是最优的方式。
从上面看到, 1000W 的数据参与排序,Lucene自带的排序方式,用了近 1秒的时间去完成排序,而预排序则只用了 0.3 秒就完成了。
总结论:
通过上面的测试,使用预排序的方式,速度提升很明显,为Lucene自带排序的 30 % 时间,对整体的搜索业务性能是一个很大的提升。同时在这里可以扩展一下,通过这样子的预先排序,还可以扩展为,对数字的搜索,或数字区间搜索,而不是使用 NumericQuery ,速度会更快平均在 30ms 的搜索用时,再再再扩展一下,还可以对数字或者数字区间进行统计,比 Solr 的自带的统计速度还要快不少!我稍候还会针对这些做一些扩展开发,请大家稍等。
缺点: 我觉得,可能是每一次加载索引,或者切换新索引的时间,需要用1分钟左右,进行一个预排序的过程,但我认为相对于优点,这一个缺点不大,一般都是通过加载完新的索引并构造好预排序后,再切换到新索引,问题不大。
如果对于那些更新并不频繁而数据量特别大如: 半小时更新一次等,我觉得很适合使用这种方法提升性能,而对于那些几分钟就更新一次的搜索业务,我觉得,这种方式就慎用了,毕竟每次这样子预排序一次,对性能伤害很大。
by kernaling.wong@2013.12.30
欢迎转载: http://kernaling-wong.iteye.com/blog/1997365 请注明作者
相关推荐
对lucene的封装对lucene的封装 对lucene的封装 对lucene的封装
lucene、lucene.NET详细使用与优化详解lucene、lucene.NET详细使用与优化详解
lucene排序、设置权重、优化、分布式搜索.pdf
SSH + Lucene + 分页 + 排序 + 高亮 模拟简单新闻网站搜索引擎--NewsWithSearch.part3 SSH + Lucene + 分页 + 排序 + 高亮 模拟简单新闻网站搜索引擎--NewsWithSearch.part2 SSH + Lucene + 分页 + 排序 + 高亮 ...
lucene3.0.3搜索的使用示例lucene3.0.3搜索的使用示例lucene3.0.3搜索的使用示例
用 Lucene 加速 Web 搜索应用程序的开发---实例代码
05.Lucene索引深入优化 共10页 06.Lucene索引搜索 共13页 07.Lucene搜索实战1 共4页 08.Lucene搜索实战2 共5页 09.Lucene搜索深入实战1 共5页 10.Lucene搜索深入实战2 共11页 11.Lucene搜索深入实战进阶1 共4页 12....
Lucene根据关键词出现次数排序以及自定义排序,可以自定义优先级,包含list字段排序与pom等
lucene自定义排序实现,大家有兴趣关注我的博客http://blog.csdn.net/wuyinggui10000/article/category/3173543
SSH + Lucene + 分页 + 排序 + 高亮 模拟简单新闻网站搜索引擎--NewsWithSearch.part3 SSH + Lucene + 分页 + 排序 + 高亮 模拟简单新闻网站搜索引擎--NewsWithSearch.part2 SSH + Lucene + 分页 + 排序 + 高亮 ...
传统上,人们将信息检索系统返回结果的排序称为"相关排序" (relevance ranking) ,隐含其中各条目的顺序反映结果和查询的相关程度。
本课程由浅入深的介绍了Lucene4的发展历史,开发环境搭建,分析lucene4的中文分词原理,深入讲了lucenne4的系统架构,分析lucene4索引实现原理及性能优化,了解关于lucene4的搜索算法优化及利用java结合lucene4实现...
在一定深度介绍LUCENE的排序算法和打分公式。
较全面的介绍Lucene的使用与优化技巧,希望对您有所帮助
lucene,solr的使用lucene,solr的使用lucene,solr的使用lucene,solr的使用lucene,solr的使用lucene,solr的使用lucene,solr的使用lucene,solr的使用lucene,solr的使用lucene,solr的使用lucene,solr的使用
对于初学者很快掌握lucene 该文档详细的介绍了如何使用lucene 以及快速理解掌握lucene
SSH + Lucene + 分页 + 排序 + 高亮 模拟简单新闻网站搜索引擎
05.Lucene索引深入优化 共10页 06.Lucene索引搜索 共13页 07.Lucene搜索实战1 共4页 08.Lucene搜索实战2 共5页 09.Lucene搜索深入实战1 共5页 10.Lucene搜索深入实战2 共11页 11.Lucene搜索深入实战进阶1 共4页 12....
lucene3.6 搜索例子
05.Lucene索引深入优化 共10页 06.Lucene索引搜索 共13页 07.Lucene搜索实战1 共4页 08.Lucene搜索实战2 共5页 09.Lucene搜索深入实战1 共5页 10.Lucene搜索深入实战2 共11页 11.Lucene搜索深入实战进阶1 共4页 12....