From a4dc4f0ace93f8d1854ad42e39626419ff59103e Mon Sep 17 00:00:00 2001 From: Brett Findlay Date: Wed, 22 Nov 2023 06:26:17 +1100 Subject: [PATCH] Add support for Flat Objects (#735) * add flat object support Signed-off-by: bfindlay * add flat object support Signed-off-by: bfindlay * update changelog Signed-off-by: bfindlay * update flatobject and user guides Signed-off-by: bfindlay * fix typo Signed-off-by: bfindlay * remove unused comments Signed-off-by: bfindlay --------- Signed-off-by: bfindlay --- CHANGELOG.md | 1 + USER_GUIDE.md | 13 + .../opensearch/_types/mapping/FieldType.java | 2 +- .../_types/mapping/FlatObjectProperty.java | 116 ++++++ .../_types/mapping/FlattenedProperty.java | 377 ------------------ .../opensearch/_types/mapping/Property.java | 26 +- .../_types/mapping/PropertyBuilders.java | 6 +- .../integTest/AbstractIndicesClientIT.java | 52 +++ .../client/samples/FlatObjectBasics.java | 111 ++++++ .../client/samples/util/IssueDocument.java | 90 +++++ 10 files changed, 400 insertions(+), 394 deletions(-) create mode 100644 java-client/src/main/java/org/opensearch/client/opensearch/_types/mapping/FlatObjectProperty.java delete mode 100644 java-client/src/main/java/org/opensearch/client/opensearch/_types/mapping/FlattenedProperty.java create mode 100644 samples/src/main/java/org/opensearch/client/samples/FlatObjectBasics.java create mode 100644 samples/src/main/java/org/opensearch/client/samples/util/IssueDocument.java diff --git a/CHANGELOG.md b/CHANGELOG.md index c7b0abe464..d94963b43b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ This section is for maintaining a changelog for all breaking changes for the cli ### Added - Added support for icu_collation_keyword type ([#725](https://github.com/opensearch-project/opensearch-java/pull/725)) +- Added support for flat_object field property ([#735](https://github.com/opensearch-project/opensearch-java/pull/735)) ### Dependencies diff --git a/USER_GUIDE.md b/USER_GUIDE.md index 4b21974f32..cce234bb3e 100644 --- a/USER_GUIDE.md +++ b/USER_GUIDE.md @@ -7,6 +7,7 @@ - [Creating an index](#creating-an-index) - [With default settings](#with-default-settings) - [With custom settings and mappings](#with-custom-settings-and-mappings) + - [With FlatObject mappings](#with-flat-object-mappings) - [Indexing data](#indexing-data) - [Searching for a document](#searching-for-a-document) - [Deleting a document](#deleting-a-document) @@ -136,6 +137,18 @@ CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder() .build(); client.indices().create(createIndexRequest); ``` +#### With flat object mappings +OpenSearch supports FlatObject mappings from version 2.7.0 without additional parameters. + +```java +final CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder().index(indexName) + .mappings(m -> m.properties("issue", Property.of(p -> p.flatObject(new FlatObjectProperty.Builder().build())))) + .build(); +client.indices().create(createIndexRequest); +``` + +You can find a working sample of the above code in [FlatObjectBasics.java](./samples/src/main/java/org/opensearch/client/samples/FlatObjectBasics.java). + ### Indexing data diff --git a/java-client/src/main/java/org/opensearch/client/opensearch/_types/mapping/FieldType.java b/java-client/src/main/java/org/opensearch/client/opensearch/_types/mapping/FieldType.java index ee1b6e052b..d2824ee1ee 100644 --- a/java-client/src/main/java/org/opensearch/client/opensearch/_types/mapping/FieldType.java +++ b/java-client/src/main/java/org/opensearch/client/opensearch/_types/mapping/FieldType.java @@ -107,7 +107,7 @@ public enum FieldType implements JsonEnum { RankFeatures("rank_features"), - Flattened("flattened"), + FlatObject("flat_object"), Shape("shape"), diff --git a/java-client/src/main/java/org/opensearch/client/opensearch/_types/mapping/FlatObjectProperty.java b/java-client/src/main/java/org/opensearch/client/opensearch/_types/mapping/FlatObjectProperty.java new file mode 100644 index 0000000000..bb317da753 --- /dev/null +++ b/java-client/src/main/java/org/opensearch/client/opensearch/_types/mapping/FlatObjectProperty.java @@ -0,0 +1,116 @@ +/* + * 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. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.client.opensearch._types.mapping; + +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; + +// typedef: _types.mapping.FlatObjectProperty + +@JsonpDeserializable +public class FlatObjectProperty extends PropertyBase implements PropertyVariant { + + // --------------------------------------------------------------------------------------------- + + private FlatObjectProperty(Builder builder) { + super(builder); + + } + + public static FlatObjectProperty of(Function> fn) { + return fn.apply(new Builder()).build(); + } + + /** + * Property variant kind. + */ + @Override + public Property.Kind _propertyKind() { + return Property.Kind.FlatObject; + } + + protected void serializeInternal(JsonGenerator generator, JsonpMapper mapper) { + + generator.write("type", "flat_object"); + super.serializeInternal(generator, mapper); + } + + // --------------------------------------------------------------------------------------------- + + /** + * Builder for {@link FlatObjectProperty}. + */ + + public static class Builder extends PropertyBase.AbstractBuilder implements ObjectBuilder { + + @Override + protected Builder self() { + return this; + } + + /** + * Builds a {@link FlatObjectProperty}. + * + * @throws NullPointerException + * if some of the required fields are null. + */ + public FlatObjectProperty build() { + _checkSingleUse(); + + return new FlatObjectProperty(this); + } + } + + // --------------------------------------------------------------------------------------------- + + /** + * Json deserializer for {@link FlatObjectProperty} + */ + public static final JsonpDeserializer _DESERIALIZER = ObjectBuilderDeserializer.lazy( + Builder::new, + FlatObjectProperty::setupFlatObjectPropertyDeserializer + ); + + protected static void setupFlatObjectPropertyDeserializer(ObjectDeserializer op) { + PropertyBase.setupPropertyBaseDeserializer(op); + + op.ignore("type"); + } + +} diff --git a/java-client/src/main/java/org/opensearch/client/opensearch/_types/mapping/FlattenedProperty.java b/java-client/src/main/java/org/opensearch/client/opensearch/_types/mapping/FlattenedProperty.java deleted file mode 100644 index f683b158a1..0000000000 --- a/java-client/src/main/java/org/opensearch/client/opensearch/_types/mapping/FlattenedProperty.java +++ /dev/null @@ -1,377 +0,0 @@ -/* - * 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. - */ - -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/* - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.client.opensearch._types.mapping; - -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.util.ObjectBuilder; - -// typedef: _types.mapping.FlattenedProperty - -@JsonpDeserializable -public class FlattenedProperty extends PropertyBase implements PropertyVariant { - @Nullable - private final Double boost; - - @Nullable - private final Integer depthLimit; - - @Nullable - private final Boolean docValues; - - @Nullable - private final Boolean eagerGlobalOrdinals; - - @Nullable - private final Boolean index; - - @Nullable - private final IndexOptions indexOptions; - - @Nullable - private final String nullValue; - - @Nullable - private final String similarity; - - @Nullable - private final Boolean splitQueriesOnWhitespace; - - // --------------------------------------------------------------------------------------------- - - private FlattenedProperty(Builder builder) { - super(builder); - - this.boost = builder.boost; - this.depthLimit = builder.depthLimit; - this.docValues = builder.docValues; - this.eagerGlobalOrdinals = builder.eagerGlobalOrdinals; - this.index = builder.index; - this.indexOptions = builder.indexOptions; - this.nullValue = builder.nullValue; - this.similarity = builder.similarity; - this.splitQueriesOnWhitespace = builder.splitQueriesOnWhitespace; - - } - - public static FlattenedProperty of(Function> fn) { - return fn.apply(new Builder()).build(); - } - - /** - * Property variant kind. - */ - @Override - public Property.Kind _propertyKind() { - return Property.Kind.Flattened; - } - - /** - * API name: {@code boost} - */ - @Nullable - public final Double boost() { - return this.boost; - } - - /** - * API name: {@code depth_limit} - */ - @Nullable - public final Integer depthLimit() { - return this.depthLimit; - } - - /** - * API name: {@code doc_values} - */ - @Nullable - public final Boolean docValues() { - return this.docValues; - } - - /** - * API name: {@code eager_global_ordinals} - */ - @Nullable - public final Boolean eagerGlobalOrdinals() { - return this.eagerGlobalOrdinals; - } - - /** - * API name: {@code index} - */ - @Nullable - public final Boolean index() { - return this.index; - } - - /** - * API name: {@code index_options} - */ - @Nullable - public final IndexOptions indexOptions() { - return this.indexOptions; - } - - /** - * API name: {@code null_value} - */ - @Nullable - public final String nullValue() { - return this.nullValue; - } - - /** - * API name: {@code similarity} - */ - @Nullable - public final String similarity() { - return this.similarity; - } - - /** - * API name: {@code split_queries_on_whitespace} - */ - @Nullable - public final Boolean splitQueriesOnWhitespace() { - return this.splitQueriesOnWhitespace; - } - - protected void serializeInternal(JsonGenerator generator, JsonpMapper mapper) { - - generator.write("type", "flattened"); - super.serializeInternal(generator, mapper); - if (this.boost != null) { - generator.writeKey("boost"); - generator.write(this.boost); - - } - if (this.depthLimit != null) { - generator.writeKey("depth_limit"); - generator.write(this.depthLimit); - - } - if (this.docValues != null) { - generator.writeKey("doc_values"); - generator.write(this.docValues); - - } - if (this.eagerGlobalOrdinals != null) { - generator.writeKey("eager_global_ordinals"); - generator.write(this.eagerGlobalOrdinals); - - } - if (this.index != null) { - generator.writeKey("index"); - generator.write(this.index); - - } - if (this.indexOptions != null) { - generator.writeKey("index_options"); - this.indexOptions.serialize(generator, mapper); - } - if (this.nullValue != null) { - generator.writeKey("null_value"); - generator.write(this.nullValue); - - } - if (this.similarity != null) { - generator.writeKey("similarity"); - generator.write(this.similarity); - - } - if (this.splitQueriesOnWhitespace != null) { - generator.writeKey("split_queries_on_whitespace"); - generator.write(this.splitQueriesOnWhitespace); - - } - - } - - // --------------------------------------------------------------------------------------------- - - /** - * Builder for {@link FlattenedProperty}. - */ - - public static class Builder extends PropertyBase.AbstractBuilder implements ObjectBuilder { - @Nullable - private Double boost; - - @Nullable - private Integer depthLimit; - - @Nullable - private Boolean docValues; - - @Nullable - private Boolean eagerGlobalOrdinals; - - @Nullable - private Boolean index; - - @Nullable - private IndexOptions indexOptions; - - @Nullable - private String nullValue; - - @Nullable - private String similarity; - - @Nullable - private Boolean splitQueriesOnWhitespace; - - /** - * API name: {@code boost} - */ - public final Builder boost(@Nullable Double value) { - this.boost = value; - return this; - } - - /** - * API name: {@code depth_limit} - */ - public final Builder depthLimit(@Nullable Integer value) { - this.depthLimit = value; - return this; - } - - /** - * API name: {@code doc_values} - */ - public final Builder docValues(@Nullable Boolean value) { - this.docValues = value; - return this; - } - - /** - * API name: {@code eager_global_ordinals} - */ - public final Builder eagerGlobalOrdinals(@Nullable Boolean value) { - this.eagerGlobalOrdinals = value; - return this; - } - - /** - * API name: {@code index} - */ - public final Builder index(@Nullable Boolean value) { - this.index = value; - return this; - } - - /** - * API name: {@code index_options} - */ - public final Builder indexOptions(@Nullable IndexOptions value) { - this.indexOptions = value; - return this; - } - - /** - * API name: {@code null_value} - */ - public final Builder nullValue(@Nullable String value) { - this.nullValue = value; - return this; - } - - /** - * API name: {@code similarity} - */ - public final Builder similarity(@Nullable String value) { - this.similarity = value; - return this; - } - - /** - * API name: {@code split_queries_on_whitespace} - */ - public final Builder splitQueriesOnWhitespace(@Nullable Boolean value) { - this.splitQueriesOnWhitespace = value; - return this; - } - - @Override - protected Builder self() { - return this; - } - - /** - * Builds a {@link FlattenedProperty}. - * - * @throws NullPointerException - * if some of the required fields are null. - */ - public FlattenedProperty build() { - _checkSingleUse(); - - return new FlattenedProperty(this); - } - } - - // --------------------------------------------------------------------------------------------- - - /** - * Json deserializer for {@link FlattenedProperty} - */ - public static final JsonpDeserializer _DESERIALIZER = ObjectBuilderDeserializer.lazy( - Builder::new, - FlattenedProperty::setupFlattenedPropertyDeserializer - ); - - protected static void setupFlattenedPropertyDeserializer(ObjectDeserializer op) { - PropertyBase.setupPropertyBaseDeserializer(op); - op.add(Builder::boost, JsonpDeserializer.doubleDeserializer(), "boost"); - op.add(Builder::depthLimit, JsonpDeserializer.integerDeserializer(), "depth_limit"); - op.add(Builder::docValues, JsonpDeserializer.booleanDeserializer(), "doc_values"); - op.add(Builder::eagerGlobalOrdinals, JsonpDeserializer.booleanDeserializer(), "eager_global_ordinals"); - op.add(Builder::index, JsonpDeserializer.booleanDeserializer(), "index"); - op.add(Builder::indexOptions, IndexOptions._DESERIALIZER, "index_options"); - op.add(Builder::nullValue, JsonpDeserializer.stringDeserializer(), "null_value"); - op.add(Builder::similarity, JsonpDeserializer.stringDeserializer(), "similarity"); - op.add(Builder::splitQueriesOnWhitespace, JsonpDeserializer.booleanDeserializer(), "split_queries_on_whitespace"); - - op.ignore("type"); - } - -} diff --git a/java-client/src/main/java/org/opensearch/client/opensearch/_types/mapping/Property.java b/java-client/src/main/java/org/opensearch/client/opensearch/_types/mapping/Property.java index 5986748e90..2634a090f4 100644 --- a/java-client/src/main/java/org/opensearch/client/opensearch/_types/mapping/Property.java +++ b/java-client/src/main/java/org/opensearch/client/opensearch/_types/mapping/Property.java @@ -84,7 +84,7 @@ public enum Kind implements JsonEnum { Alias("alias"), - Flattened("flattened"), + FlatObject("flat_object"), Float("float"), @@ -402,20 +402,20 @@ public FieldAliasProperty alias() { } /** - * Is this variant instance of kind {@code flattened}? + * Is this variant instance of kind {@code flat_object}? */ - public boolean isFlattened() { - return _kind == Kind.Flattened; + public boolean isFlatObject() { + return _kind == Kind.FlatObject; } /** - * Get the {@code flattened} variant value. + * Get the {@code flat_object} variant value. * * @throws IllegalStateException - * if the current variant is not of the {@code flattened} kind. + * if the current variant is not of the {@code flat_object} kind. */ - public FlattenedProperty flattened() { - return TaggedUnionUtils.get(this, Kind.Flattened); + public FlatObjectProperty flatObject() { + return TaggedUnionUtils.get(this, Kind.FlatObject); } /** @@ -1098,14 +1098,14 @@ public ObjectBuilder alias(Function flattened(FlattenedProperty v) { - this._kind = Kind.Flattened; + public ObjectBuilder flatObject(FlatObjectProperty v) { + this._kind = Kind.FlatObject; this._value = v; return this; } - public ObjectBuilder flattened(Function> fn) { - return this.flattened(fn.apply(new FlattenedProperty.Builder()).build()); + public ObjectBuilder flatObject(Function> fn) { + return this.flatObject(fn.apply(new FlatObjectProperty.Builder()).build()); } public ObjectBuilder float_(FloatNumberProperty v) { @@ -1457,7 +1457,7 @@ protected static void setupPropertyDeserializer(ObjectDeserializer op) op.add(Builder::double_, DoubleNumberProperty._DESERIALIZER, "double"); op.add(Builder::doubleRange, DoubleRangeProperty._DESERIALIZER, "double_range"); op.add(Builder::alias, FieldAliasProperty._DESERIALIZER, "alias"); - op.add(Builder::flattened, FlattenedProperty._DESERIALIZER, "flattened"); + op.add(Builder::flatObject, FlatObjectProperty._DESERIALIZER, "flat_object"); op.add(Builder::float_, FloatNumberProperty._DESERIALIZER, "float"); op.add(Builder::floatRange, FloatRangeProperty._DESERIALIZER, "float_range"); op.add(Builder::geoPoint, GeoPointProperty._DESERIALIZER, "geo_point"); diff --git a/java-client/src/main/java/org/opensearch/client/opensearch/_types/mapping/PropertyBuilders.java b/java-client/src/main/java/org/opensearch/client/opensearch/_types/mapping/PropertyBuilders.java index c519d4afc4..ae7f542eca 100644 --- a/java-client/src/main/java/org/opensearch/client/opensearch/_types/mapping/PropertyBuilders.java +++ b/java-client/src/main/java/org/opensearch/client/opensearch/_types/mapping/PropertyBuilders.java @@ -134,11 +134,11 @@ public static FieldAliasProperty.Builder alias() { } /** - * Creates a builder for the {@link FlattenedProperty flattened} + * Creates a builder for the {@link FlatObjectProperty flatObject} * {@code Property} variant. */ - public static FlattenedProperty.Builder flattened() { - return new FlattenedProperty.Builder(); + public static FlatObjectProperty.Builder flatObject() { + return new FlatObjectProperty.Builder(); } /** diff --git a/java-client/src/test/java/org/opensearch/client/opensearch/integTest/AbstractIndicesClientIT.java b/java-client/src/test/java/org/opensearch/client/opensearch/integTest/AbstractIndicesClientIT.java index a3f360d245..11d7de218f 100644 --- a/java-client/src/test/java/org/opensearch/client/opensearch/integTest/AbstractIndicesClientIT.java +++ b/java-client/src/test/java/org/opensearch/client/opensearch/integTest/AbstractIndicesClientIT.java @@ -12,9 +12,15 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import org.junit.Test; +import org.opensearch.Version; import org.opensearch.client.opensearch.OpenSearchAsyncClient; import org.opensearch.client.opensearch._types.OpenSearchException; +import org.opensearch.client.opensearch._types.mapping.FlatObjectProperty; +import org.opensearch.client.opensearch._types.mapping.Property; +import org.opensearch.client.opensearch.core.InfoResponse; import org.opensearch.client.opensearch.indices.CreateDataStreamResponse; +import org.opensearch.client.opensearch.indices.CreateIndexRequest; import org.opensearch.client.opensearch.indices.CreateIndexResponse; import org.opensearch.client.opensearch.indices.DataStream; import org.opensearch.client.opensearch.indices.DataStreamsStatsResponse; @@ -25,6 +31,8 @@ import org.opensearch.client.opensearch.indices.GetIndexRequest; import org.opensearch.client.opensearch.indices.GetIndexResponse; import org.opensearch.client.opensearch.indices.GetIndicesSettingsRequest; +import org.opensearch.client.opensearch.indices.GetMappingRequest; +import org.opensearch.client.opensearch.indices.GetMappingResponse; import org.opensearch.client.opensearch.indices.IndexState; import org.opensearch.client.opensearch.indices.PutIndexTemplateResponse; import org.opensearch.common.settings.Settings; @@ -192,4 +200,48 @@ public void testGetNotExistingIndexAlias() throws Exception { assertEquals(ex.getMessage(), "Request failed: [string_error] " + "alias [alias_not_exists] missing"); } } + + @Test + public void createIndex_withFlatObject_indexCreatesSuccessfully() throws IOException { + assumeFlatObjectSupport(); + + try { + final CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder().index("flat-object-test") + .mappings(m -> m.properties("sample_flat_object", Property.of(p -> p.flatObject(new FlatObjectProperty.Builder().build())))) + .build(); + final CreateIndexResponse createIndexResponse = javaClient().indices().create(createIndexRequest); + assertTrue(createIndexResponse.acknowledged()); + } catch (OpenSearchException ex) { + fail(ex.getMessage()); + } + } + + @Test + public void createIndex_withFlatObject_mappingCanBeRetrieved() throws IOException { + assumeFlatObjectSupport(); + + try { + final String indexName = "flat-object-mapping-index"; + final CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder().index(indexName) + .mappings(m -> m.properties("sample_flat_object", Property.of(p -> p.flatObject(new FlatObjectProperty.Builder().build())))) + .build(); + final CreateIndexResponse createIndexResponse = javaClient().indices().create(createIndexRequest); + assertTrue(createIndexResponse.acknowledged()); + + final GetMappingResponse response = javaClient().indices().getMapping(GetMappingRequest.of(m -> m.index(indexName))); + final Property.Kind mappingKind = response.result().get(indexName).mappings().properties().get("sample_flat_object")._kind(); + assertEquals(mappingKind, Property.Kind.FlatObject); + } catch (OpenSearchException ex) { + fail(ex.getMessage()); + } + } + + private void assumeFlatObjectSupport() throws IOException { + InfoResponse info = javaClient().info(); + String version = info.version().number(); + if (version.contains("SNAPSHOT")) { + version = version.split("-")[0]; + } + assumeTrue("Flat Object is supported after version 2.7.0 only", Version.fromString(version).onOrAfter(Version.fromString("2.7.0"))); + } } diff --git a/samples/src/main/java/org/opensearch/client/samples/FlatObjectBasics.java b/samples/src/main/java/org/opensearch/client/samples/FlatObjectBasics.java new file mode 100644 index 0000000000..240e53c67e --- /dev/null +++ b/samples/src/main/java/org/opensearch/client/samples/FlatObjectBasics.java @@ -0,0 +1,111 @@ +package org.opensearch.client.samples; + +import java.util.List; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.opensearch.client.opensearch._types.FieldValue; +import org.opensearch.client.opensearch._types.mapping.FlatObjectProperty; +import org.opensearch.client.opensearch._types.mapping.Property; +import org.opensearch.client.opensearch.core.IndexRequest; +import org.opensearch.client.opensearch.core.SearchRequest; +import org.opensearch.client.opensearch.core.SearchResponse; +import org.opensearch.client.opensearch.indices.CreateIndexRequest; +import org.opensearch.client.samples.util.IssueDocument; + +public class FlatObjectBasics { + private static final Logger LOGGER = LogManager.getLogger(IndexingBasics.class); + + public static void main(String[] args) { + try { + var client = SampleClient.create(); + + var version = client.info().version(); + LOGGER.info("Server: {}@{}", version.distribution(), version.number()); + + final var indexName = "flat_object-sample"; + + // Create a new index with an "issue" field with flat_object type + if (!client.indices().exists(e -> e.index(indexName)).value()) { + final CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder().index(indexName) + .mappings(m -> m.properties("issue", Property.of(p -> p.flatObject(new FlatObjectProperty.Builder().build())))) + .build(); + client.indices().create(createIndexRequest); + } + + // Index some flat object documents + final IssueDocument issueDocument = new IssueDocument(); + final IssueDocument.Issue issue = new IssueDocument.Issue(); + issue.setNumber("123456"); + final IssueDocument.Labels labels = new IssueDocument.Labels(); + labels.setBackport(List.of("1.3", "2.0")); + labels.setVersion("2.1"); + final IssueDocument.Category category = new IssueDocument.Category(); + category.setType("API"); + category.setLevel("enhancement"); + + labels.setCategory(category); + issue.setLabels(labels); + + issueDocument.setIssue(issue); + final IndexRequest indexRequest = new IndexRequest.Builder().index(indexName) + .id("1") + .document(issueDocument) + .build(); + + client.index(indexRequest); + + // Index second document + final IssueDocument document2 = new IssueDocument(); + final IssueDocument.Issue issue2 = new IssueDocument.Issue(); + issue2.setNumber("123457"); + + IssueDocument.Labels labels2 = new IssueDocument.Labels(); + labels2.setVersion("2.2"); + + IssueDocument.Category category2 = new IssueDocument.Category(); + category2.setType("API"); + category2.setLevel("bug"); + + labels2.setCategory(category2); + issue2.setLabels(labels2); + + document2.setIssue(issue2); + + final IndexRequest indexRequest2 = new IndexRequest.Builder().index(indexName) + .id("2") + .document(document2) + .build(); + + client.index(indexRequest2); + + // wait for the document to index - as refresh period is set to 3s + Thread.sleep(3000); + + // Search for the documents + // Ref: https://opensearch.org/docs/latest/field-types/supported-field-types/flat-object/ + // Even if you don’t know the field names, you can search for a leaf value in the entire flat object. + // For example, the following request searches for all issues labeled as bugs + SearchRequest searchRequest = new SearchRequest.Builder().index(indexName) + .query(q -> q.match(m -> m.field("issue").query(FieldValue.of("bug")))) + .build(); + + SearchResponse searchResponse = client.search(searchRequest, IssueDocument.class); + for (var hit : searchResponse.hits().hits()) { + LOGGER.info("Found {} with score {}", hit.source(), hit.score()); + } + + // Alternatively, if you know the subfield name in which to search, provide the field’s path in dot notation + SearchRequest searchRequest2 = new SearchRequest.Builder().index(indexName) + .query(q -> q.match(m -> m.field("issue.labels.category.level").query(FieldValue.of("bug")))) + .build(); + + SearchResponse searchResponse2 = client.search(searchRequest2, IssueDocument.class); + for (var hit : searchResponse2.hits().hits()) { + LOGGER.info("Found {} with score {}", hit.source(), hit.score()); + } + + } catch (Exception e) { + LOGGER.error("Unexpected exception", e); + } + } +} diff --git a/samples/src/main/java/org/opensearch/client/samples/util/IssueDocument.java b/samples/src/main/java/org/opensearch/client/samples/util/IssueDocument.java new file mode 100644 index 0000000000..45e212ed1f --- /dev/null +++ b/samples/src/main/java/org/opensearch/client/samples/util/IssueDocument.java @@ -0,0 +1,90 @@ +package org.opensearch.client.samples.util; + +import java.util.List; + +public class IssueDocument { + + private Issue issue; + + public Issue getIssue() { + return issue; + } + + public void setIssue(Issue issue) { + this.issue = issue; + } + + public static class Issue { + private String number; + private Labels labels; + + public String getNumber() { + return number; + } + + public void setNumber(String number) { + this.number = number; + } + + public Labels getLabels() { + return labels; + } + + public void setLabels(Labels labels) { + this.labels = labels; + } + + } + + public static class Labels { + private String version; + private List backport; + private Category category; + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public List getBackport() { + return backport; + } + + public void setBackport(List backport) { + this.backport = backport; + } + + public Category getCategory() { + return category; + } + + public void setCategory(Category category) { + this.category = category; + } + + } + + public static class Category { + private String type; + private String level; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getLevel() { + return level; + } + + public void setLevel(String level) { + this.level = level; + } + } +}