diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/370_multi_terms.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/370_multi_terms.yml index 6ea645d97c891..a0e4762ea9b53 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/370_multi_terms.yml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/370_multi_terms.yml @@ -23,6 +23,22 @@ setup: date: type: date + - do: + indices.create: + index: test_2 + body: + settings: + number_of_shards: 2 + number_of_replicas: 0 + mappings: + properties: + str: + type: keyword + integer: + type: long + boolean: + type: boolean + - do: cluster.health: wait_for_status: green @@ -30,7 +46,7 @@ setup: --- "Basic test": - skip: - version: "- 3.0.0" + version: "- 2.9.99" reason: multi_terms aggregation is introduced in 3.0.0 - do: @@ -80,7 +96,7 @@ setup: --- "IP test": - skip: - version: "- 3.0.0" + version: "- 2.9.99" reason: multi_terms aggregation is introduced in 3.0.0 - do: @@ -130,7 +146,7 @@ setup: --- "Boolean test": - skip: - version: "- 3.0.0" + version: "- 2.9.99" reason: multi_terms aggregation is introduced in 3.0.0 - do: @@ -180,7 +196,7 @@ setup: --- "Double test": - skip: - version: "- 3.0.0" + version: "- 2.9.99" reason: multi_terms aggregation is introduced in 3.0.0 - do: @@ -223,7 +239,7 @@ setup: --- "Date test": - skip: - version: "- 3.0.0" + version: "- 2.9.99" reason: multi_terms aggregation is introduced in 3.0.0 - do: @@ -266,7 +282,7 @@ setup: --- "Unmapped keywords": - skip: - version: "- 3.0.0" + version: "- 2.9.99" reason: multi_terms aggregation is introduced in 3.0.0 - do: @@ -306,7 +322,7 @@ setup: --- "Null value": - skip: - version: "- 3.0.0" + version: "- 2.9.99" reason: multi_terms aggregation is introduced in 3.0.0 - do: @@ -341,7 +357,7 @@ setup: --- "multiple multi_terms bucket": - skip: - version: "- 3.0.0" + version: "- 2.9.99" reason: multi_terms aggregation is introduced in 3.0.0 - do: @@ -441,7 +457,7 @@ setup: --- "top 1 ordered by metrics ": - skip: - version: "- 3.0.0" + version: "- 2.9.99" reason: multi_terms aggregation is introduced in 3.0.0 - do: @@ -486,7 +502,7 @@ setup: --- "min_doc_count": - skip: - version: "- 3.0.0" + version: "- 2.9.99" reason: multi_terms aggregation is introduced in 3.0.0 - do: @@ -554,3 +570,51 @@ setup: - match: { aggregations.m_terms.buckets.2.key: ["c", 1] } - match: { aggregations.m_terms.buckets.2.key_as_string: "c|1" } - match: { aggregations.m_terms.buckets.2.doc_count: 0 } + +--- +"sum_other_doc_count": + - skip: + version: "- 2.9.99" + reason: multi_terms aggregation is introduced in 3.0.0 + + - do: + bulk: + index: test_2 + refresh: true + body: + - '{"index": {"routing": "s1"}}' + - '{"str": "a", "integer": 1}' + - '{"index": {"routing": "s1"}}' + - '{"str": "a", "integer": 1}' + - '{"index": {"routing": "s1"}}' + - '{"str": "a", "integer": 1}' + - '{"index": {"routing": "s1"}}' + - '{"str": "a", "integer": 1}' + - '{"index": {"routing": "s2"}}' + - '{"str": "b", "integer": 1}' + - '{"index": {"routing": "s2"}}' + - '{"str": "b", "integer": 1}' + - '{"index": {"routing": "s2"}}' + - '{"str": "b", "integer": 1}' + - '{"index": {"routing": "s2"}}' + - '{"str": "a", "integer": 1}' + + - do: + search: + index: test_2 + size: 0 + body: + aggs: + m_terms: + multi_terms: + size: 1 + shard_size: 1 + terms: + - field: str + - field: integer + + - length: { aggregations.m_terms.buckets: 1 } + - match: { aggregations.m_terms.sum_other_doc_count: 4 } + - match: { aggregations.m_terms.buckets.0.key: ["a", 1] } + - match: { aggregations.m_terms.buckets.0.key_as_string: "a|1" } + - match: { aggregations.m_terms.buckets.0.doc_count: 4 } diff --git a/server/src/main/java/org/opensearch/search/aggregations/bucket/terms/InternalMultiTerms.java b/server/src/main/java/org/opensearch/search/aggregations/bucket/terms/InternalMultiTerms.java index 8de438ebfef06..bc54fec98373a 100644 --- a/server/src/main/java/org/opensearch/search/aggregations/bucket/terms/InternalMultiTerms.java +++ b/server/src/main/java/org/opensearch/search/aggregations/bucket/terms/InternalMultiTerms.java @@ -56,8 +56,8 @@ public static class Bucket extends InternalTerms.AbstractInternalBucket implemen /** * Create default {@link Bucket}. */ - public static Bucket EMPTY(List formats) { - return new Bucket(null, 0, null, false, 0, formats); + public static Bucket EMPTY(boolean showTermDocCountError, List formats) { + return new Bucket(null, 0, null, showTermDocCountError, 0, formats); } public Bucket( diff --git a/server/src/main/java/org/opensearch/search/aggregations/bucket/terms/MultiTermsAggregationFactory.java b/server/src/main/java/org/opensearch/search/aggregations/bucket/terms/MultiTermsAggregationFactory.java index b28b0849ddca4..959707afaf693 100644 --- a/server/src/main/java/org/opensearch/search/aggregations/bucket/terms/MultiTermsAggregationFactory.java +++ b/server/src/main/java/org/opensearch/search/aggregations/bucket/terms/MultiTermsAggregationFactory.java @@ -60,38 +60,25 @@ public static void registerAggregators(ValuesSourceRegistry.Builder builder) { true ); - builder.register(REGISTRY_KEY, org.opensearch.common.collect.List.of(CoreValuesSourceType.NUMERIC), config -> { - ValuesSourceConfig valuesSourceConfig = config.v1(); - IncludeExclude includeExclude = config.v2(); - ValuesSource.Numeric valuesSource = ((ValuesSource.Numeric) valuesSourceConfig.getValuesSource()); - IncludeExclude.LongFilter longFilter = null; - if (valuesSource.isFloatingPoint()) { - if (includeExclude != null) { - longFilter = includeExclude.convertToDoubleFilter(); - } - return MultiTermsAggregator.InternalValuesSourceFactory.doubleValueSource(valuesSource, longFilter); - } else { - if (includeExclude != null) { - longFilter = includeExclude.convertToLongFilter(valuesSourceConfig.format()); - } - return MultiTermsAggregator.InternalValuesSourceFactory.longValuesSource(valuesSource, longFilter); - } - }, true); - - builder.register( - REGISTRY_KEY, - org.opensearch.common.collect.List.of(CoreValuesSourceType.BOOLEAN, CoreValuesSourceType.DATE), + builder.register(REGISTRY_KEY, + org.opensearch.common.collect.List.of(CoreValuesSourceType.NUMERIC, CoreValuesSourceType.BOOLEAN, CoreValuesSourceType.DATE), config -> { ValuesSourceConfig valuesSourceConfig = config.v1(); IncludeExclude includeExclude = config.v2(); ValuesSource.Numeric valuesSource = ((ValuesSource.Numeric) valuesSourceConfig.getValuesSource()); - IncludeExclude.LongFilter longFilter = includeExclude == null - ? null - : includeExclude.convertToLongFilter(valuesSourceConfig.format()); - return MultiTermsAggregator.InternalValuesSourceFactory.longValuesSource(valuesSource, longFilter); - }, - true - ); + IncludeExclude.LongFilter longFilter = null; + if (valuesSource.isFloatingPoint()) { + if (includeExclude != null) { + longFilter = includeExclude.convertToDoubleFilter(); + } + return MultiTermsAggregator.InternalValuesSourceFactory.doubleValueSource(valuesSource, longFilter); + } else { + if (includeExclude != null) { + longFilter = includeExclude.convertToLongFilter(valuesSourceConfig.format()); + } + return MultiTermsAggregator.InternalValuesSourceFactory.longValuesSource(valuesSource, longFilter); + } + }, true); builder.registerUsage(MultiTermsAggregationBuilder.NAME); } diff --git a/server/src/main/java/org/opensearch/search/aggregations/bucket/terms/MultiTermsAggregator.java b/server/src/main/java/org/opensearch/search/aggregations/bucket/terms/MultiTermsAggregator.java index 2667c17eb8976..b4a2191b12bb1 100644 --- a/server/src/main/java/org/opensearch/search/aggregations/bucket/terms/MultiTermsAggregator.java +++ b/server/src/main/java/org/opensearch/search/aggregations/bucket/terms/MultiTermsAggregator.java @@ -125,7 +125,8 @@ public InternalAggregation[] buildAggregations(long[] owningBucketOrds) throws I InternalMultiTerms.Bucket spare = null; BytesRef dest = null; BytesKeyedBucketOrds.BucketOrdsEnum ordsEnum = bucketOrds.ordsEnum(owningBucketOrds[ordIdx]); - CheckedSupplier emptyBucketBuilder = () -> InternalMultiTerms.Bucket.EMPTY(formats); + CheckedSupplier emptyBucketBuilder = + () -> InternalMultiTerms.Bucket.EMPTY(showTermDocCountError, formats); while (ordsEnum.next()) { long docCount = bucketDocCount(ordsEnum.ord()); otherDocCounts[ordIdx] += docCount; diff --git a/server/src/main/java/org/opensearch/search/aggregations/bucket/terms/ParsedTerms.java b/server/src/main/java/org/opensearch/search/aggregations/bucket/terms/ParsedTerms.java index 466df785c87a7..054ea7d827053 100644 --- a/server/src/main/java/org/opensearch/search/aggregations/bucket/terms/ParsedTerms.java +++ b/server/src/main/java/org/opensearch/search/aggregations/bucket/terms/ParsedTerms.java @@ -139,13 +139,16 @@ static B parseTermsBucketXContent( XContentParser.Token token; String currentFieldName = parser.currentName(); while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + // field value could be list, e.g. multi_terms aggregation. + if ((token.isValue() || token == XContentParser.Token.START_ARRAY) + && CommonFields.KEY.getPreferredName().equals(currentFieldName)) { + keyConsumer.accept(parser, bucket); + } if (token == XContentParser.Token.FIELD_NAME) { currentFieldName = parser.currentName(); - } else if (token.isValue() || token == XContentParser.Token.START_ARRAY) { + } else if (token.isValue()) { if (CommonFields.KEY_AS_STRING.getPreferredName().equals(currentFieldName)) { bucket.setKeyAsString(parser.text()); - } else if (CommonFields.KEY.getPreferredName().equals(currentFieldName)) { - keyConsumer.accept(parser, bucket); } else if (CommonFields.DOC_COUNT.getPreferredName().equals(currentFieldName)) { bucket.setDocCount(parser.longValue()); } else if (DOC_COUNT_ERROR_UPPER_BOUND_FIELD_NAME.getPreferredName().equals(currentFieldName)) {