Elasticsearch提供的Java客戶端有一些不太方便的地方:
- 很多地方需要拼接Json字串,在java中拼接字串有多恐怖你應該懂的
- 需要自己把物件序列化為json存盤
- 查詢到結果也需要自己反序列化為物件
因此,我們這里就不講解原生的Elasticsearch客戶端API了,
而是學習Spring提供的套件:Spring Data Elasticsearch,
一、簡介
Spring Data Elasticsearch是Spring Data專案下的一個子模塊,
查看 Spring Data的官網:http://projects.spring.io/spring-data/

Spring Data 的使命是為資料訪問提供熟悉且一致的基于 Spring 的編程模型,同時仍保留底層資料存盤的特??殊特征,
它使使用資料訪問技術、關系和非關系資料庫、map-reduce 框架和基于云的資料服務變得容易,
這是一個傘形專案,其中包含許多特定于給定資料庫的子專案,
這些專案是通過與這些令人興奮的技術背后的許多公司和開發商合作開發的,
特征
-
強大的存盤庫和自定義物件映射抽象
-
從存盤庫方法名稱派生的動態查詢
-
提供基本屬性的實作域基類
-
支持透明審計(創建、最后更改)
-
可以集成自定義存盤庫代碼
-
通過 JavaConfig 和自定義 XML 命名空間輕松集成 Spring
-
與 Spring MVC 控制器的高級集成
-
跨店持久化實驗支持
1、Spring Data Elasticsearch


Spring Data for Elasticsearch 是 Spring Data 專案的一部分,該專案旨在為新資料存盤提供熟悉且一致的基于 Spring 的編程模型,同時保留特定于存盤的特性和功能,
Spring Data Elasticsearch 專案提供了與 Elasticsearch 搜索引擎的集成,Spring Data Elasticsearch 的關鍵功能領域是以 POJO 為中心的模型,用于與 Elastichsearch 檔案互動并輕松撰寫 Repository 樣式的資料訪問層,
(1)特征
-
Spring 配置支持使用基于 Java 的
@Configuration類或用于 ES 客戶端實體的 XML 命名空間, -
ElasticsearchTemplate幫助程式類,可提高執行常見 ES 操作的生產力,包括檔案和 POJO 之間的集成物件映射,
-
功能豐富的物件映射與 Spring 的轉換服務集成
-
基于注釋的映射元資料但可擴展以支持其他元資料格式
-
Repository介面的自動實作,包括對自定義查找器方法的支持,
-
對存盤庫的 CDI 支持
二、Demo工程的搭建(創建索引)
我們新建一個demo,學習Elasticsearch
在這之前你需要在Linux上安裝Elasticsearch:
如果有則不需要安裝,入門沒有請看我的這篇文章:
https://blog.csdn.net/qq_44757034/article/details/119717907
1、創建一個新的工程



2、引入依賴
(1)pom.xml

<?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>
<groupId>com.itzheng.demo</groupId>
<artifactId>es-demo</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>elasticsearch</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
(2)application.yml


其中192.168.56.10為你虛擬機或者服務器的ip地址
spring:
data:
elasticsearch:
cluster-name: elasticsearch
cluster-nodes: 192.168.56.101:9300
3、設定啟動類



package com.itzheng;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class EsApplication {
public static void main(String[] args) {
SpringApplication.run(EsApplication.class);
}
}
4、創建物體類


package com.itzheng.es.pojo;
public class Item {
private Long id;
private String title; //標題
private String category;//分類
private String brand;//品牌
private Double price;//價格
private String images;//圖片地址
}
添加依賴

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
完善物體類

package com.itzheng.es.pojo;
import lombok.Data;
@Data
public class Item {
private Long id;
private String title; //標題
private String category;//分類
private String brand;//品牌
private Double price;//價格
private String images;//圖片地址
}
5、創建測驗類
(1)創建索引庫


package com.itzheng.es.demo;
import com.itzheng.es.pojo.Item;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.junit4.SpringRunner;
/*
Springboot的@RunWith(SpringRunner.class)
注解的意義在于Test測驗類要使用注入的類,比如@Autowired注入的類,
有了@RunWith(SpringRunner.class)這些類才能實體化到spring容器中,自動注入才能生效,
不然直接一個NullPointerExecption
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class EsTest {
@Autowired
ElasticsearchTemplate template;
@Test
public void testCreate(){
template.createIndex(Item.class);//創建索引
}
}
完善物體類Item,設定在提交到Elasticsearch的時候的索引名稱,型別,以及分片

package com.itzheng.es.pojo;
import lombok.Data;
import org.springframework.data.elasticsearch.annotations.Document;
@Data
@Document(indexName = "itzhengitem",type = "item",shards = 1)
public class Item {
private Long id;
private String title; //標題
private String category;//分類
private String brand;//品牌
private Double price;//價格
private String images;//圖片地址
}
(2)指定映射關系
1)添加欄位映射(繼續完善Item物體類)設定型別和主鍵
映射
Spring Data通過注解來宣告欄位的映射屬性,有下面的三個注解:
@Document作用在類,標記物體類為檔案物件,一般有四個屬性- indexName:對應索引庫名稱
- type:對應在索引庫中的型別
- shards:分片數量,默認5
- replicas:副本數量,默認1
@Id作用在成員變數,標記一個欄位作為id主鍵@Field作用在成員變數,標記為檔案的欄位,并指定欄位映射屬性:- type:欄位型別,取值是列舉:FieldType
- index:是否索引,布爾型別,默認是true
- store:是否存盤,布爾型別,默認是false
- analyzer:分詞器名稱
示例:

package com.itzheng.es.pojo;
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;
@Data
@Document(indexName = "itzhengitem",type = "item",shards = 1)
@AllArgsConstructor
@NoArgsConstructor
public class Item {
@Field(type = FieldType.Long)
@Id
private Long id;
@Field(type = FieldType.Text , analyzer = "ik_smart")//設定型別是文本,并指定分詞方式為ik_smart
private String title; //標題
@Field(type = FieldType.Keyword) //Keyword設定當前也是文本型別,但是不設定分詞
private String category;//分類
@Field(type = FieldType.Keyword)
private String brand;//品牌
@Field(type = FieldType.Double)
private Double price;//價格
@Field(type = FieldType.Keyword,index = false)//index = false設定當前欄位不需要被索引,index = 默認是true
private String images;//圖片地址
}
2)完善測驗類,使用映射規則

package com.itzheng.es.demo;
import com.itzheng.es.pojo.Item;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.junit4.SpringRunner;
/*
Springboot的@RunWith(SpringRunner.class)
注解的意義在于Test測驗類要使用注入的類,比如@Autowired注入的類,
有了@RunWith(SpringRunner.class)這些類才能實體化到spring容器中,自動注入才能生效,
不然直接一個NullPointerExecption
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class EsTest {
@Autowired
ElasticsearchTemplate template;
@Test
public void testCreate(){
//創建索引庫
template.createIndex(Item.class);//創建索引
//指定映射關系
template.putMapping(Item.class);
}
}
6、運行測驗類
(1)運行測驗


運行成功

(2)通過Kabina查看

GET itzhengitem
回傳結果
{
"itzhengitem" : {
"aliases" : { },
"mappings" : {
"properties" : {
"brand" : {
"type" : "keyword"
},
"category" : {
"type" : "keyword"
},
"id" : {
"type" : "keyword"
},
"images" : {
"type" : "keyword",
"index" : false
},
"price" : {
"type" : "double"
},
"title" : {
"type" : "text",
"analyzer" : "ik_smart"
}
}
},
"settings" : {
"index" : {
"routing" : {
"allocation" : {
"include" : {
"_tier_preference" : "data_content"
}
}
},
"refresh_interval" : "1s",
"number_of_shards" : "1",
"provided_name" : "itzhengitem",
"creation_date" : "1629355397115",
"store" : {
"type" : "fs"
},
"number_of_replicas" : "1",
"uuid" : "2cUsvBtgQ4uOARwTuQoHAA",
"version" : {
"created" : "7140099"
}
}
}
}
}

只查看映射
GET itzhengitem/_mapping
{
"itzhengitem" : {
"mappings" : {
"properties" : {
"brand" : {
"type" : "keyword"
},
"category" : {
"type" : "keyword"
},
"id" : {
"type" : "keyword"
},
"images" : {
"type" : "keyword",
"index" : false
},
"price" : {
"type" : "double"
},
"title" : {
"type" : "text",
"analyzer" : "ik_smart"
}
}
}
}
}

三、洗掉索引
1、撰寫測驗方法

package com.itzheng.es.demo;
import com.itzheng.es.pojo.Item;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.junit4.SpringRunner;
/*
Springboot的@RunWith(SpringRunner.class)
注解的意義在于Test測驗類要使用注入的類,比如@Autowired注入的類,
有了@RunWith(SpringRunner.class)這些類才能實體化到spring容器中,自動注入才能生效,
不然直接一個NullPointerExecption
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class EsTest {
@Autowired
ElasticsearchTemplate template;
@Test
public void testCreate(){
//創建索引庫
template.createIndex(Item.class);//創建索引
//指定映射關系
template.putMapping(Item.class);
}
@Test
public void testDelete(){
template.deleteIndex("itzhengitem");
}
}

運行成功

2、通過Kabina查看
GET itzhengitem
回傳結果
{
"error" : {
"root_cause" : [
{
"type" : "index_not_found_exception",
"reason" : "no such index [itzhengitem]",
"resource.type" : "index_or_alias",
"resource.id" : "itzhengitem",
"index_uuid" : "_na_",
"index" : "itzhengitem"
}
],
"type" : "index_not_found_exception",
"reason" : "no such index [itzhengitem]",
"resource.type" : "index_or_alias",
"resource.id" : "itzhengitem",
"index_uuid" : "_na_",
"index" : "itzhengitem"
},
"status" : 404
}
為了方便我們需要再次創建剛剛的索引

四、Repository檔案操作
Spring Data 的強大之處,就在于你不用寫任何DAO處理,自動根據方法名或類的資訊進行CRUD操作,
只要你定義一個介面,然后繼承Repository提供的一些子介面,就能具備各種基本的CRUD功能,
我們只需要定義介面,然后繼承它就OK了,
定義一個介面

package com.itzheng.es.repository;
import com.itzheng.es.pojo.Item;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
public interface ItemRepository extends ElasticsearchRepository<Item,Long> {
//上述泛型的第一個引數的物體型別別,第二個是主鍵ID型別
}
1、新增檔案
(1)首先注入

@Autowired
private ItemRepository repository;
(2)撰寫測驗方法

@Test
public void insertIndex(){
Item item = new Item(1L, "小米手機7", " 手機", "小米", 3499.00, "http://image.leyou.com/13123.jpg");
repository.save(item);
}
(3)運行測驗方法


(4)通過Kabina查看
GET itzhengitem/_search
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "itzhengitem",
"_type" : "item",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"id" : 1,
"title" : "小米手機7",
"category" : " 手機",
"brand" : "小米",
"price" : 3499.0,
"images" : "http://image.leyou.com/13123.jpg"
}
}
]
}
}

2、批量新增

@Test
public void indexList(){
List<Item> list = new ArrayList<>();
list.add(new Item(2L, "堅果手機R1", " 手機", "錘子", 3699.00, "http://image.leyou.com/123.jpg"));
list.add(new Item(3L, "華為META10", " 手機", "華為", 4499.00, "http://image.leyou.com/3.jpg"));
repository.saveAll(list);
}
運行測驗

運行成功

通過Kabina查看
GET itzhengitem/_search
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "itzhengitem",
"_type" : "item",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"id" : 1,
"title" : "小米手機7",
"category" : " 手機",
"brand" : "小米",
"price" : 3499.0,
"images" : "http://image.leyou.com/13123.jpg"
}
},
{
"_index" : "itzhengitem",
"_type" : "item",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"id" : 2,
"title" : "堅果手機R1",
"category" : " 手機",
"brand" : "錘子",
"price" : 3699.0,
"images" : "http://image.leyou.com/123.jpg"
}
},
{
"_index" : "itzhengitem",
"_type" : "item",
"_id" : "3",
"_score" : 1.0,
"_source" : {
"id" : 3,
"title" : "華為META10",
"category" : " 手機",
"brand" : "華為",
"price" : 4499.0,
"images" : "http://image.leyou.com/3.jpg"
}
}
]
}
}
多新增幾條資料
@Test
public void indexList(){
List<Item> list = new ArrayList<>();
list.add(new Item(4L, "小米手機7", "手機", "小米", 3299.00, "http://image.leyou.com/13123.jpg"));
list.add(new Item(5L, "堅果手機R1", "手機", "錘子", 3699.00, "http://image.leyou.com/13123.jpg"));
list.add(new Item(6L, "華為META10", "手機", "華為", 4499.00, "http://image.leyou.com/13123.jpg"));
list.add(new Item(7L, "小米Mix2S", "手機", "小米", 4299.00, "http://image.leyou.com/13123.jpg"));
list.add(new Item(8L, "榮耀V10", "手機", "華為", 2799.00, "http://image.leyou.com/13123.jpg"));
repository.saveAll(list);
}
3、修改檔案
修改和新增是同一個介面,區分的依據就是id
這一點跟我們在頁面發起PUT請求是類似的,
修改id為1 的資料

@Test
public void updateIndex(){
Item item = new Item(1L, "大米手機7", " 手機", "小米", 3499.00, "http://image.leyou.com/13123.jpg");
repository.save(item);
}

通過Kabina查看
GET itzhengitem/_search

4、基本查詢
ElasticsearchRepository提供了一些基本的查詢方法:
(1)通過id查詢

@Test
public void testQuery(){
Optional<Item> optional = this.repository.findById(1L);
System.out.println(optional.get());
}


(2)查詢所有

@Test
public void testFind(){
Iterable<Item> items = repository.findAll();
for (Item item : items) {
System.out.println(item);
}
}

運行結果

(3) 自定義方法
Spring Data 的另一個強大功能,是根據方法名稱自動實作功能,
比如:你的方法名叫做:findByTitle,那么它就知道你是根據title查詢,然后自動幫你完成,無需寫實作類,
當然,方法名稱要符合一定的約定:
| Keyword | Sample | Elasticsearch Query String |
|---|---|---|
And | findByNameAndPrice | {"bool" : {"must" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}} |
Or | findByNameOrPrice | {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}} |
Is | findByName | {"bool" : {"must" : {"field" : {"name" : "?"}}}} |
Not | findByNameNot | {"bool" : {"must_not" : {"field" : {"name" : "?"}}}} |
Between | findByPriceBetween | {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}} |
LessThanEqual | findByPriceLessThan | {"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}} |
GreaterThanEqual | findByPriceGreaterThan | {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}} |
Before | findByPriceBefore | {"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}} |
After | findByPriceAfter | {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}} |
Like | findByNameLike | {"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}} |
StartingWith | findByNameStartingWith | {"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}} |
EndingWith | findByNameEndingWith | {"bool" : {"must" : {"field" : {"name" : {"query" : "*?","analyze_wildcard" : true}}}}} |
Contains/Containing | findByNameContaining | {"bool" : {"must" : {"field" : {"name" : {"query" : "**?**","analyze_wildcard" : true}}}}} |
In | findByNameIn(Collection<String>names) | {"bool" : {"must" : {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}} |
NotIn | findByNameNotIn(Collection<String>names) | {"bool" : {"must_not" : {"bool" : {"should" : {"field" : {"name" : "?"}}}}}} |
Near | findByStoreNear | Not Supported Yet ! |
True | findByAvailableTrue | {"bool" : {"must" : {"field" : {"available" : true}}}} |
False | findByAvailableFalse | {"bool" : {"must" : {"field" : {"available" : false}}}} |
OrderBy | findByAvailableTrueOrderByNameDesc | {"sort" : [{ "name" : {"order" : "desc"} }],"bool" : {"must" : {"field" : {"available" : true}}}} |
例如,我們來按照價格區間查詢,定義這樣的一個方法:
1)在介面當中定義

package com.itzheng.es.repository;
import com.itzheng.es.pojo.Item;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.List;
public interface ItemRepository extends ElasticsearchRepository<Item,Long> {
//上述泛型的第一個引數的物體型別別,第二個是主鍵ID型別
List<Item> findByPriceBetween(double price1, double price2);
}
2)在EsTest撰寫queryByPriceBetween方法(通過價格的范圍查詢)
不需要寫實作類,然后我們直接去運行:

@Test
public void queryByPriceBetween(){
List<Item> items = repository.findByPriceBetween(2000, 4000);
for (Item item : items) {
System.out.println(item);
}
}


5、高級查詢
(1)基本查詢
先看看基本玩法

@Test
public void testQueryCustom(){
//詞條查詢
MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery("title", "小米");
Iterable<Item> items = repository.search(queryBuilder);
items.forEach(System.out::println);
}
QueryBuilders提供了大量的靜態方法,用于生成各種不同型別的查詢物件,例如:詞條、模糊、通配符等QueryBuilder物件,
結果:

(2)自定義查詢
先來看最基本的match query:

@Test
public void testNativeQuery(){
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
//結果過濾
//添加查詢條件
queryBuilder.withQuery(QueryBuilders.matchQuery("title","小米"));
NativeSearchQuery searchQuery = queryBuilder.build();
//執行搜索,獲取結果
Page<Item> result = repository.search(searchQuery);
//列印總條數
System.out.println(result.getTotalElements());
//列印總頁數
System.out.println(result.getTotalPages());
result.forEach(System.out::println);
}
NativeSearchQueryBuilder:Spring提供的一個查詢條件構建器,幫助構建json格式的請求體
Page<item>:默認是分頁查詢,因此回傳的是一個分頁的結果物件,包含屬性:
- totalElements:總條數
- totalPages:總頁數
- Iterator:迭代器,本身實作了Iterator介面,因此可直接迭代得到當前頁的資料
回傳結果

(3)分頁查詢和排序
利用NativeSearchQueryBuilder可以方便的實作分頁:
需要再添加一些資料方便測驗
@Test
public void indexList(){
List<Item> list = new ArrayList<>();
list.add(new Item(9L, "小米手機7", "手機", "小米", 3299.00, "http://image.leyou.com/13123.jpg"));
list.add(new Item(10L, "堅果手機R1", "手機", "錘子", 3699.00, "http://image.leyou.com/13123.jpg"));
list.add(new Item(11L, "華為META10", "手機", "華為", 4499.00, "http://image.leyou.com/13123.jpg"));
list.add(new Item(12L, "小米Mix2S", "手機", "小米", 4299.00, "http://image.leyou.com/13123.jpg"));
list.add(new Item(13L, "榮耀V10", "手機", "華為", 2799.00, "http://image.leyou.com/13123.jpg"));
repository.saveAll(list);
}
再次測驗

@Test
public void testNativeQuery(){
// 構建查詢條件
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// 添加基本的分詞查詢
queryBuilder.withQuery(QueryBuilders.termQuery("title", "手機"));
// 初始化分頁引數
int page = 0;
int size = 3;
// 設定分頁引數
queryBuilder.withPageable(PageRequest.of(page, size));
// 執行搜索,獲取結果
Page<Item> items = this.repository.search(queryBuilder.build());
// 列印總條數
System.out.println(items.getTotalElements());
// 列印總頁數
System.out.println(items.getTotalPages());
// 每頁大小
System.out.println(items.getSize());
// 當前頁
System.out.println(items.getNumber());
items.forEach(System.out::println);
}

修改起始頁

@Test
public void testNativeQuery(){
// 構建查詢條件
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// 添加基本的分詞查詢
queryBuilder.withQuery(QueryBuilders.termQuery("title", "手機"));
// 初始化分頁引數
int page = 1;
int size = 3;
// 設定分頁引數
queryBuilder.withPageable(PageRequest.of(page, size));
// 執行搜索,獲取結果
Page<Item> items = this.repository.search(queryBuilder.build());
// 列印總條數
System.out.println("總條數"+items.getTotalElements());
// 列印總頁數
System.out.println("總頁數"+items.getTotalPages());
// 每頁大小
System.out.println("每頁大小"+items.getSize());
// 當前頁
System.out.println(items.getNumber());
items.forEach(System.out::println);
}

1是當前頁
6、聚合
(1)聚合為桶
桶就是分組,比如這里我們按照品牌brand進行分組:

@Test
public void testAgg(){
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
String aggName = "popularBrand";
//聚合
// AggregationBuilders.terms("popularBrand").field("brand")
// terms聚合型別(查詢關鍵字) popularBrand聚合名稱 brand聚合欄位
queryBuilder.addAggregation(AggregationBuilders.terms(aggName).field("brand"));
//查詢并回傳帶聚合結果
AggregatedPage<Item> result = template.queryForPage(queryBuilder.build(), Item.class);
//決議聚合
Aggregations aggs = result.getAggregations();//得到了當前查詢的JSON集合
//獲取指定名稱的聚合
StringTerms terms = aggs.get(aggName);
//獲取桶
List<StringTerms.Bucket> buckets = terms.getBuckets();
for (StringTerms.Bucket bucket : buckets) {
System.out.println("bucket.getKeyAsString() = "+bucket.getKeyAsString());
System.out.println("bucket.getDocCount() = "+bucket.getDocCount());
}
}
結果


(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.repository.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());
}
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/295365.html
標籤:其他
上一篇:Hive中的資料型別
