diff --git a/CHANGELOG.md b/CHANGELOG.md index 9af8242c8..7f47744ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Fix version and build ([#254](https://github.com/opensearch-project/opensearch-java/pull/254)) - Update Gradle to 7.6 ([#309](https://github.com/opensearch-project/opensearch-java/pull/309)) - Prevent SPI calls at runtime ([#293](https://github.com/opensearch-project/opensearch-java/pull/293)) +- Add support for OpenSearch Serverless ([#339](https://github.com/opensearch-project/opensearch-java/pull/339)) ### Deprecated diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index e26bedb87..c90e138b4 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -67,10 +67,10 @@ Run integration tests after starting OpenSearch cluster: #### AWS Transport Integration Tests -To run integration tests for the AWS transport client, ensure working AWS credentials and specify your OpenSearch domain and region as follows: +To run integration tests for the AWS transport client, ensure working AWS credentials in `/.aws/credentials` and specify your OpenSearch domain and region as follows: ``` -./gradlew integrationTest --tests "*AwsSdk2*" -Dtests.awsSdk2support.domainHost=search-...us-west-2.es.amazonaws.com -Dtests.awsSdk2support.domainRegion=us-west-2 +./gradlew integrationTest --tests "*AwsSdk2*" -Dtests.awsSdk2support.domainHost=search-...us-west-2.es.amazonaws.com -Dtests.awsSdk2support.domainRegion=us-west-2 -Dtests.awsSdk2support.serviceName=es ``` For OpenSearch Serverless, change the signing service name. diff --git a/USER_GUIDE.md b/USER_GUIDE.md index 5314d6338..3dc8e4edf 100644 --- a/USER_GUIDE.md +++ b/USER_GUIDE.md @@ -4,6 +4,8 @@ - [Sample data](#sample-data) - [IndexData class](#indexdata-class) - [Create a client](#create-a-client) + - [Create a client using `RestClientTransport`](#create-a-client-using-restclienttransport) + - [Create a client using `ApacheHttpClient5Transport`](#create-a-client-using-apachehttpclient5transport) - [Create an index](#create-an-index) - [Index data](#index-data) - [Search for the documents](#search-for-the-documents) @@ -175,7 +177,7 @@ DeleteIndexResponse deleteIndexResponse = client.indices().delete(deleteIndexReq ## Amazon Managed OpenSearch -Use `AwsSdk2Transport` to make requests to Amazon Managed OpenSearch. +Use `AwsSdk2Transport` to make requests to Amazon Managed OpenSearch and OpenSearch Serverless. ```java SdkHttpClient httpClient = ApacheHttpClient.builder().build(); @@ -184,7 +186,7 @@ OpenSearchClient client = new OpenSearchClient( new AwsSdk2Transport( httpClient, "search-...us-west-2.es.amazonaws.com", // OpenSearch endpoint, without https:// - "es" // signing service name + "es" // signing service name, use "aoss" for OpenSearch Serverless Region.US_WEST_2, // signing service region AwsSdk2TransportOptions.builder().build() ) diff --git a/java-client/src/main/java/org/opensearch/client/transport/aws/AwsSdk2Transport.java b/java-client/src/main/java/org/opensearch/client/transport/aws/AwsSdk2Transport.java index c56723055..208c90443 100644 --- a/java-client/src/main/java/org/opensearch/client/transport/aws/AwsSdk2Transport.java +++ b/java-client/src/main/java/org/opensearch/client/transport/aws/AwsSdk2Transport.java @@ -363,6 +363,9 @@ private SdkHttpFullRequest prepareRequest( } req.putHeader("Content-Length", String.valueOf(body.getContentLength())); req.contentStreamProvider(body::getInputStream); + // To add the "X-Amz-Content-Sha256" header, it needs to set as required. + // It is a required header for Amazon OpenSearch Serverless. + req.putHeader("x-amz-content-sha256", "required"); } boolean responseCompression = Optional.ofNullable(options) diff --git a/java-client/src/test/java/org/opensearch/client/opensearch/integTest/aws/AwsSdk2SearchIT.java b/java-client/src/test/java/org/opensearch/client/opensearch/integTest/aws/AwsSdk2SearchIT.java index 4b7a4578a..1e7f4ce42 100644 --- a/java-client/src/test/java/org/opensearch/client/opensearch/integTest/aws/AwsSdk2SearchIT.java +++ b/java-client/src/test/java/org/opensearch/client/opensearch/integTest/aws/AwsSdk2SearchIT.java @@ -12,9 +12,7 @@ import org.junit.Assert; import org.opensearch.client.opensearch.OpenSearchAsyncClient; import org.opensearch.client.opensearch.OpenSearchClient; -import org.opensearch.client.opensearch._types.OpType; import org.opensearch.client.opensearch._types.OpenSearchException; -import org.opensearch.client.opensearch._types.Refresh; import org.opensearch.client.opensearch.core.IndexRequest; import org.opensearch.client.opensearch.core.IndexResponse; import org.opensearch.client.opensearch.core.SearchResponse; @@ -51,11 +49,14 @@ void testClient(boolean async) throws Exception { final OpenSearchClient client = getClient(async, null, null); SimplePojo doc1 = new SimplePojo("Document 1", "The text of document 1"); - addDoc(client, "id1", doc1, false); + addDoc(client, "id1", doc1); SimplePojo doc2 = new SimplePojo("Document 2", "The text of document 2"); - addDoc(client, "id2", doc2, false); + addDoc(client, "id2", doc2); SimplePojo doc3 = getLongDoc("Long Document 3", 1000000); - addDoc(client, "id3", doc3, true); + addDoc(client, "id3", doc3); + + // wait for the document to index + Thread.sleep(1000); SearchResponse response = query(client, "NotPresent", null); Assert.assertEquals(0, response.hits().hits().size()); @@ -77,12 +78,15 @@ void testClientAsync(boolean async) throws Exception { final OpenSearchAsyncClient client = getAsyncClient(async, null, null); SimplePojo doc1 = new SimplePojo("Document 1", "The text of document 1"); - CompletableFuture add1 = addDoc(client, "id1", doc1, false); + CompletableFuture add1 = addDoc(client, "id1", doc1); SimplePojo doc2 = new SimplePojo("Document 2", "The text of document 2"); - CompletableFuture add2 = addDoc(client, "id2", doc2, false); + CompletableFuture add2 = addDoc(client, "id2", doc2); SimplePojo doc3 = getLongDoc("Long Document 3", 1000000); CompletableFuture add3 = CompletableFuture.allOf(add1, add2).thenCompose( - unused -> addDoc(client, "id3", doc3, true)); + unused -> addDoc(client, "id3", doc3)); + + // wait for the document to index + Thread.sleep(1000); List> results = add3.thenCompose(unused -> { CompletableFuture> r1 = query(client, "NotPresent", null); @@ -107,29 +111,21 @@ void testClientAsync(boolean async) throws Exception { } - private void addDoc(OpenSearchClient client, String id, SimplePojo doc, boolean wait) throws Exception { + private void addDoc(OpenSearchClient client, String id, SimplePojo doc) throws Exception { IndexRequest.Builder req = new IndexRequest.Builder() .index(TEST_INDEX) .document(doc) - .id(id) - .opType(OpType.Index); - if (wait) { - req.refresh(Refresh.WaitFor); - } + .id(id); client.index(req.build()); } private CompletableFuture addDoc( - OpenSearchAsyncClient client, String id, SimplePojo doc, boolean wait + OpenSearchAsyncClient client, String id, SimplePojo doc ) { IndexRequest.Builder req = new IndexRequest.Builder() .index(TEST_INDEX) .document(doc) - .id(id) - .opType(OpType.Index); - if (wait) { - req.refresh(Refresh.WaitFor); - } + .id(id); try { return client.index(req.build()); } catch (Exception e) {