### 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/FiltersAggregator.java
return filters;
    }
    @Override
    public InternalAggregation[] buildAggregations(long[] owningBucketOrds) throws IOException {
        return buildAggregationsForFixedBucketCount(
            owningBucketOrds,
            filters.size() + (otherBucketKey == null ? 0 : 1),
            (offsetInOwningOrd, docCount, subAggregationResults) -> {
                if (offsetInOwningOrd < filters.size()) {
                    return new InternalFilters.InternalBucket(
                        filters.get(offsetInOwningOrd).key().toString(),
                        docCount,
                        subAggregationResults,
                        keyed,
                        keyedBucket
                    );
                }
                return new InternalFilters.InternalBucket(otherBucketKey, docCount, subAggregationResults, keyed, keyedBucket);
            },
            buckets -> new InternalFilters(name, buckets, keyed, keyedBucket, metadata())
        );
    }
    @Override
    public InternalAggregation buildEmptyAggregation() {
        InternalAggregations subAggs = buildEmptySubAggregations();
        List<InternalFilters.InternalBucket> buckets = new ArrayList<>(filters.size() + (otherBucketKey == null ? 0 : 1));
        for (QueryToFilterAdapter filter : filters) {
            InternalFilters.InternalBucket bucket = new InternalFilters.InternalBucket(
                filter.key().toString(),
                0,