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