先声明一下,我的solr的版本是5.5.3
上一篇博客中说了当更新SolrIndexSearcher的时候并不是仅仅调用预热,还有其他的操作,那么都是有什么呢,看一下SolrCore的getSearcher方法(参数最多的一个),如果if (newSearcher != currSearcher) ,即索引发生了变化(无论是commit还是softCommit都算是变化),不仅仅是调用上一个博客中讲的warm,还有下面的操作:
if (currSearcher == null) { future = searcherExecutor.submit(new Callable() { @Override public Object call() throws Exception { try { for (SolrEventListener listener : firstSearcherListeners) {//循环firstSearcherListener,调用其newSearcher方法,第一个参数是新生成的searcher,第二个是null listener.newSearcher(newSearcher, null); } } catch (Throwable e) { SolrException.log(log, null, e); if (e instanceof Error) { throw (Error) e; } } return null; } }); } if (currSearcher != null) { future = searcherExecutor.submit(new Callable() { @Override public Object call() throws Exception { try { for (SolrEventListener listener : newSearcherListeners) {//和上面的firstSearcherListener一样,只不过这里的参数的第二个是当前的searcher。 listener.newSearcher(newSearcher, currSearcher); } } catch (Throwable e) { SolrException.log(log, null, e); if (e instanceof Error) { throw (Error) e; } } return null; } }); }
上面的firstearcherListener和newSearcherListener都是 List<SolrEventListener>,即多个SolrEventListener,可以总结当切换SolrIndexSearcher的时候就会触发我们配置的listener的newSearcher方法,并且对于不同的名字(firstSearcherListener还是newSearcherListener)传入的参数还是不一样的。
如何配置监听呢?我是参考的这个博客:http://blog.csdn.net/duck_genuine/article/details/7862454。
具体的配置为在solrconfig.xml中的<query></query>中添加下面的代码:
<listener event="newSearcher" class="com.comall.solr.listener.HelloWordListener"> <!--这个是配置的newSearcher,即传入新旧SolrIndexSearcher两个参数的--> <arr name="sortFields"> <!-- arr是封装为arraylist --> <str>title</str> <!-- str是字符串 --> <str>id</str> </arr> <!-- str是字符串 --> <str name="queryKeyFile">/Users/yzygenuine/56workspace/solr_jetty/solr/extConf/query.txt</str> <arr name="queries"> <lst> <!--lst是封装为NamedList org.apache.solr.common.util.NamedList 这里的封装的结果是我做实验做出来的 --> <str name="q">solr</str> <str name="qt">standard</str> <str name="sort">price desc</str> </lst> </arr> </listener>
我的HelloWordListener的代码为:
public class HelloWordListener extends AbstractSolrEventListener {//继承自org.apache.solr.core.AbstractSolrEventListener static Logger logger = LoggerFactory.getLogger(HelloWordListener.class); public HelloWordListener(SolrCore core) { super(core); logger.info("初始化HelloWordListener"); } @Override public void init(@SuppressWarnings("rawtypes") NamedList args) {//初始化,args即配置的参数,我用这个来检测封装的类型。 super.init(args); StringBuffer buffer = new StringBuffer(); Object sortFields = args.get("sortFields"); buffer.append("sortFields的类型是:") .append(sortFields.getClass().getName()) .append("---") .append("queryKeyFile的类型是:"); Object queryKeyFile = args.get("queryKeyFile"); buffer.append(queryKeyFile.getClass().getName()).append("---").append("queries的类型是:"); Object que = args.get("queries"); buffer.append(que.getClass().getName()).append(",queries的第一个元素的类型是:").append(((ArrayList)que).get(0).getClass().getName()) .append(",query的第一个元素是:").append(((ArrayList)que).get(0)); logger.info("初始化参数是:{}", buffer.toString()); // {sortFields=[title, id],queryKeyFile=/Users/yzygenuine/56workspace/solr_jetty/solr/extConf/query.txt,queries=[{q=solr,qt=standard,sort=price desc}]} } @Override public void postCommit() { logger.info("调用postCommit"); } @Override public void postSoftCommit() { logger.info("调用SoftCommit"); } @Override public void newSearcher(SolrIndexSearcher newSearcher, SolrIndexSearcher currentSearcher) {//调用newSearcher,从结果来看的确是将两个searcher都传入进去了,并且这个也对softCommit做了测试,如果没有更新索引,softCommit是不会造成已经注册的SolrINdexSearcher发生变化的 logger.info("调用newSearcher:newSearcher:{},currentSearcher:{}",new Object[]{newSearcher,currentSearcher}); } }
本来我是抱着很大的希望使用这个listener的,我的本意是能够通过SolrIndexSearcher来获得里面的多个缓存,然后得到这些缓存的统计信息,但是遗憾的是SolrIndexSearcher并没有给我们方法来得到这些缓存(我本人是比较讨厌使用反射那种暴力操作的)。不过在 http://blog.csdn.net/duck_genuine/article/details/7862454 这篇博客中我有点启发——即我们使用这个新的searcher来做一些提前的搜索,这样不就能实现指定的热身了么,不过我自己倒是没有测试过,等需要的时候再做些测试吧。http://blog.csdn.net/duck_genuine/article/details/7862454,这个博客的主人看来对solr的研究不错,是个大神。
//下面的是后来补充的,
上面说我没有找到获得SolrIndexSearcher中cache的方法,现在找到了,在solrCore中有个getInfoRegistry方法,就是获得所有的当前注册的SolrIndexSearcher的信息的,这个方法在一个新的SolrIndexSearcher注册的时候调用,我们看一下注册方法:
/** Register sub-objects such as caches */ public void register() { // register self core.getInfoRegistry().put("searcher", this);//调用solrCore的getInfoRegistry方法 core.getInfoRegistry().put(name, this); for (SolrCache cache : cacheList) {//这里的cacheList包括我们在solrConf.xml中配置的所有的cache,比如FilterCache,queryResultCache,DocumentCache,fieldValueCache,以及使用<cache>自定义的多个cache。 cache.setState(SolrCache.State.LIVE); core.getInfoRegistry().put(cache.name(), cache);//将多个cache放入到core中,这样就会覆盖原来的cache。 } registerTime = new Date(); }
这样我们就可以通过调用solrCore.getInfoRegistry来获得之前的SolrIndexSearcher的各种cache,然后获得其统计信息了。我改写的HelloWordListener的newSearcher代码如下:
public static final String filterCache_name = "filterCache"; public static final String queryResultCache_name = "queryResultCache"; public static final String documentCache_name = "documentCache"; public static final String fieldValueCache_name = "fieldValueCache"; @Override public void newSearcher(SolrIndexSearcher newSearcher, SolrIndexSearcher currentSearcher) { Map<String, SolrInfoMBean> info = getCore().getInfoRegistry(); SolrInfoMBean filterCache = (SolrInfoMBean) info.get(filterCache_name); logger.info(filterCache.getStatistics().toString()); SolrInfoMBean queryCache = info.get(queryResultCache_name); logger.info(queryCache.getStatistics().toString()); SolrInfoMBean documentCache = info.get(documentCache_name); logger.info(documentCache.getStatistics().toString()); logger.info(info.get(fieldValueCache_name)==null?"fieldvalueCache是null":"fieldValueCache不是null"); }
这样就能从控制台发现solr的缓存的使用情况了。在查询几次之后,提交一个新的document,这样就会调用listener,我自己做的测试的结果为:
{lookups=0,hits=0,hitratio=0.0,inserts=0,evictions=0,size=0,warmupTime=0,cumulative_lookups=0,cumulative_hits=0,cumulative_hitratio=0.0,cumulative_inserts=0,cumulative_evictions=0}//filterCache的 {lookups=26,hits=23,hitratio=0.88,inserts=3,evictions=0,size=3,warmupTime=0,cumulative_lookups=26,cumulative_hits=23,cumulative_hitratio=0.88,cumulative_inserts=3,cumulative_evictions=0}//queryResultCache的 {lookups=32,hits=22,hitratio=0.69,inserts=10,evictions=0,size=10,warmupTime=0,cumulative_lookups=32,cumulative_hits=22,cumulative_hitratio=0.69,cumulative_inserts=10,cumulative_evictions=0}//documentCache的 fieldValueCache不是null//可以发现fieldValueCache自己就会创建,尽管在solrconf.xml中没有配置。