preface

The function “Type” has been deprecated with the release of version 7.x. In order to adapt to this data structure change, the function “Type” has been deprecated. The new ElasticSearch Java Client is recommended from version 7.15.

If you’re not already familiar with RestHighLevelClient or the ES Rest API see the Elastic Stack-2: ElasticSearch API.

features

  1. All requests and corresponding use strong typing, use generic enhancement
  2. Support for synchronous and asynchronous requests
  3. usebuildersPattern, make complex request become smooth, good supportlambdaExpression, simplify code, enhance readability

Early adopters

Build ElasticsearchClient

Maven rely on

<dependency>
  <groupId>co.elastic.clients</groupId>
  <artifactId>elasticsearch-java</artifactId>
  <version>7.16.2</version>
</dependency>
Copy the code

Guide to pit mining:

Jakarta. json-API has been introduced in this package by default, but the author found that it did not rely on it when building the environment. If you report that you cannot find related classes, you can try importing the following dependencies:

<dependency>
  <groupId>jakarta.json</groupId>
  <artifactId>jakarta.json-api</artifactId>
  <version>2.0.1</version>
</dependency>
Copy the code

Yaml configuration

The YAML configuration and RestHighLevelClient configuration have not changed

# # ElasticSearch configuration
elasticsearch:
  schema: http
  address: 139.198152.90.: 9200
  connectTimeout: 10000
  socketTimeout: 15000
  connectionRequestTimeout: 20000
  maxConnectNum: 100
  maxConnectPerRoute: 100
  index: "aha"
Copy the code

The configuration class

package com.aha.es.config;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/** * Connect to es configuration class **@author WT
 * @date2021/12/23 15:13:39 * /
@Data
@Slf4j
@Configuration
@ConfigurationProperties(prefix = "elasticsearch")
public class ElasticSearchConfig {
    /** * agreement */
    private String schema;

    /** * Cluster address. If there are multiple cluster addresses, separate */ with commas (,)
    private String address;

    /** * Connection timeout time */
    private int connectTimeout;

    /** * Socket connection timeout time */
    private int socketTimeout;

    /** * Get the connection timeout */
    private int connectionRequestTimeout;

    /** * Maximum number of connections */
    private int maxConnectNum;

    /** * Maximum number of connections */
    private int maxConnectPerRoute;

    /** * connect to ES user name */
    private String username;

    /** * Data query index */
    private String index;

    /** * Password */
    private String passwd;

}
Copy the code

Build ElasticsearchClient

package com.aha.es.config;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;

/**
 * es java client
 * @author WT
 * @date2021/12/27 15:34:09 * /
@Configuration
public class ElasticsearchClientConfig {

    private final ElasticSearchConfig elasticSearchConfig;

    public ElasticsearchClientConfig (ElasticSearchConfig elasticSearchConfig) {
        this.elasticSearchConfig = elasticSearchConfig;
    }

    @Bean
    public RestClient restClient(a) {

        // Split the address
        List<HttpHost> hostLists = new ArrayList<>();
        String[] hostArray = elasticSearchConfig.getAddress().split(",");
        for (String temp : hostArray) {
            String host = temp.split(":") [0];
            String port = temp.split(":") [1];
            hostLists.add(new HttpHost(host, Integer.parseInt(port), elasticSearchConfig.getSchema()));
        }

        // Convert to HttpHost array
        HttpHost[] httpHost = hostLists.toArray(new HttpHost[]{});
        // Build the connection object
        RestClientBuilder builder = RestClient.builder(httpHost);
        // Set asynchronous connection delay
        builder.setRequestConfigCallback(requestConfigBuilder -> {
            requestConfigBuilder.setConnectTimeout(elasticSearchConfig.getConnectTimeout());
            requestConfigBuilder.setSocketTimeout(elasticSearchConfig.getSocketTimeout());
            requestConfigBuilder.setConnectionRequestTimeout(elasticSearchConfig.getConnectionRequestTimeout());
            return requestConfigBuilder;
        });

        // Set the number of asynchronous connections
        builder.setHttpClientConfigCallback(httpClientBuilder -> {
            httpClientBuilder.setMaxConnTotal(elasticSearchConfig.getMaxConnectNum());
            httpClientBuilder.setMaxConnPerRoute(elasticSearchConfig.getMaxConnectPerRoute());
            return httpClientBuilder;
        });

        return builder.build();
    }

    @Bean
    public ElasticsearchTransport elasticsearchTransport (RestClient restClient) {
        return new RestClientTransport(
                restClient, new JacksonJsonpMapper());
    }

    @Bean
    public ElasticsearchClient elasticsearchClient (ElasticsearchTransport transport) {
        return newElasticsearchClient(transport); }}Copy the code

Index related API examples

package com.aha.es;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.mapping.Property;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.indices.CreateIndexResponse;
import co.elastic.clients.elasticsearch.indices.DeleteIndexResponse;
import co.elastic.clients.elasticsearch.indices.GetIndexResponse;
import co.elastic.clients.transport.endpoints.BooleanResponse;
import com.aha.es.pojo.AhaIndex;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;
import java.util.Map;

/** * Test elasticSearch client index related operations **@author WT
 * @date2021/12/28 16:27:45 * /
@Slf4j
@SpringBootTest
public class ElasticsearchClientIndexTest {

    @Autowired
    private ElasticsearchClient elasticsearchClient;

    // Create index - do not specify mapping
    @Test
    public void createIndex (a) throws IOException {
        CreateIndexResponse createIndexResponse = elasticsearchClient.indices()
                .create(createIndexRequest ->
                        createIndexRequest.index("elasticsearch-client")); log.info("== {} Index created successfully: {}"."elasticsearch-client", createIndexResponse.acknowledged());
    }

    // Create index - specify mapping
    @Test
    public void createIndexWithMapping (a) throws IOException {

        CreateIndexResponse createIndexResponse = elasticsearchClient.indices()
                .create(createIndexRequest ->
                        createIndexRequest.index("elasticsearch-client")
                        // Lambda overrides the mapping above
                                .mappings(
                                        typeMapping ->
                                                typeMapping.properties("name", objectBuilder ->
                                                        objectBuilder.text(textProperty -> textProperty.fielddata(true))
                                                ).properties("age", objectBuilder ->
                                                        objectBuilder.integer(integerNumberProperty -> integerNumberProperty.index(true))))); log.info("== {} Index created successfully: {}"."elasticsearch-client", createIndexResponse.acknowledged());
    }

    // Check whether the index exists
    @Test
    public void indexIsExist (a) throws IOException {
        BooleanResponse booleanResponse = elasticsearchClient.indices()
                .exists(existsRequest ->
                        existsRequest.index("elasticsearch-client")); log.info("== {} Index creation exists: {}"."elasticsearch-client", booleanResponse.value());
    }

    // View index information
    @Test
    public void indexDetail (a) throws IOException {
        GetIndexResponse getIndexResponse = elasticsearchClient.indices()
                .get(getIndexRequest ->
                        getIndexRequest.index("elasticsearch-client")); Map<String, Property> properties = getIndexResponse.get("elasticsearch-client").mappings().properties();

        for (String key : properties.keySet()) {
            log.info(== key: {}, Property: {}"."elasticsearch-client", key, properties.get(key)._kind()); }}// Drop index
    @Test
    public void deleteIndex (a) throws IOException {
        DeleteIndexResponse deleteIndexResponse = elasticsearchClient.indices()
                .delete(deleteIndexRequest ->
                        deleteIndexRequest.index("elasticsearch-client")); log.info("== {} index created successfully deleted: {}"."elasticsearch-client", deleteIndexResponse.acknowledged());
    }

    @Test
    public void testRestClient (a) throws IOException {

        SearchResponse<AhaIndex> search = elasticsearchClient.search(s -> s.index("aha-batch")
                        .query(q -> q.term(t -> t
                                        .field("name")
                                        .value(v -> v.stringValue("1aha"))
                                )),
                AhaIndex.class);

        for (Hit<AhaIndex> hit: search.hits().hits()) {
            log.info("== hit: {}", hit.source()); }}}Copy the code

Documentation related API examples

package com.aha.es;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
import co.elastic.clients.elasticsearch.core.search.Hit;
import com.aha.es.pojo.AhaIndex;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/** * Test elasticSearch client document related operations **@author WT
 * @date2021/12/28 16:27:45 * /
@Slf4j
@SpringBootTest
public class ElasticsearchClientDocumentTest {

    @Autowired
    private ElasticsearchClient elasticsearchClient;
    private static final String INDEX_NAME = "elasticsearch-client";

    // Add a document
    @Test
    public void testAddDocument (a) throws IOException {

        IndexResponse indexResponse = elasticsearchClient.index(indexRequest ->
                indexRequest.index(INDEX_NAME).document(new AhaIndex().setName("wangWu").setAge(21))); log.info("== response: {}, responseStatus: {}", indexResponse, indexResponse.result());

    }

    // Get the document information
    @Test
    public void testGetDocument (a) throws IOException {
        GetResponse<AhaIndex> getResponse = elasticsearchClient.get(getRequest ->
                getRequest.index(INDEX_NAME).id("1"), AhaIndex.class
        );
        log.info("== document source: {}, response: {}", getResponse.source(), getResponse);
    }

    // Update document information
    @Test
    public void testUpdateDocument (a) throws IOException {
        UpdateResponse<AhaIndex> updateResponse = elasticsearchClient.update(updateRequest ->
                updateRequest.index(INDEX_NAME).id("tU4YAH4B395pyiY3b46F")
                        .doc(new AhaIndex().setName("lisi1").setAge(22)), AhaIndex.class
        );
        log.info("== response: {}, responseStatus: {}", updateResponse, updateResponse.result());
    }

    // Delete the document information
    @Test
    public void testDeleteDocument (a) throws IOException {
        DeleteResponse deleteResponse = elasticsearchClient.delete(deleteRequest ->
                deleteRequest.index(INDEX_NAME).id("1")); log.info("== response: {}, result:{}", deleteResponse, deleteResponse.result());

    }

    // Insert documents in batches
    @Test
    public void testBatchInsert (a) throws IOException {

        List<BulkOperation> bulkOperationList = new ArrayList<>();

        for (int i=0; i<10; i++) {
            AhaIndex ahaIndex = new AhaIndex().setName("lisi" + i).setAge(20 + i);
            bulkOperationList.add(new BulkOperation.Builder().create(e -> e.document(ahaIndex)).build());
        }

        BulkResponse bulkResponse = elasticsearchClient.bulk(bulkRequest ->
                bulkRequest.index(INDEX_NAME).operations(bulkOperationList)
        );

        // If the insert is successful, false is displayed
        log.info("== errors: {}", bulkResponse.errors());
    }


    @Test
    public void testRestClient (a) throws IOException {

        SearchResponse<AhaIndex> search = elasticsearchClient.search(s -> s.index("aha-batch")
                        .query(q -> q.term(t -> t
                                        .field("name")
                                        .value(v -> v.stringValue("1aha"))
                                )),
                AhaIndex.class);

        for (Hit<AhaIndex> hit: search.hits().hits()) {
            log.info("== hit: {}", hit.source()); }}}Copy the code

\

Search for related API examples

package com.aha.es; import co.elastic.clients.elasticsearch.ElasticsearchClient; import co.elastic.clients.elasticsearch._types.SortOrder; import co.elastic.clients.elasticsearch.core.SearchRequest; import co.elastic.clients.elasticsearch.core.SearchResponse; import co.elastic.clients.elasticsearch.core.search.Hit; import co.elastic.clients.json.JsonData; import com.aha.es.pojo.AhaIndex; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.io.IOException; import java.util.List; ** @author WT * @date 2021/12/28 16:27:45 */ @slf4j@springbooTtest Public class ElasticsearchClientSearchTest { @Autowired private ElasticsearchClient elasticsearchClient; private static final String INDEX_NAME = "elasticsearch-client"; /** ** The search API is the advantage of elasticSeart-Client. Lambda is a great way to simplify your code, and is a great contrast to restHighLevelClient. But there's also the problem of poor readability, */ @test public void testRestClient () throws IOException {SearchResponse<AhaIndex> search = elasticsearchClient.search(s -> s.index(INDEX_NAME) .query(q -> q.term(t -> t.field("name").value(v -> v.stringValue("lisi1")) ) ), AhaIndex.class); for (Hit<AhaIndex> hit: search.hits().hits()) { log.info("== hit: source: {}, id: {}", hit.source(), hit.id()); @test public void testMultipleCondition () throws IOException {SearchRequest Request = SearchRequest.of(searchRequest -> searchRequest.index(INDEX_NAME).from(0).size(20).sort(s -> s.field(f -> F.field ("age").order(sortorder.desc))).query(query -> query. Bool (boolQuery -> boolQuery -> bool) BoolQuery // In the same boolQuery, must overwrite should. Must (must -> must. Range (e -> e.field("age").gte(JsonData.of("21")).lte(JsonData.of("25")) )) .mustNot(mustNot -> mustNot.term( e -> e.field("name").value(value -> value.stringValue("lisi1")) )) .should(must -> must.term( e -> e.field("name").value(value -> value.stringValue("lisi2")) )) ) ) ); SearchResponse<AhaIndex> searchResponse = elasticsearchClient.search(request, AhaIndex.class); Log.info (" return total number of hits: {}", searchResponse.hits().total().value()); List<Hit<AhaIndex>> hitList = searchResponse.hits().hits(); for (Hit<AhaIndex> hit : hitList) { log.info("== hit: {}, id: {}", hit.source(), hit.id()); }}}Copy the code

Should condition example

SearchRequest request = SearchRequest.of(searchRequest -> searchRequest.index(INDEX_NAME).from(0).size(20).sort(s -> S.field (f -> f.field("age").order(sortorder.desc))).query(query -> query.bool(boolQuery -> boolQuery .should(must -> must. Term (e -> e.field("age").value(value -> value.stringValue("22")))). must.term( e -> e.field("age").value(value -> value.stringValue("23")) )) ) ));Copy the code

summary

As you can see from the sample code, the new client features the use of constructors, generic support, and Lambda support. Code simplification is indisputable for Lambda, but readability and debugging code are controversial. There are few documents on the official website for the new version of the client, so this article is just a taste of it and can be used in production environments after it stabilizes.