ElasticsearchRestTemplate 查询 API 示例

ElasticsearchRestTemplate

ElasticsearchRestTemplate 是 spring-data-elasticsearch 项目中的一个类,和其他 spring 项目中的 template 类似。

引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

分页搜索

image-20220419154906545

@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;

@Test
/** 搜索全部数据 , 分页显示 , 按 balance字段降序 排序 */
public void test1() {
    // 构建查询条件(搜索全部)
    MatchAllQueryBuilder queryBuilder1 = QueryBuilders.matchAllQuery();
    // 分页
    Pageable pageable = PageRequest.of(0, 5);
    // 排序
    FieldSortBuilder balance = new FieldSortBuilder("balance").order(SortOrder.DESC);
    // 执行查询
    NativeSearchQuery query = new NativeSearchQueryBuilder()
            .withQuery(queryBuilder1)
            .withPageable(pageable)
            .withSort(balance)
            .build();
    SearchHits<EsAccount> searchHits = elasticsearchRestTemplate.search(query, EsAccount.class);

    //封装page对象
    List<EsAccount> accounts = new ArrayList<>();
    for (SearchHit<EsAccount> hit : searchHits) {
        accounts.add(hit.getContent());
    }
    Page<EsAccount> page = new PageImpl<>(accounts,pageable,searchHits.getTotalHits());

    //输出分页对象
    System.out.println(page.getTotalPages());
    System.out.println(page.getTotalElements());
}

条件搜索

image-20220419155018041

@Test
/** 条件搜索 */
public void test2() {
    // 搜索出 account_number 为 20 的文档
    TermQueryBuilder builder = QueryBuilders.termQuery("account_number", 20);

    // 对于数值类型是精准匹配,对于文本类型是 模糊匹配,_score越高在前
    TermQueryBuilder builder1 = QueryBuilders.termQuery("address", "mill");

    // 搜索add字段同时包含 mill lane 的文档
    TermQueryBuilder builder2 = QueryBuilders.termQuery("address", "mill lane");

    NativeSearchQuery query = new NativeSearchQueryBuilder()
            .withQuery(builder1)
            .build();

    SearchHits<EsAccount> searchHits = elasticsearchRestTemplate.search(query, EsAccount.class);

    for (SearchHit<EsAccount> hit : searchHits) {
        System.out.println(hit.getContent());
    }
}

组合搜索

image-20220419155120015

@Test
/** 组合搜索 bool*/
public void test3() {
    BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
    // must表示同时满足,should满足其中一个,must_not表示同时不满足
    boolQueryBuilder.must(QueryBuilders.matchQuery("address", "mill"));
    boolQueryBuilder.must(QueryBuilders.matchQuery("address", "lane"));

    NativeSearchQuery query = new NativeSearchQueryBuilder()
        .withQuery(boolQueryBuilder)
        .build();

    SearchHits<EsAccount> searchHits = elasticsearchRestTemplate.search(query, EsAccount.class);
    for (SearchHit<EsAccount> hit : searchHits) {
        System.out.println(hit.getContent());
    }
}

过滤搜索

filter,过滤出 balance 字段在 2w~3w 的文档

image-20220419155209356

@Test
/** 过滤搜索 */
public void test4() {
    // 构建条件
    BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
    RangeQueryBuilder balance = QueryBuilders.rangeQuery("balance").gte(20000).lte(30000);
    boolQueryBuilder.filter(balance);

    NativeSearchQuery query = new NativeSearchQueryBuilder()
        .withQuery(boolQueryBuilder)
        .build();

    SearchHits<EsAccount> searchHits = elasticsearchRestTemplate.search(query, EsAccount.class);

    for (SearchHit<EsAccount> hit : searchHits) {
        System.out.println(hit.getContent());
    }
}

聚合搜索

聚合搜索,aggs,类似于 group by,对 state 字段进行聚合,

image-20220419155256939

@Test
/** 聚合搜索 ,对state字段进行聚合*/
public void test5() {

    NativeSearchQuery query = new NativeSearchQueryBuilder()
        .addAggregation(AggregationBuilders.terms("count").field("state.keyword"))
        .build();

    SearchHits<EsAccount> searchHits = elasticsearchRestTemplate.search(query, EsAccount.class);

    //取出聚合结果
    Aggregations aggregations = searchHits.getAggregations();
    Terms terms = (Terms) aggregations.asMap().get("count");

    for (Terms.Bucket bucket : terms.getBuckets()) {
        String keyAsString = bucket.getKeyAsString();   // 聚合字段列的值
        long docCount = bucket.getDocCount();           // 聚合字段对应的数量
        System.out.println(keyAsString + " " + docCount);
    }
}

嵌套聚合

统计出相同 state 的文档数量,再统计出 balance 的平均值,降序排序

image-20220419155341963

@Test
/** 嵌套聚合,统计出相同state的文档数量,再统计出balance的平均值,降序排序 */
public void test6() {
    // 创建聚合查询条件
    TermsAggregationBuilder stateAgg = AggregationBuilders.terms("count").field("state.keyword");
    AvgAggregationBuilder balanceAgg = AggregationBuilders.avg("avg_balance").field("balance");
    // 嵌套
    stateAgg.subAggregation(balanceAgg);
    // 按balance的平均值降序排序
    stateAgg.order(BucketOrder.aggregation("avg_balance", false));

    NativeSearchQuery build = new NativeSearchQueryBuilder()
            .addAggregation(stateAgg)
            .build();
    //执行查询
    SearchHits<EsAccount> searchHits = elasticsearchRestTemplate.search(build, EsAccount.class);
    // 取出聚合结果
    Aggregations aggregations = searchHits.getAggregations();
    Terms terms = (Terms) aggregations.asMap().get("count");

    for (Terms.Bucket bucket : terms.getBuckets()) {
        // state : count : avg
        ParsedAvg avg = bucket.getAggregations().get("avg_balance");
        System.out.println(bucket.getKeyAsString() + " " + bucket.getDocCount() + " " + avg.getValueAsString());
    }
}

范围聚合

按字段的范围进行分段聚合,按 age 字段 [20,30],[30,40],[40,50], 之后按 gender 统计文档个数和 balance 的平均值

image-20220419155400590

@Test
/** 按字段的范围进行分段聚合,按age字段[20,30],[30,40],[40,50],之后按gender统计文档个数和balance的平均值 */
public void test7(){
    // 创建聚合查询条件
    RangeAggregationBuilder group_by_age =
            AggregationBuilders.range("group_by_age").field("age")
                    .addRange(20, 30).addRange(30, 40).addRange(40, 50);
    TermsAggregationBuilder count = AggregationBuilders.terms("count").field("gender.keyword");
    AvgAggregationBuilder balanceAgg = AggregationBuilders.avg("avg_balance").field("balance");

    //嵌套
    group_by_age.subAggregation(count);
    count.subAggregation(balanceAgg);

    NativeSearchQuery query = new NativeSearchQueryBuilder()
            .addAggregation(group_by_age)
            .build();

    SearchHits<EsAccount> searchHits = elasticsearchRestTemplate.search(query, EsAccount.class);

    ParsedRange parsedRange = searchHits.getAggregations().get("group_by_age");

    for (Range.Bucket bucket : parsedRange.getBuckets()) {
        // "key" : "20.0-30.0",  "doc_count" : 451,
        System.out.println(bucket.getKeyAsString()+" : "+bucket.getDocCount());

        Terms group_by_gender = bucket.getAggregations().get("count");
        for (Terms.Bucket genderBucket : group_by_gender.getBuckets()) {
            //  "key" : "M", "doc_count" : 232, "key" : "F", "doc_count" : 219,
            System.out.println(genderBucket.getKeyAsString() +" : "+ genderBucket.getDocCount());
            ParsedAvg balanceAvg = genderBucket.getAggregations().get("avg_balance");
            System.out.println(balanceAvg.getValueAsString());
        }
        System.out.println("-----------\n");
    }
}