ElasticSearch new version of JavaClient using the introduction

The java client used by ElasticSearch before version 7.17 was the Java REST Client, but since version 7.17, the Java REST Client has been officially marked as deprecated and the new version of the Java Client is recommended. This article introduces the new version of the ElasticSearch Java Client’s basic usage. The specific code reference Example project.

I. Overview

Elasticsearch 7.17 version of the new Java API Client has the following advantages.

  1. strong typing
  2. synchronous and asynchronous calls
  3. streaming and functional calls
  4. seamless integration with Jackson
  5. encapsulated connection pooling, retry, json serialization and other common capabilities

II. Adding dependencies to the project

Add dependencies to the project’s gradle or maven.

Gradle:

dependencies {
    implementation 'co.elastic.clients:elasticsearch-java:8.1.2'
    implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.3'

    // Needed only if you use the spring-dependency-management
    // and spring-boot Gradle plugins
    implementation 'jakarta.json:jakarta.json-api:2.0.1' 
}

Maven:

<project>
  <dependencies>

    <dependency>
      <groupId>co.elastic.clients</groupId>
      <artifactId>elasticsearch-java</artifactId>
      <version>8.1.2</version>
    </dependency>

    <dependency
      <groupId>com.fasterxml.jackson.core</groupId
      <artifactId>jackson-databind</artifactId>
      <version>2.12.3</version>
    </dependency>

    <! -- Needed only if you use the spring-boot Maven plugin -->
    <dependency 
      <groupId>jakarta.json</groupId>
      <artifactId>jakarta.json-api</artifactId>
      <version>2.0.1</version>
    </dependency>

  </dependencies>
</project>

The jakarta.json package was introduced to address compatibility issues with the springboot project, as detailed in the official documentation

Third, the initialization of JavaClient

Java API Client contains three parts.

  1. a java client corresponding to the class ElasticsearchClient
  2. a JSON object mapper for the serialization and deserialization of data
  3. the underlying Transport communication
    RestClient restClient = RestClient.builder(new HttpHost("localhost", 9200)).build();
    ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
    elasticsearchClient = new ElasticsearchClient(transport);

Third, the basic operations of ElasticSearch

  1. save data, through the Java Client’s automatic serialization capabilities, we can directly pass the object to the Java Client, without having to manually handle the serialization of json data in ElasticSearch.
    DemoDomain record = new DemoDomain();
    record.setId("1");
    record.setName("test");

    IndexRequest<DemoDomain> indexRequest = IndexRequest.of(b -> b
            .index(MY_INDEX)
            .id(record.getId())
            .document(record)
            .refresh(Refresh.True)); // Make it visible for search

    elasticsearchClient.index(indexRequest);
  1. query all data, the same json data deserialization also has Java Client automatically handle, while functional programming makes the code is very simple.
    SearchRequest searchRequest = SearchRequest.of(s -> s
                .index(MY_INDEX)
                .query(q -> q
                        .bool(b -> b
                                .must(m -> m.term(t -> t.field("name").value(FieldValue.of("test" ))))
                        )
                ));
    SearchResponse<DemoDomain> search = elasticsearchClient.search(searchRequest, DemoDomain.class);
    return search.hits().hits().stream().map(Hit::source).toList();
  1. Query a single data, specify id condition in the query condition to query a single record precisely.
    SearchRequest searchRequest = SearchRequest.of(s -> s
                .index(MY_INDEX)
                .query(q -> q
                        .bool(b -> b
                                .must(m -> m.term(
                                        t -> t.field("id").value(FieldValue.of("1"))))
                                .must(m -> m.term(
                                        t -> t.field("name").value(FieldValue.of("test"))))
                        )
                ));
    SearchResponse<DemoDomain> search = elasticsearchClient.search(searchRequest, DemoDomain.class);
    return search.hits().hits().get(0).source();
  1. Delete a single data, you can delete the record with the specified id by DeleteRequest.
    DeleteRequest deleteRequest = DeleteRequest.of(s -> s
                .index(MY_INDEX)
                .id(id));
    elasticsearchClient.delete(deleteRequest);
  1. Delete the found data by merging the query operation and the delete operation together.
    SearchRequest searchRequest = SearchRequest.of(s -> s
                .index(MY_INDEX)
                .query(q -> q
                        .bool(b -> b
                                .must(m -> m.term(
                                        t -> t.field("name").value(FieldValue.of("test" ))))
                        )
                ));
    SearchResponse<DemoDomain> search = elasticsearchClient.search(searchRequest, DemoDomain.class);
    elasticsearchClient.search(searchRequest, DemoDomain.class).hits().hits().forEach(record -> {
            DeleteRequest deleteRequest = DeleteRequest.of(s -> s
                    .index(MY_INDEX)
                    .id(record.source().getId())));
            try {
                elasticsearchClient.delete(deleteRequest);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
    });