### Description

We have had this longstanding issue that running a top-level `filter` aggregation is often (not always, e.g. not if you need the total hit count too) a performance bug, as Elasticsearch would iterate over docs that match the `query` and would then check each of these docs against the filter of the `filter` aggregation. It's usually a better idea to put the filter directly into the query, where it can be used to drive iteration if appropriate.

We could do this automatically by implementing the `LeafCollector#competitiveIterator` API that was introduced for dynamic pruning, in order to automatically start intersecting the query with the filter of the `filter` aggregator once enough hits have been counted.
server/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/FilterByFilterAggregator.java
LeafBucketCollector subCollector = sub;
            int filterOrd;
            @Override
            public void collect(int docId) throws IOException {
                collectBucket(subCollector, docId, filterOrd);
            }
            @Override
            public void setScorer(Scorable scorer) throws IOException {}
        }
        MatchCollector collector = new MatchCollector();
        filters().get(0).collect(aggCtx.getLeafReaderContext(), collector, live);
        for (int filterOrd = 1; filterOrd < filters().size(); filterOrd++) {
            collector.subCollector = collectableSubAggregators.getLeafCollector(aggCtx);
            collector.filterOrd = filterOrd;
            filters().get(filterOrd).collect(aggCtx.getLeafReaderContext(), collector, live);
        }
    }
    @Override
    public void collectDebugInfo(BiConsumer<String, Object> add) {
        super.collectDebugInfo(add);
        add.accept("segments_counted", segmentsCounted);
        add.accept("segments_collected", segmentsCollected);
        add.accept("segments_with_deleted_docs", segmentsWithDeletedDocs);
        add.accept("segments_with_doc_count_field", segmentsWithDocCountField);
    }
}