- 浏览: 2184644 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (682)
- 软件思想 (7)
- Lucene(修真篇) (17)
- Lucene(仙界篇) (20)
- Lucene(神界篇) (11)
- Solr (48)
- Hadoop (77)
- Spark (38)
- Hbase (26)
- Hive (19)
- Pig (25)
- ELK (64)
- Zookeeper (12)
- JAVA (119)
- Linux (59)
- 多线程 (8)
- Nutch (5)
- JAVA EE (21)
- Oracle (7)
- Python (32)
- Xml (5)
- Gson (1)
- Cygwin (1)
- JavaScript (4)
- MySQL (9)
- Lucene/Solr(转) (5)
- 缓存 (2)
- Github/Git (1)
- 开源爬虫 (1)
- Hadoop运维 (7)
- shell命令 (9)
- 生活感悟 (42)
- shell编程 (23)
- Scala (11)
- MongoDB (3)
- docker (2)
- Nodejs (3)
- Neo4j (5)
- storm (3)
- opencv (1)
最新评论
-
qindongliang1922:
粟谷_sugu 写道不太理解“分词字段存储docvalue是没 ...
浅谈Lucene中的DocValues -
粟谷_sugu:
不太理解“分词字段存储docvalue是没有意义的”,这句话, ...
浅谈Lucene中的DocValues -
yin_bp:
高性能elasticsearch ORM开发库使用文档http ...
为什么说Elasticsearch搜索是近实时的? -
hackWang:
请问博主,有用solr做电商的搜索项目?
Solr中Group和Facet的用法 -
章司nana:
遇到的问题同楼上 为什么会返回null
Lucene4.3开发之第八步之渡劫初期(八)
转载请务必注明,原创地址,谢谢配合!
http://qindongliang1922.iteye.com/blog/1999154
上篇文章,散仙介绍了IndexWriter的作用,它的最大价值体现在对索引的创建,管理和维护上,通过与IndexWriterConfig这个配置管理类的组合,可以实现最佳的索引策略,当然前提是你得了解IndexWriterConfig里一些重要的参数的配置含义。
本篇文章散仙要介绍的是IndexSearcher这个类,这个类是Lucene在进行检索时必不可少的一个组件,可以称为是检索的入口,通过这个入口之后,我们就可以获取与我们检索的关键词相关的一系列Doc,然后我们就可以进行后续相关的业务处理。
所以我们经常会在代码里这样写:
大多数,情况下,我们的代码都是这样写的,实际上IndexSearcher的构造函数有4个,我们最常用的一般有2个,部分源码如下:
看了源码,我们就会发现,我们常用的构造函数实际上是会调用含有线程池并行检索的2参的构造方法,只不过,把线程池设置为null而已,这其实是一个优化的操作,在某些时候能够带来极大的性能提升,这个稍后散仙会详细分析。下面先来看下IndexSearcher里面的一些常用的API方法
IndexSearcher类里面提供了大量的方法,用来对检索的数据集的限制和过滤,从而达到我们业务需要的一部分数据,当然我们也可也通过setSimilarity方法来设置我们的自定义的打分策略,还可以通过其他的一些方法,来实现排序,过滤,收集,调试打分信息等等。
最后,回到文章开始,散仙来分析下,IndexSearcher的并行构造,如何使用多线程来提升检索性能。
大多数时候,我们默认使用的都是单线程检索,这时候的检索总耗时是顺序检索所有段文件的时间之和,而如果我们使用了并行检索,这时候,我们的检索总耗时,其实就是检索段文件里,耗时最大的那个线程的时间,因为我们是并行检索,所以影响耗时的其实就是检索耗时最长的那个线程的耗时,这有点像“木桶效应”,决定木桶装水的多少,不是由最长的木板决定的,而是由最短的那块木板决定的,反映到这里,其实就是散仙刚提及的耗时可能最长的那个线程,决定了检索的总耗时。
首先呢,这个功能,并不是说所有的场景下,都有明显的作用,比如,我的索引里就只有一个段文件,那么你开启再多的线程也没用,因为这个并行检索,是一个线程对应一个段文件。
另外一种情况,我的索引非常小,然后我又压缩成多个段文件,然后使用这个并行检索去检索数据,其实这时候的性能可能连一个单线程都不如,这也就是单线程与多线程的使用场景的区分,只要正确的理解了什么时候使用单线程,什么时候使用多线程,才有可能达到我们最想要的结果。
所以,这个并行优化的功能,最适合的场景就是我的索引非常大,然后我们把这份索引,压缩成了多个段文件,可能有5个,或者10个以上的段文件,这时候利用这个功能,检索就有很大优势了,下面我们在来看下源码里具体处理:
然后在具体的线程类里的实现:
通过源码,我们大概可以看出,这个提升,其实是利用了多线程的方式来完成的,通过实现Callable接口,以及重写其的call方法,最后通过公用的全局锁,来控制把检索到的结果集添加到公用的命中队列里,这样一来,一个检索,就被并行的分散到多个线程里,然后最后通过一个全局的容器,来获取所有线程检索的结果,由此以来,在某些场合就能大大提升检索性能。
当然这种提升是否,还跟我们的硬件环境有关系,如果我们的机器CPU不够强劲,或者我们在单核或双核上的机器上跑,可能会出现预期之外的结果,不过,现在的服务器基本都是配置很好的,一般不会出现这种情况。
好了,今天散仙要写的,就到此为止了,感谢各位道友的光临,如有什么不足之处,欢迎指正交流。
转载请务必注明,原创地址,谢谢配合!
http://qindongliang1922.iteye.com/blog/1999154
对ES还没研究过,有兴趣,可以进群里面,一起探讨下。
http://qindongliang1922.iteye.com/blog/1999154
上篇文章,散仙介绍了IndexWriter的作用,它的最大价值体现在对索引的创建,管理和维护上,通过与IndexWriterConfig这个配置管理类的组合,可以实现最佳的索引策略,当然前提是你得了解IndexWriterConfig里一些重要的参数的配置含义。
本篇文章散仙要介绍的是IndexSearcher这个类,这个类是Lucene在进行检索时必不可少的一个组件,可以称为是检索的入口,通过这个入口之后,我们就可以获取与我们检索的关键词相关的一系列Doc,然后我们就可以进行后续相关的业务处理。
所以我们经常会在代码里这样写:
Directory directory=FSDirectory.open(new File("D:\\索引测试"));//获取一个索引目录 IndexReader reader=DirectoryReader.open(directory);//返回一个复合Reader=》DirectoryReader //构造IndexSearcher 检索环境 IndexSearcher searcher=new IndexSearcher(reader);
大多数,情况下,我们的代码都是这样写的,实际上IndexSearcher的构造函数有4个,我们最常用的一般有2个,部分源码如下:
final IndexReader reader; // package private for testing! // NOTE: these members might change in incompatible ways // in the next release protected final IndexReaderContext readerContext; protected final List<AtomicReaderContext> leafContexts; /** used with executor - each slice holds a set of leafs executed within one thread */ protected final LeafSlice[] leafSlices; // These are only used for multi-threaded search private final ExecutorService executor; // the default Similarity private static final Similarity defaultSimilarity = new DefaultSimilarity(); /** * Expert: returns a default Similarity instance. * In general, this method is only called to initialize searchers and writers. * User code and query implementations should respect * {@link IndexSearcher#getSimilarity()}. * @lucene.internal */ public static Similarity getDefaultSimilarity() { return defaultSimilarity; } /** The Similarity implementation used by this searcher. */ private Similarity similarity = defaultSimilarity; /** Creates a searcher searching the provided index. */ public IndexSearcher(IndexReader r) { //调用的是2参的构造函数 this(r,null); } /** Runs searches for each segment separately, using the * provided ExecutorService. IndexSearcher will not * shutdown/awaitTermination this ExecutorService on * close; you must do so, eventually, on your own. NOTE: * if you are using {@link NIOFSDirectory}, do not use * the shutdownNow method of ExecutorService as this uses * Thread.interrupt under-the-hood which can silently * close file descriptors (see <a * href="https://issues.apache.org/jira/browse/LUCENE-2239">LUCENE-2239</a>). * * @lucene.experimental */ public IndexSearcher(IndexReader r, ExecutorService executor) { this(r.getContext(), executor); }
看了源码,我们就会发现,我们常用的构造函数实际上是会调用含有线程池并行检索的2参的构造方法,只不过,把线程池设置为null而已,这其实是一个优化的操作,在某些时候能够带来极大的性能提升,这个稍后散仙会详细分析。下面先来看下IndexSearcher里面的一些常用的API方法
方法名 | 描述 |
IndexSearcher(IndexReader r) | 构建一个搜索实例,使用指定的Reader |
IndexSearcher(IndexReader r, ExecutorService executor) | 创建一个并行的检索实例,使用ExecutorService 提供的线程池 |
doc(int docID) | 通过一个docid获取一个对应的doc |
explain(Query query, int doc) | 获取query详细的评分依据信息 |
getIndexReader() | 获取IndexReader实例 |
search(Query query, int n) | 获取前N个检索的结果 |
search(Query query, Collector results) | 通过collector对检索结果进行自定义控制 |
search(Query query, Filter filter, Collector results) | 通过检索,过滤,以及收集,获取一个特定的检索结果 |
search(Query query, Filter filter, int n) | 经过滤后 的前N个结果 |
search(Query query, Filter filter, int n, Sort sort) | 经过滤,排序后的前n个结果 |
search(Query query, Filter filter, int n, Sort sort, boolean doDocScores, boolean doMaxScore) | 对排序后的结果,是否开启评分策略 |
searchAfter(ScoreDoc after, Query query, int n) | 检索上一次query后的数据,通常用来分页使用 |
setSimilarity(Similarity similarity) | 设置自定义的打分策略 |
search(Weight weight, int nDocs, Sort sort, boolean doDocScores, boolean doMaxScore) | 检索指定分数以上的结果 |
IndexSearcher类里面提供了大量的方法,用来对检索的数据集的限制和过滤,从而达到我们业务需要的一部分数据,当然我们也可也通过setSimilarity方法来设置我们的自定义的打分策略,还可以通过其他的一些方法,来实现排序,过滤,收集,调试打分信息等等。
最后,回到文章开始,散仙来分析下,IndexSearcher的并行构造,如何使用多线程来提升检索性能。
大多数时候,我们默认使用的都是单线程检索,这时候的检索总耗时是顺序检索所有段文件的时间之和,而如果我们使用了并行检索,这时候,我们的检索总耗时,其实就是检索段文件里,耗时最大的那个线程的时间,因为我们是并行检索,所以影响耗时的其实就是检索耗时最长的那个线程的耗时,这有点像“木桶效应”,决定木桶装水的多少,不是由最长的木板决定的,而是由最短的那块木板决定的,反映到这里,其实就是散仙刚提及的耗时可能最长的那个线程,决定了检索的总耗时。
首先呢,这个功能,并不是说所有的场景下,都有明显的作用,比如,我的索引里就只有一个段文件,那么你开启再多的线程也没用,因为这个并行检索,是一个线程对应一个段文件。
另外一种情况,我的索引非常小,然后我又压缩成多个段文件,然后使用这个并行检索去检索数据,其实这时候的性能可能连一个单线程都不如,这也就是单线程与多线程的使用场景的区分,只要正确的理解了什么时候使用单线程,什么时候使用多线程,才有可能达到我们最想要的结果。
所以,这个并行优化的功能,最适合的场景就是我的索引非常大,然后我们把这份索引,压缩成了多个段文件,可能有5个,或者10个以上的段文件,这时候利用这个功能,检索就有很大优势了,下面我们在来看下源码里具体处理:
if (executor == null) { return search(leafContexts, weight, after, nDocs); } else { //通过一个公用的队列,来合并结果集 final HitQueue hq = new HitQueue(nDocs, false); final Lock lock = new ReentrantLock();//锁 final ExecutionHelper<TopDocs> runner = new ExecutionHelper<TopDocs>(executor); for (int i = 0; i < leafSlices.length; i++) { // search each sub runner.submit(new SearcherCallableNoSort(lock, this, leafSlices[i], weight, after, nDocs, hq)); } int totalHits = 0; float maxScore = Float.NEGATIVE_INFINITY; for (final TopDocs topDocs : runner) { if(topDocs.totalHits != 0) { totalHits += topDocs.totalHits; maxScore = Math.max(maxScore, topDocs.getMaxScore()); } } //最后从队列里,取值给ScoreDoc进行返回 final ScoreDoc[] scoreDocs = new ScoreDoc[hq.size()]; for (int i = hq.size() - 1; i >= 0; i--) // put docs in array scoreDocs[i] = hq.pop();
然后在具体的线程类里的实现:
private static final class SearcherCallableNoSort implements Callable<TopDocs> { private final Lock lock; private final IndexSearcher searcher; private final Weight weight; private final ScoreDoc after; private final int nDocs; private final HitQueue hq; private final LeafSlice slice; public SearcherCallableNoSort(Lock lock, IndexSearcher searcher, LeafSlice slice, Weight weight, ScoreDoc after, int nDocs, HitQueue hq) { this.lock = lock; this.searcher = searcher; this.weight = weight; this.after = after; this.nDocs = nDocs; this.hq = hq; this.slice = slice; } @Override public TopDocs call() throws IOException { final TopDocs docs = searcher.search(Arrays.asList(slice.leaves), weight, after, nDocs); final ScoreDoc[] scoreDocs = docs.scoreDocs; //it would be so nice if we had a thread-safe insert lock.lock(); try { for (int j = 0; j < scoreDocs.length; j++) { // merge scoreDocs into hq final ScoreDoc scoreDoc = scoreDocs[j]; if (scoreDoc == hq.insertWithOverflow(scoreDoc)) { break; } } } finally { lock.unlock(); } return docs; } }
通过源码,我们大概可以看出,这个提升,其实是利用了多线程的方式来完成的,通过实现Callable接口,以及重写其的call方法,最后通过公用的全局锁,来控制把检索到的结果集添加到公用的命中队列里,这样一来,一个检索,就被并行的分散到多个线程里,然后最后通过一个全局的容器,来获取所有线程检索的结果,由此以来,在某些场合就能大大提升检索性能。
当然这种提升是否,还跟我们的硬件环境有关系,如果我们的机器CPU不够强劲,或者我们在单核或双核上的机器上跑,可能会出现预期之外的结果,不过,现在的服务器基本都是配置很好的,一般不会出现这种情况。
好了,今天散仙要写的,就到此为止了,感谢各位道友的光临,如有什么不足之处,欢迎指正交流。
转载请务必注明,原创地址,谢谢配合!
http://qindongliang1922.iteye.com/blog/1999154
评论
3 楼
qindongliang1922
2014-03-03
goodluck_wgw 写道
怎么没有介绍ElasticSearch的?
对ES还没研究过,有兴趣,可以进群里面,一起探讨下。
2 楼
goodluck_wgw
2014-03-03
怎么没有介绍ElasticSearch的?
1 楼
avatar_sky
2014-02-27
楼主NB惨了 忍不住注册帐号赞一下,希望能有更多关于 lucene的文章。
发表评论
-
如何使用Spark大规模并行构建索引
2016-02-01 12:54 2718使用Spark构建索引非常简单,因为spark提供了更高级的 ... -
Lucene4.3进阶开发之纯阳无极(十九)
2014-12-09 16:37 2734原创不易,转载请务必注明,原创地址,谢谢配合! http:/ ... -
Lucene4.3进阶开发之神游北冥(十八)
2014-03-13 18:21 2418原创不易,转载请务必 ... -
Lucene4.3进阶开发之潇湘夜雨(十七)
2014-02-13 23:14 2807转载请务必注明,原创 ... -
Lucene4.3进阶开发之高山流水(十六)
2014-02-12 22:22 3644转载请务必注明,原创地址,谢谢配合! http://qind ... -
Lucene4.3进阶开发之溪山行旅(十五)
2014-02-11 00:24 3625转载请务必注明,原创地址,谢谢配合! http://qind ... -
Lucene4.3进阶开发之日照光华(十四)
2014-01-24 09:25 3958转载请务必注明,原创 ... -
Lucene4.3进阶开发之礼敬如来(十三)
2014-01-23 00:40 3904转载请务必注明,原创地址,谢谢配合! http://qind ... -
Lucene4.3进阶开发之千象奔鸣(十二)
2014-01-18 23:30 3232转载请务必注明,原创地址,谢谢配合! http://qind ... -
Lucene4.3进阶开发之气定六合(十一)
2014-01-18 22:13 1627转载请务必注明,原创地址,谢谢配合! http://qind ... -
Lucene4.3进阶开发之见龙在田(十)
2014-01-18 00:11 1594转载请务必注明,原创 ... -
Lucene4.3进阶开发之亢龙有悔( 九)
2014-01-17 00:00 1545转载请务必注明,原创 ... -
Lucene4.3进阶开发之李代桃僵( 八)
2014-01-15 18:54 1602转载请务必注明,原创地址,谢谢配合! http://qind ... -
Lucene4.3进阶开发之潜龙勿用( 七)
2014-01-14 20:38 1682转载请务必注明,原创地址,谢谢配合! http://qind ... -
Lucene4.3进阶开发之二渡天劫( 五)
2014-01-03 01:58 3265转载请务必注明,原创 ... -
Lucene4.3进阶开发之漫漫修行( 四)
2013-12-31 01:50 3021转载请务必注明,原创地址,谢谢配合! http://qind ... -
Lucene4.3进阶开发之入乡随俗(三)
2013-12-25 15:20 4604转载请务必注明,原创地址,谢谢配合! http://qind ... -
Lucene4.3进阶开发之乱世丛生(二)
2013-12-17 01:10 3777转载请务必注明,原创地址,谢谢配合! http://qind ... -
Lucene4.3进阶开发之初入仙界(一)
2013-11-25 15:40 5560转载请务必注明,原创地址,谢谢配合! http://qind ...
相关推荐
在"lucene4.3 按坐标距离排序"这个主题中,我们将探讨如何在Lucene 4.3版本中利用地理位置信息进行文档排序,特别是在处理地理空间搜索时的应用。 首先,Lucene 4.3引入了对地理空间搜索的支持,这允许我们根据地理...
Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。Lucene是一套用于全文检索和搜寻的开源程式库,由Apache软件基金会...
lucene4.3增删改查的的一个工具类,对新手来说是一份不可多得的入门资料。
全文检索lucene 4.3 所用到的3个jar包,包含lucene-queryparser-4.3.0.jar、 lucene-core-4.3.0.jar、lucene-analyzers-common-4.3.0.jar。
《Lucene高级搜索进阶项目_04》 在深入探讨Lucene的高级搜索进阶项目时,我们首先需要理解Lucene的核心概念及其在信息检索中的应用。Lucene是一个高性能、全文本搜索库,它提供了丰富的搜索功能,包括布尔运算、...
lucene4.3源代码 censed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information ...
本课程由浅入深的介绍了Lucene4的发展历史,开发环境搭建,分析lucene4的中文分词原理,深入讲了lucenne4的系统架构,分析lucene4索引实现原理及性能优化,了解关于lucene4的搜索算法优化及利用java结合lucene4实现...
Lucene是一个开源的全文搜索引擎库,由Apache软件基金会开发并维护。在Java编程环境中,它为开发者提供了强大的文本检索功能,使得在海量数据中快速查找相关信息变得简单易行。本篇文章将详细探讨Lucene 4.3.1版本的...
共13页07.Lucene搜索实战1 共4页08.Lucene搜索实战2 共5页09.Lucene搜索深入实战1 共5页10.Lucene搜索深入实战2 共11页11....Lucene高级进阶1 共23页16.Lucene高级进阶2 共4页17.Lucene高级进阶3 共4页18.Lucene排序...
1.XunTa是在lucene4.3上创建的通过“知识点”来找人的搜人引擎。 输入一个关键词(或组合),XunTa返回一个排名列表,排在前面的人是与该关键词(组合)最相关的“达人”。 可访问 http://www.xunta.so立即体验...
在本课程中,我们主要探讨了Lucene 4.x版本的高级进阶应用,特别是针对大规模文档搜索引擎的构建。Lucene作为一个开源全文搜索引擎库,它提供了高效、灵活的索引和搜索功能,是构建高性能搜索系统的基石。在这个部分...
结合笔者的实际开发经验,总结了一些新的开发技巧和开发思路,并对网上流传的一些错误...本书既可为零起点的Lucene初学者提供系统全面的学习指导,也可帮助有相关经验的开发者解决在开发过程中遇到的一些难题和疑惑。
在高级进阶部分,我们将重点探讨Lucene在索引、搜索、排序、过滤以及分词器等方面的高级用法,旨在帮助开发者掌握Lucene的精髓,打造高效、精确的搜索体验。 1. **Document与索引更新**: 在Lucene中,`Document`...
【Lucene4.X实战类baidu搜索的大型文档海量搜索系统】课程主要涵盖了Lucene搜索引擎的各个方面,包括基础和高级进阶。以下是课程的主要知识点: 1. **Lucene入门与系统架构**:介绍Lucene的基本概念,以及其系统...
Lucene是Java开发的开源库,它提供了文本分析、索引和搜索功能,使得开发者能够轻松地在应用程序中实现复杂的搜索功能。这个项目的重点在于提升对Lucene高级特性和优化技巧的理解。 首先,我们要了解Lucene的核心...
共13页07.Lucene搜索实战1 共4页08.Lucene搜索实战2 共5页09.Lucene搜索深入实战1 共5页10.Lucene搜索深入实战2 共11页11....Lucene高级进阶1 共23页16.Lucene高级进阶2 共4页17.Lucene高级进阶3 共4页18.Lucene排序...
共13页07.Lucene搜索实战1 共4页08.Lucene搜索实战2 共5页09.Lucene搜索深入实战1 共5页10.Lucene搜索深入实战2 共11页11....Lucene高级进阶1 共23页16.Lucene高级进阶2 共4页17.Lucene高级进阶3 共4页18.Lucene排序...
共13页07.Lucene搜索实战1 共4页08.Lucene搜索实战2 共5页09.Lucene搜索深入实战1 共5页10.Lucene搜索深入实战2 共11页11....Lucene高级进阶1 共23页16.Lucene高级进阶2 共4页17.Lucene高级进阶3 共4页18.Lucene排序...
共13页07.Lucene搜索实战1 共4页08.Lucene搜索实战2 共5页09.Lucene搜索深入实战1 共5页10.Lucene搜索深入实战2 共11页11....Lucene高级进阶1 共23页16.Lucene高级进阶2 共4页17.Lucene高级进阶3 共4页18.Lucene排序...
共13页07.Lucene搜索实战1 共4页08.Lucene搜索实战2 共5页09.Lucene搜索深入实战1 共5页10.Lucene搜索深入实战2 共11页11....Lucene高级进阶1 共23页16.Lucene高级进阶2 共4页17.Lucene高级进阶3 共4页18.Lucene排序...