ToParentBlockJoinQuery能够实现,主要依赖索引的结构,也就是需要在索引时,将父子文档一起索引,即在倒排链上父子文档ID是连在一起的,子文档ID在前。

ToParentBlockJoinQuery构建需要给定子文档查询query、父文档的Bit集合,以及ScoreMode,有如下几种打分模式:

  • 命中子文档得分求平均
  • 命中子文档得分最高作为分组得分
  • 命中子文档得分累加
  • 命中子文档得分最低作为分组得分
public ToParentBlockJoinQuery(Query childQuery, BitSetProducer parentsFilter, ScoreMode scoreMode) {
    super();
    this.origChildQuery = childQuery;
    this.childQuery = childQuery;
    this.parentsFilter = parentsFilter;
    this.scoreMode = scoreMode;
  }

核心实现可以见BlockJoinScorer.iterator():

 @Override
 public DocIdSetIterator iterator() {
      return new DocIdSetIterator() {
			//xxxxxxxxx
			//获取父query对应倒排链上下一个父DocID
			parentDoc = parentBits.nextSetBit(nextChildDoc);
			 do {

            //System.out.println("  c=" + nextChildDoc);
            if (pendingChildDocs != null && pendingChildDocs.length == childDocUpto) {
              pendingChildDocs = ArrayUtil.grow(pendingChildDocs);
            }
            if (pendingChildScores != null && scoreMode != ScoreMode.None && pendingChildScores.length == childDocUpto) {
              pendingChildScores = ArrayUtil.grow(pendingChildScores);
            }
            if (pendingChildDocs != null) {
              pendingChildDocs[childDocUpto] = nextChildDoc;
            }
            if (scoreMode != ScoreMode.None) {
              // TODO: specialize this into dedicated classes per-scoreMode
              final float childScore = childScorer.score();
              final int childFreq = childScorer.freq();
              if (pendingChildScores != null) {
                pendingChildScores[childDocUpto] = childScore;
              }
              maxScore = Math.max(childScore, maxScore);
              minScore = Math.min(childScore, minScore);
              totalScore += childScore;
              parentFreq += childFreq;
            }
            childDocUpto++;
            nextChildDoc = childIt.nextDoc();
          } while (nextChildDoc < parentDoc);
					//只要遍历子文档时,DocID小于父文档DocID,那么说明还没有结束当前父子块的遍历
	}