From cbaa675357c5e7b2fe739346ea7709038ef8e754 Mon Sep 17 00:00:00 2001 From: Vacha Shah Date: Thu, 2 May 2024 00:27:52 +0000 Subject: [PATCH 1/4] Fixing composite aggregations with correct parameters Signed-off-by: Vacha Shah --- .../CompositeAggregationSource.java | 67 ++--- ...mpositeDateHistogramAggregationSource.java | 192 ++++++++++++ ...CompositeGeoTileGridAggregationSource.java | 150 ++++++++++ .../CompositeHistogramAggregationSource.java | 107 +++++++ .../CompositeTermsAggregationSource.java | 84 ++++++ .../aggregations/CompositeValuesSource.java | 278 ++++++++++++++++++ .../integTest/AbstractSearchRequestIT.java | 20 ++ 7 files changed, 865 insertions(+), 33 deletions(-) create mode 100644 java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeDateHistogramAggregationSource.java create mode 100644 java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeGeoTileGridAggregationSource.java create mode 100644 java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeHistogramAggregationSource.java create mode 100644 java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeTermsAggregationSource.java create mode 100644 java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeValuesSource.java diff --git a/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeAggregationSource.java b/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeAggregationSource.java index 00ab5deca8..5d11e2b4f9 100644 --- a/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeAggregationSource.java +++ b/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeAggregationSource.java @@ -49,18 +49,16 @@ @JsonpDeserializable public class CompositeAggregationSource implements JsonpSerializable { @Nullable - private final TermsAggregation terms; + private final CompositeTermsAggregationSource terms; @Nullable - private final HistogramAggregation histogram; + private final CompositeHistogramAggregationSource histogram; @Nullable - private final DateHistogramAggregation dateHistogram; + private final CompositeDateHistogramAggregationSource dateHistogram; @Nullable - private final GeoTileGridAggregation geotileGrid; - - // --------------------------------------------------------------------------------------------- + private final CompositeGeoTileGridAggregationSource geotileGrid; private CompositeAggregationSource(Builder builder) { @@ -79,7 +77,7 @@ public static CompositeAggregationSource of(Function { @Nullable - private TermsAggregation terms; + private CompositeTermsAggregationSource terms; @Nullable - private HistogramAggregation histogram; + private CompositeHistogramAggregationSource histogram; @Nullable - private DateHistogramAggregation dateHistogram; + private CompositeDateHistogramAggregationSource dateHistogram; @Nullable - private GeoTileGridAggregation geotileGrid; + private CompositeGeoTileGridAggregationSource geotileGrid; /** * API name: {@code terms} */ - public final Builder terms(@Nullable TermsAggregation value) { + public final Builder terms(@Nullable CompositeTermsAggregationSource value) { this.terms = value; return this; } @@ -171,14 +167,14 @@ public final Builder terms(@Nullable TermsAggregation value) { /** * API name: {@code terms} */ - public final Builder terms(Function> fn) { - return this.terms(fn.apply(new TermsAggregation.Builder()).build()); + public final Builder terms(Function> fn) { + return this.terms(fn.apply(new CompositeTermsAggregationSource.Builder()).build()); } /** * API name: {@code histogram} */ - public final Builder histogram(@Nullable HistogramAggregation value) { + public final Builder histogram(@Nullable CompositeHistogramAggregationSource value) { this.histogram = value; return this; } @@ -186,14 +182,16 @@ public final Builder histogram(@Nullable HistogramAggregation value) { /** * API name: {@code histogram} */ - public final Builder histogram(Function> fn) { - return this.histogram(fn.apply(new HistogramAggregation.Builder()).build()); + public final Builder histogram( + Function> fn + ) { + return this.histogram(fn.apply(new CompositeHistogramAggregationSource.Builder()).build()); } /** * API name: {@code date_histogram} */ - public final Builder dateHistogram(@Nullable DateHistogramAggregation value) { + public final Builder dateHistogram(@Nullable CompositeDateHistogramAggregationSource value) { this.dateHistogram = value; return this; } @@ -201,14 +199,16 @@ public final Builder dateHistogram(@Nullable DateHistogramAggregation value) { /** * API name: {@code date_histogram} */ - public final Builder dateHistogram(Function> fn) { - return this.dateHistogram(fn.apply(new DateHistogramAggregation.Builder()).build()); + public final Builder dateHistogram( + Function> fn + ) { + return this.dateHistogram(fn.apply(new CompositeDateHistogramAggregationSource.Builder()).build()); } /** * API name: {@code geotile_grid} */ - public final Builder geotileGrid(@Nullable GeoTileGridAggregation value) { + public final Builder geotileGrid(@Nullable CompositeGeoTileGridAggregationSource value) { this.geotileGrid = value; return this; } @@ -216,8 +216,10 @@ public final Builder geotileGrid(@Nullable GeoTileGridAggregation value) { /** * API name: {@code geotile_grid} */ - public final Builder geotileGrid(Function> fn) { - return this.geotileGrid(fn.apply(new GeoTileGridAggregation.Builder()).build()); + public final Builder geotileGrid( + Function> fn + ) { + return this.geotileGrid(fn.apply(new CompositeGeoTileGridAggregationSource.Builder()).build()); } /** @@ -245,11 +247,10 @@ public CompositeAggregationSource build() { protected static void setupCompositeAggregationSourceDeserializer(ObjectDeserializer op) { - op.add(Builder::terms, TermsAggregation._DESERIALIZER, "terms"); - op.add(Builder::histogram, HistogramAggregation._DESERIALIZER, "histogram"); - op.add(Builder::dateHistogram, DateHistogramAggregation._DESERIALIZER, "date_histogram"); - op.add(Builder::geotileGrid, GeoTileGridAggregation._DESERIALIZER, "geotile_grid"); - + op.add(Builder::terms, CompositeTermsAggregationSource._DESERIALIZER, "terms"); + op.add(Builder::histogram, CompositeHistogramAggregationSource._DESERIALIZER, "histogram"); + op.add(Builder::dateHistogram, CompositeDateHistogramAggregationSource._DESERIALIZER, "date_histogram"); + op.add(Builder::geotileGrid, CompositeGeoTileGridAggregationSource._DESERIALIZER, "geotile_grid"); } } diff --git a/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeDateHistogramAggregationSource.java b/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeDateHistogramAggregationSource.java new file mode 100644 index 0000000000..c3f30a900f --- /dev/null +++ b/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeDateHistogramAggregationSource.java @@ -0,0 +1,192 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.client.opensearch._types.aggregations; + +import jakarta.json.stream.JsonGenerator; +import java.util.function.Function; +import javax.annotation.Nullable; +import org.opensearch.client.json.JsonpDeserializer; +import org.opensearch.client.json.JsonpMapper; +import org.opensearch.client.json.ObjectBuilderDeserializer; +import org.opensearch.client.json.ObjectDeserializer; +import org.opensearch.client.opensearch._types.Time; +import org.opensearch.client.util.ObjectBuilder; + +public class CompositeDateHistogramAggregationSource extends CompositeValuesSource { + + @Nullable + private final Time calendarInterval; + + @Nullable + private final Time fixedInterval; + + private final long offset; + + private final String zoneId; + + private CompositeDateHistogramAggregationSource(Builder builder) { + super(builder); + this.calendarInterval = builder.calendarInterval; + this.fixedInterval = builder.fixedInterval; + this.offset = builder.offset; + this.zoneId = builder.zoneId; + } + + public static CompositeDateHistogramAggregationSource of(Function> fn) { + return fn.apply(new Builder()).build(); + } + + /** + * API name: {@code calendar_interval} + */ + @Nullable + public final Time calendarInterval() { + return this.calendarInterval; + } + + /** + * API name: {@code fixed_interval} + */ + @Nullable + public final Time fixedInterval() { + return this.fixedInterval; + } + + /** + * Required - API name: {@code offset} + */ + public final long offset() { + return this.offset; + + } + + /** + * Required - API name: {@code zone_id} + */ + public final String zoneId() { + return this.zoneId; + } + + /** + * Serialize this object to JSON. + */ + @Override + public void serialize(JsonGenerator generator, JsonpMapper mapper) { + generator.writeStartObject(); + serializeInternal(generator, mapper); + generator.writeEnd(); + } + + protected void serializeInternal(JsonGenerator generator, JsonpMapper mapper) { + super.serializeInternal(generator, mapper); + if (this.calendarInterval != null) { + generator.writeKey("calendar_interval"); + this.calendarInterval.serialize(generator, mapper); + + } + if (this.fixedInterval != null) { + generator.writeKey("fixed_interval"); + this.fixedInterval.serialize(generator, mapper); + + } + generator.writeKey("offset"); + generator.write(this.offset); + + generator.writeKey("zone_id"); + generator.write(this.zoneId); + } + + /** + * Builder for {@link CompositeDateHistogramAggregationSource}. + */ + + public static class Builder extends CompositeValuesSource.AbstractBuilder + implements + ObjectBuilder { + + @Nullable + private Time calendarInterval; + + @Nullable + private Time fixedInterval; + + private long offset; + + private String zoneId; + + /** + * API name: {@code calendar_interval} + */ + public final Builder calendarInterval(@Nullable Time value) { + this.calendarInterval = value; + return this; + } + + /** + * API name: {@code fixed_interval} + */ + public final Builder fixedInterval(@Nullable Time value) { + this.fixedInterval = value; + return this; + } + + /** + * Required - API name: {@code offset} + */ + public final Builder offset(long value) { + this.offset = value; + return this; + } + + /** + * Required - API name: {@code zone_id} + */ + + public final Builder zoneId(String value) { + this.zoneId = value; + return this; + } + + /** + * Builds a {@link CompositeDateHistogramAggregationSource}. + * + * @throws NullPointerException + * if some of the required fields are null. + */ + public CompositeDateHistogramAggregationSource build() { + _checkSingleUse(); + + return new CompositeDateHistogramAggregationSource(this); + } + + @Override + protected Builder self() { + return this; + } + } + + /** + * Json deserializer for {@link CompositeDateHistogramAggregationSource} + */ + public static final JsonpDeserializer _DESERIALIZER = ObjectBuilderDeserializer.lazy( + Builder::new, + CompositeDateHistogramAggregationSource::setupCompositeDateHistogramAggregationSourceDeserializer + ); + + protected static void setupCompositeDateHistogramAggregationSourceDeserializer( + ObjectDeserializer op + ) { + CompositeValuesSource.setupCompositeValuesSourceDeserializer(op); + op.add(Builder::calendarInterval, Time._DESERIALIZER, "calendar_interval"); + op.add(Builder::fixedInterval, Time._DESERIALIZER, "fixed_interval"); + op.add(Builder::offset, JsonpDeserializer.longDeserializer(), "offset"); + op.add(Builder::zoneId, JsonpDeserializer.stringDeserializer(), "time_zone"); + } + +} diff --git a/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeGeoTileGridAggregationSource.java b/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeGeoTileGridAggregationSource.java new file mode 100644 index 0000000000..fa035e9d80 --- /dev/null +++ b/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeGeoTileGridAggregationSource.java @@ -0,0 +1,150 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.client.opensearch._types.aggregations; + +import jakarta.json.stream.JsonGenerator; +import java.util.function.Function; +import javax.annotation.Nullable; +import org.opensearch.client.json.JsonpDeserializable; +import org.opensearch.client.json.JsonpDeserializer; +import org.opensearch.client.json.JsonpMapper; +import org.opensearch.client.json.ObjectBuilderDeserializer; +import org.opensearch.client.json.ObjectDeserializer; +import org.opensearch.client.opensearch._types.GeoBounds; +import org.opensearch.client.util.ObjectBuilder; + +@JsonpDeserializable +public class CompositeGeoTileGridAggregationSource extends CompositeValuesSource { + + @Nullable + private final Integer precision; + + @Nullable + private final GeoBounds geoBounds; + + private CompositeGeoTileGridAggregationSource(Builder builder) { + super(builder); + this.precision = builder.precision; + this.geoBounds = builder.geoBounds; + } + + public static CompositeGeoTileGridAggregationSource of(Function> fn) { + return fn.apply(new Builder()).build(); + } + + /** + * API name: {@code precision} + */ + @Nullable + public final Integer precision() { + return this.precision; + } + + /** + * API name: {@code geoBounds} + */ + @Nullable + public final GeoBounds geoBounds() { + return this.geoBounds; + } + + /** + * Serialize this object to JSON. + */ + @Override + public void serialize(JsonGenerator generator, JsonpMapper mapper) { + generator.writeStartObject(); + serializeInternal(generator, mapper); + generator.writeEnd(); + } + + protected void serializeInternal(JsonGenerator generator, JsonpMapper mapper) { + super.serializeInternal(generator, mapper); + if (this.precision != null) { + generator.writeKey("precision"); + generator.write(this.precision); + } + if (this.geoBounds != null) { + generator.writeKey("bounds"); + this.geoBounds.serialize(generator, mapper); + + } + } + + /** + * Builder for {@link CompositeGeoTileGridAggregationSource}. + */ + + public static class Builder extends CompositeValuesSource.AbstractBuilder + implements + ObjectBuilder { + @Nullable + private Integer precision; + + @Nullable + private GeoBounds geoBounds; + + /** + * API name: {@code precision} + */ + public final Builder precision(@Nullable Integer precision) { + this.precision = precision; + return this; + } + + /** + * API name: {@code geoBounds} + */ + public final Builder geoBounds(@Nullable GeoBounds geoBounds) { + this.geoBounds = geoBounds; + return this; + } + + /** + * API name: {@code geoBounds} + */ + public final Builder geoBounds(Function> fn) { + return this.geoBounds(fn.apply(new GeoBounds.Builder()).build()); + } + + /** + * Builds a {@link CompositeGeoTileGridAggregationSource}. + * + * @throws NullPointerException + * if some of the required fields are null. + */ + public CompositeGeoTileGridAggregationSource build() { + _checkSingleUse(); + + return new CompositeGeoTileGridAggregationSource(this); + } + + @Override + protected Builder self() { + return this; + } + } + + /** + * Json deserializer for {@link CompositeGeoTileGridAggregationSource} + */ + public static final JsonpDeserializer _DESERIALIZER = ObjectBuilderDeserializer.lazy( + Builder::new, + CompositeGeoTileGridAggregationSource::setupCompositeGeoTileGridAggregationSourceDeserializer + ); + + protected static void setupCompositeGeoTileGridAggregationSourceDeserializer( + ObjectDeserializer op + ) { + CompositeValuesSource.setupCompositeValuesSourceDeserializer(op); + op.add(Builder::precision, JsonpDeserializer.integerDeserializer(), "precision"); + op.add(Builder::geoBounds, GeoBounds._DESERIALIZER, "bounds"); + } + +} diff --git a/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeHistogramAggregationSource.java b/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeHistogramAggregationSource.java new file mode 100644 index 0000000000..acd2cb80e1 --- /dev/null +++ b/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeHistogramAggregationSource.java @@ -0,0 +1,107 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.client.opensearch._types.aggregations; + +import jakarta.json.stream.JsonGenerator; +import java.util.function.Function; +import org.opensearch.client.json.JsonpDeserializable; +import org.opensearch.client.json.JsonpDeserializer; +import org.opensearch.client.json.JsonpMapper; +import org.opensearch.client.json.ObjectBuilderDeserializer; +import org.opensearch.client.json.ObjectDeserializer; +import org.opensearch.client.util.ObjectBuilder; + +@JsonpDeserializable +public class CompositeHistogramAggregationSource extends CompositeValuesSource { + + private final double interval; + + private CompositeHistogramAggregationSource(Builder builder) { + super(builder); + this.interval = builder.interval; + } + + public static CompositeHistogramAggregationSource of(Function> fn) { + return fn.apply(new Builder()).build(); + } + + /** + * Required - API name: {@code interval} + */ + public final double interval() { + return this.interval; + } + + /** + * Serialize this object to JSON. + */ + @Override + public void serialize(JsonGenerator generator, JsonpMapper mapper) { + generator.writeStartObject(); + serializeInternal(generator, mapper); + generator.writeEnd(); + } + + protected void serializeInternal(JsonGenerator generator, JsonpMapper mapper) { + super.serializeInternal(generator, mapper); + generator.writeKey("interval"); + generator.write(this.interval); + } + + /** + * Builder for {@link CompositeHistogramAggregationSource}. + */ + + public static class Builder extends CompositeValuesSource.AbstractBuilder + implements + ObjectBuilder { + private double interval; + + /** + * Required - API name: {@code interval} + */ + public final Builder interval(double interval) { + this.interval = interval; + return this; + } + + /** + * Builds a {@link CompositeHistogramAggregationSource}. + * + * @throws NullPointerException + * if some of the required fields are null. + */ + public CompositeHistogramAggregationSource build() { + _checkSingleUse(); + + return new CompositeHistogramAggregationSource(this); + } + + @Override + protected Builder self() { + return this; + } + } + + /** + * Json deserializer for {@link CompositeHistogramAggregationSource} + */ + public static final JsonpDeserializer _DESERIALIZER = ObjectBuilderDeserializer.lazy( + Builder::new, + CompositeHistogramAggregationSource::setupCompositeHistogramAggregationSourceDeserializer + ); + + protected static void setupCompositeHistogramAggregationSourceDeserializer( + ObjectDeserializer op + ) { + CompositeValuesSource.setupCompositeValuesSourceDeserializer(op); + op.add(Builder::interval, JsonpDeserializer.doubleDeserializer(), "interval"); + } + +} diff --git a/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeTermsAggregationSource.java b/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeTermsAggregationSource.java new file mode 100644 index 0000000000..891f6618d7 --- /dev/null +++ b/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeTermsAggregationSource.java @@ -0,0 +1,84 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.client.opensearch._types.aggregations; + +import jakarta.json.stream.JsonGenerator; +import java.util.function.Function; +import org.opensearch.client.json.JsonpDeserializable; +import org.opensearch.client.json.JsonpDeserializer; +import org.opensearch.client.json.JsonpMapper; +import org.opensearch.client.json.ObjectBuilderDeserializer; +import org.opensearch.client.json.ObjectDeserializer; +import org.opensearch.client.util.ObjectBuilder; + +@JsonpDeserializable +public class CompositeTermsAggregationSource extends CompositeValuesSource { + + private CompositeTermsAggregationSource(Builder builder) { + super(builder); + } + + public static CompositeTermsAggregationSource of(Function> fn) { + return fn.apply(new Builder()).build(); + } + + /** + * Serialize this object to JSON. + */ + @Override + public void serialize(JsonGenerator generator, JsonpMapper mapper) { + generator.writeStartObject(); + serializeInternal(generator, mapper); + generator.writeEnd(); + } + + protected void serializeInternal(JsonGenerator generator, JsonpMapper mapper) { + super.serializeInternal(generator, mapper); + } + + /** + * Builder for {@link CompositeTermsAggregationSource}. + */ + public static class Builder extends CompositeValuesSource.AbstractBuilder + implements + ObjectBuilder { + + /** + * Builds a {@link CompositeTermsAggregationSource}. + * + * @throws NullPointerException + * if some of the required fields are null. + */ + public CompositeTermsAggregationSource build() { + _checkSingleUse(); + + return new CompositeTermsAggregationSource(this); + } + + @Override + protected Builder self() { + return this; + } + } + + /** + * Json deserializer for {@link CompositeTermsAggregationSource} + */ + public static final JsonpDeserializer _DESERIALIZER = ObjectBuilderDeserializer.lazy( + Builder::new, + CompositeTermsAggregationSource::setupCompositeGeoTileGridAggregationSourceDeserializer + ); + + protected static void setupCompositeGeoTileGridAggregationSourceDeserializer( + ObjectDeserializer op + ) { + CompositeValuesSource.setupCompositeValuesSourceDeserializer(op); + } + +} diff --git a/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeValuesSource.java b/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeValuesSource.java new file mode 100644 index 0000000000..6b40580c30 --- /dev/null +++ b/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeValuesSource.java @@ -0,0 +1,278 @@ +package org.opensearch.client.opensearch._types.aggregations; + +import jakarta.json.stream.JsonGenerator; +import java.util.function.Function; +import javax.annotation.Nullable; +import org.opensearch.client.json.JsonpDeserializer; +import org.opensearch.client.json.JsonpMapper; +import org.opensearch.client.json.JsonpSerializable; +import org.opensearch.client.json.ObjectDeserializer; +import org.opensearch.client.opensearch._types.Script; +import org.opensearch.client.opensearch._types.SortOrder; +import org.opensearch.client.util.ApiTypeHelper; +import org.opensearch.client.util.ObjectBuilder; +import org.opensearch.client.util.ObjectBuilderBase; + +public abstract class CompositeValuesSource implements JsonpSerializable { + + private final String name; + + @Nullable + private final String field; + + @Nullable + private final Script script; + + @Nullable + private final ValueType valueType; + + @Nullable + private Boolean missingBucket; + + @Nullable + private MissingOrder missingOrder; + + @Nullable + private SortOrder order; + + @Nullable + private String format; + + protected CompositeValuesSource(AbstractBuilder builder) { + this.name = ApiTypeHelper.requireNonNull(builder.name, this, "name"); + ; + this.field = builder.field; + this.script = builder.script; + this.valueType = builder.valueType; + this.missingBucket = builder.missingBucket; + this.missingOrder = builder.missingOrder; + this.order = builder.order; + this.format = builder.format; + } + + /** + * API name: {@code name} + */ + public final String name() { + return this.name; + } + + /** + * API name: {@code field} + */ + @Nullable + public final String field() { + return this.field; + } + + /** + * API name: {@code script} + */ + @Nullable + public final Script script() { + return this.script; + } + + /** + * API name: {@code date_histogram} + */ + @Nullable + public final ValueType valueType() { + return this.valueType; + } + + /** + * API name: {@code missingBucket} + */ + @Nullable + public final Boolean missingBucket() { + return this.missingBucket; + } + + /** + * API name: {@code missingOrder} + */ + @Nullable + public final MissingOrder missingOrder() { + return this.missingOrder; + } + + /** + * API name: {@code order} + */ + @Nullable + public final SortOrder order() { + return this.order; + } + + /** + * API name: {@code format} + */ + @Nullable + public final String format() { + return this.format; + } + + /** + * Serialize this object to JSON. + */ + public void serialize(JsonGenerator generator, JsonpMapper mapper) { + generator.writeStartObject(); + serializeInternal(generator, mapper); + generator.writeEnd(); + } + + protected void serializeInternal(JsonGenerator generator, JsonpMapper mapper) { + generator.writeKey(this.name); + generator.write(this.name); + + if (this.field != null) { + generator.writeKey("field"); + generator.write(this.field); + } + + if (this.script != null) { + generator.writeKey("script"); + this.script.serialize(generator, mapper); + + } + if (this.valueType != null) { + generator.writeKey("value_type"); + this.valueType.serialize(generator, mapper); + + } + if (this.missingBucket != null) { + generator.writeKey("missing_bucket"); + generator.write(this.missingBucket); + } + if (this.missingOrder != null) { + generator.writeKey("missing_order"); + this.missingOrder.serialize(generator, mapper); + } + if (this.order != null) { + generator.writeKey("order"); + this.order.serialize(generator, mapper); + } + if (this.format != null) { + generator.writeKey("format"); + generator.write(this.format); + } + } + + /** + * Builder for {@link CompositeValuesSource}. + */ + + protected abstract static class AbstractBuilder> extends ObjectBuilderBase { + + private String name; + + @Nullable + private String field; + + @Nullable + private Script script; + + @Nullable + private ValueType valueType; + + @Nullable + private Boolean missingBucket; + + @Nullable + private MissingOrder missingOrder; + + @Nullable + private SortOrder order; + + @Nullable + private String format; + + /** + * Required - API name: {@code name} + */ + public final BuilderT name(String name) { + this.name = name; + return self(); + } + + /** + * API name: {@code field} + */ + public final BuilderT field(@Nullable String field) { + this.field = field; + return self(); + } + + /** + * API name: {@code script} + */ + public final BuilderT script(@Nullable Script script) { + this.script = script; + return self(); + } + + /** + * API name: {@code script} + */ + public final BuilderT script(Function> fn) { + return this.script(fn.apply(new Script.Builder()).build()); + } + + /** + * API name: {@code valueType} + */ + public final BuilderT valueType(@Nullable ValueType valueType) { + this.valueType = valueType; + return self(); + } + + /** + * API name: {@code missingBucket} + */ + public final BuilderT missingBucket(@Nullable Boolean missingBucket) { + this.missingBucket = missingBucket; + return self(); + } + + /** + * API name: {@code missingOrder} + */ + public final BuilderT missingOrder(@Nullable MissingOrder missingOrder) { + this.missingOrder = missingOrder; + return self(); + } + + /** + * API name: {@code order} + */ + public final BuilderT order(@Nullable SortOrder order) { + this.order = order; + return self(); + } + + /** + * API name: {@code format} + */ + public final BuilderT format(@Nullable String format) { + this.format = format; + return self(); + } + + protected abstract BuilderT self(); + } + + protected static > void setupCompositeValuesSourceDeserializer( + ObjectDeserializer op + ) { + op.add(AbstractBuilder::name, JsonpDeserializer.stringDeserializer(), "name"); + op.add(AbstractBuilder::field, JsonpDeserializer.stringDeserializer(), "field"); + op.add(AbstractBuilder::script, Script._DESERIALIZER, "script"); + op.add(AbstractBuilder::valueType, ValueType._DESERIALIZER, "value_type"); + op.add(AbstractBuilder::missingBucket, JsonpDeserializer.booleanDeserializer(), "missing_bucket"); + op.add(AbstractBuilder::missingOrder, MissingOrder._DESERIALIZER, "missing_order"); + op.add(AbstractBuilder::order, SortOrder._DESERIALIZER, "order"); + op.add(AbstractBuilder::format, JsonpDeserializer.stringDeserializer(), "format"); + } + +} diff --git a/java-client/src/test/java11/org/opensearch/client/opensearch/integTest/AbstractSearchRequestIT.java b/java-client/src/test/java11/org/opensearch/client/opensearch/integTest/AbstractSearchRequestIT.java index a34584f9f9..c9de30465a 100644 --- a/java-client/src/test/java11/org/opensearch/client/opensearch/integTest/AbstractSearchRequestIT.java +++ b/java-client/src/test/java11/org/opensearch/client/opensearch/integTest/AbstractSearchRequestIT.java @@ -10,12 +10,15 @@ import java.io.IOException; import java.util.Arrays; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.junit.Test; import org.opensearch.Version; import org.opensearch.client.opensearch._types.FieldValue; import org.opensearch.client.opensearch._types.SortOrder; +import org.opensearch.client.opensearch._types.aggregations.Aggregation; +import org.opensearch.client.opensearch._types.aggregations.CompositeAggregationSource; import org.opensearch.client.opensearch._types.mapping.Property; import org.opensearch.client.opensearch._types.query_dsl.MatchQuery; import org.opensearch.client.opensearch._types.query_dsl.Query; @@ -62,6 +65,23 @@ public void shouldReturnSearchResults() throws Exception { ); } + @Test + public void shouldReturnSearchResultsWithCompositeAgg() throws Exception { + final String index = "search_request"; + createIndex(index); + + CompositeAggregationSource terms = CompositeAggregationSource.of( + t -> t.terms(t1 -> t1.field("size").order(SortOrder.Asc).name(index)) + ); + final Aggregation avgSize = Aggregation.of(a -> a.composite(c -> c.sources(List.of(Map.of("composite-agg", terms))))); + final SearchRequest request = SearchRequest.of( + r -> r.index(index).query(b -> b.matchAll(QueryBuilders.matchAll().build())).aggregations("composite-agg", avgSize) + ); + + final SearchResponse response = javaClient().search(request, ShopItem.class); + assertEquals(response.hits().hits().size(), 8); + } + @Test public void hybridSearchShouldReturnSearchResults() throws Exception { assumeTrue("Hybrid search is supported from 2.10.0", getServerVersion().onOrAfter(Version.V_2_10_0)); From 7767c2ca1ebdfacff2dd1822c0ce5af65ed92b2d Mon Sep 17 00:00:00 2001 From: Vacha Shah Date: Thu, 2 May 2024 04:36:19 +0000 Subject: [PATCH 2/4] Adding tests Signed-off-by: Vacha Shah --- .../integTest/AbstractSearchRequestIT.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/java-client/src/test/java11/org/opensearch/client/opensearch/integTest/AbstractSearchRequestIT.java b/java-client/src/test/java11/org/opensearch/client/opensearch/integTest/AbstractSearchRequestIT.java index c9de30465a..463d2d9d04 100644 --- a/java-client/src/test/java11/org/opensearch/client/opensearch/integTest/AbstractSearchRequestIT.java +++ b/java-client/src/test/java11/org/opensearch/client/opensearch/integTest/AbstractSearchRequestIT.java @@ -10,7 +10,6 @@ import java.io.IOException; import java.util.Arrays; -import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.junit.Test; @@ -18,8 +17,10 @@ import org.opensearch.client.opensearch._types.FieldValue; import org.opensearch.client.opensearch._types.SortOrder; import org.opensearch.client.opensearch._types.aggregations.Aggregation; +import org.opensearch.client.opensearch._types.aggregations.AggregationBuilders; import org.opensearch.client.opensearch._types.aggregations.CompositeAggregationSource; import org.opensearch.client.opensearch._types.mapping.Property; +import org.opensearch.client.opensearch._types.query_dsl.BoolQuery; import org.opensearch.client.opensearch._types.query_dsl.MatchQuery; import org.opensearch.client.opensearch._types.query_dsl.Query; import org.opensearch.client.opensearch._types.query_dsl.QueryBuilders; @@ -70,12 +71,18 @@ public void shouldReturnSearchResultsWithCompositeAgg() throws Exception { final String index = "search_request"; createIndex(index); - CompositeAggregationSource terms = CompositeAggregationSource.of( - t -> t.terms(t1 -> t1.field("size").order(SortOrder.Asc).name(index)) - ); - final Aggregation avgSize = Aggregation.of(a -> a.composite(c -> c.sources(List.of(Map.of("composite-agg", terms))))); + BoolQuery.Builder boolQueryBuilder = QueryBuilders.bool(); + + CompositeAggregationSource compositeAggregationSource1 = new CompositeAggregationSource.Builder().terms( + t -> t.field("size.keyword").order(SortOrder.Desc).name("terms").missingBucket(true) + ).build(); + + Aggregation aggregation = new Aggregation.Builder().composite( + AggregationBuilders.composite().sources(Map.of("composite", compositeAggregationSource1)).size(0).build() + ).build(); + final SearchRequest request = SearchRequest.of( - r -> r.index(index).query(b -> b.matchAll(QueryBuilders.matchAll().build())).aggregations("composite-agg", avgSize) + r -> r.index(index).query(boolQueryBuilder.build().toQuery()).aggregations("composite", aggregation).size(1000) ); final SearchResponse response = javaClient().search(request, ShopItem.class); From a65cde7944e8fdf8c8685843571d2defd64d50ac Mon Sep 17 00:00:00 2001 From: Vacha Shah Date: Mon, 6 May 2024 20:44:57 +0000 Subject: [PATCH 3/4] Adding guides, samples and fixing tests Signed-off-by: Vacha Shah --- CHANGELOG.md | 1 + guides/search.md | 22 +++++++++ .../aggregations/CompositeValuesSource.java | 26 ---------- .../integTest/AbstractSearchRequestIT.java | 48 ++++++++++++++----- .../org/opensearch/client/samples/Search.java | 25 ++++++++++ 5 files changed, 85 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 262966246f..7d79fd6885 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ This section is for maintaining a changelog for all breaking changes for the cli ### Fixed - Fix version and build ([#254](https://github.com/opensearch-project/opensearch-java/pull/254)) - Fix integer overflow for variables in indices stats response ([#960](https://github.com/opensearch-project/opensearch-java/pull/960)) +- Fix composite aggregations for search requests ([#967](https://github.com/opensearch-project/opensearch-java/pull/967)) ### Security diff --git a/guides/search.md b/guides/search.md index 7fd3e06cc9..cf08f7a872 100644 --- a/guides/search.md +++ b/guides/search.md @@ -4,11 +4,13 @@ - [Basic Search](#basic-search) - [Get raw JSON results](#get-raw-json-results) - [Search documents using a match query](#search-documents-using-a-match-query) + - [Search documents using a hybrid query](#search-documents-using-a-hybrid-query) - [Search documents using suggesters](#search-documents-using-suggesters) - [Using completion suggester](#using-completion-suggester) - [Using term suggester](#using-term-suggester) - [Using phrase suggester](#using-phrase-suggester) - [Aggregations](#aggregations) + - [Composite Aggregations](#composite-aggregations) # Search @@ -299,4 +301,24 @@ for (Map.Entry entry : searchResponse.aggregations().entrySet } ``` +#### Composite Aggregations + +```java +final Map comAggrSrcMap = new HashMap<>(); +CompositeAggregationSource compositeAggregationSource1 = new CompositeAggregationSource.Builder().terms( + termsAggrBuilder -> termsAggrBuilder.field("title.keyword").missingBucket(false).order(SortOrder.Asc) +).build(); +comAggrSrcMap.put("titles", compositeAggregationSource1); + +CompositeAggregation compAgg = new CompositeAggregation.Builder().sources(comAggrSrcMap).build(); +Aggregation aggregation = new Aggregation.Builder().composite(compAgg).build(); + +SearchRequest request = SearchRequest.of(r -> r.index(indexName).query(q -> q.match(m -> m.field("title").query(FieldValue.of("Document 1")))).aggregations("my_buckets", aggregation)); +SearchResponse response = client.search(request, IndexData.class); +for (Map.Entry entry : response.aggregations().entrySet()) { + LOGGER.info("Agg - {}", entry.getKey()); + entry.getValue().composite().buckets().array().forEach(b -> LOGGER.info("{} : {}", b.key(), b.docCount())); +} +``` + You can find a working sample of the above code in [Search.java](../samples/src/main/java/org/opensearch/client/samples/Search.java). \ No newline at end of file diff --git a/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeValuesSource.java b/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeValuesSource.java index 6b40580c30..efd973b1cb 100644 --- a/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeValuesSource.java +++ b/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeValuesSource.java @@ -9,14 +9,11 @@ import org.opensearch.client.json.ObjectDeserializer; import org.opensearch.client.opensearch._types.Script; import org.opensearch.client.opensearch._types.SortOrder; -import org.opensearch.client.util.ApiTypeHelper; import org.opensearch.client.util.ObjectBuilder; import org.opensearch.client.util.ObjectBuilderBase; public abstract class CompositeValuesSource implements JsonpSerializable { - private final String name; - @Nullable private final String field; @@ -39,8 +36,6 @@ public abstract class CompositeValuesSource implements JsonpSerializable { private String format; protected CompositeValuesSource(AbstractBuilder builder) { - this.name = ApiTypeHelper.requireNonNull(builder.name, this, "name"); - ; this.field = builder.field; this.script = builder.script; this.valueType = builder.valueType; @@ -50,13 +45,6 @@ protected CompositeValuesSource(AbstractBuilder builder) { this.format = builder.format; } - /** - * API name: {@code name} - */ - public final String name() { - return this.name; - } - /** * API name: {@code field} */ @@ -123,9 +111,6 @@ public void serialize(JsonGenerator generator, JsonpMapper mapper) { } protected void serializeInternal(JsonGenerator generator, JsonpMapper mapper) { - generator.writeKey(this.name); - generator.write(this.name); - if (this.field != null) { generator.writeKey("field"); generator.write(this.field); @@ -165,8 +150,6 @@ protected void serializeInternal(JsonGenerator generator, JsonpMapper mapper) { protected abstract static class AbstractBuilder> extends ObjectBuilderBase { - private String name; - @Nullable private String field; @@ -188,14 +171,6 @@ protected abstract static class AbstractBuilder> void setupCompositeValuesSourceDeserializer( ObjectDeserializer op ) { - op.add(AbstractBuilder::name, JsonpDeserializer.stringDeserializer(), "name"); op.add(AbstractBuilder::field, JsonpDeserializer.stringDeserializer(), "field"); op.add(AbstractBuilder::script, Script._DESERIALIZER, "script"); op.add(AbstractBuilder::valueType, ValueType._DESERIALIZER, "value_type"); diff --git a/java-client/src/test/java11/org/opensearch/client/opensearch/integTest/AbstractSearchRequestIT.java b/java-client/src/test/java11/org/opensearch/client/opensearch/integTest/AbstractSearchRequestIT.java index 463d2d9d04..98914ec5c1 100644 --- a/java-client/src/test/java11/org/opensearch/client/opensearch/integTest/AbstractSearchRequestIT.java +++ b/java-client/src/test/java11/org/opensearch/client/opensearch/integTest/AbstractSearchRequestIT.java @@ -10,6 +10,8 @@ import java.io.IOException; import java.util.Arrays; +import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.junit.Test; @@ -17,10 +19,10 @@ import org.opensearch.client.opensearch._types.FieldValue; import org.opensearch.client.opensearch._types.SortOrder; import org.opensearch.client.opensearch._types.aggregations.Aggregation; -import org.opensearch.client.opensearch._types.aggregations.AggregationBuilders; +import org.opensearch.client.opensearch._types.aggregations.CompositeAggregation; import org.opensearch.client.opensearch._types.aggregations.CompositeAggregationSource; +import org.opensearch.client.opensearch._types.aggregations.CompositeBucket; import org.opensearch.client.opensearch._types.mapping.Property; -import org.opensearch.client.opensearch._types.query_dsl.BoolQuery; import org.opensearch.client.opensearch._types.query_dsl.MatchQuery; import org.opensearch.client.opensearch._types.query_dsl.Query; import org.opensearch.client.opensearch._types.query_dsl.QueryBuilders; @@ -71,22 +73,46 @@ public void shouldReturnSearchResultsWithCompositeAgg() throws Exception { final String index = "search_request"; createIndex(index); - BoolQuery.Builder boolQueryBuilder = QueryBuilders.bool(); + final Query query = Query.of( + q -> q.bool( + builder -> builder.filter(filter -> filter.term(TermQuery.of(term -> term.field("size").value(FieldValue.of("huge"))))) + ) + ); + final Map comAggrSrcMap = new HashMap<>(); CompositeAggregationSource compositeAggregationSource1 = new CompositeAggregationSource.Builder().terms( - t -> t.field("size.keyword").order(SortOrder.Desc).name("terms").missingBucket(true) + termsAggrBuilder -> termsAggrBuilder.field("quantity").missingBucket(false).order(SortOrder.Asc) ).build(); + comAggrSrcMap.put("quantity", compositeAggregationSource1); - Aggregation aggregation = new Aggregation.Builder().composite( - AggregationBuilders.composite().sources(Map.of("composite", compositeAggregationSource1)).size(0).build() - ).build(); + CompositeAggregation compAgg = new CompositeAggregation.Builder().sources(comAggrSrcMap).build(); - final SearchRequest request = SearchRequest.of( - r -> r.index(index).query(boolQueryBuilder.build().toQuery()).aggregations("composite", aggregation).size(1000) - ); + Aggregation aggregation = new Aggregation.Builder().composite(compAgg).build(); + + final SearchRequest request = SearchRequest.of(r -> r.index(index).query(query).aggregations("my_buckets", aggregation)); final SearchResponse response = javaClient().search(request, ShopItem.class); - assertEquals(response.hits().hits().size(), 8); + assertEquals(response.hits().hits().size(), 2); + for (Map.Entry entry : response.aggregations().entrySet()) { + CompositeAggregation compositeAggregation = entry.getValue().composite(); + assertEquals(2, compositeAggregation.buckets().size()); + assertEquals(1, Integer.parseInt(compositeAggregation.buckets().get(0).key().get("quantity").toString())); + assertEquals(1, compositeAggregation.buckets().get(0).docCount()); + assertEquals(2, Integer.parseInt(compositeAggregation.buckets().get(1).key().get("quantity").toString())); + assertEquals(1, compositeAggregation.buckets().get(1).docCount()); + } + List buckets = response.aggregations() + .entrySet() + .stream() + .filter(e -> e.getKey().equals("my_buckets")) + .map(e -> e.getValue().composite().buckets().array()) + .flatMap(List::stream) + .collect(Collectors.toList()); + assertEquals(2, buckets.size()); + assertEquals(1, Integer.parseInt(buckets.get(0).key().get("quantity").toString())); + assertEquals(1, buckets.get(0).docCount()); + assertEquals(2, Integer.parseInt(buckets.get(1).key().get("quantity").toString())); + assertEquals(1, buckets.get(1).docCount()); } @Test diff --git a/samples/src/main/java/org/opensearch/client/samples/Search.java b/samples/src/main/java/org/opensearch/client/samples/Search.java index 417ecba409..e6f02b8d92 100644 --- a/samples/src/main/java/org/opensearch/client/samples/Search.java +++ b/samples/src/main/java/org/opensearch/client/samples/Search.java @@ -10,14 +10,18 @@ import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.opensearch.client.opensearch.OpenSearchClient; import org.opensearch.client.opensearch._types.FieldValue; import org.opensearch.client.opensearch._types.Refresh; +import org.opensearch.client.opensearch._types.SortOrder; import org.opensearch.client.opensearch._types.aggregations.Aggregate; import org.opensearch.client.opensearch._types.aggregations.Aggregation; +import org.opensearch.client.opensearch._types.aggregations.CompositeAggregation; +import org.opensearch.client.opensearch._types.aggregations.CompositeAggregationSource; import org.opensearch.client.opensearch._types.analysis.Analyzer; import org.opensearch.client.opensearch._types.analysis.CustomAnalyzer; import org.opensearch.client.opensearch._types.analysis.ShingleTokenFilter; @@ -106,6 +110,27 @@ public static void main(String[] args) { entry.getValue().sterms().buckets().array().forEach(b -> LOGGER.info("{} : {}", b.key(), b.docCount())); } + // Custom Aggregations + final Map comAggrSrcMap = new HashMap<>(); + CompositeAggregationSource compositeAggregationSource1 = new CompositeAggregationSource.Builder().terms( + termsAggrBuilder -> termsAggrBuilder.field("title.keyword").missingBucket(false).order(SortOrder.Asc) + ).build(); + comAggrSrcMap.put("titles", compositeAggregationSource1); + + CompositeAggregation compAgg = new CompositeAggregation.Builder().sources(comAggrSrcMap).build(); + Aggregation aggregation = new Aggregation.Builder().composite(compAgg).build(); + + SearchRequest request = SearchRequest.of( + r -> r.index(indexName) + .query(q -> q.match(m -> m.field("title").query(FieldValue.of("Document 1")))) + .aggregations("my_buckets", aggregation) + ); + SearchResponse response = client.search(request, IndexData.class); + for (Map.Entry entry : response.aggregations().entrySet()) { + LOGGER.info("Agg - {}", entry.getKey()); + entry.getValue().composite().buckets().array().forEach(b -> LOGGER.info("{} : {}", b.key(), b.docCount())); + } + // HybridSearch Query searchQuery = Query.of( h -> h.hybrid( From b5c2d724149cb0cd9e414f84f660ce7c4e376bed Mon Sep 17 00:00:00 2001 From: Vacha Shah Date: Mon, 6 May 2024 20:47:48 +0000 Subject: [PATCH 4/4] Addressing comments Signed-off-by: Vacha Shah --- ...mpositeDateHistogramAggregationSource.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeDateHistogramAggregationSource.java b/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeDateHistogramAggregationSource.java index c3f30a900f..34fe20c093 100644 --- a/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeDateHistogramAggregationSource.java +++ b/java-client/src/main/java/org/opensearch/client/opensearch/_types/aggregations/CompositeDateHistogramAggregationSource.java @@ -26,7 +26,8 @@ public class CompositeDateHistogramAggregationSource extends CompositeValuesSour @Nullable private final Time fixedInterval; - private final long offset; + @Nullable + private final Long offset; private final String zoneId; @@ -59,9 +60,10 @@ public final Time fixedInterval() { } /** - * Required - API name: {@code offset} + * API name: {@code offset} */ - public final long offset() { + @Nullable + public final Long offset() { return this.offset; } @@ -95,8 +97,11 @@ protected void serializeInternal(JsonGenerator generator, JsonpMapper mapper) { this.fixedInterval.serialize(generator, mapper); } - generator.writeKey("offset"); - generator.write(this.offset); + if (this.offset != null) { + generator.writeKey("offset"); + generator.write(this.offset); + + } generator.writeKey("zone_id"); generator.write(this.zoneId); @@ -116,7 +121,8 @@ public static class Builder extends CompositeValuesSource.AbstractBuilder