ES java api 分组聚合,以及查询api(滚动)

package com.xhzw.electric.service.impl;

import com.alibaba.fastjson.JSON;
import com.xhzw.electric.es.ElectricMeter;
import com.xhzw.electric.service.ElasticSearchService;
import com.xhzw.electric.util.Constant;
import com.xhzw.electric.util.DateUtil;
import com.xhzw.electric.util.StringUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.MultiSearchRequest;
import org.elasticsearch.action.search.MultiSearchResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.Stats;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;

@Slf4j
@Service
@AllArgsConstructor
public class ElasticSearchServiceImpl implements ElasticSearchService {
    private final RestHighLevelClient restHighLevelClient;

    /**
     * 创建索引
     *
     * @throws IOException
     */
    @Override
    public void createIndex(String indexName) throws IOException {
//        CreateIndexRequest createIndexRequest = new CreateIndexRequest("electric-meter");
        CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
        restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
    }

    @Override
    public boolean existIndex(String indexName) {
        boolean exists=false;
//        String indexName="test-electric-meter-hour-0311";
        try {
            GetIndexRequest indexRequest=new GetIndexRequest(indexName);

            exists = restHighLevelClient.indices().exists(indexRequest, RequestOptions.DEFAULT);
        }catch (IOException e){
            e.printStackTrace();
        }

        return exists;
    }

    @Override
    public List<String> likeIndex(String likeStr) throws IOException {
        Response get = restHighLevelClient.getLowLevelClient().performRequest(new Request("GET", "_cat/indices/"+likeStr));
        get.getEntity();
        String resultJson = EntityUtils.toString(get.getEntity());

        return getAllIndex(resultJson);

    }
    /**
     * 模糊查询索引
     * @param likeStr
     * @return
     * @throws IOException
     */
    @Override
    public void deleteAllByIndexName(String indexName) throws Exception{
        SearchRequest searchRequest=new SearchRequest(indexName);

        SearchSourceBuilder sourceBuilder=new SearchSourceBuilder();
        sourceBuilder.query();
        sourceBuilder.size(5000);
        searchRequest.source(sourceBuilder);
        SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        SearchHit[] hits = response.getHits().getHits();


        BulkRequest request = new BulkRequest();
        for (SearchHit hit : hits) {
            DeleteRequest deleteRequest=new DeleteRequest(indexName,hit.getId());
            request.add(deleteRequest);

        }
        restHighLevelClient.bulk(request,RequestOptions.DEFAULT);

    }
    /**
     * 插入数据
     * @param indexName
     * @param list
     * @throws IOException
     */
    @Override
    public void insertDate(String indexName,List<?> list) throws IOException {
        if(list.size()==0){
            return;
        }
        //批量操作的Request
        BulkRequest request = new BulkRequest();
//        request.timeout("1s");
        //批量处理请求
        for (int i = 0; i < list.size(); i++) {
            request.add(
                    new IndexRequest(indexName)
                            .source(JSON.toJSONString(list.get(i)), XContentType.JSON)
            );
        }
        BulkResponse response = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
    }
    /**
     * 查询 and
     * @param indexName
     * @param map    列名,值
     * @return
     * @throws IOException
     */
    @Override
    public SearchHit[] searchLikeOne(String indexName,Map<String,Object> map) throws IOException{
        SearchRequest request = new SearchRequest(indexName);
        //构建搜索条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        map.entrySet().forEach(param->{
            boolQueryBuilder.must(QueryBuilders.termQuery(param.getKey(), param.getValue()));
        });

        sourceBuilder.query(boolQueryBuilder);
        request.source(sourceBuilder);
        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
        SearchHit[] hits = response.getHits().getHits();

        return hits;
    }

    /**
     * 查询区间段group聚合值
     * @param from 开始时间戳
     * @param to   结束时间戳
     * @param indexName   索引名称
     * @param group  计算分组
     * @param sumGroup 累计字段
     * @param sum   是否累加 或算差值
     * @return
     */
    @Override
    public Map<String, ElectricMeter> getStatsGroupByDeviceId(long from, long to, List<String> indexName, String[] group, String [] sumGroup, boolean sum){
        Map<String,ElectricMeter> result=new HashMap<>();
        SearchRequest searchRequest=new SearchRequest(indexName.toArray(new String[indexName.size()]));
        SearchSourceBuilder sourceBuilder=new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.boolQuery()
//                .must(QueryBuilders.rangeQuery("timestamp").gte(Timestamp.valueOf("2021-03-11 01:00:00").getTime()))
                        .must(QueryBuilders.rangeQuery("gather_time").gte(from).lte(to))
        );
        sourceBuilder.sort("gather_time", SortOrder.DESC);
        sourceBuilder.size(0);
//        String[] includes=new String[]{"timestamp","device_id","pf","ep"};
//        sourceBuilder.fetchSource(includes,null);
        TermsAggregationBuilder aggregation = AggregationBuilders.terms("devices")
                .field("device_id");
        Arrays.stream(group).forEach(type->{
            aggregation.subAggregation(AggregationBuilders.stats(type+"_stats")
                    .field(type));
        });
        sourceBuilder.aggregation(aggregation);
        searchRequest.source(sourceBuilder);
        try {
            SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            Aggregations aggregations = response.getAggregations();
            Terms byCompanyAggregation = aggregations.get("devices");
            List<? extends Terms.Bucket> buckets = byCompanyAggregation.getBuckets();

            for (Terms.Bucket bucket : buckets) {
                String deviceId=(String)bucket.getKey();
                Map<String,Object> metersMap=new HashMap<>();
                metersMap.put("device_id",deviceId);
                Arrays.stream(group).forEach(type->{
                    Stats stats = bucket.getAggregations().get(type+"_stats");
                    metersMap.put(type,stats.getAvgAsString());
                    if(Arrays.asList(sumGroup).contains(type)){
                        if(sum){
                            metersMap.put(type,stats.getSum());
                        } else {
                            metersMap.put(type,stats.getMax()-stats.getMin());

                        }
                    }
                });
//                metersMap.put("timestamp",to);
                ElectricMeter electricMeter = JSON.parseObject(JSON.toJSONString(metersMap), ElectricMeter.class);
                result.put(deviceId,electricMeter);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 查询表最大时间
     * @return 0 /timestamp
     */
    public long getlastHourTime(String indexHourName){
        long result=0;
        try {
            SearchRequest searchRequest=new SearchRequest(indexHourName);
            SearchSourceBuilder sourceBuilder=new SearchSourceBuilder();

            TermsAggregationBuilder aggregation = AggregationBuilders.terms("timestamp")
                    .field("gather_time")
                    .size(1)
                    .order(BucketOrder.key(false));

            sourceBuilder.query();
            sourceBuilder.aggregation(aggregation);
            searchRequest.source(sourceBuilder);
            SearchResponse response = restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);

            Aggregations aggregations = response.getAggregations();
            Terms byCompanyAggregation = aggregations.get("timestamp");
            List<? extends Terms.Bucket> buckets = byCompanyAggregation.getBuckets();
            for (Terms.Bucket bucket : buckets) {
                result=(long)bucket.getKey();
            }
        }catch (Exception e){
            log.error("查询最后一小时,不存在该表,返回0已做校验");
        }


        return result;
    }
    /**
     * 批查询
     * @param indexes  索引多表
     * @param fields   fields 判断 列的值
     * @param group    group不为null时:判断某一时刻同时都有值
     * @return
     */
    public List<SearchHit> multiSearch(List<String> indexes,Map<String,List<String>> fields,String[] group) {
        List<SearchHit> result = new ArrayList<>();

        MultiSearchRequest request = new MultiSearchRequest();

        Set<Map.Entry<String, List<String>>> entries = fields.entrySet();
        entries.forEach(entry ->{
            String field = entry.getKey();
            List<String> values = entry.getValue();
            values.forEach( value ->{
                SearchRequest searchRequest = new SearchRequest(indexes.toArray(new String[indexes.size()]));
                SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
                BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

                if(group!=null){
                    //必须同时存在值
                    Arrays.stream(group).forEach(type->{
                        boolQueryBuilder.must(QueryBuilders.existsQuery(type));
                    });
//                    //值不能同时为0
//                    BoolQueryBuilder boolQueryBuilderZero = QueryBuilders.boolQuery();
//                    Arrays.stream(group).forEach(type->{
//                        boolQueryBuilderZero.must(QueryBuilders.termQuery(type,"0"));
//                    });
//                    boolQueryBuilder.mustNot(boolQueryBuilderZero);
                }

                boolQueryBuilder.must(QueryBuilders.termQuery(field, value));
                searchSourceBuilder.query(boolQueryBuilder);

                searchSourceBuilder.size(1);
                searchSourceBuilder.sort("gather_time",SortOrder.DESC);
                searchRequest.source(searchSourceBuilder);
                request.add(searchRequest);
            });
        });
        try {
            MultiSearchResponse response = restHighLevelClient.msearch(request, RequestOptions.DEFAULT);
            response.forEach(t -> {
                SearchResponse resp = t.getResponse();
                SearchHit[] hits = resp.getHits().getHits();
                if(hits!=null && hits.length>0){
                    result.add(hits[0]);
                }

            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 查询所有devices的最新一条同时具有group的数据集合
     * @param indexName 需要有租户id及当天 5-electric-meter-20210323
     * @param devices  所需要哪些deviceId的数据
     * @param group  同时存在哪些字段
     * @return
     */
    public Map<String,ElectricMeter> getLastTimeValGroupByDeviceId(String indexName,List<String> devices,String[] group){
        String yesterIndex = indexName.substring(0,indexName.lastIndexOf("-")+1) + DateUtil.dateDaySub1(indexName.substring(indexName.lastIndexOf("-")+1));
        //返回结果
        Map<String,ElectricMeter> result=new HashMap<>();

        try {
                List<String> indexes= new ArrayList<>();
                indexes.add(indexName);
                indexes.add(yesterIndex);

                Map<String,List<String>> map = new HashMap<>();
                map.put("device_id",devices);
                List<SearchHit> searchHits = multiSearch(indexes, map, Constant.I.group_i_single);
                searchHits.forEach( hit ->{
                    Map<String, Object> sourceMap = hit.getSourceAsMap();
                    ElectricMeter electricMeter = JSON.parseObject(JSON.toJSONString(sourceMap), ElectricMeter.class);
                    result.put(electricMeter.getDevice_id(),electricMeter);
                } );

        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }
    /**
     * 单设备查询
     * 查询deviceId同时具有groups中各个group exist的数据成一条记录
     * @param indexName 表名
     * @param deviceId  设备id
     * @param groups    同时存在哪些字段group集合
     * @return
     */
    public ElectricMeter getLastTimeValByDeviceId(String indexName,String deviceId,List<String[]> groups){
        Map<String,Object> result= new HashMap<>();
        String yesterIndex = indexName.substring(0,indexName.lastIndexOf("-")+1) + DateUtil.dateDaySub1(indexName.substring(indexName.lastIndexOf("-")+1));
        List<String> indexes= new ArrayList<>();
        indexes.add(indexName);
        if(existIndex(yesterIndex)){
            indexes.add(yesterIndex);
        }
        MultiSearchRequest request = new MultiSearchRequest();

        groups.forEach( group ->{
            SearchRequest searchRequest = new SearchRequest(indexes.toArray(new String[indexes.size()]));
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

            //必须同时存在值
            Arrays.stream(group).forEach(type->{
                boolQueryBuilder.must(QueryBuilders.existsQuery(type));
            });

            boolQueryBuilder.must(QueryBuilders.termQuery("device_id", deviceId));
            searchSourceBuilder.query(boolQueryBuilder);

            searchSourceBuilder.size(1);
            searchSourceBuilder.sort("gather_time",SortOrder.DESC);
            searchRequest.source(searchSourceBuilder);
            request.add(searchRequest);
        });
        try {
            MultiSearchResponse response = restHighLevelClient.msearch(request, RequestOptions.DEFAULT);
            int i = 0;
            for (MultiSearchResponse.Item item : response) {
                SearchResponse resp = item.getResponse();
                if(resp == null) continue;
                SearchHit[] hits = resp.getHits().getHits();
                if(hits.length > 0){
                    Arrays.stream(groups.get(i)).forEach(type->{
                        result.put(type,hits[0].getSourceAsMap().get(type));
                    });
                }
                i++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }


        result.put("device_id",deviceId);
        return JSON.parseObject(JSON.toJSONString(result), ElectricMeter.class);
    }
    /**
     * 多设备查询汇总成一条记录
     * @param indexName 表名
     * @param ids  设备ids
     * @return
     */
    public ElectricMeter getLastestJoinMoreIds(String indexName,List<String> ids){
        Map<String, Object> result = new HashMap<>();


        String yesterIndex = indexName.substring(0,indexName.lastIndexOf("-")+1) + DateUtil.dateDaySub1(indexName.substring(indexName.lastIndexOf("-")+1));
        List<String> indexes= new ArrayList<>();
        indexes.add(indexName);
        if(existIndex(yesterIndex)){
            indexes.add(yesterIndex);
        }
        Map<String,List<String>> map=new HashMap<>();
        map.put("device_id",ids);
        List<SearchHit> searchHits = multiSearch(indexes, map, null);

        searchHits.forEach( hit ->{
            Map<String, Object> sourceMap = hit.getSourceAsMap();
            result.putAll(sourceMap);
        } );



        return JSON.parseObject(JSON.toJSONString(result), ElectricMeter.class);
    }

	public static List<String> getAllIndex(String content){
		List<String> result=new ArrayList<>();

		if(content.contains("\n")){
			Arrays.stream(content.split("\n")).forEach(t->{
				result.add(t.split(" ")[2]);
			});
		}
		return  result;
	}
}

public static void main(String[] args) {
        Map<String,ElectricMeter> allDevice=new HashMap<>();

        String[] group={"ua","ub","uc"};

        String indexName="index-data-20210324";

        SearchRequest request=new SearchRequest(indexName);
        SearchSourceBuilder sourceBuilder=new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        
        //记录必须同时存在值
        Arrays.stream(group).forEach(type->{
            boolQueryBuilder.must(QueryBuilders.existsQuery(type));
        });
        //值不能同时为0
        BoolQueryBuilder boolQueryBuilderZero = QueryBuilders.boolQuery();
        Arrays.stream(group).forEach(type->{
            boolQueryBuilderZero.must(QueryBuilders.termQuery(type,"0"));
        });
        boolQueryBuilder.mustNot(boolQueryBuilderZero);

        //deviceId分组 取最新时间的size 1 时间倒序
        TermsAggregationBuilder aggregation = AggregationBuilders.terms("devices")
                .field("device_id");
        aggregation.subAggregation(AggregationBuilders.topHits("one").size(1).sort("gather_time", SortOrder.DESC));

        sourceBuilder.query(boolQueryBuilder);
        sourceBuilder.aggregation(aggregation);
        request.source(sourceBuilder);
        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);

        Aggregations aggregations = response.getAggregations();
        Terms byCompanyAggregation = aggregations.get("devices");
        for(Terms.Bucket bucket:byCompanyAggregation.getBuckets()){
            // 获取name为one的top_hits结果集
            TopHits topHits = bucket.getAggregations().get("one");
            SearchHits hits = topHits.getHits();
            SearchHit[] hitArray = hits.getHits();
            // 因为top_hits的siez=1所以不进行遍历直接取第一条数据
            SearchHit hit = hitArray[0];
            Map<String, Object> sourceMap = hit.getSourceAsMap();
            //转对象
            ElectricMeter electricMeter = JSON.parseObject(JSON.toJSONString(sourceMap), ElectricMeter.class);
            allDevice.put(electricMeter.getDevice_id(),electricMeter);
        }
    }

滚动查询

List<ProductCodeIdDTO> productCodeIdDTOS = new ArrayList<>();

        if (org.apache.commons.collections4.CollectionUtils.isEmpty(descTexts)){
            return productCodeIdDTOS;
        }

        BoolQueryBuilder builder = QueryBuilders.boolQuery();
        for (String descText : descTexts) {
            builder.should(QueryBuilders.wildcardQuery("descText.keyword", "*" + descText + "*"));
        }

        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withPageable(PageRequest.of(0,queryMax))
                .withSourceFilter(new FetchSourceFilter(new String[]{"id","productCode"},new String[0]))
                .withQuery(builder)

                .build();
        searchQuery.setTrackTotalHits(true);
        searchQuery.setMaxResults(5000);

        long scrollTimeOut = 60 * 1000;
        SearchHits<ProductCodeIdDTO> result = elasticsearchRestTemplate.searchScrollStart(scrollTimeOut, searchQuery, ProductCodeIdDTO.class, IndexCoordinates.of(esIndexConfig.getBaseSpuIndexName()));

        int total = 0;
        while (result.hasSearchHits()) {
            long l = System.currentTimeMillis();
            System.out.println(total += result.getSearchHits().size());

            for (SearchHit<ProductCodeIdDTO> searchHit : result.getSearchHits()) {
                ProductCodeIdDTO book = searchHit.getContent();
            }

//            // 再次查询
            result = elasticsearchRestTemplate
                    .searchScrollContinue(((SearchHitsImpl) result).getScrollId(), scrollTimeOut,
                            ProductCodeIdDTO.class, IndexCoordinates.of(esIndexConfig.getBaseSpuIndexName()));
            log.info("use time :{}",System.currentTimeMillis() - l);

        }

        List<ProductCodeIdDTO> searchHitList = result.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用 Elasticsearch Java API 中的 Aggregation API 来实现聚合查询某一字段分组的数量。具体步骤如下: 1. 创建一个 SearchRequest 对象,并设置索引及查询条件: ``` SearchRequest searchRequest = new SearchRequest("index_name"); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.matchAllQuery()); ``` 2. 创建一个 TermsAggregationBuilder 对象,并设置聚合字段: ``` TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("group_by_field") .field("field_name") .size(10); // 设置返回结果的数量 ``` 3. 将聚合对象添加到 SearchSourceBuilder 中: ``` searchSourceBuilder.aggregation(aggregationBuilder); ``` 4. 执行查询,并处理返回结果: ``` searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT); Terms termsAggregation = response.getAggregations().get("group_by_field"); for (Terms.Bucket bucket : termsAggregation.getBuckets()) { String key = bucket.getKeyAsString(); long count = bucket.getDocCount(); System.out.println("Key: " + key + ", Count: " + count); } ``` 以上代码中,`client` 是一个 Elasticsearch 客户端对象,通过 `response.getAggregations().get("group_by_field")` 获取到聚合结果对象,然后遍历 Buckets 获取每个分组的 key 和 count。 需要注意的是,这里使用的是 TermsAggregationBuilder 对象来实现分组聚合查询,如果需要根据其他条件进行聚合查询,则需要使用其他类型的 AggregationBuilder 对象。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值