• 解决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。。结束!

  • 相关阅读:
    js实现点击图片 弹出放大效果
    Linux 命令
    前台input输入框,输入内容并同步增加输入框长度
    Git
    Git 常用命令
    Windows环境git执行git add命令warning: ....
    Tomcat配置https、访问http自动跳转至https
    An internal error occurred during: "Importing Maven projects". Unsupported IClasspathEntry kind=4
    自定义滚动条mCustomScrollbar
    本地项目,发布至服务器
  • 原文地址:https://www.cnblogs.com/llguanli/p/6951327.html
Copyright © 2020-2023  润新知