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
- All requests and corresponding use strong typing, use generic enhancement
- Support for synchronous and asynchronous requests
- use
builders
Pattern, make complex request become smooth, good supportlambda
Expression, 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.