簡介
SpringBoot 集成ElasticSearch 方式有很多,網(wǎng)上教程看的是眼花繚亂,如果先前沒接觸過ES的同學(xué),看著很懵逼,不知道用什么樣的方式集成好,其實(shí)那種方式也能集成,但是相對來說那種方式更穩(wěn)定,兼容性好咱們就用那種,這次咱們主要講下通過Spring Data Elasticsearch 套件完成對ES的操作,安裝和使用場景可直接點(diǎn)擊查看。
說明
spring-data-Elasticsearch 使用之前,必須先確定版本,elasticsearch 對版本的要求比較高,下面為版本對照表。
| spring data elasticsearch | elasticsearch |
|---|---|
| 3.2.x | 6.5.0 |
| 3.1.x | 6.2.2 |
| 3.0.x | 5.5.0 |
| 2.1.x | 2.4.0 |
| 2.0.x | 2.2.0 |
| 1.3.x | 1.5.2 |
這里選擇的版本搭配為ES 6.24, Spring-data-es 版本為3.1.5.RELEASE
特性
- 基于Java的@Configuration類的Spring配置支持或ES客戶端實(shí)例的XML命名空間
- 提供了用于操作ES的便捷工具類ElasticsearchTemplate。實(shí)現(xiàn)了文檔到POJO之間的自動智能映射
- 利用Spring的數(shù)據(jù)轉(zhuǎn)換服務(wù)實(shí)現(xiàn)功能豐富的對象映射
- 基于注解的元數(shù)據(jù)映射方式,且可擴(kuò)展以支持更多不同的數(shù)據(jù)格式
- 根據(jù)持久層接口自動生成對應(yīng)實(shí)現(xiàn)方法,無需人工編寫基本操作代碼(類似mybatis,根據(jù)接口自動得到實(shí)現(xiàn)),也支持人工定制查詢
Elasticsearch也是基于Lucene的全文檢索庫,本質(zhì)也是存儲數(shù)據(jù),很多概念與關(guān)系型數(shù)據(jù)庫是一致的,如下對照
| 索引庫 | 關(guān)系型數(shù)據(jù)庫 |
|---|---|
| 類型(type) | Table 數(shù)據(jù)表 |
| 文檔(Document) | Row 行 |
| 字段(Field) | Columns 列 |
詳細(xì)說明
索引庫(indices):indices代表許多的索引
類型(type): 模擬mysql中的table概念,一個(gè)索引庫下可以有不同類型的索引,比如商品索引,訂單索引,其數(shù)據(jù)格式不同
文檔(document): 存入索引庫原始的數(shù)據(jù)。比如每一條商品信息,就是一個(gè)文檔
字段(field): 文檔中的屬性
映射配置(mappings): 字段的數(shù)據(jù)類型、屬性、是否索引、是否存儲等特性
索引集(Indices,index的復(fù)數(shù)):邏輯上的完整索引
分片(shard):數(shù)據(jù)拆分后的各個(gè)部分
副本(replica):每個(gè)分片的復(fù)制
注意:
Elasticsearch本身就是分布式的,即便只有一個(gè)節(jié)點(diǎn),Elasticsearch默認(rèn)也會對的數(shù)據(jù)進(jìn)行分片和副本操作,向集群添加新數(shù)據(jù)時(shí),數(shù)據(jù)也會在新加入的節(jié)點(diǎn)中進(jìn)行平衡
實(shí)戰(zhàn)
Pom文件
<?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 http://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.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.glj</groupId>
<artifactId>elasticserarch-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>elasticserarch-demo</name>
<description>Demo project for Spring Boot</description>
<packaging>jar</packaging>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- elasticsearch啟動器 (必須)-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<!--Mybatis Plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.6</version>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 與swagger一起使用,需要注意-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.0-jre</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml
server:
port: 8188
spring:
application:
name: elasticserarch-demo
datasource:
url: jdbc:mysql://127.0.0.1:3306/security_oauth?serverTimezone=GMT%2B8&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
driver-class-name: com.mysql.cj.jdbc.Driver
password: root
username: root
data:
elasticsearch:
cluster-name: my-application
cluster-nodes: 127.0.0.1:9300
實(shí)體對象
package com.glj.elasticserarch.demo.biz.dto;
import io.swagger.annotations.ApiModelProperty;
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;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
/**
* <p>
*
* </p>
*
* @author gaoleijie
* @since 2019-04-09
*/
@Data
@Document(indexName = "user_index",type = "user")
public class SysUser implements Serializable {
private static final long serialVersionUID = 1L;
@Id
private Integer id;
@ApiModelProperty(value = "賬號")
@Field(type = FieldType.Keyword)
private String username;
@ApiModelProperty(value = "密碼")
@Field(type = FieldType.Keyword)
private String password;
@ApiModelProperty(value = "昵稱")
@Field(type = FieldType.Text,analyzer = "ik_max_word")
private String nickname;
@ApiModelProperty(value = "郵箱")
@Field(type = FieldType.Keyword)
private String email;
@ApiModelProperty(value = "狀態(tài)(0:鎖定,1:解鎖)")
@Field(type = FieldType.Integer)
private Integer status;
@ApiModelProperty(value = "創(chuàng)建人")
@Field(type = FieldType.Keyword)
private String createUser;
@ApiModelProperty(value = "更新人")
@Field(type = FieldType.Keyword)
private String updateUser;
@ApiModelProperty(value = "年齡")
@Field(type = FieldType.Double)
private Double age;
}
注意
SpringDataElasticSearch中,只需要操作對象,就可以操作elasticsearch中的數(shù)據(jù)
注解說明
@Document 作用在類,標(biāo)記實(shí)體類為文檔對象
包含屬性
indexName:對應(yīng)索引庫名稱
type:對應(yīng)在索引庫中的類型
shards:分片數(shù)量,默認(rèn)5
replicas:副本數(shù)量,默認(rèn)1
@Id 作用在成員變量,標(biāo)記一個(gè)字段作為id主鍵
@Field 作用在成員變量,標(biāo)記為文檔的字段,并指定字段映射屬性
包含屬性
type:字段類型,是枚舉:FieldType,可以是text、long、short、date、integer、object等
| type屬性名稱 | 含義 |
|---|---|
| text | 存儲數(shù)據(jù)時(shí)候,會自動分詞,并生成索引 |
| keyword | 存儲數(shù)據(jù)時(shí)候,不會分詞建立索引 |
| Numerical | 數(shù)值類型,一類為基本數(shù)據(jù)類型:long、interger、short、byte、double、float、half_float 。一類為浮點(diǎn)數(shù)的高精度類型:scaled_float 需要指定一個(gè)精度因子,比如10或50,elasticsearch會把真實(shí)值乘以這個(gè)因子后存儲,取出時(shí)再還原 |
| Date日期類型 | elasticsearch可以對日期格式化為字符串存儲,但是建議我們存儲為毫秒值,存儲為long,節(jié)省空間 |
index:是否索引,布爾類型,默認(rèn)是true
store:是否存儲,布爾類型,默認(rèn)是false
analyzer:分詞器名稱,這里的ik_max_word即使用ik分詞器
創(chuàng)建索引
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@PostMapping("/createIndex")
@ApiOperation("創(chuàng)建索引")
public Boolean createIndex(@RequestParam String indexName){
return elasticsearchTemplate.createIndex(indexName);
}
@PostMapping("/createIndex")
@ApiOperation("創(chuàng)建索引")
public Boolean createIndex(){
return elasticsearchTemplate.createIndex(SysUser.class);
}
可以根據(jù)類的信息自動生成,也可以手動指定indexName和Settings
刪除索引
@PostMapping("/deleteIndex")
@ApiOperation("刪除索引")
public Boolean deleteIndex(@RequestParam String indexName){
// return elasticsearchTemplate.deleteIndex(SysUser.class);
return elasticsearchTemplate.deleteIndex(indexName);
}
可以根據(jù)類名或索引名刪除
新增文檔之Repository
Repository接口
Spring Data 的強(qiáng)大之處,在于你不用寫任何DAO處理,自動根據(jù)方法名或類的信息進(jìn)行CRUD操作。只要你定義一個(gè)接口,然后繼承Repository提供的一些子接口,就能具備各種基本的CRUD功能。
來看下Repository的繼承關(guān)系,自己新建一個(gè)接口,然后繼承ElasticsearchRepository 就好了
package com.glj.elasticserarch.demo.biz.repository;
import com.glj.elasticserarch.demo.biz.dto.SysUser;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.List;
/**
* @ClassName ElasticSerarchRepository
* @Description TODO
* @Author gaoleijie
* @Date 2019/7/18 10:15
**/
public interface UserRepository extends ElasticsearchRepository<SysUser,Long> {
/**
* 根據(jù)昵稱查找用戶
* @param nickName
* @return
*/
List<SysUser> findByNickname(String nickName);
/**
* 根據(jù)昵稱或者用戶名進(jìn)行查找
* @param nickName
* @param Password
* @return
*/
List<SysUser> findByNicknameOrPassword(String nickName,String Password);
}
再來看下ElasticsearchRepository
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.data.elasticsearch.repository;
import java.io.Serializable;
import org.elasticsearch.index.query.QueryBuilder;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.data.repository.NoRepositoryBean;
@NoRepositoryBean
public interface ElasticsearchRepository<T, ID extends Serializable> extends ElasticsearchCrudRepository<T, ID> {
<S extends T> S index(S var1);
Iterable<T> search(QueryBuilder var1);
Page<T> search(QueryBuilder var1, Pageable var2);
Page<T> search(SearchQuery var1);
Page<T> searchSimilar(T var1, String[] var2, Pageable var3);
void refresh();
Class<T> getEntityClass();
}
新增文檔
@PostMapping("/save")
@ApiOperation("新增")
public SysUser save(@RequestBody SysUser user){
return repository.save(user);
}
@PostMapping("/saveAll")
@ApiOperation("批量新增")
public Iterable<SysUser> saveAll(@RequestBody List<SysUser> users){
return repository.saveAll(users);
}
運(yùn)行完畢后,可以進(jìn)入 http://localhost:9100/ 查看效果

注意
elasticsearch中本沒有修改,它的修改原理是該是先刪除再新增修改和新增是同一個(gè)接口,區(qū)分的依據(jù)就是id。
查詢
@PostMapping("/findAllAndSort")
@ApiOperation("查詢?nèi)坎⒏鶕?jù)密碼排序")
public Iterable<SysUser> findAllAndSort(){
return repository.findAll(Sort.by("password").ascending());
}
@PostMapping("/findAll")
@ApiOperation("查詢?nèi)?)
public Iterable<SysUser> findAll(){
return repository.findAll();
}
自定義方法
不知道大家有沒有看到在我的UserRepository 接口中有自定義的查詢方法,這些方法就是接下來我們要講的 Spring Data 的另一個(gè)強(qiáng)大功能,是根據(jù)方法名稱自動實(shí)現(xiàn)功能。
比如:你的方法名叫做:findByName,那么它就知道你是根據(jù)name查詢,然后自動幫你完成,無需寫實(shí)現(xiàn)類。
當(dāng)然,方法名稱要符合一定的約定:
| Keyword | Sample |
|---|---|
| findByNameAndPrice | |
| findByNameOrPrice | |
| findByName | |
| findByNameNot | |
| findByPriceBetween | |
| findByPriceLessThan | |
| findByPriceGreaterThan | |
| findByPriceBefore | |
| findByPriceAfter | |
| findByNameLike | |
| findByNameStartingWith | |
| findByNameEndingWith | |
| findByNameContaining | |
| findByNameIn(Collection<String>names) | |
| findByNameNotIn(Collection<String>names) | |
| findByStoreNear | |
| findByAvailableTrue | |
| findByAvailableFalse | |
| findByAvailableTrueOrderByNameDesc |
例如我們下面兩個(gè)例子,按照”昵稱“去查找用戶和”按照昵稱或者密碼“去查找,
不需要寫實(shí)現(xiàn)類,然后我們直接去運(yùn)行
@PostMapping("/findByNickname")
@ApiOperation("根據(jù)昵稱查詢用戶")
public List<SysUser> findByNickname(@RequestParam("nickname")String nickName){
List<SysUser> list = repository.findByNickname(nickName);
return list;
}
@PostMapping("/findByNicknameOrPassword")
@ApiOperation("根據(jù)昵稱或者密碼查詢用戶")
public List<SysUser> findByNicknameOrPassword(@RequestParam("nickname")String nickName,@RequestParam("password")String Password){
List<SysUser> list = repository.findByNicknameOrPassword(nickName,Password);
return list;
}
package com.glj.elasticserarch.demo.biz.repository;
import com.glj.elasticserarch.demo.biz.dto.SysUser;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.List;
/**
* @ClassName ElasticSerarchRepository
* @Description TODO
* @Author gaoleijie
* @Date 2019/7/18 10:15
**/
public interface UserRepository extends ElasticsearchRepository<SysUser,Long> {
/**
* 根據(jù)昵稱查找用戶
* @param nickName
* @return
*/
List<SysUser> findByNickname(String nickName);
/**
* 根據(jù)昵稱或者用戶名進(jìn)行查找
* @param nickName
* @param Password
* @return
*/
List<SysUser> findByNicknameOrPassword(String nickName,String Password);
}
查詢結(jié)果

自定義查詢
@PostMapping("/query")
@ApiOperation("自定義查詢")
public Page<SysUser> query(@RequestParam("username")String userName){
NativeSearchQueryBuilder builder=new NativeSearchQueryBuilder();
builder.withQuery(QueryBuilders.matchQuery("username",userName));
//如果實(shí)體和數(shù)據(jù)的名稱對應(yīng)就會自動封裝,pageable分頁參數(shù)
Page<SysUser> items = this.repository.search(builder.build());
long total = items.getTotalElements();
System.out.println("查詢數(shù)量為:"+total);
return items;
}
NativeSearchQueryBuilder:Spring提供的一個(gè)查詢條件構(gòu)建器,幫助構(gòu)建json格式的請求體
QueryBuilders.matchQuery(“username”, userName):利用QueryBuilders來生成一個(gè)查詢。QueryBuilders提供了大量的靜態(tài)方法,用于生成各種不同類型的查詢:
Page<SysUser>:默認(rèn)是分頁查詢,因此返回的是一個(gè)分頁的結(jié)果對象,包含屬性:
totalElements:總條數(shù)
totalPages:總頁數(shù)
Iterator:迭代器,本身實(shí)現(xiàn)了Iterator接口,因此可直接迭代得到當(dāng)前頁的數(shù)據(jù)
其它屬性

模糊查詢
/**
* 模糊查找
* @param userName
* @return
*/
@PostMapping("/fuzzyQuery")
@ApiOperation("模糊查找根據(jù)分詞去模糊,如果默認(rèn)為5,輸入4是沒有辦法模糊的")
public Page<SysUser> fuzzyQuery(@RequestParam("username") String userName){
NativeSearchQueryBuilder builder=new NativeSearchQueryBuilder();
builder.withQuery(QueryBuilders.fuzzyQuery("username",userName));
// 查找
Page<SysUser> page = this.repository.search(builder.build());
return page;
}
注意
如果在文檔對象里面沒有指定分片數(shù)量,默認(rèn)是5,查詢值必須大于5的時(shí)候才能進(jìn)行分片查詢,否則是查詢不出來的,所以如果對于特定的文檔,分片數(shù)量需要提前指定
聚合
聚合可以讓我們極其方便的實(shí)現(xiàn)對數(shù)據(jù)的統(tǒng)計(jì)、分析。例如:
什么牌子的手機(jī)最受歡迎?
這些手機(jī)的平均價(jià)格、最高價(jià)格、最低價(jià)格?
這些手機(jī)每月的銷售情況如何?
實(shí)現(xiàn)這些統(tǒng)計(jì)功能的比數(shù)據(jù)庫的sql要方便的多,而且查詢速度非???,可以實(shí)現(xiàn)近實(shí)時(shí)搜索效果
lasticsearch中的聚合,包含多種類型,最常用的兩種,一個(gè)叫桶,一個(gè)叫度量
桶
桶的作用,是按照某種方式對數(shù)據(jù)進(jìn)行分組,每一組數(shù)據(jù)在ES中稱為一個(gè)桶,比如如果按照男女進(jìn)行劃分 就會出現(xiàn)”男桶“”女桶“ 類似的桶
Elasticsearch中提供的劃分桶的方式有很多:
Date Histogram Aggregation:根據(jù)日期階梯分組,例如給定階梯為周,會自動每周分為一組
Histogram Aggregation:根據(jù)數(shù)值階梯分組,與日期類似
Terms Aggregation:根據(jù)詞條內(nèi)容分組,詞條內(nèi)容完全匹配的為一組
Range Aggregation:數(shù)值和日期的范圍分組,指定開始和結(jié)束,然后按段分組
度量
綜上所述,我們發(fā)現(xiàn)bucket aggregations 只負(fù)責(zé)對數(shù)據(jù)進(jìn)行分組,并不進(jìn)行計(jì)算,因此往往bucket中往往會嵌套另一種聚合:metrics aggregations即度量
分組完成以后,我們一般會對組中的數(shù)據(jù)進(jìn)行聚合運(yùn)算,例如求平均值、最大、最小、求和等,這些在ES中稱為度量
比較常用的一些度量聚合方式:
Avg Aggregation:求平均值
Max Aggregation:求最大值
Min Aggregation:求最小值
Percentiles Aggregation:求百分比
Stats Aggregation:同時(shí)返回avg、max、min、sum、count等
Sum Aggregation:求和
Top hits Aggregation:求前幾
Value Count Aggregation:求總數(shù)
注意:在ES中,需要進(jìn)行聚合、排序、過濾的字段其處理方式比較特殊,因此不能被分詞。這里我們將updateUser和username這兩個(gè)文字類型的字段設(shè)置為keyword類型,這個(gè)類型不會被分詞,將來就可以參與聚合
聚合為桶
/**
* 根據(jù)列名進(jìn)行聚合查詢
*/
@PostMapping("/aggregateQuery")
@ApiOperation("根據(jù)列進(jìn)行聚合查詢")
public void aggregateQuery(@RequestParam("clumname") String clumname){
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
queryBuilder.withSourceFilter(new FetchSourceFilter(new String []{""},null));
// 添加一個(gè)新的聚合,聚合類型為terms,聚合名稱為列明,列名稱為
queryBuilder.addAggregation(
AggregationBuilders.terms(clumname).field(clumname));
// 將查詢結(jié)果轉(zhuǎn)換為聚合分頁查詢
AggregatedPage<SysUser> aggPage = (AggregatedPage<SysUser>) this.repository.search(queryBuilder.build());
StringTerms agg = (StringTerms) aggPage.getAggregation(clumname);
List<StringTerms.Bucket> buckets = agg.getBuckets();
// 3.3、遍歷
for (StringTerms.Bucket bucket : buckets) {
// 3.4、獲取桶中的key,即列名稱
System.out.println(bucket.getKeyAsString());
// 3.5、獲取桶中的某列的數(shù)量
System.out.println(bucket.getDocCount());
}
}
結(jié)果顯示

關(guān)鍵API
AggregationBuilders:聚合的構(gòu)建工廠類。所有聚合都由這個(gè)類來構(gòu)建
(1)統(tǒng)計(jì)某個(gè)字段的數(shù)量
ValueCountBuilder vcb= AggregationBuilders.count("count_nickname").field("nickname");
(2)去重統(tǒng)計(jì)某個(gè)字段的數(shù)量(可能有部分誤差)
CardinalityBuilder cb= AggregationBuilders.cardinality("distinct_count_name").field("nickname");
(3)聚合過濾
FilterAggregationBuilder fab= AggregationBuilders.filter("name_filter").filter(QueryBuilders.queryStringQuery("nickname:劉德華"));
(4)按某個(gè)字段分組
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)獲取聚合里面的結(jié)果
TopHitsBuilder thb= AggregationBuilders.topHits("top_result");
(11)嵌套的聚合
NestedBuilder nb= AggregationBuilders.nested("negsted_path").path("quests");
(12)反轉(zhuǎn)嵌套
AggregationBuilders.reverseNested("res_negsted").path("kps ");
AggregatedPage:聚合查詢的結(jié)果類
嵌套聚合,求平均值
@PostMapping("/arrregateAvg")
@ApiOperation("根據(jù)列進(jìn)行聚合查詢求平均值")
public void arrregateAvg(@RequestParam("clumname") String clumname){
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
queryBuilder.withSourceFilter(new FetchSourceFilter(new String []{""},null));
queryBuilder.addAggregation(AggregationBuilders.terms(clumname).field(clumname).subAggregation(AggregationBuilders.avg("ageAvg").field("age")));
AggregatedPage aggPage =(AggregatedPage<SysUser>) repository.search(queryBuilder.build());
StringTerms agg = (StringTerms) aggPage.getAggregation(clumname);
// 3.2、獲取桶
List<StringTerms.Bucket> buckets = agg.getBuckets();
// 3.3、遍歷
for (StringTerms.Bucket bucket : buckets) {
System.out.println(bucket.getKeyAsString()+",共"+bucket.getDocCount()+"編");
// 3.6.獲取子聚合結(jié)果:
InternalAvg avg = (InternalAvg) bucket.getAggregations().asMap().get("ageAvg");
System.out.println("平均售價(jià):" + avg.getValue());
}
}
查詢結(jié)果

結(jié)束語
本文章大部分為自己實(shí)戰(zhàn)出來的,實(shí)戰(zhàn)思路是參考文章:SpringBoot整合Elasticsearch
如有什么不對,請及時(shí)指正。