diff --git a/.gitignore b/.gitignore index 96cbff8d90..b8638f2e72 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ gradle-app.setting .ci/output java-client/bin +samples/bin \ No newline at end of file diff --git a/USER_GUIDE.md b/USER_GUIDE.md index bbc609ffbf..4b21974f32 100644 --- a/USER_GUIDE.md +++ b/USER_GUIDE.md @@ -1,87 +1,52 @@ -- [User Guide](#user-guide) - - [Sample data](#sample-data) - - [IndexData class](#indexdata-class) - - [Create a client](#create-a-client) - - [Create a client using `ApacheHttpClient5Transport`](#create-a-client-using-apachehttpclient5transport) - - [Create a client using `RestClientTransport` (deprecated)](#create-a-client-using-restclienttransport-deprecated) - - [Create an index](#create-an-index) - - [Create an index with default settings](#create-an-index-with-default-settings) - - [Create an index with custom settings and mappings](#create-an-index-with-custom-settings-and-mappings) - - [Index data](#index-data) - - [Search for the documents](#search-for-the-documents) - - [Get raw JSON results](#get-raw-json-results) - - [Search documents using a match query](#search-documents-using-a-match-query) - - [Search documents using suggesters](#search-documents-using-suggesters) - - [App Data class](#app-data-class) - - [Using completion suggester](#using-completion-suggester) - - [Using term suggester](#using-term-suggester) - - [Using phrase suggester](#using-phrase-suggester) - - [Bulk requests](#bulk-requests) - - [Aggregations](#aggregations) - - [Delete the document](#delete-the-document) - - [Delete the index](#delete-the-index) - - [Data Stream API](#data-stream-api) - - [Create a data stream](#create-a-data-stream) - - [Get data stream](#get-data-stream) - - [Data stream stats](#data-stream-stats) - - [Delete data stream and backing indices](#delete-data-stream-and-backing-indices) - - [Point-In-Time API](#point-in-time-api) - - [Creating a point in time](#creating-a-point-in-time) - - [List all point in time](#list-all-point-in-time) - - [Delete point in time](#delete-point-in-time) - - [Cat API](#cat-api) - - [Cat Indices](#cat-indices) - - [Cat aliases](#cat-aliases) - - [Cat nodes](#cat-nodes) - - [Cat point in time segments](#cat-point-in-time-segments) - - [Using different transport options](#using-different-transport-options) - - [Amazon OpenSearch Service](#amazon-opensearch-service) +- [OpenSearch Java Client User Guide](#opensearch-java-client-user-guide) + - [Setup](#setup) + - [Basic Features](#basic-features) + - [Creating a client](#creating-a-client) + - [Using `ApacheHttpClient5Transport`](#using-apachehttpclient5transport) + - [Using `RestClientTransport` (deprecated)](#using-restclienttransport-deprecated) + - [Creating an index](#creating-an-index) + - [With default settings](#with-default-settings) + - [With custom settings and mappings](#with-custom-settings-and-mappings) + - [Indexing data](#indexing-data) + - [Searching for a document](#searching-for-a-document) + - [Deleting a document](#deleting-a-document) + - [Deleting an index](#deleting-an-index) + - [Advanced Features](#advanced-features) - [Plugins](#plugins) -# User Guide +# OpenSearch Java Client User Guide -## Sample data +## Setup -### IndexData class +To start using the OpenSearch Java client, you need to provide a transport. The default `ApacheHttpClient5TransportBuilder` transport comes with the Java client. To use the OpenSearch Java client with the default transport, add it to your `pom.xml` file as a dependency: -```java -static class IndexData { - private String firstName; - private String lastName; - - public IndexData(String firstName, String lastName) { - this.firstName = firstName; - this.lastName = lastName; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - @Override - public String toString() { - return String.format("IndexData{first name='%s', last name='%s'}", firstName, lastName); - } +``` + + org.opensearch.client + opensearch-java + 2.6.0 + +``` + +If you’re using Gradle, add the following dependencies to your project: + +``` +dependencies { + implementation 'org.opensearch.client:opensearch-java:2.6.0' } ``` -## Create a client +## Basic Features + +In the example below, we create a client, create an index with default and non-default settings, insert a document into the index, search for the document, delete the document, and finally delete the index. + +You can find working versions of the code below that can be run with a local instance of OpenSearch in [samples](./samples/). + +### Creating a client There are multiple low level transports which `OpenSearchClient` could be configured with, the `ApacheHttpClient5Transport` being the default one. -### Create a client using `ApacheHttpClient5Transport` +#### Using `ApacheHttpClient5Transport` ```java import org.apache.hc.core5.http.HttpHost; @@ -113,7 +78,9 @@ final OpenSearchTransport transport = ApacheHttpClient5TransportBuilder OpenSearchClient client = new OpenSearchClient(transport); ``` -### Create a client using `RestClientTransport` (deprecated) +See [SampleClient.java](./samples/src/main/java/org/opensearch/client/samples/SampleClient.java) for a working sample. + +#### Using `RestClientTransport` (deprecated) ```java import org.apache.hc.core5.http.HttpHost; @@ -141,9 +108,9 @@ OpenSearchClient client = new OpenSearchClient(transport); Upcoming OpenSearch `3.0.0` release brings HTTP/2 support and as such, the `RestClientTransport` would switch to HTTP/2 if available (for both HTTPS and/or HTTP protocols). The desired protocol could be forced using `RestClientBuilder.HttpClientConfigCallback`. -## Create an index +### Creating an index -### Create an index with default settings +#### With default settings ```java String index = "sample-index"; @@ -151,7 +118,7 @@ CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder().index(i client.indices().create(createIndexRequest); ``` -### Create an index with custom settings and mappings +#### With custom settings and mappings ```java String index = "sample-index"; @@ -170,19 +137,21 @@ CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder() client.indices().create(createIndexRequest); ``` -## Index data +### Indexing data + +[IndexData](./samples/src/main/java/org/opensearch/client/samples/util/IndexData.java) refers to sample data class. ```java -IndexData indexData = new IndexData("John", "Doe"); +IndexData indexData = new IndexData("Document 1", "Text for document 1"); IndexRequest indexRequest = new IndexRequest.Builder().index(index).id("1").document(indexData).build(); client.index(indexRequest); -indexData = new IndexData("John", "Joe"); +indexData = new IndexData("Document 2", "Text for document 2"); indexRequest = new IndexRequest.Builder().index(index).id("2").document(indexData).build(); client.index(indexRequest); ``` -## Search for the documents +### Searching for a document ```java SearchResponse searchResponse = client.search(s -> s.index(index), IndexData.class); @@ -191,278 +160,7 @@ for (int i = 0; i < searchResponse.hits().hits().size(); i++) { } ``` -### Get raw JSON results - -When the target class is not defined or if the response result is a semi-structured data not tied to an object definition, use a raw JSON data representation as the target class. For example, the below snippet uses `ObjectNode` from jackson. - -```java -SearchResponse searchResponse = client.search(b -> b.index(index), ObjectNode.class); -for (int i = 0; i < searchResponse.hits().hits().size(); i++) { - System.out.println(searchResponse.hits().hits().get(i).source()); -} -``` - -## Search documents using a match query - -```java -SearchRequest searchRequest = new SearchRequest.Builder().query(q -> q.match(m -> m.field("firstName") - .query(FieldValue.of("John")))) - .build(); - -SearchResponse searchResponse = client.search(searchRequest, IndexData.class); -for (int i = 0; i < searchResponse.hits().hits().size(); i++) { - System.out.println(searchResponse.hits().hits().get(i).source()); -} -``` - -## Search documents using suggesters - -### App Data class - -```java -public static class AppData { - - private int intValue; - private String msg; - - public int getIntValue() { - return intValue; - } - - public void setIntValue(int intValue) { - this.intValue = intValue; - } - - public String getMsg() { - return msg; - } - - public void setMsg(String msg) { - this.msg = msg; - } -} -``` - -### Using completion suggester - -```java -String index = "completion-suggester"; - -Property intValueProp = new Property.Builder() - .long_(v -> v) - .build(); -Property msgCompletionProp = new Property.Builder() - .completion(c -> c) - .build(); -client.indices().create(c -> c - .index(index) - .mappings(m -> m - .properties("intValue", intValueProp) - .properties("msg", msgCompletionProp))); - -AppData appData = new AppData(); -appData.setIntValue(1337); -appData.setMsg("foo"); - -client.index(b -> b - .index(index) - .id("1") - .document(appData) - .refresh(Refresh.True)); - -appData.setIntValue(1338); -appData.setMsg("foobar"); - -client.index(b -> b - .index(index) - .id("2") - .document(appData) - .refresh(Refresh.True)); - -String suggesterName = "msgSuggester"; - -CompletionSuggester completionSuggester = FieldSuggesterBuilders.completion() - .field("msg") - .size(1) - .build(); -FieldSuggester fieldSuggester = new FieldSuggester.Builder().prefix("foo") - .completion(completionSuggester) - .build(); -Suggester suggester = new Suggester.Builder() - .suggesters(Collections.singletonMap(suggesterName, fieldSuggester)) - .build(); -SearchRequest searchRequest = new SearchRequest.Builder() - .index(index) - .suggest(suggester) - .build(); - -SearchResponse response = client.search(searchRequest, AppData.class); -``` - -### Using term suggester - -```java - String index = "term-suggester"; - -// term suggester does not require a special mapping -client.indices().create(c -> c - .index(index)); - -AppData appData = new AppData(); -appData.setIntValue(1337); -appData.setMsg("foo"); - -client.index(b -> b - .index(index) - .id("1") - .document(appData) - .refresh(Refresh.True)); - -appData.setIntValue(1338); -appData.setMsg("foobar"); - -client.index(b -> b - .index(index) - .id("2") - .document(appData) - .refresh(Refresh.True)); - -String suggesterName = "msgSuggester"; - -TermSuggester termSuggester = FieldSuggesterBuilders.term() - .field("msg") - .size(1) - .build(); -FieldSuggester fieldSuggester = new FieldSuggester.Builder().text("fool") - .term(termSuggester) - .build(); -Suggester suggester = new Suggester.Builder() - .suggesters(Collections.singletonMap(suggesterName, fieldSuggester)) - .build(); -SearchRequest searchRequest = new SearchRequest.Builder() - .index(index) - .suggest(suggester) - .build(); - -SearchResponse response = client.search(searchRequest, AppData.class); -``` - -### Using phrase suggester - -```java -String index = "test-phrase-suggester"; - -ShingleTokenFilter shingleTokenFilter = new ShingleTokenFilter.Builder().minShingleSize("2") - .maxShingleSize("3") - .build(); - -Analyzer analyzer = new Analyzer.Builder() - .custom(new CustomAnalyzer.Builder().tokenizer("standard") - .filter(Arrays.asList("lowercase", "shingle")).build()) - .build(); - -TokenFilter tokenFilter = new TokenFilter.Builder() - .definition(new TokenFilterDefinition.Builder() - .shingle(shingleTokenFilter).build()) - .build(); - -IndexSettingsAnalysis indexSettingsAnalysis = new IndexSettingsAnalysis.Builder() - .analyzer("trigram", analyzer) - .filter("shingle", tokenFilter) - .build(); - -IndexSettings settings = new IndexSettings.Builder().analysis(indexSettingsAnalysis).build(); - -TypeMapping mapping = new TypeMapping.Builder().properties("msg", new Property.Builder() - .text(new TextProperty.Builder().fields("trigram", new Property.Builder() - .text(new TextProperty.Builder().analyzer("trigram").build()) - .build()).build()) - .build()).build(); - -client.indices().create(c -> c - .index(index) - .settings(settings) - .mappings(mapping)); - -AppData appData = new AppData(); -appData.setIntValue(1337); -appData.setMsg("Design Patterns"); - -client.index(b -> b - .index(index) - .id("1") - .document(appData) - .refresh(Refresh.True)); - -appData.setIntValue(1338); -appData.setMsg("Software Architecture Patterns Explained"); - -client.index(b -> b - .index(index) - .id("2") - .document(appData) - .refresh(Refresh.True)); - -String suggesterName = "msgSuggester"; - -PhraseSuggester phraseSuggester = FieldSuggesterBuilders.phrase() - .field("msg.trigram") - .build(); -FieldSuggester fieldSuggester = new FieldSuggester.Builder().text("design paterns") - .phrase(phraseSuggester) - .build(); -Suggester suggester = new Suggester.Builder() - .suggesters(Collections.singletonMap(suggesterName, fieldSuggester)) - .build(); -SearchRequest searchRequest = new SearchRequest.Builder() - .index(index) - .suggest(suggester) - .build(); - -SearchResponse response = client.search(searchRequest, AppData.class); -``` - -## Bulk requests - -```java -ArrayList ops = new ArrayList<>(); -SimplePojo doc1 = new SimplePojo("Document 1", "The text of document 1"); -ops.add(new BulkOperation.Builder().index( - IndexOperation.of(io -> io.index(TEST_INDEX).id("id1").document(doc1)) -).build()); -SimplePojo doc2 = new SimplePojo("Document 2", "The text of document 2"); -ops.add(new BulkOperation.Builder().index( - IndexOperation.of(io -> io.index(TEST_INDEX).id("id2").document(doc2)) -).build()); -SimplePojo doc3 = getLongDoc("Long Document 3", 100000); -ops.add(new BulkOperation.Builder().index( - IndexOperation.of(io -> io.index(TEST_INDEX).id("id3").document(doc3)) -).build()); - -BulkRequest.Builder bulkReq = new BulkRequest.Builder() - .index(index) - .operations(ops) - .refresh(Refresh.WaitFor); -BulkResponse bulkResponse = client.bulk(bulkReq.build()); -``` - -## Aggregations - -```java -SearchRequest searchRequest = new SearchRequest.Builder().query(q -> q.match(m -> m.field("firstName") - .query(FieldValue.of("John")))) - .aggregations("firstNames", new Aggregation.Builder().terms(t -> t.field("firstName.keyword")) - .build()) - .build(); - -SearchResponse searchResponse = client.search(searchRequest, IndexData.class); -for (Map.Entry entry : searchResponse.aggregations().entrySet()) { - System.out.println("Agg - " + entry.getKey()); - entry.getValue().sterms().buckets().array().forEach(b -> System.out.printf("%s : %d%n", b.key(), b.docCount())); -} -``` - -## Delete the document +### Deleting a document The following sample code deletes a document whose ID is 1. @@ -470,152 +168,23 @@ The following sample code deletes a document whose ID is 1. client.delete(d -> d.index(index).id("1")); ``` -## Delete the index +## Deleting an index ```java -DeleteIndexRequest deleteIndexRequest = new DeleteRequest.Builder().index(index).build(); +DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest.Builder().index(index).build(); DeleteIndexResponse deleteIndexResponse = client.indices().delete(deleteIndexRequest); ``` -## Data Stream API - -### Create a data stream -Before creating a data stream, you need to create an index template which configures a set of indices as a data stream. -A data stream must have a timestamp field. If not specified, OpenSearch uses `@timestamp` as the default timestamp field name. - -The following sample code creates an index template for data stream with a custom timestamp field, and creates a data stream -which matches the name pattern specified in the index template. -```java -String dataStreamIndexTemplateName = "sample-data-stream-template"; -String timestampFieldName = "my_timestamp_field"; -String namePattern = "sample-data-stream-*"; -String dataStreamName = "sample-data-stream-1"; - -// Create an index template which configures data stream -PutIndexTemplateRequest putIndexTemplateRequest = new PutIndexTemplateRequest.Builder() - .name(dataStreamIndexTemplateName) - .indexPatterns(namePattern) - .dataStream(new DataStream.Builder() - .timestampField(t -> t.name(timestampFieldName)) - .build()) - .build(); -PutIndexTemplateResponse putIndexTemplateResponse = javaClient().indices().putIndexTemplate(putIndexTemplateRequest); - -// Create a data stream -CreateDataStreamRequest createDataStreamRequest = new CreateDataStreamRequest.Builder().name(dataStreamName).build(); -CreateDataStreamResponse createDataStreamResponse = javaClient().indices().createDataStream(createDataStreamRequest); -``` - -### Get data stream -```java -GetDataStreamRequest getDataStreamRequest = new GetDataStreamRequest.Builder().name(dataStreamName).build(); -GetDataStreamResponse getDataStreamResponse = javaClient().indices().getDataStream(getDataStreamRequest); -``` - -### Data stream stats -```java -DataStreamsStatsRequest dataStreamsStatsRequest = new DataStreamsStatsRequest.Builder().name(dataStreamName).build(); -DataStreamsStatsResponse dataStreamsStatsResponse = javaClient().indices().dataStreamsStats(dataStreamsStatsRequest); -``` - -### Delete data stream and backing indices -```java -DeleteDataStreamRequest deleteDataStreamRequest = new DeleteDataStreamRequest.Builder().name(dataStreamName).build(); -DeleteDataStreamResponse deleteDataStreamResponse = javaClient().indices().deleteDataStream(deleteDataStreamRequest); -``` - -## Point-In-Time API - -### Creating a point in time - -Creates a PIT. The keep_alive query parameter is required; it specifies how long to keep a PIT. - -```java -CreatePitRequest createPitRequest = new CreatePitRequest.Builder() - .targetIndexes(Collections.singletonList(index)) - .keepAlive(new Time.Builder().time("100m").build()).build(); - -CreatePitResponse createPitResponse = javaClient() - .createPit(createPitRequest); -``` - -### List all point in time - -Returns all PITs in the OpenSearch cluster. - -```java -ListAllPitResponse listAllPitResponse = javaClient().listAllPit(); -``` - -### Delete point in time - -Deletes one, several, or all PITs. PITs are automatically deleted when the keep_alive time period elapses. However, to deallocate resources, you can delete a PIT using the Delete PIT API. The Delete PIT API supports deleting a list of PITs by ID or deleting all PITs at once. - -```java -DeletePitRequest deletePitRequest = new DeletePitRequest.Builder() - .pitId(Collections.singletonList("pit_id")).build(); - -DeletePitResponse deletePitResponse = javaClient() - .deletePit(deletePitRequest); -``` - - -## Cat API - -### Cat Indices -The following sample code cat indices with required headers and sorted by creation date - -```java -IndicesRequest indicesRequest = new IndicesRequest.Builder() - .headers("index,health,status,pri,rep,doc.count,creation.date,creation.date.string").sort("creation.date").build(); -IndicesResponse indicesResponse = javaClient().cat().indices(indicesRequest); -``` - - -### Cat aliases -The following sample code cat aliases with name "test-alias" and sorted by index -```java -AliasesRequest aliasesRequest = new AliasesRequest.Builder().name("test-alias").sort("index").build(); -AliasesResponse aliasesResponse = javaClient().cat().aliases(aliasesRequest); -``` - -### Cat nodes -The following sample code cat nodes sorted by cpu -```java -NodesResponse nodesResponse = javaClient().cat().nodes(r -> r.sort("cpu")); -``` - -### Cat point in time segments -Similarly to the CAT Segments API, the PIT Segments API provides low-level information about the disk utilization of a PIT by describing its Lucene segments. -```java -SegmentsResponse pitSegmentsResponse = javaClient().cat() - .pitSegments(r -> r.headers("index,shard,id,segment,size")); -``` - -## Using different transport options +You can find a working sample of the above code in [IndexingBasics.java](./samples/src/main/java/org/opensearch/client/samples/IndexingBasics.java). -### Amazon OpenSearch Service +## Advanced Features -Requests to [OpenSearch Service and OpenSearch Serverless](https://docs.aws.amazon.com/opensearch-service/index.html) must be signed using the AWS signing protocol. Use `AwsSdk2Transport` to send signed requests. - -```java -SdkHttpClient httpClient = ApacheHttpClient.builder().build(); - -OpenSearchClient client = new OpenSearchClient( - new AwsSdk2Transport( - httpClient, - "search-...us-west-2.es.amazonaws.com", // OpenSearch endpoint, without https:// - "es" // signing service name, use "aoss" for OpenSearch Serverless - Region.US_WEST_2, // signing service region - AwsSdk2TransportOptions.builder().build() - ) -); - -InfoResponse info = client.info(); -System.out.println(info.version().distribution() + ": " + info.version().number()); - -httpClient.close(); -``` +- [Authentication (IAM, SigV4)](./guides/auth.md) +- [Bulk Indexing](./guides/bulk.md) +- [Cat APIs](./guides/cat.md) +- [Data Stream APIs](./guides/data_stream.md) +- [Point-in-Time APIs](./guides/point_in_time.md) +- [Search](./guides/search.md) ## Plugins diff --git a/guides/auth.md b/guides/auth.md new file mode 100644 index 0000000000..658464642d --- /dev/null +++ b/guides/auth.md @@ -0,0 +1,27 @@ +- [Authentication](#authentication) + - [Amazon OpenSearch Service](#amazon-opensearch-service) + +# Authentication + +## Amazon OpenSearch Service + +Requests to [OpenSearch Service and OpenSearch Serverless](https://docs.aws.amazon.com/opensearch-service/index.html) must be signed using the AWS signing protocol. Use `AwsSdk2Transport` to send signed requests. + +```java +SdkHttpClient httpClient = ApacheHttpClient.builder().build(); + +OpenSearchClient client = new OpenSearchClient( + new AwsSdk2Transport( + httpClient, + "search-...us-west-2.es.amazonaws.com", // OpenSearch endpoint, without https:// + "es" // signing service name, use "aoss" for OpenSearch Serverless + Region.US_WEST_2, // signing service region + AwsSdk2TransportOptions.builder().build() + ) +); + +InfoResponse info = client.info(); +System.out.println(info.version().distribution() + ": " + info.version().number()); + +httpClient.close(); +``` \ No newline at end of file diff --git a/guides/bulk.md b/guides/bulk.md new file mode 100644 index 0000000000..3c12c2ddc7 --- /dev/null +++ b/guides/bulk.md @@ -0,0 +1,41 @@ +- [Bulk](#bulk) + - [Bulk Indexing](#bulk-indexing) + - [Bulk requests](#bulk-requests) + +# Bulk + +The [Bulk API](https://opensearch.org/docs/latest/api-reference/document-apis/bulk/) lets you add, update, or delete multiple documents in a single request. + +## Bulk Indexing + +## Bulk requests + +```java +String indexName = "sample-index"; +CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder().index(index).build(); +client.indices().create(createIndexRequest); + +ArrayList ops = new ArrayList<>(); +IndexData doc1 = new IndexData("Document 1", "The text of document 1"); +ops.add(new BulkOperation.Builder().index( + IndexOperation.of(io -> io.index(indexName).id("id1").document(doc1)) +).build()); +IndexData doc2 = new IndexData("Document 2", "The text of document 2"); +ops.add(new BulkOperation.Builder().index( + IndexOperation.of(io -> io.index(indexName).id("id2").document(doc2)) +).build()); +IndexData doc3 = new IndexData("Document 3", "The text of document 3"); +ops.add(new BulkOperation.Builder().index( + IndexOperation.of(io -> io.index(indexName).id("id3").document(doc3)) +).build()); + +BulkRequest.Builder bulkReq = new BulkRequest.Builder() + .index(indexName) + .operations(ops) + .refresh(Refresh.WaitFor); +BulkResponse bulkResponse = client.bulk(bulkReq.build()); +``` + +[IndexData](../samples/src/main/java/org/opensearch/client/samples/util/IndexData.java) refers to sample data class. + +You can find a working sample of the above code in [Bulk.java](../samples/src/main/java/org/opensearch/client/samples/Bulk.java). \ No newline at end of file diff --git a/guides/cat.md b/guides/cat.md new file mode 100644 index 0000000000..a5a3adcb5e --- /dev/null +++ b/guides/cat.md @@ -0,0 +1,42 @@ +- [Cat API](#cat-api) + - [Cat Indices](#cat-indices) + - [Cat aliases](#cat-aliases) + - [Cat nodes](#cat-nodes) + - [Cat point in time segments](#cat-point-in-time-segments) + +# Cat API + +The CAT API is a human-readable interface that returns plain text instead of traditional JSON. + +## Cat Indices +The following sample code cat indices with required headers and sorted by creation date + +```java +IndicesRequest indicesRequest = new IndicesRequest.Builder() + .headers("index,health,status,pri,rep,doc.count,creation.date,creation.date.string").sort("creation.date").build(); +IndicesResponse indicesResponse = javaClient().cat().indices(indicesRequest); +``` + + +## Cat aliases +The following sample code cat aliases with name "test-alias" and sorted by index + +```java +AliasesRequest aliasesRequest = new AliasesRequest.Builder().name("test-alias").sort("index").build(); +AliasesResponse aliasesResponse = javaClient().cat().aliases(aliasesRequest); +``` + +## Cat nodes +The following sample code cat nodes sorted by cpu + +```java +NodesResponse nodesResponse = javaClient().cat().nodes(r -> r.sort("cpu")); +``` + +## Cat point in time segments +Similarly to the CAT Segments API, the PIT Segments API provides low-level information about the disk utilization of a PIT by describing its Lucene segments. + +```java +SegmentsResponse pitSegmentsResponse = javaClient().cat() + .pitSegments(r -> r.headers("index,shard,id,segment,size")); +``` \ No newline at end of file diff --git a/guides/data_stream.md b/guides/data_stream.md new file mode 100644 index 0000000000..7c49807f8c --- /dev/null +++ b/guides/data_stream.md @@ -0,0 +1,54 @@ +- [Data Stream API](#data-stream-api) + - [Create a data stream](#create-a-data-stream) + - [Get data stream](#get-data-stream) + - [Data stream stats](#data-stream-stats) + - [Delete data stream and backing indices](#delete-data-stream-and-backing-indices) + +# Data Stream API + +## Create a data stream +Before creating a data stream, you need to create an index template which configures a set of indices as a data stream. +A data stream must have a timestamp field. If not specified, OpenSearch uses `@timestamp` as the default timestamp field name. + +The following sample code creates an index template for data stream with a custom timestamp field, and creates a data stream +which matches the name pattern specified in the index template. +```java +String dataStreamIndexTemplateName = "sample-data-stream-template"; +String timestampFieldName = "my_timestamp_field"; +String namePattern = "sample-data-stream-*"; +String dataStreamName = "sample-data-stream-1"; + +// Create an index template which configures data stream +PutIndexTemplateRequest putIndexTemplateRequest = new PutIndexTemplateRequest.Builder() + .name(dataStreamIndexTemplateName) + .indexPatterns(namePattern) + .dataStream(new DataStream.Builder() + .timestampField(t -> t.name(timestampFieldName)) + .build()) + .build(); +PutIndexTemplateResponse putIndexTemplateResponse = client.indices().putIndexTemplate(putIndexTemplateRequest); + +// Create a data stream +CreateDataStreamRequest createDataStreamRequest = new CreateDataStreamRequest.Builder().name(dataStreamName).build(); +CreateDataStreamResponse createDataStreamResponse = client.indices().createDataStream(createDataStreamRequest); +``` + +## Get data stream +```java +GetDataStreamRequest getDataStreamRequest = new GetDataStreamRequest.Builder().name(dataStreamName).build(); +GetDataStreamResponse getDataStreamResponse = client.indices().getDataStream(getDataStreamRequest); +``` + +## Data stream stats +```java +DataStreamsStatsRequest dataStreamsStatsRequest = new DataStreamsStatsRequest.Builder().name(dataStreamName).build(); +DataStreamsStatsResponse dataStreamsStatsResponse = client.indices().dataStreamsStats(dataStreamsStatsRequest); +``` + +## Delete data stream and backing indices +```java +DeleteDataStreamRequest deleteDataStreamRequest = new DeleteDataStreamRequest.Builder().name(dataStreamName).build(); +DeleteDataStreamResponse deleteDataStreamResponse = client.indices().deleteDataStream(deleteDataStreamRequest); +``` + +You can find a working sample of the above code in [DataStreamBasics.java](../samples/src/main/java/org/opensearch/client/samples/DataStreamBasics.java). \ No newline at end of file diff --git a/guides/point_in_time.md b/guides/point_in_time.md new file mode 100644 index 0000000000..f2fa36118b --- /dev/null +++ b/guides/point_in_time.md @@ -0,0 +1,53 @@ +- [Point-in-Time](#point-in-time) + - [Point-In-Time API](#point-in-time-api) + - [Creating a point in time](#creating-a-point-in-time) + - [List all point in time](#list-all-point-in-time) + - [Delete point in time](#delete-point-in-time) + +# Point-in-Time + +[Point in Time (PIT)](https://opensearch.org/docs/latest/search-plugins/point-in-time/) lets you run different queries against a dataset that is fixed in time. + +## Point-In-Time API + +### Creating a point in time + +To create a PIT, first create an index. + +``` +java +String index = "sample-index"; +CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder().index(index).build(); +client.indices().create(createIndexRequest); +``` + +To create a PIT, the keep_alive query parameter is required; it specifies how long to keep a PIT. + +```java +CreatePitRequest createPitRequest = new CreatePitRequest.Builder() + .targetIndexes(Collections.singletonList(index)) + .keepAlive(new Time.Builder().time("100m").build()).build(); + +CreatePitResponse createPitResponse = client.createPit(createPitRequest); +``` + +### List all point in time + +Returns all PITs in the OpenSearch cluster. + +```java +ListAllPitResponse listAllPitResponse = client.listAllPit(); +``` + +### Delete point in time + +Deletes one, several, or all PITs. PITs are automatically deleted when the keep_alive time period elapses. However, to deallocate resources, you can delete a PIT using the Delete PIT API. The Delete PIT API supports deleting a list of PITs by ID or deleting all PITs at once. + +```java +DeletePitRequest deletePitRequest = new DeletePitRequest.Builder() + .pitId(Collections.singletonList(createPitResponse.pitId())).build(); + +DeletePitResponse deletePitResponse = client.deletePit(deletePitRequest); +``` + +You can find a working sample of the above code in [PointInTime.java](../samples/src/main/java/org/opensearch/client/samples/PointInTime.java). \ No newline at end of file diff --git a/guides/search.md b/guides/search.md new file mode 100644 index 0000000000..d343b30420 --- /dev/null +++ b/guides/search.md @@ -0,0 +1,283 @@ +- [Search](#search) + - [Setup](#setup) + - [Search API](#search-api) + - [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 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) + +# Search + +OpenSearch provides a powerful search API that allows you to search for documents in an index. The search API supports a number of parameters that allow you to customize the search operation. In this guide, we will explore the search API and its parameters. + +## Setup + +To get started, first create a client, create an index and index some documents: + +```java +import org.apache.hc.core5.http.HttpHost; + +final HttpHost[] hosts = new HttpHost[] { + new HttpHost("http", "localhost", 9200) + }; + +final OpenSearchTransport transport = ApacheHttpClient5TransportBuilder + .builder(hosts) + .setMapper(new JacksonJsonpMapper()) + .build(); +OpenSearchClient client = new OpenSearchClient(transport); + +String index = "sample-index"; +CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder().index(index).build(); +client.indices().create(createIndexRequest); + +IndexData indexData = new IndexData("Document 1", "Text for document 1"); +IndexRequest indexRequest = new IndexRequest.Builder().index(index).id("1").document(indexData).build(); +client.index(indexRequest); + +indexData = new IndexData("Document 2", "Text for document 2"); +indexRequest = new IndexRequest.Builder().index(index).id("2").document(indexData).build(); +client.index(indexRequest); +``` + +[IndexData](../samples/src/main/java/org/opensearch/client/samples/util/IndexData.java) refers to sample data class. + +## Search API + +### Basic Search + +```java +SearchResponse searchResponse = client.search(s -> s.index(index), IndexData.class); +for (int i = 0; i < searchResponse.hits().hits().size(); i++) { + System.out.println(searchResponse.hits().hits().get(i).source()); +} +``` + +#### Get raw JSON results + +When the target class is not defined or if the response result is a semi-structured data not tied to an object definition, use a raw JSON data representation as the target class. For example, the below snippet uses `ObjectNode` from jackson. + +```java +SearchResponse searchResponse = client.search(b -> b.index(index), ObjectNode.class); +for (int i = 0; i < searchResponse.hits().hits().size(); i++) { + System.out.println(searchResponse.hits().hits().get(i).source()); +} +``` + +### Search documents using a match query + +```java +SearchRequest searchRequest = new SearchRequest.Builder().query(q -> q.match(m -> m.field("text") + .query(FieldValue.of("Text for document 2")))) + .build(); + +SearchResponse searchResponse = client.search(searchRequest, IndexData.class); +for (int i = 0; i < searchResponse.hits().hits().size(); i++) { + System.out.println(searchResponse.hits().hits().get(i).source()); +} +``` + +### Search documents using suggesters + +[AppData](../samples/src/main/java/org/opensearch/client/samples/util/AppData.java) refers to the sample data class used in the below samples. + +#### Using completion suggester + +```java +String index = "completion-suggester"; + +Property intValueProp = new Property.Builder() + .long_(v -> v) + .build(); +Property msgCompletionProp = new Property.Builder() + .completion(c -> c) + .build(); +client.indices().create(c -> c + .index(index) + .mappings(m -> m + .properties("intValue", intValueProp) + .properties("msg", msgCompletionProp))); + +AppData appData = new AppData(); +appData.setIntValue(1337); +appData.setMsg("foo"); + +client.index(b -> b + .index(index) + .id("1") + .document(appData) + .refresh(Refresh.True)); + +appData.setIntValue(1338); +appData.setMsg("foobar"); + +client.index(b -> b + .index(index) + .id("2") + .document(appData) + .refresh(Refresh.True)); + +String suggesterName = "msgSuggester"; + +CompletionSuggester completionSuggester = FieldSuggesterBuilders.completion() + .field("msg") + .size(1) + .build(); +FieldSuggester fieldSuggester = new FieldSuggester.Builder().prefix("foo") + .completion(completionSuggester) + .build(); +Suggester suggester = new Suggester.Builder() + .suggesters(Collections.singletonMap(suggesterName, fieldSuggester)) + .build(); +SearchRequest searchRequest = new SearchRequest.Builder() + .index(index) + .suggest(suggester) + .build(); + +SearchResponse response = client.search(searchRequest, AppData.class); +``` + +#### Using term suggester + +```java +String index = "term-suggester"; + +// term suggester does not require a special mapping +client.indices().create(c -> c + .index(index)); + +AppData appData = new AppData(); +appData.setIntValue(1337); +appData.setMsg("foo"); + +client.index(b -> b + .index(index) + .id("1") + .document(appData) + .refresh(Refresh.True)); + +appData.setIntValue(1338); +appData.setMsg("foobar"); + +client.index(b -> b + .index(index) + .id("2") + .document(appData) + .refresh(Refresh.True)); + +String suggesterName = "msgSuggester"; + +TermSuggester termSuggester = FieldSuggesterBuilders.term() + .field("msg") + .size(1) + .build(); +FieldSuggester fieldSuggester = new FieldSuggester.Builder().text("fool") + .term(termSuggester) + .build(); +Suggester suggester = new Suggester.Builder() + .suggesters(Collections.singletonMap(suggesterName, fieldSuggester)) + .build(); +SearchRequest searchRequest = new SearchRequest.Builder() + .index(index) + .suggest(suggester) + .build(); + +SearchResponse response = client.search(searchRequest, AppData.class); +``` + +#### Using phrase suggester + +```java +String index = "test-phrase-suggester"; + +ShingleTokenFilter shingleTokenFilter = new ShingleTokenFilter.Builder().minShingleSize("2") + .maxShingleSize("3") + .build(); + +Analyzer analyzer = new Analyzer.Builder() + .custom(new CustomAnalyzer.Builder().tokenizer("standard") + .filter(Arrays.asList("lowercase", "shingle")).build()) + .build(); + +TokenFilter tokenFilter = new TokenFilter.Builder() + .definition(new TokenFilterDefinition.Builder() + .shingle(shingleTokenFilter).build()) + .build(); + +IndexSettingsAnalysis indexSettingsAnalysis = new IndexSettingsAnalysis.Builder() + .analyzer("trigram", analyzer) + .filter("shingle", tokenFilter) + .build(); + +IndexSettings settings = new IndexSettings.Builder().analysis(indexSettingsAnalysis).build(); + +TypeMapping mapping = new TypeMapping.Builder().properties("msg", new Property.Builder() + .text(new TextProperty.Builder().fields("trigram", new Property.Builder() + .text(new TextProperty.Builder().analyzer("trigram").build()) + .build()).build()) + .build()).build(); + +client.indices().create(c -> c + .index(index) + .settings(settings) + .mappings(mapping)); + +AppData appData = new AppData(); +appData.setIntValue(1337); +appData.setMsg("Design Patterns"); + +client.index(b -> b + .index(index) + .id("1") + .document(appData) + .refresh(Refresh.True)); + +appData.setIntValue(1338); +appData.setMsg("Software Architecture Patterns Explained"); + +client.index(b -> b + .index(index) + .id("2") + .document(appData) + .refresh(Refresh.True)); + +String suggesterName = "msgSuggester"; + +PhraseSuggester phraseSuggester = FieldSuggesterBuilders.phrase() + .field("msg.trigram") + .build(); +FieldSuggester fieldSuggester = new FieldSuggester.Builder().text("design paterns") + .phrase(phraseSuggester) + .build(); +Suggester suggester = new Suggester.Builder() + .suggesters(Collections.singletonMap(suggesterName, fieldSuggester)) + .build(); +SearchRequest searchRequest = new SearchRequest.Builder() + .index(index) + .suggest(suggester) + .build(); + +SearchResponse response = client.search(searchRequest, AppData.class); +``` + +### Aggregations + +```java +SearchRequest searchRequest = new SearchRequest.Builder().query(q -> q.match(m -> m.field("title") + .query(FieldValue.of("Document 1")))) + .aggregations("titles", new Aggregation.Builder().terms(t -> t.field("title.keyword")) + .build()) + .build(); + +SearchResponse searchResponse = client.search(searchRequest, IndexData.class); +for (Map.Entry entry : searchResponse.aggregations().entrySet()) { + System.out.println("Agg - " + entry.getKey()); + entry.getValue().sterms().buckets().array().forEach(b -> System.out.printf("%s : %d%n", 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/samples/src/main/java/org/opensearch/client/samples/Bulk.java b/samples/src/main/java/org/opensearch/client/samples/Bulk.java new file mode 100644 index 0000000000..b3f84f04e6 --- /dev/null +++ b/samples/src/main/java/org/opensearch/client/samples/Bulk.java @@ -0,0 +1,104 @@ +/* + * 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.samples; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.opensearch.client.opensearch._types.Refresh; +import org.opensearch.client.opensearch._types.mapping.IntegerNumberProperty; +import org.opensearch.client.opensearch._types.mapping.Property; +import org.opensearch.client.opensearch._types.mapping.TypeMapping; +import org.opensearch.client.opensearch._types.query_dsl.Query; +import org.opensearch.client.opensearch.core.BulkRequest; +import org.opensearch.client.opensearch.core.BulkResponse; +import org.opensearch.client.opensearch.core.SearchRequest; +import org.opensearch.client.opensearch.core.SearchResponse; +import org.opensearch.client.opensearch.core.bulk.BulkOperation; +import org.opensearch.client.opensearch.core.bulk.IndexOperation; +import org.opensearch.client.opensearch.indices.CreateIndexRequest; +import org.opensearch.client.opensearch.indices.DeleteIndexRequest; +import org.opensearch.client.opensearch.indices.IndexSettings; +import org.opensearch.client.samples.util.IndexData; + +/** + * Run with: ./gradlew :samples:run -Dsamples.mainClass=Bulk + */ +public class Bulk { + private static final Logger LOGGER = LogManager.getLogger(Bulk.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 = "my-index"; + + if (!client.indices().exists(r -> r.index(indexName)).value()) { + LOGGER.info("Creating index {}", indexName); + IndexSettings settings = new IndexSettings.Builder() + .numberOfShards("2") + .numberOfReplicas("1") + .build(); + TypeMapping mapping = new TypeMapping.Builder() + .properties("age", new Property.Builder().integer(new IntegerNumberProperty.Builder().build()).build()) + .build(); + CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder() + .index(indexName) + .settings(settings) + .mappings(mapping) + .build(); + client.indices().create(createIndexRequest); + } + + LOGGER.info("Bulk indexing documents"); + ArrayList ops = new ArrayList<>(); + IndexData doc1 = new IndexData("Document 1", "The text of document 1"); + ops.add(new BulkOperation.Builder().index( + IndexOperation.of(io -> io.index(indexName).id("id1").document(doc1)) + ).build()); + IndexData doc2 = new IndexData("Document 2", "The text of document 2"); + ops.add(new BulkOperation.Builder().index( + IndexOperation.of(io -> io.index(indexName).id("id2").document(doc2)) + ).build()); + IndexData doc3 = new IndexData("Document 3", "The text of document 3"); + ops.add(new BulkOperation.Builder().index( + IndexOperation.of(io -> io.index(indexName).id("id3").document(doc3)) + ).build()); + + BulkRequest.Builder bulkReq = new BulkRequest.Builder() + .index(indexName) + .operations(ops) + .refresh(Refresh.WaitFor); + BulkResponse bulkResponse = client.bulk(bulkReq.build()); + LOGGER.info("Bulk response items: {}", bulkResponse.items().size()); + + Query query = Query.of(qb -> qb.match(mb -> mb.field("title").query(fv -> fv.stringValue("Document")))); + final SearchRequest.Builder searchReq = new SearchRequest.Builder() + .allowPartialSearchResults(false) + .index(List.of(indexName)) + .size(10) + .source(sc -> sc.fetch(false)) + .ignoreThrottled(false) + .query(query); + SearchResponse searchResponse = client.search(searchReq.build(), IndexData.class); + LOGGER.info("Found {} documents", searchResponse.hits().hits().size()); + + LOGGER.info("Deleting index {}", indexName); + DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest.Builder().index(indexName).build(); + client.indices().delete(deleteIndexRequest); + } catch (Exception e) { + LOGGER.error("Unexpected exception", e); + } + } +} diff --git a/samples/src/main/java/org/opensearch/client/samples/DataStreamBasics.java b/samples/src/main/java/org/opensearch/client/samples/DataStreamBasics.java new file mode 100644 index 0000000000..e6d8bf5875 --- /dev/null +++ b/samples/src/main/java/org/opensearch/client/samples/DataStreamBasics.java @@ -0,0 +1,75 @@ +/* + * 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.samples; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.opensearch.client.opensearch.indices.CreateDataStreamRequest; +import org.opensearch.client.opensearch.indices.DataStream; +import org.opensearch.client.opensearch.indices.DataStreamsStatsRequest; +import org.opensearch.client.opensearch.indices.DataStreamsStatsResponse; +import org.opensearch.client.opensearch.indices.DeleteDataStreamRequest; +import org.opensearch.client.opensearch.indices.GetDataStreamRequest; +import org.opensearch.client.opensearch.indices.GetDataStreamResponse; +import org.opensearch.client.opensearch.indices.PutIndexTemplateRequest; + +/** + * Run with: ./gradlew :samples:run -Dsamples.mainClass=DataStreamBasics + */ +public class DataStreamBasics { + private static final Logger LOGGER = LogManager.getLogger(DataStreamBasics.class); + + public static void main(String[] args) { + try { + var client = SampleClient.create(); + + var version = client.info().version(); + LOGGER.info("Server: {}@{}", version.distribution(), version.number()); + + String dataStreamIndexTemplateName = "sample-data-stream-template"; + String timestampFieldName = "my_timestamp_field"; + String namePattern = "sample-data-stream-*"; + String dataStreamName = "sample-data-stream-1"; + + // Create an index template which configures data stream + PutIndexTemplateRequest putIndexTemplateRequest = new PutIndexTemplateRequest.Builder() + .name(dataStreamIndexTemplateName) + .indexPatterns(namePattern) + .dataStream(new DataStream.Builder() + .timestampField(t -> t.name(timestampFieldName)) + .build()) + .build(); + client.indices().putIndexTemplate(putIndexTemplateRequest); + + // Create a data stream + CreateDataStreamRequest createDataStreamRequest = new CreateDataStreamRequest.Builder().name(dataStreamName).build(); + client.indices().createDataStream(createDataStreamRequest); + LOGGER.info("Created a data stream"); + + GetDataStreamRequest getDataStreamRequest = new GetDataStreamRequest.Builder().name(dataStreamName).build(); + GetDataStreamResponse getDataStreamResponse = client.indices().getDataStream(getDataStreamRequest); + LOGGER.info("Found {} data streams", getDataStreamResponse.dataStreams().size()); + + DataStreamsStatsRequest dataStreamsStatsRequest = new DataStreamsStatsRequest.Builder().name(dataStreamName).build(); + DataStreamsStatsResponse dataStreamsStatsResponse = client.indices().dataStreamsStats(dataStreamsStatsRequest); + LOGGER.info("Data stream stats:"); + LOGGER.info("Shards: {}", dataStreamsStatsResponse.shards()); + LOGGER.info("Data stream count: {}", dataStreamsStatsResponse.dataStreamCount()); + LOGGER.info("Backing indices: {}", dataStreamsStatsResponse.backingIndices()); + LOGGER.info("Total store size: {}", dataStreamsStatsResponse.totalStoreSize()); + LOGGER.info("Data stream name: {}", dataStreamsStatsResponse.dataStreams().get(0).dataStream()); + + LOGGER.info("Deleting data stream"); + DeleteDataStreamRequest deleteDataStreamRequest = new DeleteDataStreamRequest.Builder().name(dataStreamName).build(); + client.indices().deleteDataStream(deleteDataStreamRequest); + } catch (Exception e) { + LOGGER.error("Unexpected exception", e); + } + } +} diff --git a/samples/src/main/java/org/opensearch/client/samples/IndexingBasics.java b/samples/src/main/java/org/opensearch/client/samples/IndexingBasics.java new file mode 100644 index 0000000000..bba03de80b --- /dev/null +++ b/samples/src/main/java/org/opensearch/client/samples/IndexingBasics.java @@ -0,0 +1,118 @@ +/* + * 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.samples; + +import java.util.ArrayList; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.opensearch.client.json.JsonData; +import org.opensearch.client.opensearch._types.mapping.DynamicMapping; +import org.opensearch.client.opensearch._types.mapping.FieldNamesField; +import org.opensearch.client.opensearch._types.mapping.IntegerNumberProperty; +import org.opensearch.client.opensearch._types.mapping.Property; +import org.opensearch.client.opensearch._types.mapping.RoutingField; +import org.opensearch.client.opensearch._types.mapping.SourceField; +import org.opensearch.client.opensearch._types.mapping.TypeMapping; +import org.opensearch.client.opensearch.core.IndexRequest; +import org.opensearch.client.opensearch.core.SearchResponse; +import org.opensearch.client.opensearch.indices.CreateIndexRequest; +import org.opensearch.client.opensearch.indices.DeleteIndexRequest; +import org.opensearch.client.opensearch.indices.GetMappingRequest; +import org.opensearch.client.opensearch.indices.GetMappingResponse; +import org.opensearch.client.opensearch.indices.IndexSettings; +import org.opensearch.client.opensearch.indices.PutMappingRequest; +import org.opensearch.client.samples.util.IndexData; + +/** + * Run with: ./gradlew :samples:run -Dsamples.mainClass=IndexingBasics + */ +public class IndexingBasics { + 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 = "my-index"; + + if (!client.indices().exists(r -> r.index(indexName)).value()) { + LOGGER.info("Creating index {}", indexName); + IndexSettings settings = new IndexSettings.Builder() + .numberOfShards("2") + .numberOfReplicas("1") + .build(); + TypeMapping mapping = new TypeMapping.Builder() + .properties("age", new Property.Builder().integer(new IntegerNumberProperty.Builder().build()).build()) + .build(); + CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder() + .index(indexName) + .settings(settings) + .mappings(mapping) + .build(); + client.indices().create(createIndexRequest); + } + + LOGGER.info("Indexing documents"); + IndexData indexData = new IndexData("Document 1", "Text for document 1"); + IndexRequest indexRequest = new IndexRequest.Builder().index(indexName) + .id("1") + .document(indexData) + .build(); + client.index(indexRequest); + + indexData = new IndexData("Document 2", "Text for document 2"); + indexRequest = new IndexRequest.Builder().index(indexName).id("2").document(indexData).build(); + client.index(indexRequest); + + // wait for the document to index + Thread.sleep(3000); + + SearchResponse searchResponse = client.search(s -> s.index(indexName), IndexData.class); + for (var hit : searchResponse.hits().hits()) { + LOGGER.info("Found {} with score {}", hit.source(), hit.score()); + } + + LOGGER.info("Adding a new mapping to index {}", indexName); + PutMappingRequest.Builder mappingsRequestBuilder = new PutMappingRequest.Builder().index(indexName) + .source( + new SourceField.Builder() + .enabled(true) + .build()) + .routing( + new RoutingField.Builder() + .required(false) + .build()) + .dynamic(DynamicMapping.Strict) + .meta("key", JsonData.of("key value")) + .fieldNames(new FieldNamesField.Builder().enabled(false).build()) + .dateDetection(false) + .dynamicDateFormats(new ArrayList<>()) + .dynamicTemplates(new ArrayList<>()) + .numericDetection(false); + client.indices().putMapping(mappingsRequestBuilder.build()); + + GetMappingRequest mappingsRequest = new GetMappingRequest.Builder().index(indexName).build(); + GetMappingResponse getMappingResponse = client.indices().getMapping(mappingsRequest); + LOGGER.info("Mappings {} found for index {}", getMappingResponse.result().get(indexName).mappings(), indexName); + + LOGGER.info("Deleting document with id 1"); + client.delete(d -> d.index(indexName).id("1")); + + LOGGER.info("Deleting index {}", indexName); + DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest.Builder().index(indexName).build(); + client.indices().delete(deleteIndexRequest); + } catch (Exception e) { + LOGGER.error("Unexpected exception", e); + } + } +} diff --git a/samples/src/main/java/org/opensearch/client/samples/PointInTime.java b/samples/src/main/java/org/opensearch/client/samples/PointInTime.java new file mode 100644 index 0000000000..55a348ef8c --- /dev/null +++ b/samples/src/main/java/org/opensearch/client/samples/PointInTime.java @@ -0,0 +1,81 @@ +/* + * 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.samples; + +import java.util.Collections; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.opensearch.client.opensearch._types.Time; +import org.opensearch.client.opensearch._types.mapping.IntegerNumberProperty; +import org.opensearch.client.opensearch._types.mapping.Property; +import org.opensearch.client.opensearch._types.mapping.TypeMapping; +import org.opensearch.client.opensearch.core.pit.CreatePitRequest; +import org.opensearch.client.opensearch.core.pit.CreatePitResponse; +import org.opensearch.client.opensearch.core.pit.DeletePitRequest; +import org.opensearch.client.opensearch.core.pit.DeletePitResponse; +import org.opensearch.client.opensearch.core.pit.ListAllPitResponse; +import org.opensearch.client.opensearch.indices.CreateIndexRequest; +import org.opensearch.client.opensearch.indices.DeleteIndexRequest; +import org.opensearch.client.opensearch.indices.IndexSettings; + +/** + * Run with: ./gradlew :samples:run -Dsamples.mainClass=PointInTime + */ +public class PointInTime { + private static final Logger LOGGER = LogManager.getLogger(PointInTime.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 = "my-index"; + + if (!client.indices().exists(r -> r.index(indexName)).value()) { + LOGGER.info("Creating index {}", indexName); + IndexSettings settings = new IndexSettings.Builder() + .numberOfShards("2") + .numberOfReplicas("1") + .build(); + TypeMapping mapping = new TypeMapping.Builder() + .properties("age", new Property.Builder().integer(new IntegerNumberProperty.Builder().build()).build()) + .build(); + CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder() + .index(indexName) + .settings(settings) + .mappings(mapping) + .build(); + client.indices().create(createIndexRequest); + } + + CreatePitRequest createPitRequest = new CreatePitRequest.Builder() + .targetIndexes(Collections.singletonList(indexName)) + .keepAlive(new Time.Builder().time("100m").build()).build(); + + CreatePitResponse createPitResponse = client.createPit(createPitRequest); + LOGGER.info("PIT created with id: {}", createPitResponse.pitId()); + + ListAllPitResponse listAllPitResponse = client.listAllPit(); + LOGGER.info("Found {} PITs", listAllPitResponse.pits().size()); + + DeletePitRequest deletePitRequest = new DeletePitRequest.Builder() + .pitId(Collections.singletonList(createPitResponse.pitId())).build(); + DeletePitResponse deletePitResponse = client.deletePit(deletePitRequest); + LOGGER.info("Deleting PIT: {}", deletePitResponse.pits()); + + LOGGER.info("Deleting index {}", indexName); + DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest.Builder().index(indexName).build(); + client.indices().delete(deleteIndexRequest); + } catch (Exception e) { + LOGGER.error("Unexpected exception", e); + } + } +} diff --git a/samples/src/main/java/org/opensearch/client/samples/Search.java b/samples/src/main/java/org/opensearch/client/samples/Search.java new file mode 100644 index 0000000000..ccc1acb679 --- /dev/null +++ b/samples/src/main/java/org/opensearch/client/samples/Search.java @@ -0,0 +1,315 @@ +/* + * 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.samples; + +import java.util.Arrays; +import java.util.Collections; +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.aggregations.Aggregate; +import org.opensearch.client.opensearch._types.aggregations.Aggregation; +import org.opensearch.client.opensearch._types.analysis.Analyzer; +import org.opensearch.client.opensearch._types.analysis.CustomAnalyzer; +import org.opensearch.client.opensearch._types.analysis.ShingleTokenFilter; +import org.opensearch.client.opensearch._types.analysis.TokenFilter; +import org.opensearch.client.opensearch._types.analysis.TokenFilterDefinition; +import org.opensearch.client.opensearch._types.mapping.Property; +import org.opensearch.client.opensearch._types.mapping.TextProperty; +import org.opensearch.client.opensearch._types.mapping.TypeMapping; +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.core.search.CompletionSuggester; +import org.opensearch.client.opensearch.core.search.FieldSuggester; +import org.opensearch.client.opensearch.core.search.FieldSuggesterBuilders; +import org.opensearch.client.opensearch.core.search.PhraseSuggester; +import org.opensearch.client.opensearch.core.search.Suggester; +import org.opensearch.client.opensearch.core.search.TermSuggester; +import org.opensearch.client.opensearch.indices.CreateIndexRequest; +import org.opensearch.client.opensearch.indices.DeleteIndexRequest; +import org.opensearch.client.opensearch.indices.IndexSettings; +import org.opensearch.client.opensearch.indices.IndexSettingsAnalysis; +import org.opensearch.client.samples.util.AppData; +import org.opensearch.client.samples.util.IndexData; + +/** + * Run with: ./gradlew :samples:run -Dsamples.mainClass=Search + */ +public class Search { + private static final Logger LOGGER = LogManager.getLogger(IndexingBasics.class); + + private static OpenSearchClient client; + + public static void main(String[] args) { + try { + client = SampleClient.create(); + + var version = client.info().version(); + LOGGER.info("Server: {}@{}", version.distribution(), version.number()); + + final var indexName = "my-index"; + + if (!client.indices().exists(r -> r.index(indexName)).value()) { + LOGGER.info("Creating index {}", indexName); + CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder().index(indexName).build(); + client.indices().create(createIndexRequest); + } + + LOGGER.info("Indexing documents"); + IndexData indexData = new IndexData("Document 1", "Text for document 1"); + IndexRequest indexRequest = new IndexRequest.Builder().index(indexName) + .id("1") + .document(indexData) + .build(); + client.index(indexRequest); + + indexData = new IndexData("Document 2", "Text for document 2"); + indexRequest = new IndexRequest.Builder().index(indexName).id("2").document(indexData).build(); + client.index(indexRequest); + + // wait for the document to index + Thread.sleep(3000); + + SearchResponse searchResponse = client.search(s -> s.index(indexName), IndexData.class); + for (var hit : searchResponse.hits().hits()) { + LOGGER.info("Found {} with score {}", hit.source(), hit.score()); + } + + SearchRequest searchRequest = new SearchRequest.Builder().query(q -> q.match(m -> m.field("text") + .query(FieldValue.of("Text for document 2")))) + .build(); + + searchResponse = client.search(searchRequest, IndexData.class); + for (var hit : searchResponse.hits().hits()) { + LOGGER.info("Found {} with score {}", hit.source(), hit.score()); + } + + searchRequest = new SearchRequest.Builder().query(q -> q.match(m -> m.field("title") + .query(FieldValue.of("Document 1")))) + .aggregations("titles", + new Aggregation.Builder().terms(t -> t.field("title.keyword")) + .build()) + .build(); + + searchResponse = client.search(searchRequest, IndexData.class); + for (Map.Entry entry : searchResponse.aggregations().entrySet()) { + LOGGER.info("Agg - {}", entry.getKey()); + entry.getValue().sterms().buckets().array().forEach(b -> LOGGER.info("{} : {}", b.key(), b.docCount())); + } + + LOGGER.info("Deleting index {}", indexName); + DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest.Builder().index(indexName).build(); + client.indices().delete(deleteIndexRequest); + + searchWithCompletionSuggester(); + searchWithTermSuggester(); + searchWithPhraseSuggester(); + } catch (Exception e) { + LOGGER.error("Unexpected exception", e); + } + } + + public static void searchWithCompletionSuggester() { + try { + var index = "completion-suggester"; + Property intValueProp = new Property.Builder() + .long_(v -> v) + .build(); + Property msgCompletionProp = new Property.Builder() + .completion(c -> c) + .build(); + client.indices().create(c -> c + .index(index) + .mappings(m -> m + .properties("intValue", intValueProp) + .properties("msg", msgCompletionProp))); + + AppData appData = new AppData(); + appData.setIntValue(1337); + appData.setMsg("foo"); + + client.index(b -> b + .index(index) + .id("1") + .document(appData) + .refresh(Refresh.True)); + + appData.setIntValue(1338); + appData.setMsg("foobar"); + + client.index(b -> b + .index(index) + .id("2") + .document(appData) + .refresh(Refresh.True)); + + String suggesterName = "msgSuggester"; + + CompletionSuggester completionSuggester = FieldSuggesterBuilders.completion() + .field("msg") + .size(1) + .build(); + FieldSuggester fieldSuggester = new FieldSuggester.Builder().prefix("foo") + .completion(completionSuggester) + .build(); + Suggester suggester = new Suggester.Builder() + .suggesters(Collections.singletonMap(suggesterName, fieldSuggester)) + .build(); + SearchRequest searchRequest = new SearchRequest.Builder() + .index(index) + .suggest(suggester) + .build(); + + SearchResponse searchResponse = client.search(searchRequest, AppData.class); + LOGGER.info("Suggester response size {}", searchResponse.suggest().get(suggesterName).size()); + + client.indices().delete(new DeleteIndexRequest.Builder().index(index).build()); + } catch (Exception e) { + LOGGER.error("Unexpected exception", e); + } + } + + public static void searchWithTermSuggester() { + try { + String index = "term-suggester"; + + // term suggester does not require a special mapping + client.indices().create(c -> c + .index(index)); + + AppData appData = new AppData(); + appData.setIntValue(1337); + appData.setMsg("foo"); + + client.index(b -> b + .index(index) + .id("1") + .document(appData) + .refresh(Refresh.True)); + + appData.setIntValue(1338); + appData.setMsg("foobar"); + + client.index(b -> b + .index(index) + .id("2") + .document(appData) + .refresh(Refresh.True)); + + String suggesterName = "msgSuggester"; + + TermSuggester termSuggester = FieldSuggesterBuilders.term() + .field("msg") + .size(1) + .build(); + FieldSuggester fieldSuggester = new FieldSuggester.Builder().text("fool") + .term(termSuggester) + .build(); + Suggester suggester = new Suggester.Builder() + .suggesters(Collections.singletonMap(suggesterName, fieldSuggester)) + .build(); + SearchRequest searchRequest = new SearchRequest.Builder() + .index(index) + .suggest(suggester) + .build(); + + SearchResponse searchResponse = client.search(searchRequest, AppData.class); + LOGGER.info("Suggester response size {}", searchResponse.suggest().get(suggesterName).size()); + + client.indices().delete(new DeleteIndexRequest.Builder().index(index).build()); + } catch (Exception e) { + LOGGER.error("Unexpected exception", e); + } + } + + public static void searchWithPhraseSuggester() { + try { + String index = "test-phrase-suggester"; + + ShingleTokenFilter shingleTokenFilter = new ShingleTokenFilter.Builder().minShingleSize("2") + .maxShingleSize("3") + .build(); + + Analyzer analyzer = new Analyzer.Builder() + .custom(new CustomAnalyzer.Builder().tokenizer("standard") + .filter(Arrays.asList("lowercase", "shingle")).build()) + .build(); + + TokenFilter tokenFilter = new TokenFilter.Builder() + .definition(new TokenFilterDefinition.Builder() + .shingle(shingleTokenFilter).build()) + .build(); + + IndexSettingsAnalysis indexSettingsAnalysis = new IndexSettingsAnalysis.Builder() + .analyzer("trigram", analyzer) + .filter("shingle", tokenFilter) + .build(); + + IndexSettings settings = new IndexSettings.Builder().analysis(indexSettingsAnalysis).build(); + + TypeMapping mapping = new TypeMapping.Builder().properties("msg", new Property.Builder() + .text(new TextProperty.Builder().fields("trigram", new Property.Builder() + .text(new TextProperty.Builder().analyzer("trigram").build()) + .build()).build()) + .build()).build(); + + client.indices().create(c -> c + .index(index) + .settings(settings) + .mappings(mapping)); + + AppData appData = new AppData(); + appData.setIntValue(1337); + appData.setMsg("Design Patterns"); + + client.index(b -> b + .index(index) + .id("1") + .document(appData) + .refresh(Refresh.True)); + + appData.setIntValue(1338); + appData.setMsg("Software Architecture Patterns Explained"); + + client.index(b -> b + .index(index) + .id("2") + .document(appData) + .refresh(Refresh.True)); + + String suggesterName = "msgSuggester"; + + PhraseSuggester phraseSuggester = FieldSuggesterBuilders.phrase() + .field("msg.trigram") + .build(); + FieldSuggester fieldSuggester = new FieldSuggester.Builder().text("design paterns") + .phrase(phraseSuggester) + .build(); + Suggester suggester = new Suggester.Builder() + .suggesters(Collections.singletonMap(suggesterName, fieldSuggester)) + .build(); + SearchRequest searchRequest = new SearchRequest.Builder() + .index(index) + .suggest(suggester) + .build(); + + SearchResponse searchResponse = client.search(searchRequest, AppData.class); + LOGGER.info("Suggester response size {}", searchResponse.suggest().get(suggesterName).size()); + + client.indices().delete(new DeleteIndexRequest.Builder().index(index).build()); + } catch (Exception e) { + LOGGER.error("Unexpected exception", e); + } + } +} diff --git a/samples/src/main/java/org/opensearch/client/samples/knn/KnnBasics.java b/samples/src/main/java/org/opensearch/client/samples/knn/KnnBasics.java index c34bcd510b..1ac93a2723 100644 --- a/samples/src/main/java/org/opensearch/client/samples/knn/KnnBasics.java +++ b/samples/src/main/java/org/opensearch/client/samples/knn/KnnBasics.java @@ -12,8 +12,8 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.opensearch.client.opensearch.core.BulkRequest; -import org.opensearch.client.samples.RandUtil; import org.opensearch.client.samples.SampleClient; +import org.opensearch.client.samples.util.RandUtil; /** * Run with: ./gradlew :samples:run -Dsamples.mainClass=knn.KnnBasics diff --git a/samples/src/main/java/org/opensearch/client/samples/knn/KnnBooleanFilter.java b/samples/src/main/java/org/opensearch/client/samples/knn/KnnBooleanFilter.java index 9b8121da5e..47f637a8d0 100644 --- a/samples/src/main/java/org/opensearch/client/samples/knn/KnnBooleanFilter.java +++ b/samples/src/main/java/org/opensearch/client/samples/knn/KnnBooleanFilter.java @@ -12,8 +12,8 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.opensearch.client.opensearch.core.BulkRequest; -import org.opensearch.client.samples.RandUtil; import org.opensearch.client.samples.SampleClient; +import org.opensearch.client.samples.util.RandUtil; /** * Run with: ./gradlew :samples:run -Dsamples.mainClass=knn.KnnBooleanFilter diff --git a/samples/src/main/java/org/opensearch/client/samples/knn/KnnPainlessScript.java b/samples/src/main/java/org/opensearch/client/samples/knn/KnnPainlessScript.java index de39b8a82b..3ff803138a 100644 --- a/samples/src/main/java/org/opensearch/client/samples/knn/KnnPainlessScript.java +++ b/samples/src/main/java/org/opensearch/client/samples/knn/KnnPainlessScript.java @@ -13,8 +13,8 @@ import org.apache.logging.log4j.Logger; import org.opensearch.client.json.JsonData; import org.opensearch.client.opensearch.core.BulkRequest; -import org.opensearch.client.samples.RandUtil; import org.opensearch.client.samples.SampleClient; +import org.opensearch.client.samples.util.RandUtil; /** * Run with: ./gradlew :samples:run -Dsamples.mainClass=knn.KnnPainlessScript diff --git a/samples/src/main/java/org/opensearch/client/samples/knn/KnnScriptScore.java b/samples/src/main/java/org/opensearch/client/samples/knn/KnnScriptScore.java index 035aabb3e4..0ee46e4fc0 100644 --- a/samples/src/main/java/org/opensearch/client/samples/knn/KnnScriptScore.java +++ b/samples/src/main/java/org/opensearch/client/samples/knn/KnnScriptScore.java @@ -13,8 +13,8 @@ import org.apache.logging.log4j.Logger; import org.opensearch.client.json.JsonData; import org.opensearch.client.opensearch.core.BulkRequest; -import org.opensearch.client.samples.RandUtil; import org.opensearch.client.samples.SampleClient; +import org.opensearch.client.samples.util.RandUtil; /** * Run with: ./gradlew :samples:run -Dsamples.mainClass=knn.KnnScriptScore diff --git a/samples/src/main/java/org/opensearch/client/samples/util/AppData.java b/samples/src/main/java/org/opensearch/client/samples/util/AppData.java new file mode 100644 index 0000000000..3b6968722a --- /dev/null +++ b/samples/src/main/java/org/opensearch/client/samples/util/AppData.java @@ -0,0 +1,30 @@ +/* + * 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.samples.util; + +public class AppData { + private int intValue; + private String msg; + + public int getIntValue() { + return intValue; + } + + public void setIntValue(int intValue) { + this.intValue = intValue; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } +} diff --git a/samples/src/main/java/org/opensearch/client/samples/util/IndexData.java b/samples/src/main/java/org/opensearch/client/samples/util/IndexData.java new file mode 100644 index 0000000000..759f03be8f --- /dev/null +++ b/samples/src/main/java/org/opensearch/client/samples/util/IndexData.java @@ -0,0 +1,43 @@ +/* + * 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.samples.util; + +public class IndexData { + private String title; + private String text; + + public IndexData() { + } + + public IndexData(String title, String text) { + this.title = title; + this.text = text; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + @Override + public String toString() { + return String.format("IndexData{title='%s', text='%s'}", title, text); + } +} diff --git a/samples/src/main/java/org/opensearch/client/samples/RandUtil.java b/samples/src/main/java/org/opensearch/client/samples/util/RandUtil.java similarity index 92% rename from samples/src/main/java/org/opensearch/client/samples/RandUtil.java rename to samples/src/main/java/org/opensearch/client/samples/util/RandUtil.java index f6706aa24f..fbc2249621 100644 --- a/samples/src/main/java/org/opensearch/client/samples/RandUtil.java +++ b/samples/src/main/java/org/opensearch/client/samples/util/RandUtil.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.client.samples; +package org.opensearch.client.samples.util; public class RandUtil { public static float[] rand2SfArray(int n) {