diff --git a/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinCollector.java b/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinCollector.java
index f81b943..d70b040 100644
--- a/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinCollector.java
+++ b/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinCollector.java
@@ -271,7 +271,7 @@ public class ToParentBlockJoinCollector implements Collector {
       }
       
       // Pulls out child doc and scores for all join queries:
-      private void copyGroups(OneGroup og) {
+      private void copyGroups(OneGroup og) throws IOException {
         // While rare, it's possible top arrays could be too
         // short if join query had null scorer on first
         // segment(s) but then became non-null on later segments
@@ -293,8 +293,8 @@ public class ToParentBlockJoinCollector implements Collector {
         for(int scorerIDX = 0;scorerIDX < numSubScorers;scorerIDX++) {
           final ToParentBlockJoinQuery.BlockJoinScorer joinScorer = joinScorers[scorerIDX];
           //System.out.println("  scorer=" + joinScorer);
-          if (joinScorer != null && docBase + joinScorer.getParentDoc() == og.doc) {
-            og.counts[scorerIDX] = joinScorer.getChildCount();
+          if (joinScorer != null && docBase + joinScorer.docID() == og.doc) {
+            og.counts[scorerIDX] = joinScorer.freq();
             //System.out.println("    count=" + og.counts[scorerIDX]);
             og.docs[scorerIDX] = joinScorer.swapChildDocs(og.docs[scorerIDX]);
             assert og.docs[scorerIDX].length >= og.counts[scorerIDX]: "length=" + og.docs[scorerIDX].length + " vs count=" + og.counts[scorerIDX];
diff --git a/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinQuery.java
index 432ebcc..93254b7 100644
--- a/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinQuery.java
+++ b/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinQuery.java
@@ -17,18 +17,19 @@
 package org.apache.lucene.search.join;
 
 import java.io.IOException;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.Locale;
+
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexWriter;
 import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.search.FilterWeight;
 import org.apache.lucene.search.DocIdSetIterator;
 import org.apache.lucene.search.Explanation;
+import org.apache.lucene.search.FilterWeight;
 import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.Scorer;
+import org.apache.lucene.search.ScorerSupplier;
+import org.apache.lucene.search.TwoPhaseIterator;
 import org.apache.lucene.search.Weight;
 import org.apache.lucene.search.grouping.TopGroups;
 import org.apache.lucene.util.ArrayUtil;
@@ -90,7 +91,7 @@ public class ToParentBlockJoinQuery extends Query {
   private final ScoreMode scoreMode;
 
   /** Create a ToParentBlockJoinQuery.
-   * 
+   *
    * @param childQuery Query matching child documents.
    * @param parentsFilter Filter identifying the parent documents.
    * @param scoreMode How to aggregate multiple child scores
@@ -116,7 +117,7 @@ public class ToParentBlockJoinQuery extends Query {
   public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException {
     return new BlockJoinWeight(this, childQuery.createWeight(searcher, needsScores, boost), parentsFilter, needsScores ? scoreMode : ScoreMode.None);
   }
-  
+
   /** Return our child query. */
   public Query getChildQuery() {
     return childQuery;
@@ -132,324 +133,330 @@ public class ToParentBlockJoinQuery extends Query {
       this.scoreMode = scoreMode;
     }
 
-    // NOTE: acceptDocs applies (and is checked) only in the
-    // parent document space
     @Override
-    public Scorer scorer(LeafReaderContext readerContext) throws IOException {
-
-      final Scorer childScorer = in.scorer(readerContext);
+    public ScorerSupplier scorerSupplier(LeafReaderContext context) throws IOException {
+      final Scorer childScorer = in.scorer(context);
       if (childScorer == null) {
         // No matches
         return null;
       }
 
-      final int firstChildDoc = childScorer.iterator().nextDoc();
-      if (firstChildDoc == DocIdSetIterator.NO_MORE_DOCS) {
+      final BitSet parents = parentsFilter.getBitSet(context);
+
+      if (parents == null) {
         // No matches
         return null;
       }
 
-      // NOTE: this does not take accept docs into account, the responsibility
-      // to not match deleted docs is on the scorer
-      final BitSet parents = parentsFilter.getBitSet(readerContext);
+      return new ScorerSupplier() {
 
-      if (parents == null) {
-        // No matches
+        @Override
+        public Scorer get(boolean randomAccess) throws IOException {
+          return new BlockJoinScorer(BlockJoinWeight.this, childScorer, parents, scoreMode);
+        }
+
+        @Override
+        public long cost() {
+          return childScorer.iterator().cost();
+        }
+      };
+    }
+
+    @Override
+    public Scorer scorer(LeafReaderContext context) throws IOException {
+      ScorerSupplier scorerSupplier = scorerSupplier(context);
+      if (scorerSupplier == null) {
         return null;
       }
-
-      return new BlockJoinScorer(this, childScorer, parents, firstChildDoc, scoreMode);
+      return scorerSupplier.get(false);
     }
 
     @Override
     public Explanation explain(LeafReaderContext context, int doc) throws IOException {
-      BlockJoinScorer scorer = (BlockJoinScorer) scorer(context);
-      if (scorer != null && scorer.iterator().advance(doc) == doc) {
-        return scorer.explain(context, in);
+      final Scorer childScorer = in.scorer(context);
+      if (childScorer == null) {
+        return Explanation.noMatch("Null child scorer");
+      }
+
+      final BitSet parents = parentsFilter.getBitSet(context);
+      if (parents == null) {
+        return Explanation.noMatch("No parents");
+      }
+
+      if (parents.get(doc) == false) {
+        return Explanation.noMatch("Document is not a parent document");
+      }
+
+      final int firstChildTarget = doc == 0 ? 0 : parents.prevSetBit(doc - 1) + 1;
+      DocIdSetIterator childIterator = childScorer.iterator();
+      final int firstChildDoc = childIterator.advance(firstChildTarget);
+      if (firstChildDoc >= doc) {
+        return Explanation.noMatch("No child documents matched");
       }
-      return Explanation.noMatch("Not a match");
+
+      Explanation bestMatch = null;
+      int freq2 = 0;
+      for (int childDoc = firstChildDoc; childDoc < doc; childDoc = childIterator.nextDoc()) {
+        Explanation childExpl = in.explain(context, childIterator.docID());
+        if (bestMatch == null || childExpl.getValue() > bestMatch.getValue()) {
+          bestMatch = childExpl;
+        }
+        ++freq2;
+      }
+
+      Scorer scorer = scorer(context);
+      scorer.iterator().advance(doc);
+      assert scorer.docID() == doc;
+      final float score = scorer.score();
+      final int freq = scorer.freq();
+      assert freq == freq2;
+      return Explanation.match(score, String.format(Locale.ROOT,
+          "Score based on %d child docs in range from %d to %d, best match:",
+          freq, context.docBase + firstChildTarget, context.docBase + doc - 1),
+          bestMatch);
     }
   }
-  
-  /** 
-   * Ascendant for {@link ToParentBlockJoinQuery}'s scorer. 
+
+  /**
+   * Ascendant for {@link ToParentBlockJoinQuery}'s scorer.
    * @lucene.experimental it might be removed at <b>6.0</b>
    * */
   public static abstract class ChildrenMatchesScorer extends Scorer{
-    
+
     /** inherited constructor */
     protected ChildrenMatchesScorer(Weight weight) {
       super(weight);
     }
-    
-    /** 
-     * enables children matches recording 
-     * */
-    public abstract void trackPendingChildHits() ;
-    
+
     /**
-     * reports matched children 
-     * @return number of recorded matched children docs 
+     * enables children matches recording
      * */
-    public abstract int getChildCount() ;
-    
+    public abstract void trackPendingChildHits() ;
+
     /**
-     * reports matched children 
+     * reports matched children
      * @param other array for recording matching children docs of next parent,
-     * it might be null (that's slower) or the same array which was returned 
+     * it might be null (that's slower) or the same array which was returned
      * from the previous call
-     * @return array with {@link #getChildCount()} matched children docnums
+     * @return array with {@link #freq()} matched children docnums
      *  */
     public abstract int[] swapChildDocs(int[] other);
   }
-  
-  static class BlockJoinScorer extends ChildrenMatchesScorer {
-    private final Scorer childScorer;
+
+  private static class ParentApproximation extends DocIdSetIterator {
+
+    private final DocIdSetIterator childApproximation;
     private final BitSet parentBits;
-    private final ScoreMode scoreMode;
-    private int parentDoc = -1;
-    private int prevParentDoc;
-    private float parentScore;
-    private int parentFreq;
-    private int nextChildDoc;
-    private int[] pendingChildDocs;
-    private float[] pendingChildScores;
-    private int childDocUpto;
-
-    public BlockJoinScorer(Weight weight, Scorer childScorer, BitSet parentBits, int firstChildDoc, ScoreMode scoreMode) {
-      super(weight);
-      //System.out.println("Q.init firstChildDoc=" + firstChildDoc);
+    private int doc = -1;
+
+    ParentApproximation(DocIdSetIterator childApproximation, BitSet parentBits) {
+      this.childApproximation = childApproximation;
       this.parentBits = parentBits;
-      this.childScorer = childScorer;
-      this.scoreMode = scoreMode;
-      nextChildDoc = firstChildDoc;
     }
 
     @Override
-    public Collection<ChildScorer> getChildren() {
-      return Collections.singleton(new ChildScorer(childScorer, "BLOCK_JOIN"));
+    public int docID() {
+      return doc;
     }
 
     @Override
-    public int getChildCount() {
-      return childDocUpto;
-    }
-
-    int getParentDoc() {
-      return parentDoc;
+    public int nextDoc() throws IOException {
+      return advance(doc + 1);
     }
 
     @Override
-    public int[] swapChildDocs(int[] other) {
-      final int[] ret = pendingChildDocs;
-      if (other == null) {
-        pendingChildDocs = new int[5];
-      } else {
-        pendingChildDocs = other;
+    public int advance(int target) throws IOException {
+      if (target >= parentBits.length()) {
+        return doc = NO_MORE_DOCS;
       }
-      return ret;
-    }
 
-    float[] swapChildScores(float[] other) {
-      if (scoreMode == ScoreMode.None) {
-        throw new IllegalStateException("ScoreMode is None; you must pass trackScores=false to ToParentBlockJoinCollector");
+      final int firstChildTarget = target == 0 ? 0 : parentBits.prevSetBit(target - 1) + 1;
+      int childDoc = childApproximation.docID();
+      if (childDoc < firstChildTarget) {
+        childDoc = childApproximation.advance(firstChildTarget);
       }
-      final float[] ret = pendingChildScores;
-      if (other == null) {
-        pendingChildScores = new float[5];
-      } else {
-        pendingChildScores = other;
+
+      if (childDoc == NO_MORE_DOCS) {
+        return doc = NO_MORE_DOCS;
       }
-      return ret;
+      return doc = parentBits.nextSetBit(childDoc + 1);
     }
 
     @Override
-    public DocIdSetIterator iterator() {
-      return new DocIdSetIterator() {
-        final DocIdSetIterator childIt = childScorer.iterator();
-
-        @Override
-        public int nextDoc() throws IOException {
-          //System.out.println("Q.nextDoc() nextChildDoc=" + nextChildDoc);
-          if (nextChildDoc == NO_MORE_DOCS) {
-            //System.out.println("  end");
-            return parentDoc = NO_MORE_DOCS;
-          }
-
-          // Gather all children sharing the same parent as
-          // nextChildDoc
-
-          parentDoc = parentBits.nextSetBit(nextChildDoc);
-
-          // Parent & child docs are supposed to be
-          // orthogonal:
-          checkOrthogonal(nextChildDoc, parentDoc);
+    public long cost() {
+      return childApproximation.cost();
+    }
 
-          //System.out.println("  parentDoc=" + parentDoc);
-          assert parentDoc != DocIdSetIterator.NO_MORE_DOCS;
+  }
 
-          float totalScore = 0;
-          float maxScore = Float.NEGATIVE_INFINITY;
-          float minScore = Float.POSITIVE_INFINITY;
+  private static class ParentTwoPhase extends TwoPhaseIterator {
 
-          childDocUpto = 0;
-          parentFreq = 0;
-          do {
+    private final ParentApproximation parentApproximation;
+    private final DocIdSetIterator childApproximation;
+    private final TwoPhaseIterator childTwoPhase;
 
-            //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);
-
-          // Parent & child docs are supposed to be
-          // orthogonal:
-          checkOrthogonal(nextChildDoc, parentDoc);
-
-          switch(scoreMode) {
-          case Avg:
-            parentScore = totalScore / childDocUpto;
-            break;
-          case Max:
-            parentScore = maxScore;
-            break;
-          case Min:
-            parentScore = minScore;
-            break;
-          case Total:
-            parentScore = totalScore;
-            break;
-          case None:
-            break;
-          }
+    ParentTwoPhase(ParentApproximation parentApproximation, DocIdSetIterator childApproximation,
+        TwoPhaseIterator childTwoPhase) {
+      super(parentApproximation);
+      this.parentApproximation = parentApproximation;
+      this.childApproximation = childApproximation;
+      this.childTwoPhase = childTwoPhase;
+    }
 
-          //System.out.println("  return parentDoc=" + parentDoc + " childDocUpto=" + childDocUpto);
-          return parentDoc;
+    @Override
+    public boolean matches() throws IOException {
+      assert childApproximation.docID() < parentApproximation.docID();
+      do {
+        if (childTwoPhase == null || childTwoPhase.matches()) {
+          return true;
         }
+      } while (childApproximation.nextDoc() < parentApproximation.docID());
+      return false;
+    }
 
-        @Override
-        public int advance(int parentTarget) throws IOException {
+    @Override
+    public float matchCost() {
+      // TODO: how could we compute a match cost?
+      return (childTwoPhase == null ? 0 : childTwoPhase.matchCost()) + 10;
+    }
 
-          //System.out.println("Q.advance parentTarget=" + parentTarget);
-          if (parentTarget == NO_MORE_DOCS) {
-            return parentDoc = NO_MORE_DOCS;
-          }
+  }
 
-          if (parentTarget == 0) {
-            // Callers should only be passing in a docID from
-            // the parent space, so this means this parent
-            // has no children (it got docID 0), so it cannot
-            // possibly match.  We must handle this case
-            // separately otherwise we pass invalid -1 to
-            // prevSetBit below:
-            return nextDoc();
-          }
+  static class BlockJoinScorer extends ChildrenMatchesScorer {
 
-          prevParentDoc = parentBits.prevSetBit(parentTarget-1);
+    final Scorer childScorer;
+    final DocIdSetIterator childApproximation;
+    final TwoPhaseIterator childTwoPhase;
+    final BitSet parentBits;
+    final ParentApproximation parentApproximation;
+    final ParentTwoPhase iterator;
+    final ScoreMode scoreMode;
+    float score;
+    int freq;
+
+    // for ToParentBlockJoinCollector
+    // TODO: remove?
+    int[] pendingChildDocs;
+    float[] pendingChildScores;
+
+    BlockJoinScorer(BlockJoinWeight weight, Scorer childScorer, BitSet parentBits, ScoreMode scoreMode) {
+      super(weight);
+      this.childScorer = childScorer;
+      this.parentBits = parentBits;
+      this.childTwoPhase = childScorer.twoPhaseIterator();
+      this.childApproximation = childTwoPhase == null ? childScorer.iterator() : childTwoPhase.approximation();
+      this.parentApproximation = new ParentApproximation(childApproximation, parentBits);
+      this.iterator = new ParentTwoPhase(parentApproximation, childApproximation, childTwoPhase);
+      this.scoreMode = scoreMode;
+    }
 
-          //System.out.println("  rolled back to prevParentDoc=" + prevParentDoc + " vs parentDoc=" + parentDoc);
-          assert prevParentDoc >= parentDoc;
-          if (prevParentDoc > nextChildDoc) {
-            nextChildDoc = childIt.advance(prevParentDoc);
-            // System.out.println("  childScorer advanced to child docID=" + nextChildDoc);
-          //} else {
-            //System.out.println("  skip childScorer advance");
-          }
+    @Override
+    public DocIdSetIterator iterator() {
+      return TwoPhaseIterator.asDocIdSetIterator(iterator);
+    }
 
-          // Parent & child docs are supposed to be orthogonal:
-          checkOrthogonal(nextChildDoc, prevParentDoc);
+    @Override
+    public TwoPhaseIterator twoPhaseIterator() {
+      return iterator;
+    }
 
-          final int nd = nextDoc();
-          //System.out.println("  return nextParentDoc=" + nd);
-          return nd;
-        }
+    private void setScoreAndFreq() throws IOException {
+      if (childApproximation.docID() >= parentApproximation.docID()) {
+        return;
+      }
 
-        @Override
-        public int docID() {
-          return parentDoc;
+      double score = scoreMode == ScoreMode.None ? 0 : childScorer.score();
+      if (pendingChildDocs != null) {
+        pendingChildDocs[0] = childApproximation.docID();
+        if (pendingChildScores != null) {
+          pendingChildScores[0] = (float) score;
         }
-
-        @Override
-        public long cost() {
-          return childIt.cost();
+      }
+      int freq = 1;
+      while (childApproximation.nextDoc() < parentApproximation.docID()) {
+        if (childTwoPhase == null || childTwoPhase.matches()) {
+          final float childScore = childScorer.score();
+          if (pendingChildDocs != null) {
+            pendingChildDocs = ArrayUtil.grow(pendingChildDocs, freq + 1);
+            pendingChildDocs[freq] = childApproximation.docID();
+            if (pendingChildScores != null) {
+              pendingChildScores = ArrayUtil.grow(pendingChildScores, freq + 1);
+              pendingChildScores[freq] = childScore;
+            }
+          }
+          freq += 1;
+          switch (scoreMode) {
+            case Total:
+            case Avg:
+              score += childScore;
+              break;
+            case Min:
+              score = Math.min(score, childScore);
+              break;
+            case Max:
+              score = Math.min(score, childScore);
+              break;
+            case None:
+              break;
+            default:
+              throw new AssertionError();
+          }
         }
-      };
-    }
-
-    private void checkOrthogonal(int childDoc, int parentDoc) {
-      if (childDoc==parentDoc) {
-        throw new IllegalStateException("Child query must not match same docs with parent filter. "
-             + "Combine them as must clauses (+) to find a problem doc. "
-             + "docId=" + nextChildDoc + ", " + childScorer.getClass());
-        
       }
+      if (scoreMode == ScoreMode.Avg) {
+        score /= freq;
+      }
+      this.score = (float) score;
+      this.freq = freq;
     }
 
     @Override
     public int docID() {
-      return parentDoc;
+      return parentApproximation.docID();
     }
 
     @Override
     public float score() throws IOException {
-      return parentScore;
+      setScoreAndFreq();
+      return score;
     }
-    
+
     @Override
-    public int freq() {
-      return parentFreq;
+    public int freq() throws IOException {
+      setScoreAndFreq();
+      return freq;
     }
 
-    public Explanation explain(LeafReaderContext context, Weight childWeight) throws IOException {
-      int start = context.docBase + prevParentDoc + 1; // +1 b/c prevParentDoc is previous parent doc
-      int end = context.docBase + parentDoc - 1; // -1 b/c parentDoc is parent doc
-
-      Explanation bestChild = null;
-      int matches = 0;
-      for (int childDoc = start; childDoc <= end; childDoc++) {
-        Explanation child = childWeight.explain(context, childDoc - context.docBase);
-        if (child.isMatch()) {
-          matches++;
-          if (bestChild == null || child.getValue() > bestChild.getValue()) {
-            bestChild = child;
-          }
-        }
+    @Override
+    public void trackPendingChildHits() {
+      pendingChildDocs = new int[1];
+      if (scoreMode != ScoreMode.None) {
+        pendingChildScores = new float[1];
       }
-
-      return Explanation.match(score(), String.format(Locale.ROOT,
-          "Score based on %d child docs in range from %d to %d, best match:", matches, start, end), bestChild
-      );
     }
 
-    /**
-     * Instructs this scorer to keep track of the child docIds and score ids for retrieval purposes.
-     */
     @Override
-    public void trackPendingChildHits() {
-      pendingChildDocs = new int[5];
-      if (scoreMode != ScoreMode.None) {
+    public int[] swapChildDocs(int[] other) {
+      final int[] ret = pendingChildDocs;
+      if (other == null) {
+        pendingChildDocs = new int[5];
+      } else {
+        pendingChildDocs = ArrayUtil.grow(other, 1);
+      }
+      return ret;
+    }
+
+    float[] swapChildScores(float[] other) {
+      if (scoreMode == ScoreMode.None) {
+        throw new IllegalStateException("ScoreMode is None; you must pass trackScores=false to ToParentBlockJoinCollector");
+      }
+      final float[] ret = pendingChildScores;
+      if (other == null) {
         pendingChildScores = new float[5];
+      } else {
+        pendingChildScores = ArrayUtil.grow(other, 1);
       }
+      return ret;
     }
   }
 
diff --git a/lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoin.java b/lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoin.java
index cf21fa4..532a206 100644
--- a/lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoin.java
+++ b/lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoin.java
@@ -764,7 +764,7 @@ public class TestBlockJoin extends LuceneTestCase {
         System.out.println("TEST: iter=" + (1+iter) + " of " + iters);
       }
 
-      final Query childQuery;
+      Query childQuery;
       if (random().nextInt(3) == 2) {
         final int childFieldID = random().nextInt(childFields.length);
         childQuery = new TermQuery(new Term("child" + childFieldID,
@@ -799,6 +799,9 @@ public class TestBlockJoin extends LuceneTestCase {
                random().nextBoolean() ? BooleanClause.Occur.MUST : BooleanClause.Occur.MUST_NOT);
         childQuery = bq.build();
       }
+      if (random().nextBoolean()) {
+        childQuery = new RandomApproximationQuery(childQuery, random());
+      }
 
 
       final ScoreMode agg = ScoreMode.values()[random().nextInt(ScoreMode.values().length)];
diff --git a/lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoinValidation.java b/lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoinValidation.java
index aa68d09..db37165 100644
--- a/lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoinValidation.java
+++ b/lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoinValidation.java
@@ -78,34 +78,6 @@ public class TestBlockJoinValidation extends LuceneTestCase {
     super.tearDown();
   }
 
-  public void testNextDocValidationForToParentBjq() throws Exception {
-    Query parentQueryWithRandomChild = createChildrenQueryWithOneParent(getRandomChildNumber(0));
-    ToParentBlockJoinQuery blockJoinQuery = new ToParentBlockJoinQuery(parentQueryWithRandomChild, parentsFilter, ScoreMode.None);
-    IllegalStateException expected = expectThrows(IllegalStateException.class, () -> {
-      indexSearcher.search(blockJoinQuery, 1);
-    });
-    assertTrue(expected.getMessage() != null && expected.getMessage().contains("Child query must not match same docs with parent filter"));
-  }
-
-  public void testAdvanceValidationForToParentBjq() throws Exception {
-    int randomChildNumber = getRandomChildNumber(0);
-    // we need to make advance method meet wrong document, so random child number
-    // in BJQ must be greater than child number in Boolean clause
-    int nextRandomChildNumber = getRandomChildNumber(randomChildNumber);
-    Query parentQueryWithRandomChild = createChildrenQueryWithOneParent(nextRandomChildNumber);
-    ToParentBlockJoinQuery blockJoinQuery = new ToParentBlockJoinQuery(parentQueryWithRandomChild, parentsFilter, ScoreMode.None);
-    // advance() method is used by ConjunctionScorer, so we need to create Boolean conjunction query
-    BooleanQuery.Builder conjunctionQuery = new BooleanQuery.Builder();
-    WildcardQuery childQuery = new WildcardQuery(new Term("child", createFieldValue(randomChildNumber)));
-    conjunctionQuery.add(new BooleanClause(childQuery, BooleanClause.Occur.MUST));
-    conjunctionQuery.add(new BooleanClause(blockJoinQuery, BooleanClause.Occur.MUST));
-    
-    IllegalStateException expected = expectThrows(IllegalStateException.class, () -> {
-      indexSearcher.search(conjunctionQuery.build(), 1);
-    });
-    assertTrue(expected.getMessage() != null && expected.getMessage().contains("Child query must not match same docs with parent filter"));
-  }
-
   public void testNextDocValidationForToChildBjq() throws Exception {
     Query parentQueryWithRandomChild = createParentsQueryWithOneChild(getRandomChildNumber(0));
 
diff --git a/solr/core/src/java/org/apache/solr/search/join/BlockJoinFacetAccsHolder.java b/solr/core/src/java/org/apache/solr/search/join/BlockJoinFacetAccsHolder.java
index 00b3ac4..09d2f13 100644
--- a/solr/core/src/java/org/apache/solr/search/join/BlockJoinFacetAccsHolder.java
+++ b/solr/core/src/java/org/apache/solr/search/join/BlockJoinFacetAccsHolder.java
@@ -65,8 +65,8 @@ class BlockJoinFacetAccsHolder {
     final int[] docNums = blockJoinScorer.swapChildDocs(childDocs);
     // now we don't
     //includeParentDoc(parent);
-    //final int childCountPlusParent = childTracking.getChildCount()+1;
-    final int childCountNoParent = blockJoinScorer.getChildCount();
+    //final int childCountPlusParent = childTracking.freq()+1;
+    final int childCountNoParent = blockJoinScorer.freq();
     final SortedIntsAggDocIterator iter = new SortedIntsAggDocIterator(docNums, childCountNoParent, parent);
     countFacets(iter);
   }
