当前位置: 首页 > 工具软件 > namesearch > 使用案例 >

Java操作Elasticsearch6实现count统计、distinct去重

濮阳振海
2023-12-01

引言

很久没有更新Elasticsearch系列文章,一方面是之前学会的条件查询足以满足项目需求,另一方面是前段时间一直很忙,几个项目的需求交叉进行,没什么时间学习新的东西。
本篇博客将更新count、distinct、count(distinct)这几个新学到的Elasticsearch关于查询的方法。

1. Count计算

在项目中,count也算是一个比较常用的方法。之前项目中有需要用到,都是基于查询所有的方法,直接取total的值返回。最近发现,其实Elasticsearch单独封装了一个CountRequest类来获取数量。代码如下:
/**
 * 查询指定索引文档总数(可增加查询条件,如果为空,则查询所有)
 */
@Test
public void testCount() {
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    CountRequest countRequest = new CountRequest();
    //构造查询条件
//        searchSourceBuilder.query(QueryBuilders.termQuery("fieldName", 1));
    countRequest.indices("indexName").source(searchSourceBuilder);
    CountResponse countResponse = null;
    try {
        countResponse = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT);
        return countResponse.getCount();
    } catch (IOException e) {
        log.error("[EsClientConfig.countDocumentSize][error][fail to count document size,param is {}]", countRequest);
    }
    return 0;
    log.info("[document size is {}, indexName is {}]", size, indexName);
}
相关类:CountRequest、CountResponse

2. distinct查询

distinct同样属于项目中使用较广泛的查询方法,对应mysql中的sql语句如下:
select distinct(field_name) from table_name;
下面就来看下Elasticsearch6中,我们该如何实现,代码如下:
/**
 * 查询指定索引下,按某个字段distinct的结果
 * 需要注意的:
 * 1. 如果字段是keyword类型,需要在字段后加上keyword,形如:subject.keyword
 * 2. 不指定size的情况下,默认只返回10条
 */
@Test
public void testDistinct() {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("indexName").types("indexType");
    BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
    //构造条件
//        boolQueryBuilder
//                .filter(QueryBuilders.termQuery("fieldName", "fieldValue"));
	//指定distinct字段
    CollapseBuilder collapseBuilder = new CollapseBuilder("fieldName.keyword");
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    searchSourceBuilder.query(boolQueryBuilder).collapse(collapseBuilder);
    //执行查询
    searchRequest.source(searchSourceBuilder);
    String key = "fieldName.keyword";
    List<Object> resultList = new ArrayList<>();
    SearchResponse response;
    try {
        response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        if (hits.getTotalHits() > 0) {
            SearchHit[] searchHitsArr = hits.getHits();
            for (int i = 0; i < searchHitsArr.length; i++) {
            //在Fields属性中可以获取对应字段的值,这里我增加了一个参数key对应distinct的字段名
            	resultList.add(searchHitsArr[i].getFields().get(key).getValue());
            }
        }
    } catch (IOException e) {
        log.error("[EsClientConfig.searchDocumentDistinct] [error] [fail to query, param is {},key is {}]", JSON.toJSON(searchRequest), key, e);
        return resultList;
    }
    return resultList;
}
相关类:CollapseBuilder、SearchResponse

3. Count(distinct)查询

先拿项目中的场景举个例子,学生可以报名参加多门学科的多场公开课,现在想要知道某个学生参加了几门学科的公开课,对应mysql中的sql语句如下:
select count(distinct(field_name)) from table_name where student_id = '**';
对应Elasticsearch中的查询,代码如下:

/**
 * 计算指定索引,按某个字段去重后的count结果
 */
@Test
public void testCountDistinct() {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("indexName").types("indexType");
    String key = "subjectId";
    BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
    //查询条件,查询指定学员
    boolQueryBuilder
            .filter(QueryBuilders.termQuery("uuid", "**"));
    //指定count(distinct)字段名,cardinality为指定字段的别名,field为指定字段
    CardinalityAggregationBuilder aggregationBuilder = AggregationBuilders.cardinality(key).field("subjectId.keyword");
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    searchSourceBuilder.query(boolQueryBuilder).aggregation(aggregationBuilder);
    //执行查询
    searchRequest.source(searchSourceBuilder);
    int count = 0;
    SearchResponse response;
    try {
        response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        ParsedCardinality result = response.getAggregations().get(key);
        log.info("result is {}", result.getValue());
    } catch (IOException e) {
        log.error("[EsClientConfig.countDocumentDistinct] [error] [fail to query, param is {}]", JSON.toJSON(searchRequest), e);
        return count;
    }
    return count;
}
相关类:CardinalityAggregationBuilder、ParsedCardinality

总结

以上方法是基于已经做好SpringBoot与Elasticsearch整合的基础上,如果需要,可以查看Elasticsearch系列文章
另外,以上代码是基于Elasticsearch6.8版本,其他版本在使用的时候可能会有所差别,如果在使用中有遇到其他问题,可以私信交流。
 类似资料: