默认情况下,Solr查询语法只有两种形式:关键词或者以空格分隔的关键词组。当查询英文时,英文本身就是以空格来区分词的,所以Solr就能直接获取英文词并组装Query;但是中文句子中间没有空格,Solr查询时把整个句子交给Query,然后由Query再按照Field来分词、查询。这样就丧失了DisMax中qf所能带来的好处。
如果能够在用户输入之后,传入DisMax和QueryComponent之前,把中文句子分割为:关键词+空格+关键词,就能享受Solr中的所有好处。分析DisMaxQParserPlugin和DisMaxQParser的实现,在DisMaxQParser中能够获得默认查询字段和分析器,假如默认查询字段是中文类型,那么就可以通过默认字段和分析器对中文句子拆词了。
具体实现:
修改solrconfig.xml
增加一行:<queryParser name="myDisMax" class="my.MyQParserPlugin"/>
增加类MyQParserPlugin
public class MyQParserPlugin extends QParserPlugin {
public static String NAME = "myDisMax";
public void init(NamedList args) {
}
public QParser createParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
return new MyQParser(qstr, localParams, params, req);
}
}
增加类MyQParser
public class MyQParser extends DisMaxQParser {
private static Logger log = LoggerFactory.getLogger(MyQParser.class);
public MyQParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
super(qstr, localParams, params, req);
Analyzer analyzer = req.getSchema().getQueryAnalyzer();
if(null == analyzer)
return;
StringBuilder norm = new StringBuilder();
log.info("before analyzer, qstr="+this.qstr);
try{
TokenStream tokens = analyzer.reusableTokenStream( req.getSchema().getDefaultSearchFieldName(), new StringReader( this.qstr ) );
tokens.reset();
Token token = tokens.next();
while( token != null ) {
norm.append( new String(token.termBuffer(), 0, token.termLength()) ).append(" ");
token = tokens.next();
}
} catch(Exception ex){
log.info("Ex="+ex);
}
if(norm.length() > 0)
this.qstr = norm.toString();
log.info("after analyzer, qstr="+this.qstr);
}
}