Solr 获取searcher实例分析
每一个搜索请求都会持有一个searcher的引用,而不是创建一个新的searcher,处理完后会释放掉这个引用。
Solr在初始化化时,通过SolrCore核心类要做很多的初始化工作,包过读取solrconfig.xml配置文件里的内容,代码如下:
1 booleanQueryMaxClauseCount();
2 //设置布尔查询最多个数。
3 initListeners();
4 //读取配置文件的search实例的监听器。
5
6 initDeletionPolicy();
7 initIndex();
8
9 initWriters();
10 initQParsers();
11
12 initValueSourceParsers();
13 this.searchComponents = loadSearchComponents();
15 // Processors initialized before
16 the handlers
17 updateProcessorChains = loadUpdateProcessorChains();
19 reqHandlers = new
20 RequestHandlers(this);
21 reqHandlers.initHandlersFromConfig(solrConfig);
23 highlighter = initHighLighter();
25 // Handle things that should eventually
26 go away
28 initDeprecatedSupport();
loadSearchComponents方法就是初始化indexSearch实例。详细说明如下:
getSearcher
– (forceNew, returnSearcher, waitSearcher-Futures)
关注solr全局三个点调用getSearcher函数
: solrCore初始化时(false, false, null),QueryComponent处理查询
请求时(false, true,
null),UpdateHandler在处理commit请求时(true, false, new
Future[1])
---------
1.solrCore初始化时
根据solrconfig配置的IndexReaderFactory&DirectoryFactory获取索引的IndexReader,再使用这个reader封装一个SolrIndexReader,再使用这个SolrIndexReader封装一个RefCounted(searcher的引用计数器,当搜索组件获取一个组件后引用++,用完后调用close引用--,当引用数为0时将这个引用从core管理的一个当前被使用的searcher的链表移除,同时调用searcher.close回收资源),将这个引用添加到core管理的一个当前被使用的searcher的链表里如果firstSearcherListeners不为空则回调这些监听器,这个回调是交给core的一个newSingleThreadExecutor去做的,再往这个线程池里添加一个任务:将这个RefCounted设置为core当前最新的searcher的引用计数器最后返回null,因为returnSearcher=false在solrCore初始化时这样做的主要目的是在初始化时就加载好IndexSearcher,搜索请求来了之后能立即返回,而不必等待加载IndexSearcher
---------
2.QueryComponent处理查询请求时
由于core当前最新的searcher的引用计数器不为null且这个获取IndexSearcher的请求不是强制要求获取最新的,且returnSearcher=true故直接返回core当前最新的searcher的引用计数器,且这个引用计数器做++这里面还有段当前searcher的引用计数器为null的逻辑,但是没有发现有什么情况会导致这种情况发生故不累述了
---------
3.UpdateHandler在处理commit请求时
首先到core管理的一个当前被使用的searcher的链表里获取目前最新的searcher;同时会加载索引目录下的index.properties文件(如果存在的话),拿到KEY=’index’的值,其指明目前索引的存放地方;如果获取的目录和当前最新的searcher使用的目录一致且solrConfig.reopenReaders为true则获取通过searher.reader.reopen获取最新的reader -> 封装成searcher,否则直接IndexReader.open获取reader。获取到searcher后的一段逻辑[RefCount封装,添加到searchers链表]和core初始化时是一样的,接下来的逻辑是如果solrConfig.useColdSearcher为TRUE其当前searcher的引用为null-导致来自QueryComponent的请求阻塞[现在还没发现什么情况会导致searcher的引用为null]立即将这个新的searcher的引用设置为core当前最新的searcher的引用计数器,这样来自QueryComponent的请求拿到这个引用后返回,当时这时这个新建的searcher是没有经过其前一个searcher的cache热身的,同时这样会导致这个新建的searcher不会进行热身活动如果solrConfig.useColdSearcher为FALSE则会往线程池里添加一个热身的任务如果newSearcherListeners不为空则回调这些监听器,也是给线程池的任务最后如果先前没有做将新的searcher的引用设置为core当前最新的searcher的引用计数器的行为的话,则往线程池添加一个任务 – 将新的searcher的引用设置为core当前最新的searcher的引用计数器最后返回null,因为returnSearcher=false