解决solr搜索多词匹配度和排序方案

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hu948162999/article/details/47727159

转载请标明出处:http://blog.csdn.net/hu948162999/article/details/47727159


本文主要介绍了在短语、句子、多词查询中,solr在控制查询命中数量、之后再对结果集进行排序

在solr中 默认是or 查询,也就是说:如果搜索q 中 分出来的词越多,所匹配的数量也就越多。如:搜索短语  “中国联想笔记本” ,分词结果:中国 、联想 、 笔记本。 

覆盖结果集:只要文档中包含这3个任意词,都给返回。

排序结果:按照solr的打分公式。默认匹配相关度最高的文档放在第一位。。简单的说。就是文档中,同时含有 中国 、联想 、 笔记本 分值最高。这种需求一般可以满足部分的企业级搜索。

但是:如果需要自定义排序的话,问题就逐渐暴露了。

通过requestHandler queryParser edismax 中的 df qf,通过字段的权重配置和 各个维度的积分模型之后,得出的排序。就不一定按照同时 含有 中国 、联想 、 笔记本优先级排序了。。有些只包含 中国  这个词的优先级很高 也有可能。这种结果排序 明显不能理解和符合用户的意思。


如何合理的控制solr查询的命中的数量和质量???

在上篇文章中,提到了两种关于solr 对短语、短句(非关键词)的搜索精度解决方案,solr控制多词联合查询命中的数量

但是上面解决了返回精度的问题。但是设置mm匹配精度 或者全词匹配defaultOperator=“AND”。df和qf 自定义的排序 就不起作用了。


默认情况下,Solr查询语法只有两种形式:关键词或者以空格分隔的关键词组。当查询英文时,英文本身就是以空格来区分词的,所以Solr就能直接获取英文词并组装Query;但是中文句子中间没有空格,Solr查询时把整个句子交给Query,然后由Query再按照Field来分词、查询。这样就丧失了DisMax中qf所能带来的好处。 

所以:思考了这么一种思路。对“中国联想笔记本”分词之后。对每个词单元 中间接一个空格,就可以满足控制搜索词匹配度的前提下,提供自定义排序。这个时候就需要重写lucene的默认的queryParser 。

版本:solr4.10.3

solrconfig.xml代码

<span style="font-size:14px;"><str name="defType">myparser</str></span>

<span style="font-size:14px;"> <!-- 自定义queryParser -->
  <queryParser name="myparser" class="com.lubanec.util.MyQParserPlugin"/></span>

重写QParserPlugin和DisMaxQParser

<span style="font-size:14px;">package com.lubanec.util;

import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.search.QParser;
import org.apache.solr.search.QParserPlugin;

public class MyQParserPlugin extends QParserPlugin {

	public void init(NamedList args) {
	}

	public QParser createParser(String qstr, SolrParams localParams,
			SolrParams params, SolrQueryRequest req) {
		return new MyQParser(qstr, localParams, params, req);
	}
}
</span>

<span style="font-size:14px;">package com.lubanec.util;

import java.io.StringReader;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.search.DisMaxQParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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 ts = analyzer.tokenStream(req.getSchema().getDefaultSearchFieldName(), new StringReader(this.qstr));
			ts.reset();
			while (ts.incrementToken()) {
			  CharTermAttribute termAttribute = ts.getAttribute(CharTermAttribute.class);
//              System.out.println(termAttribute.toString());
              norm.append(new String(termAttribute.toString())).append(" ");  
			}
			ts.end();
			ts.close();
		} catch (Exception ex) {
			log.info("Ex=" + ex);
		}
		if (norm.length() > 0)
			this.qstr = norm.toString();
//		log.info("after analyzer, qstr=" + this.qstr);
	}

}
</span>

最好的办法,就把默认的ExtendedDismaxQParser复制过来,加上本地代码。。保留dismax所有功能。

如下:

在ExtendedDismaxQParser构造方法中加入上面那部分代码;

  public ExtendedDismaxQParser(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();
		try {
			TokenStream ts = analyzer.tokenStream(req.getSchema()
					.getDefaultSearchFieldName(), new StringReader(this.qstr));
			ts.reset();
			while (ts.incrementToken()) {
				CharTermAttribute termAttribute = ts.getAttribute(CharTermAttribute.class);
				norm.append(new String(termAttribute.toString())).append(" ");
			}
			ts.end();
			ts.close();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		if (norm.length() > 0)
			this.qstr = norm.toString();
		config = this.createConfiguration(qstr,localParams,params,req);
  }

OK。。结束!

展开阅读全文

没有更多推荐了,返回首页