解決solr搜索多詞匹配度和排序方案


轉載請標明出處: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。。結束!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM