1.springboot 集成elasticsearch组件

1.前置条件已经安装和搭建好了elasticsearch中间件

一:项目中引入elasticsearch相关依赖

我安装的elasticsearch版本是7.10.2 对应依赖的版本保持一致

此处省略springboot 搭建及必要的依赖项

xml 复制代码
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.10.2</version>
        </dependency>

        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>7.10.2</version>
        </dependency>

二:项目配置文件里配置上elasticsearch相关的信息

application.yml

yml 复制代码
es:
  data:
    host: ip # es安装所在的服务器ip
    port: 9200 #es对外暴露的端口
    clusterName: hc-es-cluster #es的集群

三:工程里编写elasticsearch相关的配置代码

java 复制代码
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;



@Configuration
public class ESConfig {

    @Value("${es.data.host}")
    private String host;
    @Value("${es.data.clusterName}")
    private String clusterName;
    @Value("${es.data.port}")
    private Integer port;


    @Bean
    public RestHighLevelClient restHighLevelClient() {
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(new HttpHost(host, port, "http"))
        );
        return client;
    }
}

四:项目中的引入和测试

java 复制代码
import cn.hutool.json.JSONUtil;
import com.jinyi.up.user.JinyiUserProviderApplication;
import com.jinyi.up.user.esPojo.AggDimensionEnum;
import com.jinyi.up.user.esPojo.EsUser;
import com.jinyi.up.user.esPojo.EsUserSearchQueryDto;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.*;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author huangchong
 * @date 2023/9/2 14:36
 * @desc
 */
@SpringBootTest(classes = {JinyiUserProviderApplication.class})
public class TestES {

    @Resource
    private RestHighLevelClient esClient;

    /**
     * 创建索引
     *
     * @throws IOException
     */
    @Test
    public void createIndex() throws IOException {
        //1.创建索引请求
        CreateIndexRequest request = new CreateIndexRequest("hc_index");
        //2.执行创建请求
        CreateIndexResponse indexResponse = esClient.indices().create(request, RequestOptions.DEFAULT);
        System.out.println(indexResponse);
    }

    /**
     * 获取索引 判断是否存在
     *
     * @throws IOException
     */
    @Test
    public void getIndex() throws IOException {
        //1.创建索引请求
        GetIndexRequest request = new GetIndexRequest("hc_index");
        //2.执行存在请求
        Boolean exists = esClient.indices().exists(request, RequestOptions.DEFAULT);
        System.out.println(exists);
    }

    /**
     * 删除索引
     *
     * @throws IOException
     */
    @Test
    public void deleteIndex() throws IOException {
        //1.创建索引请求
        DeleteIndexRequest request = new DeleteIndexRequest("hc_index");
        //2.执行删除请求
        AcknowledgedResponse response = esClient.indices().delete(request, RequestOptions.DEFAULT);
        System.out.println(response.isAcknowledged());
    }

    /**
     * 添加文档
     *
     * @throws IOException
     */
    @Test
    public void addEsDocument() throws IOException {
        EsUser esUser = new EsUser(1L, "hc", 32, 12, new Date());
        //1.指定索引库
        IndexRequest request = new IndexRequest("hc_index");
        // PUT /hc_index/_doc/1
        request.id("1")
                .timeout(TimeValue.timeValueSeconds(2));
        //2.将数据放入请求
        request.source(JSONUtil.toJsonStr(esUser), XContentType.JSON);
        //发送请求

        IndexResponse response = esClient.index(request, RequestOptions.DEFAULT);
        System.out.println(response.toString());
    }

    /**
     * 判断文档是否存在文档
     *
     * @throws IOException
     */
    @Test
    public void existsEsDocument() throws IOException {

        //1.指定索引库 和 查询id
        GetRequest request = new GetRequest("hc_index", "1");
        //不获取返回的_source 的上下文
        request.fetchSourceContext(new FetchSourceContext(false));
        request.storedFields("_none_");
        boolean exists = esClient.exists(request, RequestOptions.DEFAULT);
        System.out.println(exists);
    }

    /**
     * 获取文档
     *
     * @throws IOException
     */
    @Test
    public void getEsDocument() throws IOException {
        //1.指定索引库 和 查询id
        GetRequest request = new GetRequest("hc_index", "1");
        //不获取返回的_source 的上下文
        //  request.fetchSourceContext(new FetchSourceContext(false));
        //  request.storedFields("_none_");
        GetResponse getResponse = esClient.get(request, RequestOptions.DEFAULT);
        System.out.println(getResponse.toString());
        String sourceAsString = getResponse.getSourceAsString();
        System.out.println(sourceAsString); //返回全部内容 ,和命令一样
    }

    /**
     * 更新文档
     *
     * @throws IOException
     */
    @Test
    public void updateEsDocument() throws IOException {
        //1.指定索引库 和 查询id
        GetRequest request = new GetRequest("hc_index", "1");
        GetResponse getResponse = esClient.get(request, RequestOptions.DEFAULT);
        System.out.println(getResponse.toString());
        String sourceAsString = getResponse.getSourceAsString();
        EsUser esUser = JSONUtil.toBean(sourceAsString, EsUser.class);
        //1.指定索引库 和 查询id
        UpdateRequest updateRequest = new UpdateRequest("hc_index", String.valueOf(esUser.getId()));
        //不获取返回的_source 的上下文
        updateRequest.timeout(TimeValue.timeValueSeconds(2));
        esUser.setUserName("huangchong 2");
        updateRequest.doc(JSONUtil.toJsonStr(esUser), XContentType.JSON);
        UpdateResponse updateResponse = esClient.update(updateRequest, RequestOptions.DEFAULT);
        System.out.println(updateResponse.toString());
    }

    /**
     * 删除文档
     *
     * @throws IOException
     */
    @Test
    public void deleteEsDocument() throws IOException {
        //1.指定索引库 和 查询id
        DeleteRequest deleteRequest = new DeleteRequest("hc_index", "1");
        deleteRequest.timeout("1s");
        DeleteResponse delete = esClient.delete(deleteRequest, RequestOptions.DEFAULT);
        System.out.println(delete.toString());
    }


    /**
     * 批量操作
     *
     * @throws IOException
     */
    @Test
    public void bulkAddEsDocument() throws IOException {
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("10s");
        List<EsUser> esUsers = new ArrayList<EsUser>();
        esUsers.add(new EsUser(11L, "hc1", 31, 1, new Date()));
        esUsers.add(new EsUser(17L, "hc2", 31, 1, new Date()));
        esUsers.add(new EsUser(18L, "hc3", 28, 2, new Date()));
        esUsers.add(new EsUser(19L, "hc4", 25, 2, new Date()));
        esUsers.add(new EsUser(20L, "hc5", 19, 3, new Date()));
        //批量插入
        for (int i = 0; i < esUsers.size(); i++) {
            EsUser esUser = esUsers.get(i);
            bulkRequest.add(new IndexRequest("hc_index").id(String.valueOf(esUser.getId()))
                    .source(JSONUtil.toJsonStr(esUser), XContentType.JSON).opType(DocWriteRequest.OpType.CREATE));
        }
        esClient.bulk(bulkRequest, RequestOptions.DEFAULT);
    }

    /**
     * private AggregatorFactories.Builder aggregations;
     * 1.SearchRequest 请求
     * 2.SearchSourceBuilder 条件构建
     * searchSourceBuilder.highlighter() 高亮
     *
     * @throws IOException
     */
    @Test
    public void queryEsDocument() throws IOException {
        // 1.指定索引库
        SearchRequest searchRequest = new SearchRequest("hc_index");
        //2.构建查询请求条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //QueryBuilders工具类 termQuery 精确查询
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("userName", "hc4");

        searchSourceBuilder.query(termQueryBuilder);
        searchSourceBuilder.timeout(TimeValue.timeValueSeconds(60L));

        searchRequest.source(searchSourceBuilder);

        SearchResponse response = esClient.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits searchHits = response.getHits();
        SearchHit[] hits = searchHits.getHits();

        for (int i = 0; i < hits.length; i++) {
            SearchHit hit = hits[i];
            String sourceAsString = hit.getSourceAsString();
            System.out.println(JSONUtil.toBean(sourceAsString, EsUser.class).toString());
        }
    }

    /**
     * private AggregatorFactories.Builder aggregations;
     * 1.SearchRequest 请求
     * 2.SearchSourceBuilder 条件构建
     * searchSourceBuilder.highlighter() 高亮
     *
     * @throws IOException
     */
    @Test
    public void aggsEsDocument() throws IOException {
        //对hc_index库的查询请求
        SearchRequest searchRequest = new SearchRequest("hc_index");
        //paramDto 转BoolQueryBuilder :对查询条件统一封装
        EsUserSearchQueryDto queryDto = new EsUserSearchQueryDto();
        queryDto.setLikeWords("hc");
        queryDto.setUserStatus("1,2,3");
        queryDto.setAggDimensions("age");

        BoolQueryBuilder boolQueryBuilder = buildQuery(queryDto);
        //查询条件构建
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(boolQueryBuilder);
        //聚合分析无需得到分页结果,只要聚合结果就行
        buildQueryFromSize(searchSourceBuilder, 1, 0);
        //构建聚合
        aggregationsBuild(searchSourceBuilder, queryDto);
        searchRequest.source(searchSourceBuilder);
        //获取结果
        SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);
        Map<String, Aggregation> aggregationMap = searchResponse.getAggregations().asMap();
        ParsedValueCount idNumAggs = (ParsedValueCount) aggregationMap.get("idNum");
        ParsedSum ageSumAggs = (ParsedSum) aggregationMap.get("ageSum");
        ParsedAvg ageAveAggs = (ParsedAvg) aggregationMap.get("ageAve");
        ParsedCardinality userNumAggs = (ParsedCardinality) aggregationMap.get("userStatusCount");

    }

    /**
     * 构建聚合方式
     */
    private void aggregationsBuild(SearchSourceBuilder sourceBuilder, EsUserSearchQueryDto queryDto) {

        ValueCountAggregationBuilder idNumAggs = AggregationBuilders.count("idNum").field("id");
        SumAggregationBuilder ageSumAggs = AggregationBuilders.sum("ageSum").field("age");
        //平均值
        AvgAggregationBuilder ageAvgAggs = AggregationBuilders.avg("ageAve").field("age");
        //统计去重后的数量
        CardinalityAggregationBuilder userStatusAggs = AggregationBuilders.cardinality("userStatusCount").field("userStatus");

        sourceBuilder.aggregation(idNumAggs);
        sourceBuilder.aggregation(ageSumAggs);
        sourceBuilder.aggregation(userStatusAggs);
        sourceBuilder.aggregation(ageAvgAggs);

        if (StringUtils.isNotEmpty(queryDto.getAggDimensions())) {
            List<String> list = Arrays.asList(queryDto.getAggDimensions().split(",")).stream().map(s -> s.trim()).collect(Collectors.toList());
            for (String dimension : list) {
                AggDimensionEnum dimensionEnum = AggDimensionEnum.getByDimension(dimension);
                if (dimension == null) {
                    continue;
                }
                TermsAggregationBuilder aggs = AggregationBuilders.terms(dimensionEnum.getDimension()).field(dimensionEnum.getField())
                        .size(10000);
                sourceBuilder.aggregation(aggs);
                aggs.subAggregation(idNumAggs);
                aggs.subAggregation(ageSumAggs);
                aggs.subAggregation(ageAvgAggs);
                aggs.subAggregation(userStatusAggs);
            }
        }
    }


    protected void buildQueryFromSize(SearchSourceBuilder sourceBuilder, Integer start, Integer size) {
        sourceBuilder.from(start);
        sourceBuilder.size(size);
    }


    /**
     * 构建查询条件
     *
     * @param queryDto
     * @return
     */
    private BoolQueryBuilder buildQuery(EsUserSearchQueryDto queryDto) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        //搜索  分词
        if (StringUtils.isNotEmpty(queryDto.getUserName())) {
            query.must(QueryBuilders.matchQuery("userName", queryDto.getUserName()));
        }
        //匹配  包含  模糊查询
        if (StringUtils.isNotEmpty(queryDto.getLikeWords())) {
            query.must(QueryBuilders.wildcardQuery("userName", "*" + queryDto.getLikeWords() + "*"));
        }
        //订单状态  多状态 or查询
        if (StringUtils.isNotEmpty(queryDto.getUserStatus())) {
            String[] orderStatuss = StringUtils.split(queryDto.getUserStatus(), ",");
            BoolQueryBuilder orQuery = QueryBuilders.boolQuery()
                    // 多个状态查询
                    .should(QueryBuilders.termsQuery("userStatus", orderStatuss));
            query.must(orQuery);
        }
        //订单创建时间
        if (queryDto.getBeginCreateTime() != null) {
            query.must(QueryBuilders.rangeQuery("createTime").gte(queryDto.getBeginCreateTime().getTime()));
        }
        if (queryDto.getEndCreateTime() != null) {
            query.must(QueryBuilders.rangeQuery("createTime").lte(queryDto.getEndCreateTime().getTime()));
        }

        return query;
    }
}
java 复制代码
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * @author huangchong
 * @date 2023/9/2 14:51
 * @desc
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
public class EsUser {

    private Long id;

    private String userName;

    private Integer age;

    private Integer userStatus;

    private Date createTime;

}
java 复制代码
import lombok.Data;

import java.util.Date;

/**
 * @author huangchong
 * @date 2023/9/3 16:12
 * @desc
 */
@Data
public class EsUserSearchQueryDto {

    private Long id;

    private String userName;

    private String likeWords;

    private Integer age;
    private String userStatus;

    private Date beginCreateTime;

    private Date endCreateTime;

    private String aggDimensions;
}
java 复制代码
package com.jinyi.up.user.esPojo;

import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 聚合分析维度
 * @author huangchong
 * @date 2023/9/3 17:00
 * @desc
 */
public enum AggDimensionEnum {
    userStatus("userStatus", "userStatus", "用户状态"),
    age("age", "age", "年纪类型"),
    name("userName", "userName", "名字")
    ;

    private final String dimension;
    private final String field;
    private final String desc;

    AggDimensionEnum(String dimension, String field, String desc) {
        this.dimension = dimension;
        this.field = field;
        this.desc = desc;
    }

    public String getDesc() {
        return desc;
    }

    public String getDimension() {
        return dimension;
    }

    public String getField() {
        return field;
    }


    private static final Map<String, String> aggDimensionEnumMap = Arrays.stream(values()).collect(Collectors.toMap(AggDimensionEnum::getDimension, AggDimensionEnum::getDesc));

    public static Map<String, String> getAggDimensionEnumMap() {
        return aggDimensionEnumMap;
    }

    public static AggDimensionEnum getByDimension(String dimension) {
        for (AggDimensionEnum dimensionEnum : values()) {
            if (dimensionEnum.dimension.equals(dimension)) {
                return dimensionEnum;
            }
        }
        return null;

    }
}
相关推荐
世间万物皆对象5 小时前
Spring Boot核心概念:日志管理
java·spring boot·单元测试
qq_17448285757 小时前
springboot基于微信小程序的旧衣回收系统的设计与实现
spring boot·后端·微信小程序
java1234_小锋7 小时前
Elasticsearch是如何实现Master选举的?
大数据·elasticsearch·搜索引擎
代码小鑫9 小时前
A043-基于Spring Boot的秒杀系统设计与实现
java·开发语言·数据库·spring boot·后端·spring·毕业设计
真心喜欢你吖9 小时前
SpringBoot与MongoDB深度整合及应用案例
java·spring boot·后端·mongodb·spring
周全全9 小时前
Spring Boot + Vue 基于 RSA 的用户身份认证加密机制实现
java·vue.js·spring boot·安全·php
飞升不如收破烂~10 小时前
Spring boot常用注解和作用
java·spring boot·后端
计算机毕设源码qq-383653104110 小时前
(附项目源码)Java开发语言,215 springboot 大学生爱心互助代购网站,计算机毕设程序开发+文案(LW+PPT)
java·开发语言·spring boot·mysql·课程设计
岁岁岁平安11 小时前
springboot实战(15)(注解@JsonFormat(pattern=“?“)、@JsonIgnore)
java·spring boot·后端·idea
梦幻通灵13 小时前
ES分词环境实战
大数据·elasticsearch·搜索引擎