SpringBoot实现ES各功能举例(附源码,持续更新)

本文详细介绍了如何使用 Elasticsearch 进行查询、聚合操作,包括全值匹配、模糊查询、范围查询和聚合统计。首先讲解了配置 Elasticsearch 客户端,然后通过实例展示了不同类型的查询和聚合方法,如按字段分组统计、时间分组统计等。此外,还分享了如何利用 DEBUG 调试以及代码封装技巧,提高代码复用性和可维护性。
摘要由CSDN通过智能技术生成

版权说明: 本文由博主keep丶原创,转载请注明出处。
原文地址: https://blog.csdn.net/qq_38688267/article/details/120283675

准备工作

依赖

<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>7.10.2</version>
</dependency>
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-client</artifactId>
    <version>7.10.2</version>
</dependency>
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.10.2</version>
</dependency>

配置

属性类

/**
 * ES参数
 */
@Data
@ConfigurationProperties(prefix = "map.es")
public class EsProperties {
    /**
     * 地址
     */
    private String host;
    /**
     * 端口
     */
    private Integer port;
    /**
     * 协议
     */
    private String scheme;
    /**
     * 端口
     */
    private String username;
    /**
     * 协议
     */
    private String password;
}

配置类

/**
 * ES配置类
 */
@Configuration
@RequiredArgsConstructor
@EnableConfigurationProperties(EsProperties.class)
public class EsConfig {

    private final EsProperties properties;

    @Bean
    @SneakyThrows
    public RestHighLevelClient startRestClient() {
        BasicCredentialsProvider basicCredentialsProvider = new BasicCredentialsProvider();

        // 登录认证
        basicCredentialsProvider.setCredentials(AuthScope.ANY,
                new UsernamePasswordCredentials(properties.getUsername(), properties.getPassword()));

        // https连接需要增加以下配置
        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (arg0, arg1) -> true).build();
        RestClientBuilder restClientBuilder = RestClient.builder(new HttpHost(properties.getHost(), properties.getPort(), properties.getScheme()))
                .setHttpClientConfigCallback(httpAsyncClientBuilder -> {
                    httpAsyncClientBuilder.disableAuthCaching();
                    httpAsyncClientBuilder.setSSLContext(sslContext);
                    httpAsyncClientBuilder.setSSLHostnameVerifier((s, sslSession) -> true);
                    return httpAsyncClientBuilder.setDefaultCredentialsProvider(basicCredentialsProvider);
                });
        return new RestHighLevelClient(restClientBuilder);
    }
}

实战前言

请求结构介绍

  在进行实战之前,我们先来学习一下ES的API请求及其响应的结构。以下展示的是ES自带的请求工具的信息,JAVA请求实际也是通过代码实现这些对象的构建。

请求体

在这里插入图片描述

响应体

在这里插入图片描述

代码逻辑介绍

  大的代码逻辑如下,几个核心对象是SearchRequestSearchSourceQueryAggregation,,SearchResponseHits等。
  ES官方提供的API多是以建造者模式实现对象创建,核心工具类是QueryBuilders和各种xxxBuilders

// 创建请求
SearchRequest searchRequest = new SearchRequest();
// 设置索引
request.indices(IDX);
// 创建查询构造器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
// 设置查询详情返回条数,如果不传则默认使用服务端的值
searchSourceBuilder.size(10);
// 全值匹配
QueryBuilder fullMatchQuery = QueryBuilders.termQuery(field, param);
// 将条件注入到查询中
searchSourceBuilder.query(fullMatchQuery);
// 定义聚合操作
AggregationBuilder appNumBuilder = AggregationBuilders.cardinality("fieldResultName").field("fieldName.keyword");
// 将聚合操作注入到请求中
searchSourceBuilder.aggregation(appNumBuilder);
// 将查询体注入到请求中
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse;
try {
	// 发送请求
    searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
    }
} catch (IOException e) {
    e.printStackTrace();
}
// 拿到总数
SearchHits searchhits = searchResponse.getHits();
long totalCount = searchhits.getTotalHits().value;
meta.setTotalCount(totalCount);
// 遍历查询内容
for (SearchHit searchHit : searchhits) {
	// ...
}
// 获取聚合操作返回值
ParsedCardinality appResult = response.getAggregations().get("fieldResultName");
long appNum = appResult.getValue();

需求实战

普通查询

全值匹配

QueryBuilders.termQuery("fieldName", "param");

请求体:

{
    "query":{
        "term":{
            "fieldName":{
                "value":"param"
            }
        }
    }
}

模糊查询

// .keyword表示不分词
// * 号必须手动加,API本身不会加,因此要全模糊就左右拼"*"号。
QueryBuilders.wildcardQuery("fieldName", "*param*");

请求体:

{
    "query":{
        "wildcard":{
            "fieldName.keyword":{
                "value":"*param*"
            }
        }
    }
}

范围查询

// 参数可以为时间、数字等,需要与字段类型一致
QueryBuilders.rangeQuery("fieldName")
		// 大于等于, gt 大于
		.gte(1)
		// 小于等于, lt 小于
		.lte(100);

请求体:

{
    "query":{
        "range":{
            "fieldName":{
                "gte":1,
                "lte":100
            }
        }
    }
}

聚合查询

根据一个字段分组统计

// 如果不需要返回数据详情,则设置size为0,规避不必要的消耗。
searchRequest.size(0);
AggregationBuilders.terms("resultFieldName")
                .field("fieldName.keyword");

请求体:

{
	"size": 0,
    "query":{
	    "aggregations":{
	        "resultFieldName":{
	            "terms":{
	                "field":"fieldName.keyword"
	            }
	        }
	    }
    }
}

根据时间分组统计

// 如果不需要返回数据详情,则设置size为0,规避不必要的消耗。
DateHistogramAggregationBuilder aggregationBuilder = AggregationBuilders
                .dateHistogram("resultFieldName")
                .field("fieldName")
                // 按天统计
                .calendarInterval(DateHistogramInterval.DAY);

请求体:

GET _search
{
  "size": 0,
    "aggregations":{
        "StartUTC_groupby":{
            "date_histogram":{
                "field":"traefik.time",
                "calendar_interval":"1d"
            }
        }
    }
}

calendar_interval取值介绍:

含义
1y
1q
1M
1w
1d
1h
1m
1s

多字段统计

// 如果不需要返回数据详情,则设置size为0,规避不必要的消耗。
DateHistogramAggregationBuilder aggregationBuilder = AggregationBuilders
                .dateHistogram("resultFieldName")
                .field("fieldName")
                // 按天统计
                .calendarInterval(DateHistogramInterval.DAY);

// 添加子聚合对象
//最大值
aggregationBuilder.subAggregation(AggregationBuilders.max("maxResultFieldName").field("fieldName"));
//最小值
aggregationBuilder.subAggregation(AggregationBuilders.max("minResultFieldName").field("fieldName"));
//平均值
aggregationBuilder.subAggregation(AggregationBuilders.avg("avgResultFieldName").field("fieldName"));
//失败响应次数, 添加一个范围统计字段
aggregationBuilder.subAggregation(
        AggregationBuilders.range("failRequestResultName")
                .addRange(HttpStatus.HTTP_BAD_REQUEST, HttpStatus.HTTP_VERSION)
                .field("fieldName2")
);

请求体:

GET _search
{
 	"size": 0,
    "aggregations":{
        "StartUTC_groupby":{
            "date_histogram":{
                "field":"traefik.time",
                "calendar_interval":"1d"
            },
            "aggregations":{
                "maxResultFieldName":{
                    "max":{
                        "field":"fieldName"
                    }
                },
                "minResultFieldName":{
                    "min":{
                        "field":"fieldName"
                    }
                },
                "avgResultFieldName":{
                    "avg":{
                        "field":"fieldName"
                    }
                },
                "failRequestResultName":{
                    "range":{
                        "field":"fieldName2",
                        "ranges":[
                            {
                                "from":400,
                                "to":505
                            }
                        ],
                        "keyed":false
                    }
                }
            }
        }
    }
}

补充

灵活利用DEBUG调试

  在实际编码过程中,难免会碰到各种问题,此时我们可以在request.source(sourceBuilder);代码之后打个断点,查看searchRequest中的查询信息,如下图,并复制source属性的值,将该值直接复制到ES提供的工具中执行查看效果,并调试。
在这里插入图片描述
  
  在获取返回值的时候亦然,如果不清楚该如何获取返回值,则打个断点,先查看response的结构,在根据结构一个个将需要的数据获取出来。
在这里插入图片描述

封装代码

字段名封装

  一定要封装代码,虽然ES提供的API已经很多了,但是结合需求,还是有很多可以封装的,比如字段值,文中这种直接传"fieldName"的方式是非常不可取的,我们要专门用一个类来声明维护,同时可能还需要声明不分词还需要拼接.keyword后缀,还需要定义返回值列名等,作者是直接将这些字段封装成一个ENUM枚举类:

@AllArgsConstructor
public enum EsFieldEnum {
    /**
     * 应用名
     */
    REQUEST_HOST("RequestHost"),
    /**
     * uri
     */
    REQUEST_PATH("RequestPath"),
    /**
     * 响应码
     */
    ORIGIN_STATUS("OriginStatus"),
    /**
     * 调用方IP
     */
    CLIENT_ADDR("ClientAddr");


    private final String name;

    // 字段名前缀
    private static final String NAME_PREFIX = "traefik.";
    // 关键词后缀
    private static final String KEY_WORD_SUFFIX = ".keyword";
    // 分组字段名统一后缀
    private static final String GROUP_BY_SUFFIX = "_groupby";
    // 分组字段名统一后缀
    private static final String MAX_SUFFIX = "_max";
    // 分组字段名统一后缀
    private static final String MIN_SUFFIX = "_min";
    // 分组字段名统一后缀
    private static final String AVG_SUFFIX = "_avg";
    // 统计字段名统一后缀
    private static final String COUNT_SUFFIX = "_count";

    /**
     * 获取该字段值
     */
    public String getName() {
        return NAME_PREFIX + name;
    }

    /**
     * 获取该字段对应的关键词字段名
     */
    public String keyword() {
        return NAME_PREFIX + name + KEY_WORD_SUFFIX;
    }



    /* **********以下为字段别名********** */

    /**
     * 获取该字段对应的分组字段名
     */
    public String groupBy() {
        return name + GROUP_BY_SUFFIX;
    }

    /**
     * 获取该字段对应的分组字段名
     */
    public String max() {
        return name + MAX_SUFFIX;
    }

    /**
     * 获取该字段对应的分组字段名
     */
    public String min() {
        return name + MIN_SUFFIX;
    }

    /**
     * 获取该字段对应的分组字段名
     */
    public String avg() {
        return name + AVG_SUFFIX;
    }

    /**
     * 获取该字段对应的统计字段名
     */
    public String count() {
        return name + COUNT_SUFFIX;
    }

  
  这样在使用的时候就非常方便:
在这里插入图片描述

工具类封装

  为了提高代码复用率,作者封装了基于自身需求的工具类,提高代码复用率。这里抛砖引玉,希望能给大家带来一些启发:


/**
 * ES操作辅助类
 *
 * @author zzf
 * @date 2021年9月9日09:14:00
 */
public class EsHelper {

    private static final String IDX = "traefik-*";

    /**
     * 新建一个固定索引的SearchRequest
     * *****************注意********************
     * 此方法创建的请求没有指定固定的索引,因此需要使用{@link #newSearchBuilder(Date, Date)}方法创建包含时间区间条件的builder
     *
     * @return 一个指定索引的SearchRequest
     */
    public static SearchRequest newRequest() {
        SearchRequest request = new SearchRequest();
        request.indices(IDX);
        return request;
    }


    /**
     * 新建一个包含请求时间条件的Builder
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     */
    public static SearchSourceBuilder newSearchBuilder(Date startTime, Date endTime) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(
                new RangeQueryBuilder(EsFieldEnum.START_UTC.getName())
                        .gte(startTime)
                        .lte(endTime)
        );
        searchSourceBuilder.size(0);
        return searchSourceBuilder;
    }

    /**
     * 新建一个包含请求时间条件的Builder
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     */
    public static SearchSourceBuilder newAggSearchBuilder(Date startTime, Date endTime) {
        SearchSourceBuilder searchSourceBuilder = newAggSearchBuilder();
        searchSourceBuilder.query(
                new RangeQueryBuilder(EsFieldEnum.START_UTC.getName())
                        .gte(startTime)
                        .lte(endTime)
        );
        return searchSourceBuilder;
    }

    public static SearchSourceBuilder newAggSearchBuilder() {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.size(0);
        return searchSourceBuilder;
    }


    /**
     * 新建一个包含请求时间条件的Builder
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     */
    public static QueryBuilder newRangeQuery(Date startTime, Date endTime) {
        return new RangeQueryBuilder(EsFieldEnum.START_UTC.getName())
                .gte(startTime)
                .lte(endTime);
    }


    /**
     * 新建包含请求时间条件并与传入条件为取并集(and &)的Builder
     *
     * @param otherCondition 另外一个条件builder
     * @param startTime      开始时间
     * @param endTime        结束时间
     */
    public static QueryBuilder newMustQuery(QueryBuilder otherCondition, Date startTime, Date endTime) {
        return QueryBuilders.boolQuery()
                .must(otherCondition)
                .must(QueryBuilders.rangeQuery(EsFieldEnum.START_UTC.getName()).gte(startTime).lte(endTime));
    }


    /**
     * 新建包含请求时间条件的条件Builder
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     */
    public static BoolQueryBuilder newBoolQuery(Date startTime, Date endTime) {
        return QueryBuilders.boolQuery()
                .must(QueryBuilders.rangeQuery(EsFieldEnum.START_UTC.getName()).gte(startTime).lte(endTime));
    }

    /**
     * 新建一个包含分页的Builder
     *
     * @param from
     * @param size
     */
    public static SearchSourceBuilder newPageBuilder(Integer from, Integer size) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.from(from);
        searchSourceBuilder.size(size);
        return searchSourceBuilder;
    }

    /**
     * 新建一个根据指定字段统计的聚合builder
     *
     * @param fieldEnum 字段枚举值
     */
    public static AggregationBuilder newCountBuilder(EsFieldEnum fieldEnum) {
        return AggregationBuilders
                .cardinality(fieldEnum.count())
                .field(fieldEnum.keyword());
    }

    /**
     * 新建一个根据指定字段统计的聚合builder
     *
     * @param fieldEnum 字段枚举值
     */
    public static AggregationBuilder newTermsBuilder(EsFieldEnum fieldEnum) {
        return AggregationBuilders
                .terms(fieldEnum.groupBy())
                .field(fieldEnum.keyword());
    }

    private static final DecimalFormat df = new DecimalFormat("######0.00");

    public static String formatDouble(Double number) {
        if (number.equals(Double.NEGATIVE_INFINITY) || number.equals(Double.POSITIVE_INFINITY)) {
            return "0";
        }
        return df.format(number);
    }


    /**
     * 请求ES并获取通用柱状图结果
     *
     * @param client        es客户端对象
     * @param searchRequest 请求参数
     */
    public static List<CurrencyChartVo> queryAndGetCurrencyChartResult(RestHighLevelClient client, SearchRequest searchRequest, EsFieldEnum fieldEnum) {
        List<CurrencyChartVo> result = new LinkedList<>();
        SearchResponse searchResponse;
        try {
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            Terms terms = searchResponse.getAggregations().get(fieldEnum.groupBy());
            for (Terms.Bucket buck : terms.getBuckets()) {
                String xvalue = buck.getKeyAsString();
                long yvalue = buck.getDocCount();
                result.add(new CurrencyChartVo(xvalue, yvalue));
            }
        } catch (IOException e) {
            ThrowQueryException();
        }
        return result;
    }


    /**
     * 获取根据指定维度统计的结果
     * <p>
     * 当筛选字段与分组字段相同时,使用该方法,传入统一的字段枚举{@link EsFieldEnum}
     *
     * <b>这里的筛选字段使用的是模糊查询</b>
     *
     * @param client           es客户端
     * @param startTime        开始时间
     * @param endTime          结束时间
     * @param para             筛选字段参数
     * @param groupByFieldEnum 用于分组的字段(维度字段)
     */
    public static List<CurrencyChartVo> getErrCountChartResult(RestHighLevelClient client,
                                                               Date startTime,
                                                               Date endTime,
                                                               String para,
                                                               EsFieldEnum groupByFieldEnum) {
        RangeQueryBuilder errQuery = QueryBuilders.rangeQuery(EsFieldEnum.ORIGIN_STATUS.getName()).gte(HttpStatus.HTTP_BAD_REQUEST);
        return getCurrencyChartResult(client, errQuery, startTime, endTime, para, groupByFieldEnum);
    }


    /**
     * 获取根据指定维度统计的结果
     * <p>
     * 当筛选字段与分组字段不同时,使用该方法,分别传入其字段枚举{@link EsFieldEnum}
     *
     * <b>这里的筛选字段使用的是全值匹配</b>
     *
     * @param client           es客户端
     * @param startTime        开始时间
     * @param endTime          结束时间
     * @param para             筛选字段值
     * @param paraFieldEnum    筛选字段枚举值
     * @param groupByFieldEnum 用于分组的字段(维度字段)
     */
    public static List<CurrencyChartVo> getErrCountChartResult(RestHighLevelClient client,
                                                               Date startTime,
                                                               Date endTime,
                                                               String para,
                                                               EsFieldEnum paraFieldEnum,
                                                               EsFieldEnum groupByFieldEnum) {
        RangeQueryBuilder errQuery = QueryBuilders.rangeQuery(EsFieldEnum.ORIGIN_STATUS.getName()).gte(HttpStatus.HTTP_BAD_REQUEST);
        return getCurrencyChartResult(client, errQuery, startTime, endTime, para, paraFieldEnum, groupByFieldEnum);
    }


    /**
     * 获取根据指定维度统计的结果
     * <p>
     * 当筛选字段与分组字段相同时,使用该方法,传入统一的字段枚举{@link EsFieldEnum}
     *
     * <b>这里的筛选字段使用的是模糊查询</b>
     *
     * @param client           es客户端
     * @param startTime        开始时间
     * @param endTime          结束时间
     * @param para             筛选字段参数
     * @param groupByFieldEnum 用于分组的字段(维度字段)
     */
    public static List<CurrencyChartVo> getCurrencyChartResult(RestHighLevelClient client,
                                                               Date startTime,
                                                               Date endTime,
                                                               String para,
                                                               EsFieldEnum groupByFieldEnum) {
        return getCurrencyChartResult(client, null, startTime, endTime, para, groupByFieldEnum);
    }


    /**
     * 获取根据指定维度统计的结果
     * <p>
     * 当筛选字段与分组字段不同时,使用该方法,分别传入其字段枚举{@link EsFieldEnum}
     *
     * <b>这里的筛选字段使用的是全值匹配</b>
     *
     * @param client           es客户端
     * @param startTime        开始时间
     * @param endTime          结束时间
     * @param para             筛选字段值
     * @param paraFieldEnum    筛选字段枚举值
     * @param groupByFieldEnum 用于分组的字段(维度字段)
     */
    public static List<CurrencyChartVo> getCurrencyChartResult(RestHighLevelClient client,
                                                               Date startTime,
                                                               Date endTime,
                                                               String para,
                                                               EsFieldEnum paraFieldEnum,
                                                               EsFieldEnum groupByFieldEnum) {
        return getCurrencyChartResult(client, null, startTime, endTime, para, paraFieldEnum, groupByFieldEnum);
    }


    /**
     * 获取根据指定维度统计的结果
     * <p>
     * 当筛选字段与分组字段相同时,使用该方法,传入统一的字段枚举{@link EsFieldEnum}
     *
     * <b>这里的筛选字段使用的是模糊查询</b>
     *
     * @param client           es客户端
     * @param startTime        开始时间
     * @param endTime          结束时间
     * @param para             筛选字段参数
     * @param groupByFieldEnum 用于分组的字段(维度字段)
     */
    public static List<CurrencyChartVo> getCurrencyChartResult(RestHighLevelClient client,
                                                               QueryBuilder otherCondition,
                                                               Date startTime,
                                                               Date endTime,
                                                               String para,
                                                               EsFieldEnum groupByFieldEnum) {
        SearchRequest searchRequest = newRequest();
        // 该searchSourceBuilder.size() = 0, 即数据条数为0,我们只需要聚合函数的结果
        SearchSourceBuilder searchSourceBuilder = newAggSearchBuilder();
        BoolQueryBuilder queryBuilder = newBoolQuery(startTime, endTime);
        if (StringUtils.isNotBlank(para)) {
            queryBuilder.must(QueryBuilders.wildcardQuery(groupByFieldEnum.keyword(), toLikeParam(para)));
        }
        if (otherCondition != null) {
            queryBuilder.must(otherCondition);
        }
        searchSourceBuilder.query(queryBuilder);
        searchSourceBuilder.aggregation(newTermsBuilder(groupByFieldEnum));
        searchRequest.source(searchSourceBuilder);
        return queryAndGetCurrencyChartResult(client, searchRequest, groupByFieldEnum);
    }

    /**
     * 将参数加上左右模糊查询
     */
    public static String toLikeParam(String para) {
        return StringPool.ASTERISK + para + StringPool.ASTERISK;
    }


    /**
     * 获取根据指定维度统计的结果
     * <p>
     * 当筛选字段与分组字段不同时,使用该方法,分别传入其字段枚举{@link EsFieldEnum}
     *
     * <b>这里的筛选字段使用的是全值匹配</b>
     *
     * @param client           es客户端
     * @param startTime        开始时间
     * @param endTime          结束时间
     * @param para             筛选字段值
     * @param paraFieldEnum    筛选字段枚举值
     * @param groupByFieldEnum 用于分组的字段(维度字段)
     */
    public static List<CurrencyChartVo> getCurrencyChartResult(RestHighLevelClient client,
                                                               QueryBuilder otherCondition,
                                                               Date startTime,
                                                               Date endTime,
                                                               String para,
                                                               EsFieldEnum paraFieldEnum,
                                                               EsFieldEnum groupByFieldEnum) {
        SearchRequest searchRequest = newRequest();
        // 该searchSourceBuilder.size() = 0, 即数据条数为0,我们只需要聚合函数的结果
        SearchSourceBuilder searchSourceBuilder = newAggSearchBuilder();
        BoolQueryBuilder queryBuilder = newBoolQuery(startTime, endTime);
        if (StringUtils.isNotBlank(para)) {
            queryBuilder.must(QueryBuilders.termQuery(paraFieldEnum.keyword(), para));
        }
        if (otherCondition != null) {
            queryBuilder.must(otherCondition);
        }
        searchSourceBuilder.query(queryBuilder);
        searchSourceBuilder.aggregation(newTermsBuilder(groupByFieldEnum));
        searchRequest.source(searchSourceBuilder);
        return queryAndGetCurrencyChartResult(client, searchRequest, groupByFieldEnum);
    }


    /**
     * 获取根据指定维度的响应时间统计信息
     * <p>
     * 当筛选字段与分组字段不同时,使用该方法,分别传入其字段枚举{@link EsFieldEnum}
     *
     * <b>这里的筛选字段使用的是全值匹配</b>
     *
     * @param client           es客户端
     * @param startTime        开始时间
     * @param endTime          结束时间
     * @param para             筛选字段值
     * @param groupByFieldEnum 用于分组的字段(维度字段)
     */
    public static List<ResponseTimeVo> getRespTimeResult(RestHighLevelClient client,
                                                         Date startTime,
                                                         Date endTime,
                                                         String para,
                                                         EsFieldEnum groupByFieldEnum) {
        List<ResponseTimeVo> result = new LinkedList<>();
        SearchRequest searchRequest = newRequest();
        SearchSourceBuilder searchSourceBuilder = newAggSearchBuilder();
        BoolQueryBuilder queryBuilder = newBoolQuery(startTime, endTime);
        if (StringUtils.isNotBlank(para)) {
            queryBuilder.must(QueryBuilders.wildcardQuery(groupByFieldEnum.keyword(), toLikeParam(para)));
        }
        searchSourceBuilder.query(queryBuilder);
        //分组
        resTimeResultHandler(client, groupByFieldEnum, result, searchRequest, searchSourceBuilder);

        return result;
    }


    /**
     * 获取根据指定维度的响应时间统计信息
     * <p>
     * 当筛选字段与分组字段不同时,使用该方法,分别传入其字段枚举{@link EsFieldEnum}
     *
     * <b>这里的筛选字段使用的是全值匹配</b>
     *
     * @param client           es客户端
     * @param startTime        开始时间
     * @param endTime          结束时间
     * @param para             筛选字段值
     * @param paraFieldEnum    筛选字段枚举值
     * @param groupByFieldEnum 用于分组的字段(维度字段)
     */
    public static List<ResponseTimeVo> getRespTimeResult(RestHighLevelClient client,
                                                         Date startTime,
                                                         Date endTime,
                                                         String para,
                                                         EsFieldEnum paraFieldEnum,
                                                         EsFieldEnum groupByFieldEnum) {
        List<ResponseTimeVo> result = new LinkedList<>();
        SearchRequest searchRequest = newRequest();
        SearchSourceBuilder searchSourceBuilder = newAggSearchBuilder();
        BoolQueryBuilder queryBuilder = newBoolQuery(startTime, endTime);
        if (StringUtils.isNotBlank(para)) {
            queryBuilder.must(QueryBuilders.wildcardQuery(paraFieldEnum.keyword(), toLikeParam(para)));
        }
        searchSourceBuilder.query(queryBuilder);
        resTimeResultHandler(client, groupByFieldEnum, result, searchRequest, searchSourceBuilder);

        return result;
    }

    private static void resTimeResultHandler(RestHighLevelClient client, EsFieldEnum groupByFieldEnum, List<ResponseTimeVo> result, SearchRequest searchRequest, SearchSourceBuilder searchSourceBuilder) {
        //分组
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms(groupByFieldEnum.groupBy()).field(groupByFieldEnum.keyword());
        //最大值
        aggregationBuilder.subAggregation(AggregationBuilders.max(EsFieldEnum.DURATION.max()).field(EsFieldEnum.DURATION.getName()));
        //最小值
        aggregationBuilder.subAggregation(AggregationBuilders.max(EsFieldEnum.DURATION.min()).field(EsFieldEnum.DURATION.getName()));
        //平均值
        aggregationBuilder.subAggregation(AggregationBuilders.avg(EsFieldEnum.DURATION.avg()).field(EsFieldEnum.DURATION.getName()));
        searchSourceBuilder.aggregation(aggregationBuilder);
        searchRequest.source(searchSourceBuilder);

        SearchResponse searchResponse;
        try {
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            Terms terms = searchResponse.getAggregations().get(groupByFieldEnum.groupBy());
            for (Terms.Bucket buck : terms.getBuckets()) {
                String xvalue = buck.getKeyAsString();
                ParsedSingleValueNumericMetricsAggregation max = buck.getAggregations().get(EsFieldEnum.DURATION.max());
                ParsedSingleValueNumericMetricsAggregation min = buck.getAggregations().get(EsFieldEnum.DURATION.min());
                ParsedSingleValueNumericMetricsAggregation avg = buck.getAggregations().get(EsFieldEnum.DURATION.avg());
                result.add(
                        new ResponseTimeVo(
                                xvalue,
                                formatDouble(max.value()),
                                formatDouble(min.value()),
                                formatDouble(avg.value())
                        )
                );
            }
        } catch (IOException e) {
            ThrowQueryException();
        }
    }


    public static void ThrowQueryException() {
        throw new AuthBankException("ES请求错误,请联系管理员!");
    }
}

  
  封装完后,实际业务代码就非常少了,就是各种传参:
在这里插入图片描述

总结

  ES的API功能非常多,目前暂时只介绍了部分查询功能,后续会陆续丰富内容,一键三连不迷路哦~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值