Before diving into the code, ensure your Elasticsearch server is running. Open a terminal and execute the elasticsearch command to start the server.
Understanding the Two REST Client Types
Elasticsearch provides two distinct REST client implementations:
High-Level REST Client (RestHighLevelClient): This wrapper handles serialization and deserialization automatically. Developers interact with higher-level abstractions like Index and Document objects, making it the preferred choice for most use cases due to its simplicity.
Low-Level REST Client (RestLowLevelClient): This client works directly with raw HTTP requests and responses. All JSON serialization/deserialization must be handled manually by the developer, offering maximum flexibility but requiring more code.
Auto-Configuration Behavior in Spring Boot
When Spring Boot detects the elasticsearch-rest-high-level-client dependency on the classpath, it automatically configures a RestHighLevelClient bean. Notably, this auto-configuration works without requiring Spring Data Elasticsearch.
To access the low-level client, simply call getLowLevelClient() on the high-level client instance.
Key Takeaways:
- Spring Boot auto-configures
RestHighLevelClient RestLowLevelClientis accessible via the high-level client
Auto-Configuration Classes Overview
Spring Boot provides six auto-configuration classes for Elasticsearch:
- ElasticsearchRestClientAutoConfiguration: Configures
RestClientBuilder,RestClientBuilderCustomizer, andRestHighLevelClient - ElasticsearchDataAutoConfiguration: Requires Spring Data Elasticsearch; configures
ElasticsearchRestTemplate - ElasticsearchRepositoriesAutoConfiguration: Enables repository support
- ReactiveElasticsearchRestClientAutoConfiguration: Reactive variant for the rest client
- ReactiveElasticsearchDataAutoConfiguration: Reactive variant for data operations
- ReactiveElasticsearchRepositoriesAutoConfiguration: Reactive repository support
Common RestHighLevelClient Operations
The RestHighLevelClient provides both synchronous and asynchronous versions of each method. Synchronous methods block until completion, while async methods use callbacks for result handling.
Document Count:
count(CountRequest request, RequestOptions options)
countAsync(CountRequest request, RequestOptions options, ActionListener<CountResponse> listener)
Document Retrieval:
get(GetRequest request, RequestOptions options)
getAsync(GetRequest request, RequestOptions options, ActionListener<GetResponse> listener)
mget(MultiGetRequest request, RequestOptions options)
Document Creation/Updates:
index(IndexRequest request, RequestOptions options)
indexAsync(IndexRequest request, RequestOptions options, ActionListener<IndexResponse> listener)
update(UpdateRequest request, RequestOptions options)
updateAsync(UpdateRequest request, RequestOptions options, ActionListener<lt;UpdateResponse> listener)
Document Deletion:
delete(DeleteRequest request, RequestOptions options)
deleteAsync(DeleteRequest request, RequestOptions options, ActionListener<DeleteResponse> listener)
deleteByQuery(DeleteByQueryRequest request, RequestOptions options)
Search Operations:
search(SearchRequest request, RequestOptions options)
searchAsync(SearchRequest request, RequestOptions options, ActionListener<SearchResponse> listener)
msearch(MultiSearchRequest request, RequestOptions options)
Utility Methods:
exists(GetRequest request, RequestOptions options)
updateByQuery(UpdateByQueryRequest request, RequestOptions options)
API Design Pattern
Most methods follow a consistent pattern: they accept an XxxRequest object containing primary request data and a RequestOptions object for additional configuration. Async variants replace RequestOptions with an ActionListener callback.
The client also provides factory methods returning specialized clients: indices() returns IndicesClient, cluster() returns ClusterClient, asyncSearch() returns AsyncSearchClient, and eql() returns EqlClient.
Setting Up HTTPS Connections to Elasticsearch
Scenario Overview
This section demonstrates configuring a Spring Boot application to connect to an Elasticsearch server using HTTPS with a self-signed certificate. When using certificates from trusted Certificate Authorities, Spring Boot handles trust automatically. Self-signed certificates require addisional configuration.
Step 1: Create a Spring Boot Project
Step 2: Configure Elasticsearch Connection
The ElasticsearchRestClientProperties class handles properties prefixed with spring.elasticsearch.rest.*:
# Elasticsearch server endpoint using HTTPS
spring.elasticsearch.rest.uris=https://127.0.0.1:9200
spring.elasticsearch.rest.read-timeout=10s
# Authentication credentials
spring.elasticsearch.rest.username=elastic
spring.elasticsearch.rest.password=e32147
Step 3: Add Required Dependencies
Add the high-level REST client dependency from Maven Central, ensuring the version matches your Elasticsearch server version:
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.14.1</version>
</dependency>
Step 4: Configure Trust for Self-Signed Certificates
Since we are using a self-signed certificate, Spring Boot will not automatically trust it. We need to add the certificate to a truststore.
Certificate Import Procedure
Export the public certificate from Elasticsearch's keystore:
keytool -export -alias ca -file elastic.cer -keystore elastic-certificates.p12
Import the certificate into a new truststore:
keytool -import -alias ca -file elastic.cer -keystore elastic.store
Place the truststore in your project's resources directory.
Create a configuration class to register the truststore:
static
{
String truststoreLocation = new File(
ApplicationContext.class
.getResource("/")
.getFile()
)
.getParentFile()
.getAbsolutePath() + "\\classes\\elastic.store";
System.setProperty("javax.net.ssl.trustStore", truststoreLocation);
System.setProperty("javax.net.ssl.trustStorePassword", "345678");
}
Complete Implementation
application.properties
# Elasticsearch connection configuration
# Server endpoint (HTTPS)
spring.elasticsearch.rest.uris=https://127.0.0.1:9200
spring.elasticsearch.rest.read-timeout=10s
# Authentication
spring.elasticsearch.rest.username=elastic
spring.elasticsearch.rest.password=123456
ElasticsearchConfig.java
package com.example.elasticsearch.config;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.client.RestClientBuilder;
import org.springframework.boot.autoconfigure.elasticsearch.RestClientBuilderCustomizer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.File;
@Configuration(proxyBeanMethods = false)
public class ElasticsearchConfiguration
{
static
{
String keystorePath = new File(
ApplicationContext.class
.getResource("/")
.getFile()
)
.getParentFile()
.getAbsolutePath() + "\\classes\\elastic.store";
System.setProperty("javax.net.ssl.trustStore", keystorePath);
System.setProperty("javax.net.ssl.trustStorePassword", "123456");
}
@Bean
public RestClientBuilderCustomizer restClientBuilderCustomizer()
{
return new RestClientBuilderCustomizer()
{
@Override
public void customize(RestClientBuilder builder)
{
// Builder customization if needed
}
@Override
public void customize(HttpAsyncClientBuilder builder)
{
// Skip hostname verification for local development
builder.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE);
}
@Override
public void customize(RequestConfig.Builder builder)
{
// Request config customization if needed
}
};
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
</parent>
<groupId>com.example</groupId>
<artifactId>elasticsearch-client-demo</artifactId>
<version>1.0.0</version>
<name>elasticsearch-client-demo</name>
<properties>
<java.version>11</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.14.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>