### 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/QueryToFilterAdapter.java
return searcher;
    }
    /**
     * Make a filter that matches this filter and the provided query.
     * <p>
     * Note: This method rewrites the query against the {@link IndexSearcher}.
     */
    QueryToFilterAdapter union(Query extraQuery) throws IOException {
        /*
         * Wrapping with a ConstantScoreQuery enables a few more rewrite
         * rules as of Lucene 9.2.
         * It'd be *wonderful* if Lucene could do fancy optimizations
         * when merging queries like combining ranges but it doesn't at
         * the moment. Admittedly, we have a much more limited problem.
         * We don't care about score here at all. We know which queries
         * it's worth spending time to optimize because we know which aggs
         * rewrite into this one.
         */
        extraQuery = searcher().rewrite(new ConstantScoreQuery(extraQuery));
        Query unwrappedExtraQuery = unwrap(extraQuery);
        Query unwrappedQuery = unwrap(query);
        if (unwrappedQuery instanceof PointRangeQuery && unwrappedExtraQuery instanceof PointRangeQuery) {
            Query merged = MergedPointRangeQuery.merge((PointRangeQuery) unwrappedQuery, (PointRangeQuery) unwrappedExtraQuery);
            if (merged != null) {
                
                return new QueryToFilterAdapter(searcher(), key(), merged);
            }
        }
        BooleanQuery.Builder builder = new BooleanQuery.Builder();
        builder.add(query, BooleanClause.Occur.FILTER);