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,那么说明还没有结束当前父子块的遍历
}