目前在公司,实现solr的一个菜名推荐模块的时候,遇到了一个困扰了好几天的问题,就是当实现了模块的逻辑代码并确认功能实现后,在部署测试后发现了一个bug,就是多次查询结果均重复第一次查询的结果。
问题排查
首先想到是不是之后的几次查询并没有真正调用到实现的逻辑,所以在本地IDEA中远程调试服务器上代码,发现当在solr中查询时,确实进入到逻辑代码中打得断点,而且确实传递了不同的query参数到方法中,只是返回的结果依旧不符合预期,只是重复第一次的结果。
再次考虑到是不是solr的某些缓存机制,将多条查询结果识别为了同一条,并直接返回了缓存中的结果。想到这个结果后,我开始了漫长的单步调试过程,希望定位到可能有问题的代码中,并同时在查找关于solr缓存的相关内容。
最后在solr的conf文件中,定位到了相关缓存代码
1024
测试时发现当删掉中间标注的一段时,查询正常,所以确认是由于queryResultCache缓存将不同的query判断为同一个key,所以之后的查询均直接调用第一次缓存的结果。
发现这个结果后,查看queryResultCache的key是由什么确定的。
package org.apache.solr.search; public QueryResultKey(Query query, Listfilters, Sort sort, int nc_flags) { this.query = query; this.sort = sort; this.filters = filters; this.nc_flags = nc_flags; int h = query.hashCode(); Query filt; if(filters != null) { for(Iterator var6 = filters.iterator(); var6.hasNext(); h += filt.hashCode()) { filt = (Query)var6.next(); } } this.sfields = this.sort != null?this.sort.getSort():defaultSort; SortField[] var10 = this.sfields; int var11 = var10.length; for(int var8 = 0; var8 < var11; ++var8) { SortField sf = var10[var8]; h = h * 29 + sf.hashCode(); } this.hc = h; }
以上就是queryResultCache的key的定义类,其中key的hashcode就是hc属性。由定义可知,
int h = query.hashCode(); this.hc = h;,经过单步调试,发现不同的query查询后,在此处得到的hc都是一样的,所以精确定位了问题出在自定义的query的hashcode生成中。
FreqQuery entends bitQuery extends Query
在超类Query中,定义方法
@Override public int hashCode() { return getClass().hashCode(); }
继承的子类均没有覆写hashcode()方法,所以每个query的hashcode均相同。
定位问题后,修改方法也就很简单了,在FreqQuery中覆写此方法,注意做到各query的区分,同时也要保证相同query能命中缓存,此处我采用query的hashcode作为query的hashcode。修改完成后,提交代码,部署应用,发现结果和预期相同了。
远程调试的教程
https://www.cnblogs.com/wy2325/p/5600232.html
浅谈solr缓存
http://www.cnblogs.com/phinecos/archive/2012/05/24/2517018.html