通過Spring Data Elasticsearch操作ES

簡介

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

特性

  1. 基于Java的@Configuration類的Spring配置支持或ES客戶端實(shí)例的XML命名空間
  2. 提供了用于操作ES的便捷工具類ElasticsearchTemplate。實(shí)現(xiàn)了文檔到POJO之間的自動智能映射
  3. 利用Spring的數(shù)據(jù)轉(zhuǎn)換服務(wù)實(shí)現(xiàn)功能豐富的對象映射
  4. 基于注解的元數(shù)據(jù)映射方式,且可擴(kuò)展以支持更多不同的數(shù)據(jù)格式
  5. 根據(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/ 查看效果

image.png

注意
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
\color{red}{And} findByNameAndPrice
\color{red}{Or} findByNameOrPrice
\color{red}{Is} findByName
\color{red}{Not} findByNameNot
\color{red}{Between} findByPriceBetween
\color{red}{LessThanEqual} findByPriceLessThan
\color{red}{GreaterThanEqual} findByPriceGreaterThan
\color{red}{Before} findByPriceBefore
\color{red}{After} findByPriceAfter
\color{red}{Like} findByNameLike
\color{red}{StartingWith} findByNameStartingWith
\color{red}{EndingWith} findByNameEndingWith
\color{red}{Contains/Containing} findByNameContaining
\color{red}{In} findByNameIn(Collection<String>names)
\color{red}{NotIn} findByNameNotIn(Collection<String>names)
\color{red}{Near } findByStoreNear
\color{red}{True } findByAvailableTrue
\color{red}{False} findByAvailableFalse
\color{red}{OrderBy} 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é)果


image.png

自定義查詢

@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ù)

其它屬性


image.png

模糊查詢

 /**
     * 模糊查找
     * @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é)果顯示


image.png

關(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é)果


image.png

結(jié)束語

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容