方式一(性能更好)

注意事项:
1、折叠功能ES5.3版本之后才发布的。
2、聚合&折叠只能针对keyword类型和number类型有效

POST /qt_config_device/_search
{
  "query": {
    "term": {
      "tenantId": 554
    }
  },
  "_source": "",  // 过滤无关内容
  "collapse": {
    "field": "vendorName.keyword"
  },
  "size": 3, 
  "aggs": {
    "vendor_count": { // 查询总数
      "cardinality": {
        "field": "vendorName.keyword"
      }
    }
  }
}

对应的java实现

/**
     * 折叠的实现方式,性能更好
     * @param fuzzySearchPO
     * @return
     * @throws IOException
     */
    private List<String> searchVendorV2(FuzzySearchPO fuzzySearchPO) throws IOException {
        Long tenantId = Long.valueOf(UserContext.currentUser().getTenantId());

        SearchRequest request = new SearchRequest(EsDb.qt_device.getValue());
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.fetchSource(false);
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.must(QueryBuilders.termQuery("tenantId", tenantId));
        if (StringUtils.isNotBlank(fuzzySearchPO.getKey())) {
            boolQueryBuilder.must(QueryBuilders.wildcardQuery("vendorName.keyword", "*" + fuzzySearchPO.getKey() + "*"));
        }
        sourceBuilder.query(boolQueryBuilder);

        //指定去重字段
        CollapseBuilder collapseBuilder = new CollapseBuilder("vendorName.keyword");
        sourceBuilder.collapse(collapseBuilder);
        sourceBuilder.size(Optional.ofNullable(fuzzySearchPO.getSize()).orElse(10));
        log.info("es查询语句:{}", sourceBuilder.toString());
        request.source(sourceBuilder);
        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);

        SearchHit[] hits = response.getHits().getHits();
        List<String> vendorNames = Arrays.stream(hits).map(h -> h.getFields().get("vendorName.keyword").getValues().get(0).toString()).collect(Collectors.toList());

        return vendorNames;
    }

方式二

POST /qt_config_device/_search
{
  "query": {
    "term": {
      "tenantId": 554
    }
  },
  "size": 0,  // 过滤无关内容
  "timeout": "60s",
  "aggs": {
    "vendor_terms": {
      "terms": {
        "field": "vendorName.keyword",
        "size": 3
      }
      
    }
  }
}

对应的java实现

/**
     * 存储桶的实现方式
     * @param fuzzySearchPO
     * @return
     * @throws IOException
     */
    private List<String> searchVendorV1(FuzzySearchPO fuzzySearchPO) throws IOException {
        Long tenantId = Long.valueOf(UserContext.currentUser().getTenantId());

        SearchRequest request = new SearchRequest(EsDb.qt_device.getValue());
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.must(QueryBuilders.termQuery("tenantId", tenantId));
        if (StringUtils.isNotBlank(fuzzySearchPO.getKey())) {
            boolQueryBuilder.must(QueryBuilders.wildcardQuery("vendorName.keyword", "*" + fuzzySearchPO.getKey() + "*"));
        }
        sourceBuilder.query(boolQueryBuilder);

        TermsAggregationBuilder terms = AggregationBuilders.terms("vendor_terms").field("vendorName.keyword").size(Optional.ofNullable(fuzzySearchPO.getSize()).orElse(10));
        sourceBuilder.aggregation(terms);
        sourceBuilder.size(0);
        log.info("es查询语句:{}", sourceBuilder.toString());
        request.source(sourceBuilder);
        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);

        ParsedTerms terms1 = (ParsedTerms) response.getAggregations().getAsMap().get("vendor_terms");
        List<ParsedTerms.ParsedBucket> buckets = (List<ParsedTerms.ParsedBucket>) terms1.getBuckets();
        List<String> vendorNames = buckets.stream().map(ParsedMultiBucketAggregation.ParsedBucket::getKeyAsString).collect(Collectors.toList());

        return vendorNames;
    }