edismax支持boost函数与score相乘作为,而dismax只能使用bf作用效果是相加,所以在处理多个维度排序时,score其实也应该是其中一个维度 ,用相加的方式处理调整麻烦。

而dismax的实现代码逻辑比较简单,看起来比较易理解,edismax是它的加强版,其实是改变了不少。。比如在以下:

先看看dismax的解析主要实现思路:

首先取出搜索字段名qf

将最终解析成一个BooleanQuery

先解析主mainQuery:

  1. 用户主要是搜索串的解析
  2. altQuery解析处理,看是否使用用户定义的后备搜索串
  3. PhraseQuery解析组装
再解析bq查询,主要是额外加分的查询,不会影响搜索结果数,只会影响排序

再则是bf解析,函数搜索最后会以加的方式作用于文档评分

看主要代码更清晰:

[java] view
plain
copy

  1. @Override
  2. public Query parse() throws ParseException {
  3. SolrParams solrParams = SolrParams.wrapDefaults(localParams, params);
  4. queryFields = SolrPluginUtils.parseFieldBoosts(solrParams.getParams(DisMaxParams.QF));
  5. if (0 == queryFields.size()) {
  6. queryFields.put(req.getSchema().getDefaultSearchFieldName(), 1.0f);
  7. }
  8. /* the main query we will execute.  we disable the coord because
  9. * this query is an artificial construct
  10. */
  11. BooleanQuery query = new BooleanQuery(true);
  12. boolean notBlank = addMainQuery(query, solrParams);
  13. if (!notBlank)
  14. return null;
  15. addBoostQuery(query, solrParams);
  16. addBoostFunctions(query, solrParams);
  17. return query;
  18. }

edismax的主要实现思路跟dismax差不多,以下是一些主要差别之处:

edismax解析含有+,OR,NOT,-语法时,就会忽略掉使用MM。

以下是主要代码实现:

统计搜索串中+,OR ,NOT,-语法元个数

[java] view
plain
copy

  1. // defer escaping and only do if lucene parsing fails, or we need phrases
  2. // parsing fails.  Need to sloppy phrase queries anyway though.
  3. List<Clause> clauses = null;
  4. int numPluses = 0;
  5. int numMinuses = 0;
  6. int numOR = 0;
  7. int numNOT = 0;
  8. clauses = splitIntoClauses(userQuery, false);
  9. for (Clause clause : clauses) {
  10. if (clause.must == '+') numPluses++;
  11. if (clause.must == '-') numMinuses++;
  12. if (clause.isBareWord()) {
  13. String s = clause.val;
  14. if ("OR".equals(s)) {
  15. numOR++;
  16. } else if ("NOT".equals(s)) {
  17. numNOT++;
  18. } else if (lowercaseOperators && "or".equals(s)) {
  19. numOR++;
  20. }
  21. }
  22. }

/////当搜索串里包含有+,OR ,NOT,-这四种时候,mm就会失效

[java] view
plain
copy

  1. boolean doMinMatched = (numOR + numNOT + numPluses + numMinuses) == 0;
  2. (parsedUserQuery != null && doMinMatched) {
  3. String minShouldMatch = solrParams.get(DisMaxParams.MM, "100%");
  4. if (parsedUserQuery instanceof BooleanQuery) {
  5. SolrPluginUtils.setMinShouldMatch((BooleanQuery)parsedUserQuery, minShouldMatch);
  6. }
  7. }

短语查询,先找出普通的查询,原来就是短语查询的、或者属于“OR”,“AND”,“NOT”,’TO‘类型的都不要。由于edismax支持解析符合lucene语法的搜索串,所以不像dismax那样,只需要简单的将搜索串去掉\“,然后加个“”括起来就行

// find non-field clauses

List<Clause>normalClauses =new ArrayList<Clause>(clauses.size());

for (Clauseclause :clauses) {

if (clause.field !=null ||clause.isPhrase)continue;

// check for keywords "AND,OR,TO"

if (clause.isBareWord()) {

String s =clause.val.toString();

// avoid putting explict operators in the phrase query

if ("OR".equals(s) ||"AND".equals(s) ||"NOT".equals(s) || "TO".equals(s))continue;

}

normalClauses.add(clause);

}

// full phrase...

addShingledPhraseQueries(query, normalClauses, phraseFields, 0,

tiebreaker,pslop);

// shingles...

addShingledPhraseQueries(query, normalClauses, phraseFields2, 2,

tiebreaker,pslop);

addShingledPhraseQueries(query, normalClauses, phraseFields3, 3,

tiebreaker,pslop);

////下面是dismax获取短语查询的作法:

[java] view
plain
copy

  1. protected Query getPhraseQuery(String userQuery, SolrPluginUtils.DisjunctionMaxQueryParser pp) throws ParseException {
  2. String userPhraseQuery = userQuery.replace("\"", "");
  3. return pp.parse("\"" + userPhraseQuery + "\"");
  4. }

下面是edismax的作法:

[java] view
plain
copy

  1. private void addShingledPhraseQueries(final BooleanQuery mainQuery,
  2. final List<Clause> clauses,
  3. final Map<String,Float> fields,
  4. int shingleSize,
  5. final float tiebreaker,
  6. final int slop)
  7. throws ParseException {
  8. if (null == fields || fields.isEmpty() ||
  9. null == clauses || clauses.size() <= shingleSize )
  10. return;
  11. if (0 == shingleSize) shingleSize = clauses.size();
  12. final int goat = shingleSize-1; // :TODO: better name for var?
  13. StringBuilder userPhraseQuery = new StringBuilder();
  14. for (int i=0; i < clauses.size() - goat; i++) {
  15. userPhraseQuery.append('"');
  16. for (int j=0; j <= goat; j++) {
  17. userPhraseQuery.append(clauses.get(i + j).val);
  18. userPhraseQuery.append(' ');
  19. }
  20. userPhraseQuery.append('"');
  21. userPhraseQuery.append(' ');
  22. }
  23. ExtendedSolrQueryParser pp =
  24. new ExtendedSolrQueryParser(this, IMPOSSIBLE_FIELD_NAME);
  25. pp.addAlias(IMPOSSIBLE_FIELD_NAME, tiebreaker, fields);
  26. pp.setPhraseSlop(slop);
  27. pp.setRemoveStopFilter(true);  // remove stop filter and keep stopwords
  28. pp.makeDismax = true;
  29. pp.minClauseSize = 2;
  30. Query phrase = pp.parse(userPhraseQuery.toString());
  31. if (phrase != null) {
  32. mainQuery.add(phrase, BooleanClause.Occur.SHOULD);
  33. }
  34. }

edismax技术另一个重要的boost查询,

boost查询也是不会影响搜索结果数,但是影响排序,主要作用是将最后得分以相乘的方式作用于score,函数的解析跟bf差不多。

[java] view
plain
copy

  1. //
  2. // create a boosted query (scores multiplied by boosts)
  3. //
  4. Query topQuery = query;
  5. multBoosts = solrParams.getParams("boost");
  6. if (multBoosts!=null && multBoosts.length>0) {
  7. List<ValueSource> boosts = new ArrayList<ValueSource>();
  8. for (String boostStr : multBoosts) {
  9. if (boostStr==null || boostStr.length()==0) continue;
  10. Query boost = subQuery(boostStr, FunctionQParserPlugin.NAME).getQuery();
  11. ValueSource vs;
  12. if (boost instanceof FunctionQuery) {
  13. vs = ((FunctionQuery)boost).getValueSource();
  14. } else {
  15. vs = new QueryValueSource(boost, 1.0f);
  16. }
  17. boosts.add(vs);
  18. }
  19. if (boosts.size()>1) {
  20. ValueSource prod = new ProductFloatFunction(boosts.toArray(new ValueSource[boosts.size()]));
  21. topQuery = new BoostedQuery(query, prod);
  22. } else if (boosts.size() == 1) {
  23. topQuery = new BoostedQuery(query, boosts.get(0));
  24. }
  25. }

可以看到最后不是一个BooleanQuery,而是一个BoostedQuery。

它就是简单处理子查询的分值再与函数查询的分值相乘返回 :主要的score方法如下:

[java] view
plain
copy

  1. public float score() throws IOException {
  2. float score = qWeight * scorer.score() * vals.floatVal(scorer.docID());
  3. return score>Float.NEGATIVE_INFINITY ? score : -Float.MAX_VALUE;
  4. }

转贴请声明来源:http://blog.csdn.net/duck_genuine/article/details/8060026


solr 的edismax与dismax比较与分析的更多相关文章

  1. solr 使用edismax来控制评分

    如何控制评分 如果设置了sort字段,那么将会按照sort字段的顺序返回结果. 如果没有设置sort字段,那么将会根据相关度打分来排序.也就是说,相关度更高的排在前面. 如何来定制适合自身业务的排序打 ...

  2. solr 请求参数过长报错,Solr配置maxBooleanClauses属性不生效原因分析

    博客分类:   上次已经写过一篇关于solr中,查询条件过多的异常的文章,这次在总结扩展一下: 有时候我们的查询条件会非常多,由于solr的booleanquery默认设置的条件数为1024,所以超过 ...

  3. solr入门之权重排序方法初探之使用edismax改变权重

    做搜索引擎避免不了排序问题,当排序没有要求时,solr有自己的排序打分机制及sorce字段 1.无特殊排序要求时,根据查询相关度来进行排序(solr自身规则) 2.当涉及到一个字段来进行相关度排序时, ...

  4. Solr Dismax查询解析器-深入分析

    Solr 支持多种查询解析,给搜索引擎开发人员提供灵活的查询解析.Solr 中主要包含这几个查询解析器:标准查询解析器.DisMax 查询解析器,扩展 DisMax 查询解析器(eDisMax) Di ...

  5. [solr] - defType - 查询权重排序

    Solr的defType有dismax/edismax两种,这两种的区别,可参见:http://blog.csdn.net/duck_genuine/article/details/8060026 下 ...

  6. solr defType查询权重排序

    Solr的defType有dismax/edismax两种,这两种的区别,可参见:http://blog.csdn.net/duck_genuine/article/details/8060026 下 ...

  7. solr特点三: defType(查询权重排序)

    Solr的defType有dismax/edismax两种,这两种的区别,可参见:http://blog.csdn.net/duck_genuine/article/details/8060026 e ...

  8. 初探solr搜索

    solr是一个基于lucene的搜索引擎,lucene是一个全文检索引擎的架构.solr在此之上进行了封装完善,变成了一个很流行实用的搜索引擎,可以应对绝大部分的搜索需求.使用搜索引擎有以下几点好处: ...

  9. Solr系列五:solr搜索详解(solr搜索流程介绍、查询语法及解析器详解)

    一.solr搜索流程介绍 1. 前面我们已经学习过Lucene搜索的流程,让我们再来回顾一下 流程说明: 首先获取用户输入的查询串,使用查询解析器QueryParser解析查询串生成查询对象Query ...

随机推荐

  1. redux中的compose源码分析

    1. redux中compose用来组合各种中间件来实现链式调用,例子如下 compose( applyMiddleware, devTools, persistState, createStore ...

  2. 经典排序方法 python

    数据的排序是在解决实际问题时经常用到的步骤,也是数据结构的考点之一,下面介绍10种经典的排序方法. 首先,排序方法可以大体分为插入排序.选择排序.交换排序.归并排序和桶排序四大类,其中,插入排序又分为 ...

  3. 命令行视频(ts/m3u8)下载工具 —— youtube-dl(ffmpeg 解码)

    youtube-dl 支持的站点:youtube-dl Supported sites youtube-dl 命令行参数: –version:查看版本: 1. 命令行工具安装 安装视频编解码工具 ff ...

  4. tomcat日志文件目录修改

    tomcat每次启动时,自动在logs目录下生产以下日志文件,造成日志文件众多: 将logs的日志文件放置到新建的文件夹位置,避免主硬盘空间的占用.主要更改catalina.out的文件位置和每日的日 ...

  5. lmdb数据格式

    http://deepdish.io/2015/04/28/creating-lmdb-in-python/ https://lmdb.readthedocs.org/en/release/ http ...

  6. Spring的JDBC Template

    Spring的JDBC Template(JDBC模板)简化JDBC API开发,使用上和Apache公司的DBUtils框架非常类似) 快速入门实例 1.创建项目后,导入Spring基础核心开发包. ...

  7. ES6必知必会 (八)—— async 函数

    async 函数 1.ES2017 标准引入了 async 函数,它是对 Generator 函数的改进 , 我们先看一个读取文件的例子: Generator 写法是这样的 : var fs = re ...

  8. streamsets mongodb destinations 使用

    测试集成了directory(excel) 以及redis && field splitter 组件 pipeline flow docker-compose 配置 redis 服务& ...

  9. 远程连接Linux虚拟机上的mysql失败的解决方法

    今天在虚拟机Ubuntu上折腾了一晚上mysql,然后试着用java连接,搞了很久都没成功,但是同学配好的Debian上却连接成功了,也就是说我的配置有问题. 折腾了很久,最后还是通过理解异常信息来大 ...

  10. Jython:java调用python文件之第三方包路径问题

    本文转载自:http://blog.csdn.net/ztf312/article/details/51338060 本方法解决python代码的可移植性,不需要在新机器上配置python环境,只通过 ...