solr中的dismax解析器

之前一直用dismax,但是一直没有看看他到底是怎么实现的,今天终于看了一遍源码,记个笔记,方便以后查阅。
当我们使用defType=dismax的时候就会使用到DisMaxQParser这个类,他是一个QParser,用于根据用户的输入解析为一个Query类的实例。我们看看他的解析方法:
  @Override
  public Query parse() throws SyntaxError {
      parsed = true;
      SolrParams solrParams = SolrParams.wrapDefaults(localParams, params);// 将localParams域params合并。优先使用localParams
    
      queryFields = parseQueryFields(req.getSchema(), solrParams);//获得所有的qf,即要匹配的域已经各个域的boost,queryFields是个map,key是String,value是float。
    
      /*
       * the main query we will execute. we disable the coord because this query is an artificial construct
       */
      BooleanQuery query = new BooleanQuery(true);//最后形成的BooleanQuery,
    
      boolean notBlank = addMainQuery(query, solrParams);//向最后的BooleanQuery中添加mainQuery,mainQuery包含两部分,一个是匹配的qf,一个是匹配的pf,等会再看
      if (!notBlank) return null;
      addBoostQuery(query, solrParams);//向最后的booleanQuery中添加boostQuery,用于提高某些文档的得分
      addBoostFunctions(query, solrParams);//向最后的booleaQuery中添加boostFunction的query,用于提高某些文档的得分
    
      return query;
  }
 下面我们一个一个方法的来看:
1、addMainQuery:
 protected boolean addMainQuery(BooleanQuery query, SolrParams solrParams) throws SyntaxError {
    
    Map<String,Float> phraseFields = SolrPluginUtils.parseFieldBoosts(solrParams.getParams(DisMaxParams.PF));//获得pf的域以及每个域的boost
    float tiebreaker = solrParams.getFloat(DisMaxParams.TIE, 0.0f);//获得参数中的tie,也就是disjunctionMaxQuery中的tie,用于计算最后的得分。默认是0.0f,也就是只关心最大的得分,不关心其他的得分。
    
    /*
     * a parser for dealing with user input, which will convert things to DisjunctionMaxQueries
     */
    SolrPluginUtils.DisjunctionMaxQueryParser up = getParser(queryFields, DisMaxParams.QS, solrParams, tiebreaker);//这个是解析queryFields的queryParser,也即是产生由参数中的查询字符串和qf以及qs(query slope)形成的query的queryParser。
    
    /* for parsing sloppy phrases using DisjunctionMaxQueries */
    SolrPluginUtils.DisjunctionMaxQueryParser pp = getParser(phraseFields, DisMaxParams.PS, solrParams, tiebreaker);//这个和上面的up差不多,只不过他是产生由查询字符串,phraseFields,以及ps(phrase fileds)形成的query的queryParser。
    
    /* * * Main User Query * * */
    parsedUserQuery = null;
    String userQuery = getString();//前台输入的字符串。
    altUserQuery = null;
    if (userQuery == null || userQuery.trim().length() < 1) {// 优先使用q,如果没有则使用q.alt。之后的逻辑和使用userQuery的逻辑一样。
      // If no query is specified, we may have an alternate
      altUserQuery = getAlternateUserQuery(solrParams);
      if (altUserQuery == null) return false;
      query.add(altUserQuery, BooleanClause.Occur.MUST);
    } else {
      // There is a valid query string
      userQuery = SolrPluginUtils.partialEscape(SolrPluginUtils.stripUnbalancedQuotes(userQuery)).toString();//删除不对称的引号(逻辑是如果是奇数个引号,则将引号全部删了),然后过滤特殊字符(比如*、:、!、@、(、{,【,[),只保留" + -。
从这里可以看出,使用*:*是什么也搜不到的,也就是他不支持luceneQParser的普通的功能,仅仅支持+、-两个特殊的字符。
      userQuery = SolrPluginUtils.stripIllegalOperators(userQuery).toString();//删掉过多的+、-
      
      parsedUserQuery = getUserQuery(userQuery, up, solrParams);//用up这个queryParser解析成query,并设置mm这个属性(也就是如果在查询字符串中有用空格分开的字符串的话,对于optional的booleanClause必须要满足的个数),因为可能parsdUserQuery是一个booleanquery
      query.add(parsedUserQuery, BooleanClause.Occur.MUST);//将解析的parsedUserQuery添加到最后的query中,设置为must,即必须出现。
      
      Query phrase = getPhraseQuery(userQuery, pp);//这个和上面的getUserQuery是一样的,只不过没有设置mm的步骤。
      if (null != phrase) {
        query.add(phrase, BooleanClause.Occur.SHOULD);//如果有phrase,则添加到最后的booleanQuery中,设置为optional的,即仅仅用于将那些匹配的document提高得分。
      }
    }
    return true;
  }
 2、addBoostQuery:
  protected void addBoostQuery(BooleanQuery query, SolrParams solrParams) throws SyntaxError {
    boostParams = solrParams.getParams(DisMaxParams.BQ);//从请求参数中获得bq
    boostQueries = null;
    if (boostParams != null && boostParams.length > 0) {
      boostQueries = new ArrayList<>();//最后形成的boost query。
      for (String qs : boostParams) {
        if (qs.trim().length() == 0) continue;
        Query q = subQuery(qs, null).getQuery();//这个是使用默认的queryParser对qs进行解析,解析为一个query,默认的queryParser即QParserPlugin中的LuceneQParserPlugin。
        boostQueries.add(q);//
      }
    }
//下面是将上面形成的boost query添加到最终的booleanquery中去,用于提高命中的document的得分。
    if (null != boostQueries) {
      if (1 == boostQueries.size() && 1 == boostParams.length) {//如果生成的boostquery仅仅有一个子query
        Query f = boostQueries.get(0);
        if (1.0f == f.getBoost() && f instanceof BooleanQuery) {
          /*
           * if the default boost was used, and we've got a BooleanQuery extract the subqueries out and use them
           * directly
           */
          for (Object c : ((BooleanQuery) f).clauses()) {
            query.add((BooleanClause) c);
          }
        } else {
          query.add(f, BooleanClause.Occur.SHOULD);
        }
      } else {
        for (Query f : boostQueries) {
          query.add(f, BooleanClause.Occur.SHOULD);
        }
      }
    }
  }
 3、addFunctionQuery
  protected void addBoostFunctions(BooleanQuery query, SolrParams solrParams) throws SyntaxError {
    String[] boostFuncs = solrParams.getParams(DisMaxParams.BF);//获得bf参数,即函数查询的参数,
    if (null != boostFuncs && 0 != boostFuncs.length) {
      for (String boostFunc : boostFuncs) {
        if (null == boostFunc || "".equals(boostFunc)) continue;
        Map<String,Float> ff = SolrPluginUtils.parseFieldBoosts(boostFunc);
        for (String f : ff.keySet()) {
          Query fq = subQuery(f, FunctionQParserPlugin.NAME).getQuery();//指定了解析器
          Float b = ff.get(f);
          if (null != b) {
            fq.setBoost(b);
          }
          query.add(fq, BooleanClause.Occur.SHOULD);//将解析的query作为一个optional的添加到最终的query中
        }
      }
    }
  }
就这样就看完了dismax,qf,qs是限定要获取的数据的,体现在他在最终的booleanQuery中是must,pf 、ps是用来增加命中的得分的,一般都是将ps设置的比qs大得多,bq也是用来增加命中的document的得分的,bf同样如此。
 

猜你喜欢

转载自suichangkele.iteye.com/blog/2370790