整合Spring Data ElasticSearch

1、概述

  • Spring Data ElasticSearch 对原生的 ElasticSearch 简化
  • 特点:
      1. 基于 @Configuration 配置,只要在 yml 文件中配置,项目中就可以使用。
      1. 工具类 ElasticsearchTemplate ES 模板,类似通用 mapper,通过对象操作 ES
      1. 提供持久层接口 Repository,相当于通过 mapper

Elasticsearch 和 传统数据库对比

关系型数据库(如 MySQL)非关系型数据库(Es)
数据库 Database索引 Index
表 Table类型 Type
数据行 Row文档 Document
数据列 Column字段 field

基本概念

专业术语概念
Node(节点)单个的装有Elasticsearch服务并且提供故障转移和扩展的服务器。
Cluster(集群)一个集群就是由一个或多个node组织在一起,共同工作,共同分享整个数据具有负载均衡功能的集群。
Document(文档)一个文档是一个可被索引的基础信息单元。
Index(索引)索引就是一个拥有几分相似特征的文档的集合。
Type(类型)一个索引中,你可以定义一种或多种类型。
Field(列)Field是Elasticsearch的最小单位,相当于数据的某一列。
Shards(分片)Elasticsearch将索引分成若干份,每个部分就是一个shard。
Replicas(复制)Replicas是索引一份或多份拷贝。

2、搭建环境

  • 随便创建一个子模块,学习Elasticsearch

  • 步骤一:修改 pom.xml 文件,添加对应坐标。添加ES的依赖

    <dependencies>
            <!--redis-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
            <dependency>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
            </dependency>
            <!--测试-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
            </dependency>
            <!--自定义common-->
            <dependency>
                <groupId>com.czxy</groupId>
                <artifactId>changgou3_common</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
            <!--es-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
            </dependency>
    
        </dependencies>
    
  • 步骤二:修改 yml 文件,添加 elasticsearch 相关配置

     spring:
      redis:
        database:   1     #确定使用库
        host: 127.0.0.1   #redis服务地址
        port: 6379      #redis 端口号
      data:
        elasticsearch:
          cluster-name: elasticsearch
          cluster-nodes: 127.0.0.1:9300
    
  • 步骤三:添加配置类

package com.czxy.config;

import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

/**
 * @author 庭前云落
 * @Date 2020/4/13 20:38
 * @description
 */
@Configuration
public class ESConfig {
    @PostConstruct
    public void init(){
        System.setProperty("es.set.netty.runtime.available.processors","false");
    }
}

3、索引操作

3.1、映射类

  • 映射类:用于表示 java 的数据和 elasticsearch 的数据对应关系。在spring data elasticsearch 中使用注解完成。

    注解名称描述
    @Document用于配置Java类与索引/类型对应关系<br/> - indexName:对应索引库名称<br/> - type:对应在索引库中的类型<br/> - shards:分片数量,默认5<br/> - replicas:副本数量,默认1
    @Id唯一标识
    @Field用于配置Java属性和es的字段对应关系<br>– type:字段类型,枚举:FieldType<br>– analyzer:分词器名称<br>– index:是否索引,布尔类型,默认是true<br>– store:是否存储,布尔类型,默认是false
  • 实现

package com.czxy.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

/**
 * @author 庭前云落
 * @Date 2020/4/13 20:40
 * @description
 */
@Document(indexName = "czxy56",type = "book",shards = 4,replicas = 2)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ESBook {
    @Id
    private Long id;

    @Field(type= FieldType.Text, analyzer = "ik_max_word")
    private String title;//标题

    @Field(type=FieldType.Keyword , index = true)
    private String images;//图片

    @Field(type=FieldType.Float)
    private Float price;//价格
}

3.2、创建索引、添加映射、删除索引

  • ElasticsearchTemplate 工具类提供对应方法完成以下功能:

    • 创建索引:createIndex(映射类.class)
    • 添加映射:putMapping(映射类.class)
    • 删除索引:deleteIndex(映射类.class)
  • 一、测试类中,注入 ElasticsearchTemplate

  • 二、调用对应的 API 进行操作

    package com.czxy.elasticsearch;
    
    import com.czxy.TestApplication;
    import com.czxy.vo.ESBook;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import javax.annotation.Resource;
    
    /**
     * @author 庭前云落
     * @Date 2020/4/13 20:33
     * @description
     */
    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = TestApplication.class)
    public class TestES {
    
        @Resource
        private ElasticsearchTemplate elasticsearchTemplate;
    
    
        @Test
        public void demo01() {
            //创建索引,会根据czxy56类的@Document注解信息来创建
            elasticsearchTemplate.createIndex(ESBook.class);
        }
    
        @Test
        public void demo02() {
            //配置映射,会根据czxy56类中的id、Field等字段来自动完成映射
            elasticsearchTemplate.putMapping(ESBook.class);
        }
    
        @Test
        public void demo03() {
            //删除映射,可以根据类名或索引名删除
            elasticsearchTemplate.deleteIndex(ESBook.class);
        }
    }
    
    

4、文档操作(增删改)

4.1、顶级接口:Repository

  • Spring Data Elasticsearch 提供了一个顶级接口 Repository,你不用写任何DAO处理,自动根据方法名或类的信息进行CRUD操作。只要你定义一个接口,然后继承Repository提供的一些子接口,就能具备各种基本的CRUD功能。

    • PagingAndSortingRepository:(第二代) 完成分页和排序功能
    • ElasticsearchCrudRepository:(第三代) 增删改查功能
    • ElasticsearchRepository:(第四代) 完成所有功能
  • 编写:只需要编写子接口,继承 ElasticsearchRepository 即可,且Spring Data 自动加载该类。

  • 注意:接口在使用时,需要确定 2 个泛型信息
    • 第一个泛型:映射类,这里是ESBook
    • 第二个泛型:映射类唯一标识的类型,ID的类型 Long
package com.czxy.Repository;

import com.czxy.vo.ESBook;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

import java.util.List;

/**
 * @author 庭前云落
 * @Date 2020/4/13 20:49
 * @description
 */
public interface ESBookRepository extends ElasticsearchRepository<ESBook, Long> {

}

4.2、添加数据

方法名描述
save(T t)保存一个数据
saveAll( Iterable )保存一组数据
package com.czxy.elasticsearch;

import com.czxy.Repository.ESBookRepository;
import com.czxy.TestApplication;
import com.czxy.vo.ESBook;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import java.util.ArrayList;

/**
 * @author 庭前云落
 * @Date 2020/4/13 20:51
 * @description
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class TestData {

    @Resource
    private ESBookRepository esBookRepository;

    @Test
    public void demo01() {
        ESBook esBook = new ESBook(1L, "测试一", "1.jpg", 998f);
        //添加
        esBookRepository.save(esBook);
    }

    @Test
    public void demo02() {
        ArrayList<ESBook> esBooks = new ArrayList<>();
        esBooks.add(new ESBook(2L, "测试二", "2.jpg", 456f));
        esBooks.add(new ESBook(3L, "测试三", "3.jpg", 290f));
        esBooks.add(new ESBook(4L, "测试四", "4.jpg", 100f));
        //添加一组数据  
        esBookRepository.saveAll(esBooks);
    }
}

4.3、修改数据

  • 修改和添加使用的是同一个方法

  • 区分标准:

    • 如果 id 的值有对应的数据,则进行更新操作。
    • 如果 id 的值没有对应的数据,则进行添加操作。
        @Test
        public void demo03() {
            //更新数据,es中必须有id=1的数据
            ESBook esBook = new ESBook(1L, "测试一改", "1111.jpg", 1998f);
            esBookRepository.save(esBook);
        }
    

4.3、删除数据

  @Test
    public void demo04() {
        ESBook esBook = new ESBook();
        esBook.setId(1L);
        esBookRepository.delete(esBook);
    }

4.4、查询

方法描述
findAll()查询所有
findById( Long )通过id查询详情
package com.czxy.elasticsearch;

import com.czxy.Repository.ESBookRepository;
import com.czxy.TestApplication;
import com.czxy.vo.ESBook;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;

/**
 * @author 庭前云落
 * @Date 2020/4/13 21:01
 * @description
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class TestESFind {
    @Resource
    private ESBookRepository esBookRepository;

    @Test
    public void demo01() {
        //查询所有
        Iterable<ESBook> iterable = esBookRepository.findAll();
        Iterator<ESBook> iterator = iterable.iterator();
        while (iterator.hasNext()) {
            ESBook esBook = iterator.next();
            System.out.println(esBook);
        }
    }

    @Test
    public void demo02() {
        //通过id查询详情
        Optional<ESBook> optional = esBookRepository.findById(2L);
        ESBook esBook = optional.get();
        System.out.println(esBook);
    }
}

4.5、自定义方法查询

  • 自定义查询,Spring Data 根据约定的方法名进行自动查询。
    • 约定方法名要求:findBy 字段名|关键字 等
    • 例如:findByTitle(值) 根据 title 进行查询
KeywordSampleElasticsearch Query String
AndfindByNameAndPrice{"bool" : {"must" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}}
OrfindByNameOrPrice{"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}}
IsfindByName{"bool" : {"must" : {"field" : {"name" : "?"}}}}
NotfindByNameNot{"bool" : {"must_not" : {"field" : {"name" : "?"}}}}
BetweenfindByPriceBetween{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}
LessThanEqualfindByPriceLessThan{"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}
GreaterThanEqualfindByPriceGreaterThan{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}
BeforefindByPriceBefore{"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}
AfterfindByPriceAfter{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}
LikefindByNameLike{"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}
StartingWithfindByNameStartingWith{"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}
EndingWithfindByNameEndingWith{"bool" : {"must" : {"field" : {"name" : {"query" : "*?","analyze_wildcard" : true}}}}}
Contains/ContainingfindByNameContaining{"bool" : {"must" : {"field" : {"name" : {"query" : "**?**","analyze_wildcard" : true}}}}}
InfindByNameIn(Collection<String>names){"bool" : {"must" : {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}}
NotInfindByNameNotIn(Collection<String>names){"bool" : {"must_not" : {"bool" : {"should" : {"field" : {"name" : "?"}}}}}}
NearfindByStoreNearNot Supported Yet !
TruefindByAvailableTrue{"bool" : {"must" : {"field" : {"available" : true}}}}
FalsefindByAvailableFalse{"bool" : {"must" : {"field" : {"available" : false}}}}
OrderByfindByAvailableTrueOrderByNameDesc{"sort" : [{ "name" : {"order" : "desc"} }],"bool" : {"must" : {"field" : {"available" : true}}}}
  • 实例1:根据 title 进行查询

      1. 修改 response 自定义接口,添加方法声明
      package com.czxy.Repository;
      
      import com.czxy.vo.ESBook;
      import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
      
      import java.util.List;
      
      /**
       * @author 庭前云落
       * @Date 2020/4/13 20:49
       * @description
       */
      public interface ESBookRepository extends ElasticsearchRepository<ESBook, Long> {
          //实例1:根据title查询
          public List<ESBook> findByTitle(String title);
      }
      
      
      1. 调用自定义方法,完成功能
          @Test
          public void demo03() {
              List<ESBook> list = esBookRepository.findByTitle("测试二");
              System.out.println(list);
          }
      
  • 实例2:区间查询,价格 50-300

      1. 声明
           //实例2:区间查询,价格50-300
          public List<ESBook> findByPriceBetween(Float start, Float end);
      
      1. 调用
          @Test
          public void demo04() {
              List<ESBook> list = esBookRepository.findByPriceBetween(50f, 300f);
              System.out.println(list);
          }
      
  • 实例3:查询价格 >=290

      1. 声明
          //实例3:查询价格>=290
          public List<ESBook> findByPriceGreaterThanEqual(Float price);
      
      
      1. 调用
          @Test
          public void demo05(){
              List<ESBook> list = esBookRepository.findByPriceGreaterThanEqual(290f);
              System.out.println(list);
          }
      
  • 实例4:区间查询,价格 50-300,且按照 images 进行降序排序

      1. 声明
      //实例4:区间查询,价格50-300,且按照image进行降序排序 
      public List<ESBook> findByPriceBetweenOrderByImagesDesc(Float start, Float end);
      
      
      1. 调用
          @Test
          public void demo06(){
              List<ESBook> list = esBookRepository.findByPriceBetweenOrderByImagesDesc(50f,300f);
              System.out.println(list);
          }
      
      

4.6、自定义查询

4.6.1、关键字查询:match

  • 查询条件构建器:NativeSearchQueryBuilder

  • match条件:QueryBuilder.matchQuery(字段,值)

  • 查询条件:queryBuilder.withQuery(...)

  • 查询:repository.search(条件)

  • Page 返回类型,本身就是容器,可以直接遍历获得数据

    • 总条数:page.getTotalElements()

    • 总页数:page.getTotalPages()

```java
/**
 * @author 庭前云落
 * @Date 2020/4/14 20:13
 * @description
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class TestESQuery {

    @Resource
    private ESBookRepository esBookRepository;

    //查询:title为"测试"
    @Test
    public void demo01() {
        //查询条件构建器
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //关键字查询 match
        queryBuilder.withQuery(QueryBuilders.matchQuery("title", "测试"));
        //查询
        Page<ESBook> page = esBookRepository.search(queryBuilder.build());
        //处理结果
        System.out.println("总条数:" + page.getTotalElements());
        System.out.println("总页数:" + page.getTotalPages());
        for (ESBook esBook : page) {
            System.out.println(esBook);
        }
    }
}    
```

4.6.2、多条件查询:bool -- must/mustNot(交集)

  • 多条件拼凑,使用BoolQueryBuilder对象

    • QueryBuilders.boolQuery()
  • 并集操作:must()/mustNot()

//多条件查询,查询title为"测试",不含"二"
    @Test
    public void demo02() {
        //查询条件构建器
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //查询条件 -- 多条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //条件1:必须
        boolQueryBuilder.must(QueryBuilders.matchQuery("title", "测试"));
        //条件2:不需要
        boolQueryBuilder.mustNot(QueryBuilders.matchQuery("title", "三"));

        queryBuilder.withQuery(boolQueryBuilder);
        //查询
        Page<ESBook> page = esBookRepository.search(queryBuilder.build());

        System.out.println("总条数:" + page.getTotalElements());
        System.out.println("总页数:" + page.getTotalPages());
        for (ESBook esBook : page) {
            System.out.println(esBook);
        }
    }

4.6.3、多条件查询:bool -- should (并集)

  • BoolQueryBuilder提供should用于编写并集条件

   //查询 title包含"二"、"三"的相关数据
    @Test
    public void demo03() {
        //查询条件构建器
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.should(QueryBuilders.matchQuery("title", "三"));
        boolQueryBuilder.should(QueryBuilders.matchQuery("title", "二"));
        queryBuilder.withQuery(boolQueryBuilder);

        //查询
        Page<ESBook> page = esBookRepository.search(queryBuilder.build());
        for (ESBook esBook : page) {
            System.out.println(esBook);
        }
    }

4.6.3、精确查询(term)

term 查询被用于精确值 匹配,这些精确值可能是数字、时间、布尔或者那些 未分词 的字符串

    //查询价格为456
    @Test
    public void demo04() {
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        queryBuilder.withQuery(QueryBuilders.termQuery("price", 456));
        Page<ESBook> page = esBookRepository.search(queryBuilder.build());
        System.out.println("总条数:" + page.getTotalElements());
        System.out.println("总页数:" + page.getTotalPages());
        for (ESBook esBook : page) {
            System.out.println(esBook);
        }
    }

4.6.4、范围查询(range)

操作符说明
gt大于
gte大于等于
lt小于
lte小于等于
    //查询价格在 50-300之间
    @Test
    public void demo05() {
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        queryBuilder.withQuery(QueryBuilders.rangeQuery("price").gte(50).lte(300));

        Page<ESBook> page = esBookRepository.search(queryBuilder.build());

        System.out.println("总条数:" + page.getTotalElements());
        System.out.println("总页数:" + page.getTotalPages());
        for (ESBook esBook : page) {
            System.out.println(esBook);
        }
    }

4.6.5、分页查询

  • 构建器提供 withPageable() 用于设置分页数据

  • 通过工具类设置分页具体参数:PageRequest.of(pageNum,pageSize)

    Elasticsearch中的分页是从第0页开始。

 @Test
    public void demo06() {
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        int pageNum=1;
        int pageSize=2;

        queryBuilder.withPageable(PageRequest.of(pageNum,pageSize));

        Page<ESBook> page = esBookRepository.search(queryBuilder.build());

        System.out.println("总条数:" + page.getTotalElements());
        System.out.println("总页数:" + page.getTotalPages());
        for (ESBook esBook : page) {
            System.out.println(esBook);
        }
    }

4.6.6、排序查询

  • 通过 queryBuilder.withSort 设置排序条件

  • 通过 SortBuilders.fieldSort("price") 确定排序字段

  • 通过 .order(SortOrder.DESC) 确定排序方式

    @Test
    public void demo07() {
        //查询条件构建器
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //查询条件
        queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC));
        //查询
        Page<ESBook> page = esBookRepository.search(queryBuilder.build());

        System.out.println("总条数:" + page.getTotalElements());
        System.out.println("总页数:" + page.getTotalPages());

        for (ESBook esBook : page) {
            System.out.println(esBook);
        }
    }

4.7、总结

  • 查询条件构建器:NativeSearchQueryBuilder
    • 查询条件:withQuery( .... )
    • 分页条件:withPageable( ... )
    • 排序条件:withSort( .... )
    • 生成条件:build()
  • 查询条件,通过工具类 QueryBuilders 获得
    • 关键字查询:matchQuery(字段, 值)
    • 多条件查询:boolQuery()
      • 必须有:must()
      • 必须没有:mustNot()
      • 并集:should()
    • 精确查询:termQuery(字段, 值)
    • 范围查询:rangeQuery(字段)
      • 大于:gt()
      • 大于等于:gte()
      • 小于:lt()
      • 小于等于:lte()
  • 分页条件
    • 通过设置分页参数 PageRequest.of( pageNum , pageSize )
  • 排序条件,通过工具类 SortBuilders 获得
    • 排序字段:fieldSort(排序字段)
    • 排序方式:order( SortOrder.DESC | SortOrder.ASC )
  • 查询结果:Page对象
    • 总条数:page.getTotalElements()
    • 总页数:page.getTotalPages()
    • 第几页:page.getNumber()
    • 每页个数:page.getSize()
    • 获得内容:page.getContent() ,Page对象可以直接遍历

5、聚合

5.1、聚合为桶

桶就是分组,这里我们按照品牌 brand 进行分组:

@Test
public void testAgg(){
    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
    // 不查询任何结果
    queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));
    // 1、添加一个新的聚合,聚合类型为terms,聚合名称为brands,聚合字段为brand
    queryBuilder.addAggregation(
        AggregationBuilders.terms("brands").field("brand"));
    // 2、查询,需要把结果强转为AggregatedPage类型
    AggregatedPage<Item> aggPage = (AggregatedPage<Item>) this.itemRepository.search(queryBuilder.build());
    // 3、解析
    // 3.1、从结果中取出名为brands的那个聚合,
    // 因为是利用String类型字段来进行的term聚合,所以结果要强转为StringTerm类型
    StringTerms agg = (StringTerms) aggPage.getAggregation("brands");
    // 3.2、获取桶
    List<StringTerms.Bucket> buckets = agg.getBuckets();
    // 3.3、遍历
    for (StringTerms.Bucket bucket : buckets) {
        // 3.4、获取桶中的key,即品牌名称
        System.out.println(bucket.getKeyAsString());
        // 3.5、获取桶中的文档数量
        System.out.println(bucket.getDocCount());
    }

}

5.2、嵌套聚合,求平均值

@Test
public void testSubAgg(){
    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
    // 不查询任何结果
    queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));
    // 1、添加一个新的聚合,聚合类型为terms,聚合名称为brands,聚合字段为brand
    queryBuilder.addAggregation(
        AggregationBuilders.terms("brands").field("brand")
        .subAggregation(AggregationBuilders.avg("priceAvg").field("price")) // 在品牌聚合桶内进行嵌套聚合,求平均值
    );
    // 2、查询,需要把结果强转为AggregatedPage类型
    AggregatedPage<Item> aggPage = (AggregatedPage<Item>) this.itemRepository.search(queryBuilder.build());
    // 3、解析
    // 3.1、从结果中取出名为brands的那个聚合,
    // 因为是利用String类型字段来进行的term聚合,所以结果要强转为StringTerm类型
    StringTerms agg = (StringTerms) aggPage.getAggregation("brands");
    // 3.2、获取桶
    List<StringTerms.Bucket> buckets = agg.getBuckets();
    // 3.3、遍历
    for (StringTerms.Bucket bucket : buckets) {
        // 3.4、获取桶中的key,即品牌名称  3.5、获取桶中的文档数量
        System.out.println(bucket.getKeyAsString() + ",共" + bucket.getDocCount() + "台");

        // 3.6.获取子聚合结果:
        InternalAvg avg = (InternalAvg) bucket.getAggregations().asMap().get("priceAvg");
        System.out.println("平均售价:" + avg.getValue());
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值