设为首页 收藏本站
查看: 1024|回复: 0

[经验分享] 结合源码分析Solr&Lucene查询打分的工作流程

[复制链接]

尚未签到

发表于 2015-11-12 09:28:01 | 显示全部楼层 |阅读模式
  基于solr4.4
  solr中的搜索打分是在QueryComponent中进行的。
在prepare中根据查询的参数,QueryParser对查询语句进行分词,并生成Query对象树。      QParser parser = QParser.getParser(rb.getQueryString(), defType, req);      Query q = parser.getQuery();      if (q == null) {        // normalize a null query to a query that matches nothing        q = new BooleanQuery();              }  在process方法中,进行搜索打分的过程
  调用SolrIndexSearcher进行查询,
    SolrIndexSearcher searcher = req.getSearcher();    // normal search result    searcher.search(result,cmd);search(Query query, Filter filter, Collector results)  SolrIndexSearcher集成lucene的IndexSearcher类,
最终调用IndexSearcher的search(Query query, Filter filter, Collector results)  public void search(Query query, Filter filter, Collector results)    throws IOException {//在这个方法中,会先创建Weight树,计算TermWeight    search(leafContexts, createNormalizedWeight(wrapFilter(query, filter)), results);  }   protected void search(List<AtomicReaderContext> leaves, Weight weight, Collector collector)      throws IOException { .........//根据weight树,构造Score对象树,以及SumScore对象树,为合并倒排表做准备//      Scorer scorer = weight.scorer(ctx, !collector.acceptsDocsOutOfOrder(), true, ctx.reader().getLiveDocs());      if (scorer != null) {        try {//根据SumScorer对象树,进行文档的合并,收集文档结果结合,并进行打分排名          scorer.score(collector);        } catch (CollectionTerminatedException e) {          // collection was terminated prematurely          // continue with the following leaf        }      }    }  }  1、先看一下Weight对象树的生成,
  这一部分包括query的打分计算,参见红色部分
   DSC0000.jpg
IndexSearcher.createNormalizedWeight(Query query)//重写Query对象树     query = rewrite(query);//创建weight对象树,递归计算idf   DSC0001.jpg     Weight weight = query.createWeight(this);计算Weight分数, DSC0002.jpg     float v = weight.getValueForNormalization();//计算queryNorm DSC0003.jpg     float norm = getSimilarity().queryNorm(v);    if (Float.isInfinite(norm) || Float.isNaN(norm)) {      norm = 1.0f;    }//将queryNorm的计算打分,递归调用weight     weight.normalize(norm, 1.0f); 根据Query对象树,递归的调用query对象节点的createWeight方法比如BooleanQuery对应的是BooleanWeight对象,每个BooleanWeight包含weight对象数组最终叶子节点为TermWeight对象public TermWeight(IndexSearcher searcher, TermContext termStates)      throws IOException {      assert termStates != null : &quot;TermContext must not be null&quot;;      this.termStates = termStates;      this.similarity = searcher.getSimilarity();//计算idf      this.stats = similarity.computeWeight(          getBoost(),           searcher.collectionStatistics(term.field()),           searcher.termStatistics(term, termStates));    }  public final SimWeight computeWeight(float queryBoost, CollectionStatistics collectionStats, TermStatistics... termStats) {    final Explanation idf = termStats.length == 1    ? idfExplain(collectionStats, termStats[0])    : idfExplain(collectionStats, termStats);    return new IDFStats(collectionStats.field(), idf, queryBoost);  }  public Explanation idfExplain(CollectionStatistics collectionStats, TermStatistics termStats) {    final long df = termStats.docFreq();    final long max = collectionStats.maxDoc();    final float idf = idf(df, max);    return new Explanation(idf, &quot;idf(docFreq=&quot; &#43; df &#43; &quot;, maxDocs=&quot; &#43; max &#43; &quot;)&quot;);  } 计算Weight分数    public float getValueForNormalization() throws IOException {      float sum = 0.0f;      for (int i = 0 ; i < weights.size(); i&#43;&#43;) {        // call sumOfSquaredWeights for all clauses in case of side effects        float s = weights.get(i).getValueForNormalization();         // sum sub weights        if (!clauses.get(i).isProhibited())          // only add to sum for non-prohibited clauses          sum &#43;= s;      }      sum *= getBoost() * getBoost();             // boost each sub-weight      return sum ;    }  2、根据weight树,构造Score对象树,以及SumScore对象树,为合并倒排表做准备
Scorer scorer = weight.scorer(ctx, !collector.acceptsDocsOutOfOrder(), true, ctx.reader().getLiveDocs());BooleanWeight递归调用节点weight.score创建score对象   public Scorer scorer(AtomicReaderContext context, boolean scoreDocsInOrder,        boolean topScorer, Bits acceptDocs)        throws IOException {      List<Scorer> required = new ArrayList<Scorer>();      List<Scorer> prohibited = new ArrayList<Scorer>();      List<Scorer> optional = new ArrayList<Scorer>();      Iterator<BooleanClause> cIter = clauses.iterator();      for (Weight w  : weights) {        BooleanClause c =  cIter.next();        Scorer subScorer = w.scorer(context, true, false, acceptDocs);         required.add(subScorer);          return new BooleanScorer2(this, disableCoord, minNrShouldMatch, required, prohibited, optional, maxCoord);       }//在创建BooleanScore2的过程中,计算coordBooleanQuery$BooleanWeight,coord,    public float coord(int overlap, int maxOverlap) {      return maxOverlap == 1 ? 1F : similarity.coord(overlap, maxOverlap);    }//最终调用TermWeight.scorer方法,创建score对象 public Scorer scorer(AtomicReaderContext context, boolean scoreDocsInOrder,        boolean topScorer, Bits acceptDocs) throws IOException {      assert termStates.topReaderContext == ReaderUtil.getTopLevelContext(context) : &quot;The top-reader used to create Weight (&quot; &#43; termStates.topReaderContext &#43; &quot;) is not the same as the current reader's top-reader (&quot; &#43; ReaderUtil.getTopLevelContext(context);      final TermsEnum termsEnum = getTermsEnum(context);      if (termsEnum == null) {        return null;      }//Term对应的docs      DocsEnum docs = termsEnum.docs(acceptDocs, null);      assert docs != null;//TermScorer负责doc的打分      return new TermScorer(this, docs, similarity.simScorer(stats, context));    }   TermScorer(Weight weight, DocsEnum td, Similarity.SimScorer docScorer) {    super(weight);    this.docScorer = docScorer;    this.docsEnum = td;  }  
3、根据SumScorer对象树,进行文档的合并,收集文档结果结合,并进行打分排名          scorer.score(collector);  public void score(Collector collector) throws IOException {    assert docID() == -1; // not started    collector.setScorer(this);    int doc;//在nextDoc的过程中合并document,合并倒排表是按照树的结构进行,先合并子树,子树与子树合并,一直到根    while ((doc = nextDoc()) != NO_MORE_DOCS) {//收集doc,并打分,根据文档的打分,放入优先级队列(最小堆)中      collector.collect(doc);    }  }//整个Score以及SumScorer对象数的打分计算,最终会落到叶子节点TermScorer上TermScorer: @Override  public float score() throws IOException {    assert docID() != NO_MORE_DOCS;    return docScorer.score(docsEnum.docID(), docsEnum.freq());    }
//打分计算公式:tf * norm * weightValue = tf * norm *queryNorm * idf^2 * t.getBoost()TFIDFSimilarity$TFIDFSimScorer    @Override    public float score(int doc, float freq) {//weight是在创建weight阶段的query分词的打分,   //这一部分计算打分公式的蓝色部分,再乘以weight DSC0004.jpg       final float raw = tf(freq) * weightValue; // compute tf(f)*weight,weight=queryNorm * idf^2 * t.getBoost()      return norms == null ? raw : raw * decodeNormValue(norms.get(doc));  // normalize for field, norm部分    }  
  
  
  
  
  
  
  
  
  
         版权声明:本文为博主原创文章,未经博主允许不得转载。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-138190-1-1.html 上篇帖子: Windows下面安装和配置Solr 下篇帖子: SOLR搭建企业搜索平台
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表