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;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author:Grant
 * @Description:
 * @Date: 2023/05/29/15:26
 */
@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;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author:Grant
 * @Description:
 * @Date: 2023/05/30/10:59
 */
@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;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author:Grant
 * @Description:
 * @Date: 2023/05/19/15:45
 */
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;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author:Grant
 * @Description:
 * @Date: 2023/05/19/15:56
 */
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();

        //使用jackson映射器创建传输层
        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;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author:Grant
 * @Description:
 * @Date: 2023/05/18/10:50
 */
@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;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author:Grant
 * @Description:
 * @Date: 2023/05/23/9:55
 */
@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

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值