diff --git a/docs/reference/aggregations/metrics/cardinality-aggregation.asciidoc b/docs/reference/aggregations/metrics/cardinality-aggregation.asciidoc index 0dcad9709858..48c45c574ae9 100644 --- a/docs/reference/aggregations/metrics/cardinality-aggregation.asciidoc +++ b/docs/reference/aggregations/metrics/cardinality-aggregation.asciidoc @@ -237,3 +237,24 @@ POST /sales/_search?size=0 -------------------------------------------------- // TEST[setup:sales] <1> Documents without a value in the `tag` field will fall into the same bucket as documents that have the value `N/A`. +==== Execution Hint + +There are different mechanisms by which cardinality aggregations can be executed: + + - by using field values directly (`direct`) + - by using global ordinals of the field and resolving those values after + finishing a shard (`global_ordinals`) + - by using segment ordinal values and resolving those values after each + segment (`segment_ordinals`) + +Additionally, there are two "heuristic based" modes. These modes will cause +Elasticsearch to use some data about the state of the index to choose an +appropriate execution method. The two heuristics are: + - `save_time_heuristic` - this is the default in Elasticsearch 8.4 and later. + - `save_memory_heuristic` - this was the default in Elasticsearch 8.3 and + earlier + +When not specified, Elasticsearch will apply a heuristic to chose the +appropriate mode. Also note that some data (i.e. non-ordinal fields), `direct` +is the only option, and the hint will be ignored in these cases. Generally +speaking, it should not be necessary to set this value. diff --git a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/search.aggregation/170_cardinality_metric.yml b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/search.aggregation/170_cardinality_metric.yml index f35c85034f0b..7f1fc24ef9fb 100644 --- a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/search.aggregation/170_cardinality_metric.yml +++ b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/search.aggregation/170_cardinality_metric.yml @@ -286,3 +286,135 @@ setup: - gt: { profile.shards.0.aggregations.0.breakdown.collect: 0 } - gt: { profile.shards.0.aggregations.0.breakdown.build_aggregation: 0 } - gt: { profile.shards.0.aggregations.0.breakdown.post_collection: 0 } +--- +"profiler string save memory hint": + - skip: + version: " - 8.3.99" + reason: execution hints introduced in 8.4.0 + - do: + search: + body: + profile: true + size: 0 + aggs: + distinct_string: + cardinality: + field: string_field + execution_hint: save_memory_heuristic + - match: { aggregations.distinct_string.value: 1 } + - match: { profile.shards.0.aggregations.0.type: "GlobalOrdCardinalityAggregator" } + - gt: { profile.shards.0.aggregations.0.breakdown.initialize: 0 } + - gt: { profile.shards.0.aggregations.0.breakdown.build_leaf_collector: 0 } + - gt: { profile.shards.0.aggregations.0.breakdown.collect: 0 } + - gt: { profile.shards.0.aggregations.0.breakdown.build_aggregation: 0 } + - gt: { profile.shards.0.aggregations.0.breakdown.post_collection: 0 } +--- +"profiler string save time hint": + - skip: + version: " - 8.3.99" + reason: execution hints introduced in 8.4.0 + - do: + search: + body: + profile: true + size: 0 + aggs: + distinct_string: + cardinality: + field: string_field + execution_hint: save_time_heuristic + - match: { aggregations.distinct_string.value: 1 } + - match: { profile.shards.0.aggregations.0.type: "GlobalOrdCardinalityAggregator" } + - gt: { profile.shards.0.aggregations.0.breakdown.initialize: 0 } + - gt: { profile.shards.0.aggregations.0.breakdown.build_leaf_collector: 0 } + - gt: { profile.shards.0.aggregations.0.breakdown.collect: 0 } + - gt: { profile.shards.0.aggregations.0.breakdown.build_aggregation: 0 } + - gt: { profile.shards.0.aggregations.0.breakdown.post_collection: 0 } +--- +"profiler string global ords hint": + - skip: + version: " - 8.3.99" + reason: execution hints introduced in 8.4.0 + - do: + search: + body: + profile: true + size: 0 + aggs: + distinct_string: + cardinality: + field: string_field + execution_hint: global_ordinals + - match: { aggregations.distinct_string.value: 1 } + - match: { profile.shards.0.aggregations.0.type: "GlobalOrdCardinalityAggregator" } + - gt: { profile.shards.0.aggregations.0.breakdown.initialize: 0 } + - gt: { profile.shards.0.aggregations.0.breakdown.build_leaf_collector: 0 } + - gt: { profile.shards.0.aggregations.0.breakdown.collect: 0 } + - gt: { profile.shards.0.aggregations.0.breakdown.build_aggregation: 0 } + - gt: { profile.shards.0.aggregations.0.breakdown.post_collection: 0 } +--- +"profiler string segment ords hint": + - skip: + version: " - 8.3.99" + reason: execution hints introduced in 8.4.0 + - do: + search: + body: + profile: true + size: 0 + aggs: + distinct_string: + cardinality: + field: string_field + execution_hint: segment_ordinals + - match: { aggregations.distinct_string.value: 1 } + - match: { profile.shards.0.aggregations.0.type: "CardinalityAggregator" } + - gt: { profile.shards.0.aggregations.0.breakdown.initialize: 0 } + - gt: { profile.shards.0.aggregations.0.breakdown.build_leaf_collector: 0 } + - gt: { profile.shards.0.aggregations.0.breakdown.collect: 0 } + - gt: { profile.shards.0.aggregations.0.breakdown.build_aggregation: 0 } + - gt: { profile.shards.0.aggregations.0.breakdown.post_collection: 0 } + - gt: { profile.shards.0.aggregations.0.debug.ordinals_collectors_used: 0 } + - match: { profile.shards.0.aggregations.0.debug.ordinals_collectors_overhead_too_high: 0 } + - match: { profile.shards.0.aggregations.0.debug.string_hashing_collectors_used: 0 } +--- +"profiler string direct hint": + - skip: + version: " - 8.3.99" + reason: execution hints introduced in 8.4.0 + - do: + search: + body: + profile: true + size: 0 + aggs: + distinct_string: + cardinality: + field: string_field + execution_hint: direct + - match: { aggregations.distinct_string.value: 1 } + - match: { profile.shards.0.aggregations.0.type: "CardinalityAggregator" } + - gt: { profile.shards.0.aggregations.0.breakdown.initialize: 0 } + - gt: { profile.shards.0.aggregations.0.breakdown.build_leaf_collector: 0 } + - gt: { profile.shards.0.aggregations.0.breakdown.collect: 0 } + - gt: { profile.shards.0.aggregations.0.breakdown.build_aggregation: 0 } + - gt: { profile.shards.0.aggregations.0.breakdown.post_collection: 0 } + - match: { profile.shards.0.aggregations.0.debug.ordinals_collectors_used: 0 } + - match: { profile.shards.0.aggregations.0.debug.ordinals_collectors_overhead_too_high: 0 } + - gt: { profile.shards.0.aggregations.0.debug.string_hashing_collectors_used: 0 } +--- +"invalid execution hint throws": + - skip: + version: " - 8.3.99" + reason: execution hints introduced in 8.4.0 + - do: + catch: /Invalid execution mode for cardinality aggregation/ + search: + body: + profile: true + size: 0 + aggs: + distinct_string: + cardinality: + field: string_field + execution_hint: bogus diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/TermsAggregatorFactory.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/TermsAggregatorFactory.java index 955bb256266a..904d8b72d70d 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/TermsAggregatorFactory.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/TermsAggregatorFactory.java @@ -108,7 +108,7 @@ public class TermsAggregatorFactory extends ValuesSourceAggregatorFactory { execution = ExecutionMode.fromString(executionHint); } // In some cases, using ordinals is just not supported: override it - if (valuesSource instanceof ValuesSource.Bytes.WithOrdinals == false) { + if (valuesSource.hasOrdinals() == false) { execution = ExecutionMode.MAP; } if (execution == null) { diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/metrics/CardinalityAggregationBuilder.java b/server/src/main/java/org/elasticsearch/search/aggregations/metrics/CardinalityAggregationBuilder.java index 30aff7017866..db3ea3a0f62e 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/metrics/CardinalityAggregationBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/metrics/CardinalityAggregationBuilder.java @@ -39,6 +39,7 @@ public final class CardinalityAggregationBuilder extends ValuesSourceAggregation private static final ParseField REHASH = new ParseField("rehash").withAllDeprecated("no replacement - values will always be rehashed"); public static final ParseField PRECISION_THRESHOLD_FIELD = new ParseField("precision_threshold"); + public static final ParseField EXECUTION_HINT_FIELD_NAME = new ParseField("execution_hint"); public static final ObjectParser PARSER = ObjectParser.fromBuilder( NAME, @@ -48,6 +49,7 @@ public final class CardinalityAggregationBuilder extends ValuesSourceAggregation ValuesSourceAggregationBuilder.declareFields(PARSER, true, false, false); PARSER.declareLong(CardinalityAggregationBuilder::precisionThreshold, CardinalityAggregationBuilder.PRECISION_THRESHOLD_FIELD); PARSER.declareLong((b, v) -> {/*ignore*/}, REHASH); + PARSER.declareString(CardinalityAggregationBuilder::executionHint, EXECUTION_HINT_FIELD_NAME); } public static void registerAggregators(ValuesSourceRegistry.Builder builder) { @@ -56,6 +58,8 @@ public final class CardinalityAggregationBuilder extends ValuesSourceAggregation private Long precisionThreshold = null; + private String executionHint = null; + public CardinalityAggregationBuilder(String name) { super(name); } @@ -67,6 +71,7 @@ public final class CardinalityAggregationBuilder extends ValuesSourceAggregation ) { super(clone, factoriesBuilder, metadata); this.precisionThreshold = clone.precisionThreshold; + this.executionHint = clone.executionHint; } @Override @@ -82,6 +87,9 @@ public final class CardinalityAggregationBuilder extends ValuesSourceAggregation if (in.readBoolean()) { precisionThreshold = in.readLong(); } + if (in.getVersion().onOrAfter(Version.V_8_4_0)) { + executionHint = in.readOptionalString(); + } } @Override @@ -96,6 +104,9 @@ public final class CardinalityAggregationBuilder extends ValuesSourceAggregation if (hasPrecisionThreshold) { out.writeLong(precisionThreshold); } + if (out.getVersion().onOrAfter(Version.V_8_4_0)) { + out.writeOptionalString(executionHint); + } } @Override @@ -126,6 +137,26 @@ public final class CardinalityAggregationBuilder extends ValuesSourceAggregation return precisionThreshold; } + /** + * Get the execution hint. This is an optional user specified hint that + * will be used to decide on the specific collection algorithm. Since this + * is a hint, the implementation may choose to ignore it (typically when + * the specified method is not applicable to the given field type) + */ + public String ExecutionHint() { + return executionHint; + } + + /** + * Set the execution hint. This is an optional user specified hint that + * will be used to decide on the specific collection algorithm. Since this + * is a hint, the implementation may choose to ignore it (typically when + * the specified method is not applicable to the given field type) + */ + public void executionHint(String executionHint) { + this.executionHint = executionHint; + } + @Override protected CardinalityAggregatorFactory innerBuild( AggregationContext context, @@ -139,6 +170,7 @@ public final class CardinalityAggregationBuilder extends ValuesSourceAggregation name, config, precisionThreshold, + executionHint, context, parent, subFactoriesBuilder, @@ -152,12 +184,15 @@ public final class CardinalityAggregationBuilder extends ValuesSourceAggregation if (precisionThreshold != null) { builder.field(PRECISION_THRESHOLD_FIELD.getPreferredName(), precisionThreshold); } + if (executionHint != null) { + builder.field(EXECUTION_HINT_FIELD_NAME.getPreferredName(), executionHint); + } return builder; } @Override public int hashCode() { - return Objects.hash(super.hashCode(), precisionThreshold); + return Objects.hash(super.hashCode(), precisionThreshold, executionHint); } @Override @@ -166,7 +201,7 @@ public final class CardinalityAggregationBuilder extends ValuesSourceAggregation if (obj == null || getClass() != obj.getClass()) return false; if (super.equals(obj) == false) return false; CardinalityAggregationBuilder other = (CardinalityAggregationBuilder) obj; - return Objects.equals(precisionThreshold, other.precisionThreshold); + return Objects.equals(precisionThreshold, other.precisionThreshold) && Objects.equals(executionHint, other.executionHint); } @Override diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/metrics/CardinalityAggregator.java b/server/src/main/java/org/elasticsearch/search/aggregations/metrics/CardinalityAggregator.java index 1b584a3a3f6a..4f5020c9b2f9 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/metrics/CardinalityAggregator.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/metrics/CardinalityAggregator.java @@ -43,6 +43,7 @@ import java.util.function.BiConsumer; public class CardinalityAggregator extends NumericMetricsAggregator.SingleValue { private final int precision; + private final CardinalityAggregatorFactory.ExecutionMode executionMode; private final ValuesSource valuesSource; // Expensive to initialize, so we only initialize it when we have an actual value source @@ -61,6 +62,7 @@ public class CardinalityAggregator extends NumericMetricsAggregator.SingleValue String name, ValuesSourceConfig valuesSourceConfig, int precision, + CardinalityAggregatorFactory.ExecutionMode executionMode, AggregationContext context, Aggregator parent, Map metadata @@ -70,6 +72,7 @@ public class CardinalityAggregator extends NumericMetricsAggregator.SingleValue this.valuesSource = valuesSourceConfig.hasValues() ? valuesSourceConfig.getValuesSource() : null; this.precision = precision; this.counts = valuesSource == null ? null : new HyperLogLogPlusPlus(precision, context.bigArrays(), 1); + this.executionMode = executionMode; } @Override @@ -99,14 +102,15 @@ public class CardinalityAggregator extends NumericMetricsAggregator.SingleValue return new EmptyCollector(); } - final long ordinalsMemoryUsage = OrdinalsCollector.memoryOverhead(maxOrd); - final long countsMemoryUsage = HyperLogLogPlusPlus.memoryUsage(precision); - // only use ordinals if they don't increase memory usage by more than 25% - if (ordinalsMemoryUsage < countsMemoryUsage / 4) { + if (executionMode.useSegmentOrdinals(maxOrd, precision)) { ordinalsCollectorsUsed++; return new OrdinalsCollector(counts, ordinalValues, bigArrays()); } - ordinalsCollectorsOverheadTooHigh++; + + if (executionMode.isHeuristicBased()) { + // if we could have used segment ordinals, and it was our heuristic that made the choice not to, increment the counter + ordinalsCollectorsOverheadTooHigh++; + } } stringHashingCollectorsUsed++; @@ -229,7 +233,7 @@ public class CardinalityAggregator extends NumericMetricsAggregator.SingleValue } - private static class OrdinalsCollector extends Collector { + static class OrdinalsCollector extends Collector { private static final long SHALLOW_FIXEDBITSET_SIZE = RamUsageEstimator.shallowSizeOfInstance(FixedBitSet.class); diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/metrics/CardinalityAggregatorFactory.java b/server/src/main/java/org/elasticsearch/search/aggregations/metrics/CardinalityAggregatorFactory.java index a275a93aaea3..4481254aba36 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/metrics/CardinalityAggregatorFactory.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/metrics/CardinalityAggregatorFactory.java @@ -22,17 +22,118 @@ import org.elasticsearch.search.aggregations.support.ValuesSourceRegistry; import java.io.IOException; import java.util.List; +import java.util.Locale; import java.util.Map; -class CardinalityAggregatorFactory extends ValuesSourceAggregatorFactory { +public class CardinalityAggregatorFactory extends ValuesSourceAggregatorFactory { + + public enum ExecutionMode { + GLOBAL_ORDINALS(false) { + @Override + public boolean useGlobalOrdinals(AggregationContext context, ValuesSource.Bytes.WithOrdinals source, int precision) { + return true; + } + + @Override + public boolean useSegmentOrdinals(long maxOrd, int precision) { + return false; + } + }, + SEGMENT_ORDINALS(false) { + @Override + public boolean useGlobalOrdinals(AggregationContext context, ValuesSource.Bytes.WithOrdinals source, int precision) { + return false; + } + + @Override + public boolean useSegmentOrdinals(long maxOrd, int precision) { + return true; + } + }, + DIRECT(false) { + @Override + public boolean useGlobalOrdinals(AggregationContext context, ValuesSource.Bytes.WithOrdinals source, int precision) { + return false; + } + + @Override + public boolean useSegmentOrdinals(long maxOrd, int precision) { + return false; + } + }, + SAVE_MEMORY_HEURISTIC(true) { + @Override + public boolean useGlobalOrdinals(AggregationContext context, ValuesSource.Bytes.WithOrdinals source, int precision) + throws IOException { + return useGlobalOrds(context, source, precision); + } + + @Override + public boolean useSegmentOrdinals(long maxOrd, int precision) { + final long ordinalsMemoryUsage = CardinalityAggregator.OrdinalsCollector.memoryOverhead(maxOrd); + final long countsMemoryUsage = HyperLogLogPlusPlus.memoryUsage(precision); + // only use ordinals if they don't increase memory usage by more than 25% + if (ordinalsMemoryUsage < countsMemoryUsage / 4) { + return true; + } + return false; + } + }, + SAVE_TIME_HEURISTIC(true) { + @Override + public boolean useGlobalOrdinals(AggregationContext context, ValuesSource.Bytes.WithOrdinals source, int precision) + throws IOException { + return useGlobalOrds(context, source, precision); + } + + @Override + public boolean useSegmentOrdinals(long maxOrd, int precision) { + // Using segment ordinals is much faster than using the direct collector, even when it uses more memory + return true; + } + }; + + public static ExecutionMode fromString(String value) { + if (value == null) { + return null; + } + try { + return ExecutionMode.valueOf(value.toUpperCase(Locale.ROOT)); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException( + "Invalid execution mode for cardinality aggregation. Got [" + + value + + "]" + + "expected one of [global_ordinal, segment_ordinal, direct]" + ); + } + } + + boolean isHeuristicBased; + + ExecutionMode(boolean isHeuristicBased) { + this.isHeuristicBased = isHeuristicBased; + } + + public boolean isHeuristicBased() { + return isHeuristicBased; + } + + public abstract boolean useGlobalOrdinals(AggregationContext context, ValuesSource.Bytes.WithOrdinals source, int precision) + throws IOException; + + public abstract boolean useSegmentOrdinals(long maxOrd, int precision); + } private final Long precisionThreshold; private final CardinalityAggregatorSupplier aggregatorSupplier; + private final ExecutionMode executionMode; CardinalityAggregatorFactory( String name, ValuesSourceConfig config, Long precisionThreshold, + String executionHint, AggregationContext context, AggregatorFactory parent, AggregatorFactories.Builder subFactoriesBuilder, @@ -43,17 +144,19 @@ class CardinalityAggregatorFactory extends ValuesSourceAggregatorFactory { this.aggregatorSupplier = aggregatorSupplier; this.precisionThreshold = precisionThreshold; + // For BWC reasons, the parameter is nullable. + this.executionMode = executionHint == null ? ExecutionMode.SAVE_TIME_HEURISTIC : ExecutionMode.fromString(executionHint); } public static void registerAggregators(ValuesSourceRegistry.Builder builder) { builder.register( CardinalityAggregationBuilder.REGISTRY_KEY, CoreValuesSourceType.ALL_CORE, - (name, valuesSourceConfig, precision, context, parent, metadata) -> { + (name, valuesSourceConfig, precision, executionMode, context, parent, metadata) -> { // check global ords if (valuesSourceConfig.hasValues()) { if (valuesSourceConfig.getValuesSource()instanceof final ValuesSource.Bytes.WithOrdinals source) { - if (useGlobalOrds(context, source, precision)) { + if (executionMode.useGlobalOrdinals(context, source, precision)) { final long maxOrd = source.globalMaxOrd(context.searcher()); return new GlobalOrdCardinalityAggregator( name, @@ -68,7 +171,7 @@ class CardinalityAggregatorFactory extends ValuesSourceAggregatorFactory { } } // fallback in the default aggregator - return new CardinalityAggregator(name, valuesSourceConfig, precision, context, parent, metadata); + return new CardinalityAggregator(name, valuesSourceConfig, precision, executionMode, context, parent, metadata); }, true ); @@ -91,13 +194,13 @@ class CardinalityAggregatorFactory extends ValuesSourceAggregatorFactory { @Override protected Aggregator createUnmapped(Aggregator parent, Map metadata) throws IOException { - return new CardinalityAggregator(name, config, precision(), context, parent, metadata); + return new CardinalityAggregator(name, config, precision(), null, context, parent, metadata); } @Override protected Aggregator doCreateInternal(Aggregator parent, CardinalityUpperBound cardinality, Map metadata) throws IOException { - return aggregatorSupplier.build(name, config, precision(), context, parent, metadata); + return aggregatorSupplier.build(name, config, precision(), executionMode, context, parent, metadata); } private int precision() { diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/metrics/CardinalityAggregatorSupplier.java b/server/src/main/java/org/elasticsearch/search/aggregations/metrics/CardinalityAggregatorSupplier.java index c664ad8ae7e2..54051de7f811 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/metrics/CardinalityAggregatorSupplier.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/metrics/CardinalityAggregatorSupplier.java @@ -20,6 +20,7 @@ public interface CardinalityAggregatorSupplier { String name, ValuesSourceConfig valuesSourceConfig, int precision, + CardinalityAggregatorFactory.ExecutionMode executionMode, AggregationContext context, Aggregator parent, Map metadata diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/metrics/CardinalityAggregatorTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/metrics/CardinalityAggregatorTests.java index 63b4a423afe2..e4ae38fcaed5 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/metrics/CardinalityAggregatorTests.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/metrics/CardinalityAggregatorTests.java @@ -56,6 +56,7 @@ import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.function.Consumer; @@ -669,12 +670,16 @@ public class CardinalityAggregatorTests extends AggregatorTestCase { } private void testAggregation( - AggregationBuilder aggregationBuilder, + CardinalityAggregationBuilder aggregationBuilder, Query query, CheckedConsumer buildIndex, Consumer verify, MappedFieldType... fieldTypes ) throws IOException { testCase(aggregationBuilder, query, buildIndex, verify, fieldTypes); + for (CardinalityAggregatorFactory.ExecutionMode mode : CardinalityAggregatorFactory.ExecutionMode.values()) { + aggregationBuilder.executionHint(mode.toString().toLowerCase(Locale.ROOT)); + testCase(aggregationBuilder, query, buildIndex, verify, fieldTypes); + } } } diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/metrics/CardinalityTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/metrics/CardinalityTests.java index c86035d8d520..9e4ad42a5fb6 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/metrics/CardinalityTests.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/metrics/CardinalityTests.java @@ -10,6 +10,8 @@ package org.elasticsearch.search.aggregations.metrics; import org.elasticsearch.search.aggregations.BaseAggregationTestCase; +import java.util.List; + public class CardinalityTests extends BaseAggregationTestCase { @Override @@ -20,6 +22,11 @@ public class CardinalityTests extends BaseAggregationTestCase new CardinalityAggregator( + name, + valuesSourceConfig, + precision, + // Force execution mode to null + null, + context, + parent, + metadata + ), + true + ); } private ContextParser checkLicense(ContextParser realParser, LicensedFeature.Momentary feature) { diff --git a/x-pack/qa/runtime-fields/build.gradle b/x-pack/qa/runtime-fields/build.gradle index a066d7460307..41bdd762b127 100644 --- a/x-pack/qa/runtime-fields/build.gradle +++ b/x-pack/qa/runtime-fields/build.gradle @@ -95,6 +95,11 @@ subprojects { 'search.aggregation/20_terms/string profiler via global ordinals native implementation', 'search.aggregation/20_terms/Global ordinals are loaded with the global_ordinals execution hint', 'search.aggregation/170_cardinality_metric/profiler string', + 'search.aggregation/170_cardinality_metric/profiler string segment ords hint', + 'search.aggregation/170_cardinality_metric/profiler string global ords hint', + 'search.aggregation/170_cardinality_metric/profiler string direct hint', + 'search.aggregation/170_cardinality_metric/profiler string save memory hint', + 'search.aggregation/170_cardinality_metric/profiler string save time hint', 'search.aggregation/235_composite_sorted/*', // timeseries dimensions can't be runtime fields 'search.aggregation/450_time_series/*',