private List<String> getTargetIndexNames(final ElasticsearchClient elasticClient, final Long streamId)
            throws LoggedException {
        final String indicesAggregationKey = "indices";
        final String indexNameSourceKey = "index_name";

        final Map<String, CompositeAggregationSource> compositeAggregationSource = Map.of(
                indexNameSourceKey,
                CompositeAggregationSource.of(source -> source
                        .terms(t -> t.field(ElasticIndexConstants.INDEX_NAME))
                )
        );

        // Create a composite aggregation to collect all the unique indices that we need to issue delete requests
        // against
        try {
            List<String> allIndexNames = new ArrayList<>();
            Map<String, FieldValue> afterKey = null;
            int bucketSize = -1;
            while (bucketSize != 0) {
                TermQuery query = TermQuery.of(m -> m
                        .field(ElasticIndexConstants.STREAM_ID)
                        .value(streamId)
                );

                final CompositeAggregation.Builder compositeAggBuilder = AggregationBuilders.composite()
                        .sources(List.of(compositeAggregationSource));
                if (afterKey != null) {
                    compositeAggBuilder.after(afterKey);
                }

                final SearchResponse<Void> response = elasticClient.search(s -> s
                                .index(getIndexBaseName() + "*")
                                .size(ES_COMPOSITE_BATCH_SIZE)
                                .query(query._toQuery())
                                .aggregations(indicesAggregationKey, compositeAggBuilder.build()._toAggregation()),
                        Void.class
                );

                if (response.aggregations() != null && !response.aggregations().isEmpty()) {
                    CompositeAggregate compositeAgg = response.aggregations()
                            .get(indicesAggregationKey)
                            .composite();

                    final List<String> indexNames = compositeAgg.buckets().array()
                            .stream().map(bucket -> bucket.key().get(indexNameSourceKey).stringValue())
                            .toList();
                    allIndexNames.addAll(indexNames);
                    afterKey = compositeAgg.afterKey();
                    bucketSize = indexNames.size();
                } else {
                    // No index exists for this stream, so no deletion necessary
                    return null;
                }
            }
            return allIndexNames;
        } catch (IOException e) {
            fatalError("Failed to list indices for reindex purge. StreamId: " + streamId + ". " +
                       "Base name: '" + indexName + "'", e);
            return null;
        }
    }
Given a StreamId, retrieve a list of names of all indices containing matching documents
stroom-search/stroom-search-elastic/src/main/java/stroom/search/elastic/indexing/ElasticIndexingFilter.java