先声明一下,我的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.youkuaiyun.com/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.youkuaiyun.com/duck_genuine/article/details/7862454 这篇博客中我有点启发——即我们使用这个新的searcher来做一些提前的搜索,这样不就能实现指定的热身了么,不过我自己倒是没有测试过,等需要的时候再做些测试吧。http://blog.youkuaiyun.com/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中没有配置。