Elastic Search 8.7.1 整合springboot 并使用构建通用查询
springboot 整合Elastic Search Client
pom中整合依赖
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
<version>8.7.1</version>
</dependency>
生成dto和vo
package com.grant.es.domain;
import com.grant.es.annotation.EsQueryType;
import com.grant.es.constant.EsQuery;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.io.Serializable;
@Data
@AllArgsConstructor
public class Blog implements Serializable {
private static final long serialVersionUID =1L;
@EsQueryType(value = EsQuery.TERM,name = "title")
private String title;
@EsQueryType(value = EsQuery.TERM,name = "kind")
private String kind;
@EsQueryType(value = EsQuery.TERM,name = "author")
private String author;
}
package com.grant.es.domain.vo;
import lombok.Data;
import java.io.Serializable;
@Data
public class BlogVo implements Serializable {
private static final long serialVersionUID =1L;
private String title;
private String kind;
private String author;
}
构建es连接池
构建池化类
package com.grant.es.pool;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
public class ElasticsearchClientGenericObjectPool<T> extends GenericObjectPool<T> {
public ElasticsearchClientGenericObjectPool(PooledObjectFactory<T> factory, GenericObjectPoolConfig config){
super(factory,config);
}
}
构建工厂类
package com.grant.es.pool;
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.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
public class ElasticsearchClientFactory implements PooledObjectFactory<ElasticsearchClient> {
private HttpHost hosts[];
private int connectTimeouot;
private int socketTimeout;
private int connectionRequestTimeout;
private int maxRetryTimeout;
public ElasticsearchClientFactory(HttpHost[] hosts, int connectTimeouot, int socketTimeout, int connectionRequestTimeout, int maxRetryTimeout) {
super();
this.hosts = hosts;
this.connectTimeouot = connectTimeouot;
this.socketTimeout = socketTimeout;
this.connectionRequestTimeout = connectionRequestTimeout;
this.maxRetryTimeout = maxRetryTimeout;
}
@Override
public PooledObject<ElasticsearchClient> makeObject() throws Exception {
RestClient client = RestClient.builder(hosts).build();
ElasticsearchTransport transport = new RestClientTransport(client,new JacksonJsonpMapper());
ElasticsearchClient elasticsearchClient = new ElasticsearchClient(transport);
return new DefaultPooledObject<>(elasticsearchClient);
}
@Override
public void destroyObject(PooledObject<ElasticsearchClient> pooledObject) throws Exception {
ElasticsearchClient elasticsearchClient = pooledObject.getObject();
}
@Override
public boolean validateObject(PooledObject<ElasticsearchClient> pooledObject) {
return true;
}
@Override
public void activateObject(PooledObject<ElasticsearchClient> pooledObject) throws Exception {
}
@Override
public void passivateObject(PooledObject<ElasticsearchClient> pooledObject) throws Exception {
}
}
构建Es配置类
package com.grant.es.config;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import com.grant.es.pool.ElasticsearchClientFactory;
import com.grant.es.pool.ElasticsearchClientGenericObjectPool;
import com.grant.es.util.ElasticSearchUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.http.HttpHost;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import java.util.Arrays;
@Configuration
@Slf4j
public class EsConfig implements DisposableBean {
@Value("${spring.elasticsearch.nodes}")
private String nodes;
@Value("${spring.elasticsearch.max-connect-total}")
private Integer maxConnectTotal;
@Value("${spring.elasticsearch.max-connect-per-route}")
private Integer maxConnectPerRoute;
@Value("${spring.elasticsearch.connection-request-timeout-millis}")
private Integer connectionRequestTimeoutMillis;
@Value("${spring.elasticsearch.socket-timeout-millis}")
private Integer socketTimeoutMillis;
@Value("${spring.elasticsearch.connect_timeout-millis}")
private Integer connectTimeoutMillis;
@Value("${spring.elasticsearch.max-retry-timeout-millis}")
private Integer maxRetryTimeoutMillis;
private ElasticsearchClientGenericObjectPool<ElasticsearchClient> pool;
@Bean(name = "elasticsearchClientGenericObjectPool")
@ConditionalOnMissingBean(ElasticsearchClientGenericObjectPool.class)
public ElasticsearchClientGenericObjectPool elasticsearchClientGenericObjectPool(){
pool = new ElasticsearchClientGenericObjectPool<>(
new ElasticsearchClientFactory(
getClusterHosts(),
connectTimeoutMillis,
socketTimeoutMillis,
connectionRequestTimeoutMillis,
maxRetryTimeoutMillis)
, getPoolConfig()
);
return pool;
}
@Bean(name = "elasticSearchUtil")
@DependsOn("elasticsearchClientGenericObjectPool")
@ConditionalOnMissingBean(ElasticsearchClient.class)
public ElasticSearchUtil elasticSearchClient(){
return new ElasticSearchUtil(pool);
}
private GenericObjectPoolConfig getPoolConfig(){
GenericObjectPoolConfig config = new GenericObjectPoolConfig<>();
config.setMaxIdle(maxConnectPerRoute);
config.setMaxWaitMillis(10000L);
config.setMaxTotal(maxConnectTotal);
config.setMinEvictableIdleTimeMillis(10000L);
config.setTestOnBorrow(true);
config.setTestWhileIdle(true);
config.setTimeBetweenEvictionRunsMillis(1800000);
config.setJmxEnabled(false);
return config;
}
private HttpHost[] getClusterHosts(){
String[] str = nodes.split(",");
return Arrays.stream(str).map(item -> {
String address[] = item.split(":");
return new HttpHost(address[0],Integer.parseInt(address[1]));
}).toArray(HttpHost[]::new);
}
@Override
public void destroy() throws Exception {
pool.close();
}
}
构建工具类
package com.grant.es.util;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.indices.*;
import co.elastic.clients.elasticsearch.indices.ExistsRequest;
import com.alibaba.fastjson2.JSONObject;
import com.grant.es.annotation.EsQueryType;
import com.grant.es.constant.EsQuery;
import com.grant.es.pool.ElasticsearchClientGenericObjectPool;
import io.micrometer.common.util.StringUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.parsson.JsonUtil;
import org.springframework.util.ObjectUtils;
import javax.annotation.Nonnull;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Slf4j
public class ElasticSearchUtil {
private final ElasticsearchClientGenericObjectPool<ElasticsearchClient> pool;
public ElasticSearchUtil(ElasticsearchClientGenericObjectPool<ElasticsearchClient> pool){
this.pool = pool;
}
public boolean createIndex(String index,String alias) throws Exception{
ElasticsearchClient client = null;
try {
client = pool.borrowObject();
CreateIndexResponse response = client.indices()
.create(createIndexBuilder ->createIndexBuilder
.index(index)
.aliases(alias,a -> a.isWriteIndex(true))
);
return response.acknowledged();
}
finally {
if (client!=null){
pool.returnObject(client);
}
}
}
public boolean deleteIndex(String index) throws Exception{
ElasticsearchClient client = null;
try{
client = pool.borrowObject();
DeleteIndexResponse response = client.indices()
.delete(deleteIndexBuilder -> deleteIndexBuilder
.index(index)
);
return response.acknowledged();
}
finally {
if (client != null){
pool.returnObject(client);
}
}
}
public boolean isExistIndex(String indexName) throws Exception{
ElasticsearchClient client = null;
try {
ExistsRequest.Builder builder = new ExistsRequest.Builder();
builder.index(indexName);
ExistsRequest request = builder.build();
client = pool.borrowObject();
return client.indices().exists(request).value();
}
finally {
if (client!=null){
pool.returnObject(client);
}
}
}
public boolean batchInsert(String indexName, List<JSONObject> list)throws Exception{
ElasticsearchClient client = null;
try{
List<BulkOperation> operations= new ArrayList<>();
list.forEach(jsonObject -> operations.add(new BulkOperation.Builder().create(
builder -> builder.document(jsonObject)
).build()
));
BulkRequest bulkRequest = new BulkRequest.Builder().index(indexName).operations(operations).build();
client = pool.borrowObject();
BulkResponse response = client.bulk(bulkRequest);
return response.errors();
}
finally {
if (client != null){
pool.returnObject(client);
}
}
}
@SneakyThrows
public <DTO,VO> List<VO> queryByDto(@Nonnull String indexName, DTO dto, Class<VO> voClass){
ElasticsearchClient client = null;
try{
client = pool.borrowObject();
SearchRequest.Builder builder = new SearchRequest.Builder();
builder.index(indexName);
builder.query(builder1 -> builder1.bool(getAnnotationParams(dto)));
SearchResponse<VO> response = client.search(builder.build(),voClass);
List<Hit<VO>> hits = response.hits().hits();
List<VO> res = new ArrayList<>();
for (Hit<VO> hit: hits) {
VO vo = hit.source();
res.add(vo);
}
return res;
}
finally {
if (client != null){
pool.returnObject(client);
}
}
}
@SneakyThrows
public <DTO> BoolQuery getAnnotationParams(DTO dto){
BoolQuery.Builder builder = new BoolQuery.Builder();
Class <?> clazz = dto.getClass();
Field []fields = clazz.getDeclaredFields();
for (Field field:fields){
field.setAccessible(true);
EsQueryType esQueryType = field.getAnnotation(EsQueryType.class);
Object fieldValue = field.get(dto);
if (esQueryType == null || ObjectUtils.isEmpty(fieldValue)){
continue;
}
String fieldName = StringUtils.isEmpty(esQueryType.name()) ? field.getName(): esQueryType.name();
String searchType = esQueryType.value();
if (fieldValue instanceof Date){
fieldValue = ((Date)fieldValue).getTime();
}
setQueryParams(builder,searchType,fieldName,fieldValue);
}
return new BoolQuery.Builder().build();
}
public static void setQueryParams(BoolQuery.Builder builder, String searchType, String fieldName,Object fieldValue){
switch (searchType){
case EsQuery.TERM :
builder.must(builder1 -> builder1.term(
builder2 -> builder2.field(fieldName).value((String) fieldValue)
));
break;
default:{
log.error("查询异常");
}
}
}
}
yml配置文件
spring:
elasticsearch:
nodes: 127.0.0.1:9200
schema: http
max-connect-total: 50
max-connect-per-route: 50
connection-request-timeout-millis: 500
socket-timeout-millis: 30000
connect_timeout-millis: 1000
max-retry-timeout-millis: 120000