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