Elasticsearch 三、 springboot 整合 Elasticsearch6.4.3 及使用repository实现各种查询

本为讲解:
1、Elasticsearch 简单描叙
2、springboot 整合Elasticsearch6.4.3
3 、None of the configured nodes are available 错误处理
4、 springboot 使用 Elasticsearch 的各种复杂查询操作及添加删除示例

一、Elasticsearch 简单描叙

ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。
我们建立一个网站或应用程序,并要添加搜索功能,但是想要完成搜索工作的创建是非常困难的。我们希望搜索解决方案要运行速度快,我们希望能有一个零配置和一个完全免费的搜索模式,我们希望能够简单地使用JSON通过HTTP来索引数据,我们希望我们的搜索服务器始终可用,我们希望能够从一台开始并扩展到数百台,我们要实时搜索,我们要简单的多租户,我们希望建立一个云的解决方案。因此我们利用Elasticsearch来解决所有这些问题及可能出现的更多其它问题。

操作Elasticsearch6.4.3 类似于jpa 操作数据库一样,使用Crud 方式
Elasticsearch6.4.3 是基于文档保存数据,mysql是基于行列保存数据

关系数据库       ⇒ 数据库         ⇒ 表         ⇒ 行              ⇒ 列(Columns)
Elasticsearch   ⇒ 索引(Index)   ⇒ 类型(type)  ⇒ 文档(Docments)  ⇒ 字段(Fields) 
  
具体的对应规则如下:
Relational DB -> Database-> Table -> Row -> Column
Elasticsearch -> Index -> Type -> Document-> Field

Elasticsearch是文件存储,Elasticsearch是面向文档型数据库,一条数据在这里就是一个文档,用JSON作为文档序列化的格式,比如下面这条用户数据:

{
    "name" :     "wangsong",
    "sex" :      0,
    "age" :      25
}

注:

关于type
6.*版本中type已过时, 并且当前版本只能建一个type
7.*版本将删除type, 所以在开发过程中弱化type的概念

二、环境搭建

1、创建springboot 项目,结构如下

springboot2.0.0 到 2.2.2 配置都相同
搭建Elasticsearch 就想搭建web 环境一样,非常简单,也是dao,entity,controller层
在这里插入图片描述

2、maven 依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>springboot-elasticsearch</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-elasticsearch</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
</project>

3、yml 配置

cluster-name 默认为 elasticsearch,等同与配置数据库地址

spring:
  data:
    elasticsearch:
      ####集群名称
      cluster-name: elasticsearch
      #### elasticsearch服务地址
      cluster-nodes: 192.168.177.128:9300

4、添加userEntuity

等同于配置实体类

package com.example.springbootelasticsearch.entity;

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;

/**
 * TODO    添加文档 /索引名称/类型/id =》 indexName 索引名称(必须小写), type = 类型,@Id =id   
 */
@Document(indexName = "estest", type = "user")
@Data
public class UserEntity {
    @Id
    private String id;
    private String name;
    private int sex;
    private int age;
}

5、添加UserReposiory(类似于jpa)

等同于配置数据库的数据层,可以使用CrudRepository的子类 ElasticsearchCrudRepository实现更多复杂查询

package com.example.springbootelasticsearch.dao;

import com.example.springbootelasticsearch.entity.UserEntity;
import org.springframework.data.repository.CrudRepository;

public interface UserReposiory extends CrudRepository<UserEntity, String> {

}

6、添加控制层EsController

mvc 的控制层

package com.example.springbootelasticsearch.controller;

import com.example.springbootelasticsearch.dao.UserReposiory;
import com.example.springbootelasticsearch.entity.UserEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Optional;

@RestController
public class EsController {

    @Autowired
    private UserReposiory userReposiory;

    /**
     * TODO    添加
     */
    @RequestMapping("/addUser")
    public UserEntity addUser() {
        UserEntity user = new UserEntity();
        user.setId("1");
        user.setName("wangsong");
        user.setSex(1);
        user.setAge(22);
        return userReposiory.save(user);
    }

    /**
     * TODO    查询
     */
    @RequestMapping("/findUser")
    public Optional<UserEntity> findUser(String id) {
        return userReposiory.findById(id);
    }
}

7、启动类

添加@EnableElasticsearchRepositories 注解,并添加数据层dao 扫包地址(数据层)

package com.example.springbootelasticsearch;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;

@EnableElasticsearchRepositories(basePackages = "com.example.springbootelasticsearch.dao")
@SpringBootApplication
public class SpringbootElasticsearchApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootElasticsearchApplication.class, args);
    }
}

8 、启动项目

添加:http://localhost:8080/addUser ,报错看步骤十处理

在这里插入图片描述
查询:http://localhost:8080/findUser?id=1
在这里插入图片描述

三、None of the configured nodes are available 错误处理

cluster_name 必须一致,不然会抛出 None of the configured nodes are available 错误,如图
在这里插入图片描述
使用默认cluster_name 参数无视下方配置,默认elasticsearch

1、修改服务端cluster_name

Vi /usr/local/elasticsearch-6.4.3/config/elasticsearch.yml

cluster.name: my-application  # 服务端与客户端相同即可

在这里插入图片描述

2、修改后需重启服务(关闭重启)

ps -ef | grep lasticsearch  # 查看进程
kill -9 2382(进程号)        # 杀死进程
./elasticsearch -d          # 后台启动

访问 http://192.168.177.128:9200/ 查看cluster_name 参数是否修改成功

3、修改yml 配置cluster_name

在这里插入图片描述
重启Elasticsearch服务和项目即可

四 、 springboot 使用Elasticsearch6.4.3

1、entity文件配置说明

entity中注解说明

Spring Data 通过注解来声明字段的映射属性,有下面的三个注解:
    @Document 作用在类,标记实体类为文档对象,一般有两个属性
        indexName:对应索引库名称
		type:对应在索引库中的类型
		shards:分片数量,默认5
		replicas:副本数量,默认1
	@Id 作用在成员变量,标记一个字段作为id主键
	@Field 作用在成员变量,标记为文档的字段,并指定字段映射属性:
		type:字段类型,是枚举:FieldType,可以是text、longshort、date、integer、object等
			text:存储数据时候,会自动分词,并生成索引
			keyword:存储数据时候,不会分词建立索引
			Numerical:数值类型,分两类
				基本数据类型:long、interger、short、byte、doublefloat、half_float
				浮点数的高精度类型:scaled_float
					需要指定一个精度因子,比如10100。
                                        elasticsearch会把真实值乘以这个因子后存储,取出时再还原。
			Date:日期类型
				elasticsearch可以对日期格式化为字符串存储,
                                但是建议我们存储为毫秒值,存储为long,节省空间。
		index:是否索引,布尔类型,默认是true
		store:是否存储,布尔类型,默认是false
		analyzer:分词器名称,这里的ik_max_word 即使用ik分词器

2、entity示例

package org.fiend.entity;

import lombok.Data;
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 langpf 2019/2/27
 */
// indexName索引名称 可以理解为数据库名 必须为小写,
//                          不然会报org.elasticsearch.indices.InvalidIndexNameException异常
// type类型 可以理解为表名
@Document(indexName = "item", type = "docs", shards = 1, replicas = 0)
@Data
public class Item {
    /**
     * 注: 该注解是必填项
     * @Description: @Id注解必须是springframework包下的
     * org.springframework.data.annotation.Id
     * @Author: https://blog.csdn.net/chen_2890
     */
    @Id
    private Long id;
 
    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String title; //标题
 
    @Field(type = FieldType.Keyword)
    private String category;// 分类
 
    @Field(type = FieldType.Keyword)
    private String brand; // 品牌
 
    @Field(type = FieldType.Double)
    private Double price; // 价格
 
    @Field(index = false, type = FieldType.Keyword)
    private String images; // 图片地址
 
    public Item(Long id, String title, String category, 
                String brand, Double price, String images) {
        this.id       = id;
        this.title    = title;
        this.category = category;
        this.brand    = brand;
        this.price    = price;
        this.images   = images;
    }
}

3. repository配置

package org.fiend.repository;
 
import org.fiend.entity.Item;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Component;
 
import java.util.List;
 
/**
 * @author langpf 2019/2/27
 */
@Component
// <ItemEntity, Long>: ItemEntity的@Id所注解的数据项的数据类型, 必须与Long一致,
//   即ItemEntity的@Id如果是String类型, 这里的Long就变为String
public interface ItemRepository extends ElasticsearchRepository<Item, Long> {
    /**
     * @Description:根据价格区间查询
     * @Param price1
     * @Param price2
     * @Author: https://blog.csdn.net/chen_2890
     */
    List<Item> findByPriceBetween(double price1, double price2);
}

4. controller层使用ElasticsearchTemplate

ElasticsearchTemplate用来对索引的创建,删除,以及数据的插入,查询(包括按页查询)等。
repository用来实现对数据的CRUD操作

package org.fiend.controller;
 
import com.alibaba.fastjson.JSONObject;
import org.fiend.entity.Item;
import org.fiend.repository.ItemRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
 
/**
 * @author Administrator
 */
@Controller
@RequestMapping(value = "item")
public class ItemController {
    Logger log = LoggerFactory.getLogger(getClass());
 
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;
 
    @Autowired
    private ItemRepository itemRepository;
 
    /**
     * 创建索引
     */
    @GetMapping("createIndex")
    public JSONObject createIndex(Object obj) {
        JSONObject json = new JSONObject();
 
        boolean result = elasticsearchTemplate.createIndex(obj.getClass());
        json.put("result", result);
 
        return json;
    }
 
    @GetMapping("insert")
    public String insert() {
        Item item = new Item(1L, "小米手机7", " 手机",
                "小米", 3499.00, "http://image.baidu.com/13123.jpg");
        itemRepository.save(item);
        return "success";
    }
 
    //http://localhost:8888/delete?id=1525415333329
    @GetMapping("delete")
    public String delete(long id) {
        itemRepository.deleteById(id);
        return "success";
    }
 
    /**
    * elasticsearch中本没有修改,它的修改原理是该是先删除在新增
    * 修改和新增是同一个接口,区分的依据就是id。
    */
    //http://localhost:8888/update?id=1525417362754&name=修改&description=修改
    @GetMapping("update")
    public String update(Long id, String title, String category, String brand, Double price, String images) {
        Item item = new Item(id, title, category, brand, price, images);
        itemRepository.save(item);
 
        return "success";
    }
 
    /**
     * 查找所有
     */
    @GetMapping("findAll")
    public List<Item> findAll() {
        // 查找所有
        // Iterable<Item> list = this.itemRepository.findAll();
        // 对某字段排序查找所有 Sort.by("price").descending() 降序
        // Sort.by("price").ascending(): 升序
        Iterable<Item> iterable = itemRepository.findAll(Sort.by("price").ascending();
        List<Item> list = Lists.newArrayList(iterable);
 
        return list;
    }
}

5. repository自定义方法

Spring Data 的另一个强大功能,是根据方法名称自动实现功能。

比如:你的方法名叫做:findByTitle,那么它就知道你是根据title查询,然后自动帮你完成,无需写实现类。

当然,方法名称要符合一定的约定:

KeywordSample
AndfindNameAndPrice
OrfindByNameOrPrice
IsfindByName
NotfindByNameNot
BetweenfindByPriceBetween
LessThanEqualfindByPriceLessThan
GreaterThanEqualfindByPriceGreaterThan
BeforefindByPriceBefore
AfterfindByPriceAfter
LikefindByNameLike
StartingWithfindByNameStartingWith
EndingWithfindByNameEndingWith
Contains/ContainingfindByNameContaining
InfindByNameIn(Collectionnames)
NotInfindByNameNotIn(Collectionnames)
NearfindByStoreNear
TruefindByAvailableTrue
FalsefindByAvailableFalse
OrderByfindByAvailableTrueOrderByNameDesc

例如,按照价格区间查询,定义这样的一个方法:

public interface ItemRepository extends ElasticsearchRepository<Item,Long> {
    /**
     * @Description:根据价格区间查询
     * @Param price1
     * @Param price2
     * @Author: https://blog.csdn.net/chen_2890
     */
    List<Item> findByPriceBetween(double price1, double price2);
}

添加一些测试数据:

@Autowired
private ItemRepository itemRepository;
 
/**
 * @Description:准备测试数据
 * @Author: https://blog.csdn.net/chen_2890
 */
@Test
public void insertList() {
  List<Item> list = new ArrayList<>();
  list.add(new Item(1L, "小米手机7", "手机", "小米", 3299.00, "http://image.baidu.com/13123.jpg"));
  list.add(new Item(2L, "坚果手机R1", "手机", "锤子", 3699.00, "http://image.baidu.com/13123.jpg"));
  list.add(new Item(3L, "华为META10", "手机", "华为", 4499.00, "http://image.baidu.com/13123.jpg"));
  list.add(new Item(4L, "小米Mix2S", "手机", "小米", 4299.00, "http://image.baidu.com/13123.jpg"));
  list.add(new Item(5L, "荣耀V10", "手机", "华为", 2799.00, "http://image.baidu.com/13123.jpg"));
 
 // 接收对象集合,实现批量新增
 itemRepository.saveAll(list);
}

6. 其它查询方法–controller调用

/**
 * 自定义查询: matchQuery
 */
@GetMapping("matchQuery")
public Page<Item> matchQuery() {

	// 构建查询条件
	// NativeSearchQueryBuilder:Spring提供的一个查询条件构建器, 帮助构建json格式的请求体
	NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
 
 
	// 添加基本分词查询
	// QueryBuilders.matchQuery(“title”, “小米手机”):利用QueryBuilders来生成一个查询。
	// QueryBuilders提供了大量的静态方法, 用于生成各种不同类型的查询:
	queryBuilder.withQuery(QueryBuilders.matchQuery("title", "小米手机"));
 
	
	// 搜索, 获取结果
	// Page<item>:默认是分页查询, 因此返回的是一个分页的结果对象, 包含属性:
	// totalElements:总条数
	// totalPages:总页数
	// Iterator:迭代器, 本身实现了Iterator接口, 因此可直接迭代得到当前页的数据
	Page<Item> page = this.itemRepository.search(queryBuilder.build());
	for (Item item : page) {
		System.out.println(item);
	}
 
	// 总条数
	long total = page.getTotalElements();
	System.out.println("total = " + total);
 
	// Iterator<Item> iterable = page.iterator();
 
	return page;
}
 
/**
 * 自定义查询: termQuery
 * termQuery: 功能更强大, 除了匹配字符串以外, 还可以匹配 int/long/double/float/....
 */
@GetMapping("termQuery")
public Page<Item> termQuery() {
	NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
	builder.withQuery(QueryBuilders.termQuery("price", 998.0));
 
	// 查找
	Page<Item> page = this.itemRepository.search(builder.build());
	for (Item item : page) {
		System.out.println(item);
	}
 
	return page;
}
 
 
/**
 * 自定义查询: fuzzyQuery -- 模糊查询
 */
@GetMapping("fuzzyQuery")
public Page<Item> fuzzyQuery() {
	NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
	builder.withQuery(QueryBuilders.fuzzyQuery("title", "faceoooo"));
	Page<Item> page = this.itemRepository.search(builder.build());
 
	for (Item item : page) {
		System.out.println(item + "");
	}
 
	return page;
}
 
/**
 * 分页查询
 */
@GetMapping("searchByPage")
public Page<Item> searchByPage() {
	// 构建查询条件
	NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
 
	// 添加基本分词查询
	queryBuilder.withQuery(QueryBuilders.termQuery("category", "手机"));
 
	// 分页:
	int pageNum = 0;
	int size    = 2;
	queryBuilder.withPageable(PageRequest.of(pageNum, size));
 
	// 搜索, 获取结果
	Page<Item> page = this.itemRepository.search(queryBuilder.build());
 
	// 总条数
	long total = page.getTotalElements();
	System.out.println("总条数 = " + total);
 
	// 总页数
	System.out.println("总页数 = " + page.getTotalPages());
 
	// 当前页
	System.out.println("当前页:" + page.getNumber());
 
	// 每页大小
	System.out.println("每页大小:" + page.getSize());
 
	for (Item item : page) {
		System.out.println(item);
	}
 
	return page;
}
 
 
/**
 * 排序查询
 */
@GetMapping("searchAndSort")
public Page<Item> searchAndSort() {
	// 构建查询条件
	NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
 
	// 添加基本分词查询
	queryBuilder.withQuery(QueryBuilders.termQuery("category", "手机"));
 
	// 排序
	queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC));
 
	// 搜索, 获取结果
	Page<Item> page = this.itemRepository.search(queryBuilder.build());
 
	// 总条数
	long totalNum = page.getTotalElements();
	System.out.println("总条数: " + totalNum);
 
	// 总页数
	System.out.println("总页数 = " + page.getTotalPages());
 
	// 当前页
	System.out.println("当前页: " + page.getNumber());
 
	// 每页大小
	System.out.println("每页大小:" + page.getSize());
 
	for (Item item : page) {
		System.out.println(item);
	}
 
	return page;
}
 
// 聚合查询:
//   比较常用的一些度量聚合方式:
//     Avg Aggregation:求平均值
//     Max Aggregation:求最大值
//     Min Aggregation:求最小值
//     Percentiles Aggregation:求百分比
//     Stats Aggregation:同时返回avg、max、min、sum、count等
//     Sum Aggregation:求和
//     Top hits Aggregation:求前几
//     Value Count Aggregation:求总数
//     ……


/**
 * Elasticsearch中的聚合, 包含多种类型, 最常用的两种, 一个叫桶, 一个叫度量:
 * 聚合查询: 聚合为桶 -- 查询
 * aggregation bucket 查询
 */
@GetMapping("aggBucketSearch")
public AggregatedPage<Item> aggBucketSearch() {
	// 构建查询条件
	NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
 
	// 不查询任何结果
	queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));
 
	// 1、添加一个新的聚合, 聚合类型为terms, 聚合名称为brands, 聚合字段为brand
	// AggregationBuilders:聚合的构建工厂类, 所有聚合都由这个类来构建
	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());
	}
 
	return aggPage;
}
 
// (1)统计某个字段的数量
//     ValueCountBuilder vcb=  AggregationBuilders.count("count_uid").field("uid");
// (2)去重统计某个字段的数量(有少量误差)
//     CardinalityBuilder cb= AggregationBuilders.cardinality("distinct_count_uid").field("uid");
// (3)聚合过滤
//     FilterAggregationBuilder fab= AggregationBuilders.filter("uid_filter")
//                                   .filter(QueryBuilders.queryStringQuery("uid:001"));
// (4)按某个字段分组
//     TermsBuilder tb=  AggregationBuilders.terms("group_name").field("name");
// (5)求和
//     SumBuilder  sumBuilder=	AggregationBuilders.sum("sum_price").field("price");
// (6)求平均
//     AvgBuilder ab= AggregationBuilders.avg("avg_price").field("price");
// (7)求最大值
//     MaxBuilder mb= AggregationBuilders.max("max_price").field("price");
// (8)求最小值
//     MinBuilder min=	AggregationBuilders.min("min_price").field("price");
// (9)按日期间隔分组
//     DateHistogramBuilder dhb= AggregationBuilders.dateHistogram("dh").field("date");
// (10)获取聚合里面的结果
//     TopHitsBuilder thb=  AggregationBuilders.topHits("top_result");
// (11)嵌套的聚合
//     NestedBuilder nb= AggregationBuilders.nested("negsted_path").path("quests");
// (12)反转嵌套
//    AggregationBuilders.reverseNested("res_negsted").path("kps ");
 
 
/**
 * 聚合查询: 嵌套聚合, 求平均值
 */
@GetMapping("aggSubSearch")
public AggregatedPage<Item> aggSubSearch() {
	// 构建查询条件
	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());
	}
 
	return aggPage;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值