当前位置:

首页 > 编程开发 > springboot2+es7怎么使用RestHighLevelClient

springboot2+es7怎么使用RestHighLevelClient

由于spring和es的集成并不是特别友好,es的高低版本兼容问题、api更新频率高等问题,所以我选择是官网提供的原生Client(RestHighLevelClient),但又不想去关注es的配置类以及和spring的集成配置、jar包冲突等问题,所以使用spring-boot-starter-data-elasticsearch。一、引入依赖jarorg.springframework.bootspring-boot-starter-data-elasticsearch二、application.pr

由于spring和es的集成并不是特别友好,es的高低版本兼容问题、api更新频率高等问题,所以我选择是官网提供的原生Client(RestHighLevelClient),但又不想去关注es的配置类以及和spring的集成配置、jar包冲突等问题,所以使用spring-boot-starter-data-elasticsearch。

一、引入依赖jar

        
            org.springframework.boot
            spring-boot-starter-data-elasticsearch
        

二、application.properties配置

spring.elasticsearch.rest.uris=http://127.0.0.1:9200,http://127.0.0.1:9201,http://127.0.0.1:9202
spring.elasticsearch.rest.connection-timeout=5s
spring.elasticsearch.rest.read-timeout=30s
logging.level.org.springframework.data.convert.CustomConversions=error

spring-boot-starter-data-elasticsearch中自动装配es的配置类:ElasticsearchRestClientAutoConfiguration、ElasticsearchRestClientProperties。

ElasticsearchRestClientAutoConfiguration:

@ConditionalOnClass({RestHighLevelClient.class})
@ConditionalOnMissingBean({RestClient.class})
@EnableConfigurationProperties({ElasticsearchRestClientProperties.class})
public class ElasticsearchRestClientAutoConfiguration {
 
    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnMissingBean({RestHighLevelClient.class})
    static class RestHighLevelClientConfiguration {
        RestHighLevelClientConfiguration() {
        }
 
        @Bean
        RestHighLevelClient elasticsearchRestHighLevelClient(RestClientBuilder restClientBuilder) {
            return new RestHighLevelClient(restClientBuilder);
        }
    }
 
    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnMissingBean({RestClientBuilder.class})
    static class RestClientBuilderConfiguration {
        RestClientBuilderConfiguration() {
        }
 
        @Bean
        RestClientBuilderCustomizer defaultRestClientBuilderCustomizer(ElasticsearchRestClientProperties properties) {
            return new ElasticsearchRestClientAutoConfiguration.DefaultRestClientBuilderCustomizer(properties);
        }
 
        @Bean
        RestClientBuilder elasticsearchRestClientBuilder(ElasticsearchRestClientProperties properties, ObjectProvider builderCustomizers) {
            HttpHost[] hosts = (HttpHost[])properties.getUris().stream().map(this::createHttpHost).toArray((x$0) -> {
                return new HttpHost[x$0];
            });
            RestClientBuilder builder = RestClient.builder(hosts);
            builder.setHttpClientConfigCallback((httpClientBuilder) -> {
                builderCustomizers.orderedStream().forEach((customizer) -> {
                    customizer.customize(httpClientBuilder);
                });
                return httpClientBuilder;
            });
            builder.setRequestConfigCallback((requestConfigBuilder) -> {
                builderCustomizers.orderedStream().forEach((customizer) -> {
                    customizer.customize(requestConfigBuilder);
                });
                return requestConfigBuilder;
            });
            builderCustomizers.orderedStream().forEach((customizer) -> {
                customizer.customize(builder);
            });
            return builder;
        }
 
        private HttpHost createHttpHost(String uri) {
            try {
                return this.createHttpHost(URI.create(uri));
            } catch (IllegalArgumentException var3) {
                return HttpHost.create(uri);
            }
        }
 
        private HttpHost createHttpHost(URI uri) {
            if (!StringUtils.hasLength(uri.getUserInfo())) {
                return HttpHost.create(uri.toString());
            } else {
                try {
                    return HttpHost.create((new URI(uri.getScheme(), (String)null, uri.getHost(), uri.getPort(), uri.getPath(), uri.getQuery(), uri.getFragment())).toString());
                } catch (URISyntaxException var3) {
                    throw new IllegalStateException(var3);
                }
            }
        }
    }
}

ElasticsearchRestClientProperties: 

@ConfigurationProperties(
    prefix = "spring.elasticsearch.rest"
)
public class ElasticsearchRestClientProperties {
    private List uris = new ArrayList(Collections.singletonList("http://localhost:9200"));
    private String username;
    private String password;
    private Duration connectionTimeout = Duration.ofSeconds(1L);
    private Duration readTimeout = Duration.ofSeconds(30L);
 
    public ElasticsearchRestClientProperties() {
    }
 
    public List getUris() {
        return this.uris;
    }
 
    public void setUris(List uris) {
        this.uris = uris;
    }
 
    public String getUsername() {
        return this.username;
    }
 
    public void setUsername(String username) {
        this.username = username;
    }
 
    public String getPassword() {
        return this.password;
    }
 
    public void setPassword(String password) {
        this.password = password;
    }
 
    public Duration getConnectionTimeout() {
        return this.connectionTimeout;
    }
 
    public void setConnectionTimeout(Duration connectionTimeout) {
        this.connectionTimeout = connectionTimeout;
    }
 
    public Duration getReadTimeout() {
        return this.readTimeout;
    }
 
    public void setReadTimeout(Duration readTimeout) {
        this.readTimeout = readTimeout;
    }
}

三、使用

ES基本操作持久层

/**
 * es持久层
 *
 * @author yangzihe
 * @date 2022/1/24
 */
@Repository
@Slf4j
public class EsRepository {
 
    @Resource
    private RestHighLevelClient highLevelClient;
 
    /**
     * 判断索引是否存在
     */
    public boolean existIndex(String index) {
        try {
            return highLevelClient.indices().exists(new GetIndexRequest(index), RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("es持久层异常!index={}", index, e);
        }
        return Boolean.FALSE;
    }
 
    /**
     * 创建索引
     */
    public boolean createIndex(String index, Map columnMap) {
        if (existIndex(index)) {
            return Boolean.FALSE;
        }
 
        CreateIndexRequest request = new CreateIndexRequest(index);
        if (columnMap != null && columnMap.size() > 0) {
            Map source = new HashMap<>();
            source.put("properties", columnMap);
            request.mapping(source);
        }
        try {
            highLevelClient.indices().create(request, RequestOptions.DEFAULT);
            return Boolean.TRUE;
        } catch (IOException e) {
            log.error("es持久层异常!index={}, columnMap={}", index, columnMap, e);
        }
        return Boolean.FALSE;
    }
 
    /**
     * 删除索引
     */
    public boolean deleteIndex(String index) {
        try {
            if (existIndex(index)) {
                AcknowledgedResponse response = highLevelClient.indices().delete(new DeleteIndexRequest(index), RequestOptions.DEFAULT);
                return response.isAcknowledged();
            }
        } catch (Exception e) {
            log.error("es持久层异常!index={}", index, e);
        }
        return Boolean.FALSE;
    }
 
    /**
     * 数据新增
     */
    public boolean insert(String index, String jsonString) {
        IndexRequest indexRequest = new IndexRequest(index);
 
        indexRequest.id(new Snowflake().nextIdStr());
        indexRequest.source(jsonString, XContentType.JSON);
 
        try {
            log.info("indexRequest={}", indexRequest);
            IndexResponse indexResponse = highLevelClient.index(indexRequest, RequestOptions.DEFAULT);
            log.info("indexResponse={}", indexResponse);
            return Boolean.TRUE;
        } catch (IOException e) {
            log.error("es持久层异常!index={}, jsonString={}", index, jsonString, e);
        }
        return Boolean.FALSE;
    }
 
    /**
     * 数据更新,可以直接修改索引结构
     */
    public boolean update(String index, Map dataMap) {
        UpdateRequest updateRequest = new UpdateRequest(index, dataMap.remove("id").toString());
        updateRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
        updateRequest.doc(dataMap);
        try {
            highLevelClient.update(updateRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("es持久层异常!index={}, dataMap={}", index, dataMap, e);
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }
 
    /**
     * 删除数据
     */
    public boolean delete(String index, String id) {
        DeleteRequest deleteRequest = new DeleteRequest(index, id);
        try {
            highLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("es持久层异常!index={}, id={}", index, id, e);
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }
 
}

ES查询持久层

/**
 * es查询持久层
 *
 * @author yangzihe
 * @date 2022/1/25
 */
@Repository
@Slf4j
public class EsSearchRepository {
 
    @Resource
    private RestHighLevelClient highLevelClient;
 
    /**
     * 分页查询
     *
     * @param queryPO 分页查询对象
     *
     * @return 分页查询结果
     */
    public EsQueryRespPO> searchPage(EsQueryReqPO queryPO) {
        // 默认分页参数设置
        if (queryPO.getPageNum() == null) {
            queryPO.setPageNum(1);
        }
        if (queryPO.getPageSize() == null) {
            queryPO.setPageSize(10);
        }
 
        // 设置索引
        SearchRequest searchRequest = new SearchRequest(queryPO.getIndex());
 
        // 封装查询源对象
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        searchRequest.source(sourceBuilder);
 
        // 查询条件
        sourceBuilder.query(queryPO.getQuery());
 
        // 排序字段
        if (StringUtils.isNotBlank(queryPO.getSortField()) && queryPO.getSort() != null) {
            FieldSortBuilder order = new FieldSortBuilder(queryPO.getSortField()).order(queryPO.getSort());
            sourceBuilder.sort(order);
        }
 
        // 开始行数,默认0
        sourceBuilder.from((queryPO.getPageNum() - 1) * queryPO.getPageSize());
        // 页大小,默认10
        sourceBuilder.size(queryPO.getPageSize());
 
        // 查询结果
        SearchResponse searchResponse = null;
        try {
            // log.info("es查询请求对象:searchRequest={}", searchRequest);
            log.info("es查询请求对象source:sourceBuilder={}", searchRequest.source());
            // 执行搜索
            searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            log.info("es查询响应结果:searchResponse={}", searchResponse);
        } catch (IOException e) {
            log.error("es查询,IO异常!searchRequest={}", searchRequest, e);
            // 异常处理
            return EsQueryRespPO.error("es查询,IO异常!");
        }
 
        if (RestStatus.OK.equals(searchResponse.status())) {
            // 解析对象
            SearchHit[] hits = searchResponse.getHits().getHits();
            // 获取source
            List> sourceList = Arrays.stream(hits).map(SearchHit::getSourceAsMap).collect(Collectors.toList());
            long totalHits = searchResponse.getHits().getTotalHits().value;
            return EsQueryRespPO.success(sourceList, queryPO.getPageNum(), queryPO.getPageSize(), totalHits);
        } else {
            log.error("es查询返回的状态码异常!searchResponse.status={}, searchRequest={}", searchResponse.status(), searchRequest);
            return EsQueryRespPO.error("es查询返回的状态码异常!");
        }
    }
 
    /**
     * 聚合的分页查询
     *
     * @param queryPO 查询请求对象
     *
     * @return 聚合分页查询结果
     */
    public EsQueryRespPO searchAggregation(EsQueryReqPO queryPO) {
        // 设置索引
        SearchRequest searchRequest = new SearchRequest(queryPO.getIndex());
 
        // 封装查询源对象
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        searchRequest.source(sourceBuilder);
 
        // 查询条件
        sourceBuilder.query(queryPO.getQuery());
 
        // 排序字段
        if (StringUtils.isNotBlank(queryPO.getSortField()) && queryPO.getSort() != null) {
            FieldSortBuilder order = new FieldSortBuilder(queryPO.getSortField()).order(queryPO.getSort());
            sourceBuilder.sort(order);
        }
 
        // 页大小0,只返回聚合结果
        sourceBuilder.size(0);
 
        // 设置聚合查询,可以设置多个聚合查询条件,只要聚合查询命名不同就行
        // 聚合分组条件, group by
        sourceBuilder.aggregation(queryPO.getTermsAggregation());
        // 聚合统计条件, count分组后的数据,计算分组后的总大小
        sourceBuilder.aggregation(queryPO.getCardinalityAggregation());
 
        // 查询结果
        SearchResponse searchResponse = null;
        try {
            // log.info("es查询请求对象:searchRequest={}", searchRequest);
            log.info("es查询请求对象source:sourceBuilder={}", searchRequest.source());
            // 执行搜索
            searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            log.info("es查询响应结果:searchResponse={}", searchResponse);
        } catch (IOException e) {
            log.error("es查询,IO异常!searchRequest={}", searchRequest, e);
            return EsQueryRespPO.error("es查询,IO异常!");
        }
 
        if (RestStatus.OK.equals(searchResponse.status())) {
            // 解析对象
            Aggregations aggregations = searchResponse.getAggregations();
 
            long docTotal = searchResponse.getHits().getTotalHits().value;
 
            // 遍历terms聚合结果
            Terms terms = aggregations.get(queryPO.getTermsAggregation().getName());
            List bucketList = terms.getBuckets().stream().map(bucket -> {
                String key = bucket.getKeyAsString();
                long docCount = bucket.getDocCount();
                return new AggregationBucketPO(key, docCount, docTotal);
            }).collect(Collectors.toList());
 
            // 总数量
            Cardinality cardinality = aggregations.get(queryPO.getCardinalityAggregation().getName());
            long totalHits = cardinality.getValue();
 
            return EsQueryRespPO.success(bucketList, queryPO.getPageNum(), queryPO.getPageSize(), totalHits);
        } else {
            log.error("es查询返回的状态码异常!searchResponse.status={}, searchRequest={}", searchResponse.status(), searchRequest);
            return EsQueryRespPO.error("es查询返回的状态码异常!");
        }
    }
}

其中,EsQueryReqPO、EsQueryRespPO、AggregationBucketPO等类如下:

/**
 * es查询请求对象
 */
@Data
public class EsQueryReqPO {
 
    /**
     * 索引名
     */
    String[] index;
 
    /**
     * 查询条件
     */
    QueryBuilder query;
 
    /**
     * 排序字段
     */
    String sortField;
 
    /**
     * 排序方式 SortOrder.ASC、SortOrder.DESC
     */
    SortOrder sort;
 
    /**
     * 页数
     */
    private Integer pageNum;
 
    /**
     * 页大小
     */
    private Integer pageSize;
 
    /**
     * 聚合分组条件, group by
     */
    private TermsAggregationBuilder termsAggregation;
 
    /**
     * 聚合统计条件, count分组后的数据
     */
    private CardinalityAggregationBuilder cardinalityAggregation;
}
/**
 * es分页响应对象
 *
 * @author yangzihe
 * @date 2022/1/25
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EsQueryRespPO {
 
    /**
     * 是否成功
     */
    private Boolean success;
 
    /**
     * 信息
     */
    private String message;
 
    /**
     * 页数
     */
    private Integer pageNum;
 
    /**
     * 页大小
     */
    private Integer pageSize;
 
    /**
     * 总大小
     */
    private Long totalSize;
 
    /**
     * 数据
     */
    private List sourceList;
 
    public static  EsQueryRespPO success(List sourceList, Integer pageNum, Integer pageSize,
                                               Long totalSize) {
        EsQueryRespPO esQueryRespPO = new EsQueryRespPO<>();
        esQueryRespPO.setSuccess(true);
        esQueryRespPO.setSourceList(sourceList);
        esQueryRespPO.setPageNum(pageNum);
        esQueryRespPO.setPageSize(pageSize);
        esQueryRespPO.setTotalSize(totalSize);
        return esQueryRespPO;
    }
 
    public static EsQueryRespPO error() {
        EsQueryRespPO esQueryRespPO = new EsQueryRespPO();
        esQueryRespPO.setSuccess(false);
        esQueryRespPO.setMessage("es查询异常");
        return esQueryRespPO;
    }
 
    public static EsQueryRespPO error(String message) {
        EsQueryRespPO esQueryRespPO = new EsQueryRespPO();
        esQueryRespPO.setSuccess(false);
        esQueryRespPO.setMessage(message);
        return esQueryRespPO;
    }
 
}
/**
 * 聚合桶对象
 *
 * @author yangzihe
 * @date 2022/1/26
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AggregationBucketPO {
 
    /**
     * 聚合Bucket的key名
     */
    private String key;
 
    /**
     * 聚合Bucket的文档数量
     */
    private Long docCount;
 
    /**
     * 文档总数量
     */
    private Long docTotal;
 
}

ES多级(二级)聚合分桶查询

import com.yy.armor.manager.common.exception.EsException;
import com.yy.armor.manager.persist.es.po.AggregationBucketPO;
import com.yy.armor.manager.persist.es.po.EsMultiAggregationReqPO;
 
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Resource;
 
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.pulsar.shade.org.apache.commons.compress.utils.Lists;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.springframework.stereotype.Repository;
 
 
@Repository
@Slf4j
public class EsSearchRepository {
 
    @Resource
    private RestHighLevelClient highLevelClient;
 
 
    /**
     * 多级聚合查询(二级聚合)
     *
     * @param reqPO 查询请求对象
     *
     * @return 聚合查询结果
     */
    public List searchMultiAggregation(EsMultiAggregationReqPO reqPO) {
        // 设置索引
        SearchRequest searchRequest = new SearchRequest(reqPO.getIndex());
 
        // 封装查询源对象
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        searchRequest.source(sourceBuilder);
 
        // 查询条件
        sourceBuilder.query(reqPO.getQuery());
 
        // 排序字段
        if (StringUtils.isNotBlank(reqPO.getSortField()) && reqPO.getSort() != null) {
            FieldSortBuilder order = new FieldSortBuilder(reqPO.getSortField()).order(reqPO.getSort());
            sourceBuilder.sort(order);
        }
 
        // 页大小0,只返回聚合结果
        sourceBuilder.size(0);
 
        // 聚合分桶。创建terms桶聚合,聚合名字=terms_by_XXX, 字段=XXX
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("terms_by_" + reqPO.getField()).field(reqPO.getField());
        if (reqPO.getFieldSize() != null) {
            termsAggregationBuilder.size(reqPO.getFieldSize());
        }
        // 二级聚合分桶
        TermsAggregationBuilder subTermsAggregationBuilder = AggregationBuilders.terms("terms_by_" + reqPO.getSubField()).field(reqPO.getSubField());
        if (reqPO.getSubFieldSize() != null) {
            subTermsAggregationBuilder.size(reqPO.getSubFieldSize());
        }
        termsAggregationBuilder.subAggregation(subTermsAggregationBuilder);
 
        // 聚合分组条件
        sourceBuilder.aggregation(termsAggregationBuilder);
 
        // 查询结果
        SearchResponse searchResponse = null;
        try {
            log.info("es查询请求对象source:sourceBuilder={}", searchRequest.source());
            // 执行搜索
            searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            log.info("es查询响应结果:searchResponse={}", searchResponse);
        } catch (IOException e) {
            log.error("es查询,IO异常!searchRequest={}", searchRequest, e);
            throw new EsException("es查询,IO异常!");
        }
 
        if (RestStatus.OK.equals(searchResponse.status())) {
            // 遍历terms聚合结果
            Terms terms = searchResponse.getAggregations().get(termsAggregationBuilder.getName());
            List bucketList = terms.getBuckets().stream().map(bucket -> {
                // 一级聚合分桶的数据
                String key = bucket.getKeyAsString();
                long docCount = bucket.getDocCount();
                // 二级聚合分桶的数据
                Terms subTerms = bucket.getAggregations().get(subTermsAggregationBuilder.getName());
                List subBucketList = convertTerms(subTerms);
                return new AggregationBucketPO(key, docCount, subBucketList);
            }).collect(Collectors.toList());
 
            return bucketList;
        } else {
            log.error("es查询返回的状态码异常!searchResponse.status={}, searchRequest={}", searchResponse.status(), searchRequest);
            throw new EsException("es查询返回的状态码异常!");
        }
    }
 
    private List convertTerms(Terms terms) {
        if (CollectionUtils.isEmpty(terms.getBuckets())) {
            return Lists.newArrayList();
        }
 
        return terms.getBuckets().stream().map(bucket -> {
            String key = bucket.getKeyAsString();
            long docCount = bucket.getDocCount();
            return new AggregationBucketPO(key, docCount);
        }).collect(Collectors.toList());
    }
}

其中,EsMultiAggregationReqPO、AggregationBucketPO类如下:

@Data
public class EsMultiAggregationReqPO {
    
    /**
     * 索引名
     */
    String[] index;
 
    /**
     * 查询条件
     */
    QueryBuilder query;
 
    /**
     * 聚合分桶字段
     */
    private String field;
 
    /**
     * 二级聚合分桶字段
     */
    private String subField;
 
    /**
     * 聚合分桶大小,非必传
     */
    private Integer fieldSize;
 
    /**
     * 二级聚合分桶大小,非必传
     */
    private Integer subFieldSize;
 
    /**
     * 排序字段,非必传
     */
    String sortField;
 
    /**
     * 排序方式 SortOrder.ASC、SortOrder.DESC,非必传
     */
    SortOrder sort;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AggregationBucketPO {
    /**
     * 聚合Bucket的key名
     */
    private String key;
 
    /**
     * 聚合Bucket的文档数量
     */
    private Long docCount;
 
    /**
     * 子桶集合
     */
    private List subBucketList;
 
    public AggregationBucketPO(String key, Long docCount) {
        this.key = key;
        this.docCount = docCount;
    }
}

二级聚合分桶测试代码 

    @PostConstruct
    private void init() {
        // 查询对象的封装
        EsMultiAggregationReqPO reqPO = new EsMultiAggregationReqPO();
 
        reqPO.setIndex(new String[]{"test_log"});
 
        List ids = Lists.newArrayList();
        ids.add(140L);
        ids.add(141L);
        ids.add(142L);
        QueryBuilder queryBuilder4 = QueryBuilders.termsQuery("eventId", ids);
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery().must(queryBuilder4);
        reqPO.setQuery(queryBuilder);
 
        reqPO.setField("eventId");
        reqPO.setFieldSize(9999);
        reqPO.setSubField("riskFlag");
 
        // 执行查询
        List esQueryRespPO = searchMultiAggregation(reqPO);
        System.out.println("esQueryRespPO=" + esQueryRespPO);
    }

其它

如果没有用spring-boot-starter-data-elasticsearch来自动注入es组件,那么需要自己做es client的注入,es配置类如下:

/**
 * @author yangzihe
 * @date 2022/1/25
 */
@Configuration
public class EsClientConfig {
 
    @Value("${spring.elasticsearch.rest.uris}")
    private List uris;
 
    @Bean
    public RestHighLevelClient restHighLevelClient() {
        List httpHostList = uris.stream().map(HttpHost::create).collect(Collectors.toList());
        HttpHost[] httpHost = new HttpHost[uris.size()];
        httpHostList.toArray(httpHost);
        RestClientBuilder clientBuilder = RestClient.builder(httpHost);
        return new RestHighLevelClient(clientBuilder);
    }
 
}

Snowflake是hutool包里的,导包:

        
        
            cn.hutool
            hutool-all
            5.7.14
        

聚合查询的测试用例:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = StartApplication.class)
public class EsTest {
 
    @Resource
    private EsSearchRepository esSearchRepository;
 
    @Test
    public void testSearchAggregation() {
        // 查询对象的封装
        EsQueryReqPO queryPO = new EsQueryReqPO();
        queryPO.setIndex(new String[]{"yzh2", "yzh3"});
        queryPO.setPageNum(1);
        queryPO.setPageSize(10);
 
        // 时间戳范围
        QueryBuilder queryBuilder1 = QueryBuilders.rangeQuery("timestamp")
            .from(System.currentTimeMillis() - 1000)
            .to(System.currentTimeMillis());
        // 登录标识
        QueryBuilder queryBuilder2 = QueryBuilders.termQuery("name", "yang");
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery().must(queryBuilder1).must(queryBuilder2);
        queryPO.setQuery(queryBuilder);
 
        // 根据userName分组。创建terms桶聚合,聚合名字=terms_by_userName, 字段=payload.userName.keyword
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders
            .terms("terms_by_userName").field("payload.userName.keyword");
        termsAggregationBuilder.size(queryPO.getPageSize() * queryPO.getPageNum());
        termsAggregationBuilder.subAggregation(new BucketSortPipelineAggregationBuilder("bucket_field", null)
            .from((queryPO.getPageNum() - 1) * queryPO.getPageSize()).size(queryPO.getPageSize()));
        queryPO.setTermsAggregation(termsAggregationBuilder);
 
        // 根据userName聚合count统计. cardinality名=count_userName, 字段=payload.userName.keyword
        CardinalityAggregationBuilder cardinalityAggregationBuilder = AggregationBuilders
            .cardinality("count_userName").field("payload.userName.keyword");
        queryPO.setCardinalityAggregation(cardinalityAggregationBuilder);
 
        // 执行查询
        EsQueryRespPO esQueryRespPO = esSearchRepository.searchAggregation(queryPO);
    }
}
本文内容来源于互联网,如有侵权请联系删除。
作者最新文章
编程开发
相关文章 更多
using namespace 使用中遇到的问题怎么解决
using namespace 使用中遇到的问题怎么解决

命名空间的基本概念与常见引入问题在C++等编程语言中,命名空间(namespace)是一种将代码标识符(如变量、函数、类名)封装在特定名称下的机制,其主要目的是避免命名冲突,尤其是在大型项目或使用多个第三方库时。使用“using namespace”指令可以将指定命名空间中的所有名称引入当前作用域,

c语言函数递归 实操经验总结:这些技巧很实用
c语言函数递归 实操经验总结:这些技巧很实用

理解递归的基本原理在C语言中,递归是一种函数调用自身的编程技术。要掌握它,首先需要理解其核心思想:将一个复杂的大问题,分解为一个或几个与原问题相似但规模更小的子问题,直到子问题足够简单,可以直接求解。这个过程通常包含两个关键部分:递归出口和递归体。递归出口定义了问题何时不再继续分解,即最简单、可直接

c语言函数递归 怎么选?常见方案对比分析
c语言函数递归 怎么选?常见方案对比分析

递归函数的基本概念与适用场景在C语言编程中,递归是一种函数调用自身的编程技巧。它并非适用于所有问题,但在处理某些具有自相似结构的问题时,能提供极其清晰和优雅的解决方案。递归的核心思想是将一个大规模问题分解为一个或多个同类型但规模更小的子问题,直到子问题简单到可以直接求解。典型的适用场景包括树形结构的

Objective-C 内存管理入门:从 alloc 到 dealloc 的生命周期详解
Objective-C 内存管理入门:从 alloc 到 dealloc 的生命周期详解

理解内存管理的基石在Objective-C的编程世界中,内存管理是开发者必须掌握的核心技能之一。它直接关系到应用的性能、稳定性与资源利用效率。与一些采用自动垃圾回收机制的语言不同,Objective-C在很长一段时间里,依赖一套基于引用计数的、需要开发者部分介入的管理规则。这套规则的核心思想是明确的

如何正确使用 dealloc 以避免 iOS 应用中的内存泄漏
如何正确使用 dealloc 以避免 iOS 应用中的内存泄漏

理解 dealloc 的角色与时机在 iOS 应用开发中,内存管理是保障应用性能与稳定性的基石。dealloc 方法是 Objective-C 中对象生命周期结束时的关键回调,它标志着对象即将被系统回收内存。正确理解其触发时机至关重要:当一个对象的引用计数降为零时,运行时系统会自动调用该对象的 de

深入理解 Objective-C 中的 dealloc 方法:内存管理核心机制
深入理解 Objective-C 中的 dealloc 方法:内存管理核心机制

内存管理的基石在Objective-C的世界里,内存管理是开发者必须掌握的核心技能之一。作为一门在手动引用计数(MRC)时代诞生的语言,Objective-C要求程序员对对象的生命周期有清晰的认识。dealloc方法正是这一生命周期中至关重要的终点站。它是一个实例方法,当对象的引用计数降为零时,系统

理解 native2ascii:Java 国际化开发中的字符编码工具
理解 native2ascii:Java 国际化开发中的字符编码工具

native2ascii 工具的基本定位在Ja va应用程序的国际化与本地化开发过程中,处理非拉丁字符集是一个常见且关键的环节。Ja va内部使用Unicode字符集来统一表示全球各种语言的文字,但其属性文件(.properties)在历史上要求使用ASCII编码,或者更准确地说,要求非ASCII字

如何使用 native2ascii 转换中文字符为 Unicode 转义序列
如何使用 native2ascii 转换中文字符为 Unicode 转义序列

理解 native2ascii 工具的基本用途在软件开发,特别是涉及国际化处理的场景中,开发者常常需要处理不同编码的文本资源。native2ascii 是 Ja va 开发工具包(JDK)中提供的一个命令行实用程序,其主要功能是将包含本地字符编码(非ASCII字符)的文件,转换为包含 Unicode

Java native2ascii 命令详解:解决属性文件乱码问题
Java native2ascii 命令详解:解决属性文件乱码问题

native2ascii 命令的由来与作用在Ja va开发中,处理国际化资源文件是一个常见需求。资源文件通常以.properties格式存储,用于支持多语言界面。然而,Ja va属性文件默认采用ISO-8859-1字符集编码,这导致了一个直接的问题:当文件中包含非拉丁字符(如中文、日文、韩文等)时,

一个 memwatch 实战案例:定位野指针问题
一个 memwatch 实战案例:定位野指针问题

内存监控工具的价值与挑战在软件开发,尤其是使用C/C++这类手动管理内存的语言时,内存错误是程序员最常遭遇的难题之一。其中,野指针问题因其隐蔽性和破坏性,往往成为最难定位的“幽灵”缺陷。它可能潜伏在代码中,在特定条件下才被触发,导致程序崩溃、数据损坏或难以预测的行为。传统的调试手段,如打印日志或使用

查看更多
精品专题 更多
装机必备
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows
Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

macOS软件
macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

Mac软件 更多
灵活计算器
灵活计算器
macOS/iOS/Android

灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

赤友清理大师
赤友清理大师
macOS

赤友清理大师是一款为 Mac 设计的智能清理优化工具,可精准扫描垃圾、大文件、重复文件等,释放磁盘空间。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

WINDOWS 更多
Windows 10
Windows 10
Windows

Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

密码键盘
密码键盘
Windows/macOS/iOS/Android

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。