前几天安装了elasticsearch7.6.1,今天准备实践下spring-data-elasticsearch,没想到4.0改动大资料少,全靠官方文档撑着
文章目录
搭建环境
进入spring官网,了解一下spring-data-elasticsearch版本
从上面可以看到,目前版本为3.2.5,但是点进去看后发现,这个版本并不适用于elasticsearch7.6.1,而适用于6.8.6.
而我们真正需要使用的是spring-data-elasticsearch4.0以上
与spring boot2.3以上
所以在maven中的pom要导入如下依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.M3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<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>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
编写yml配置
配置es
#配置es
spring:
elasticsearch:
rest:
uris: 192.168.231.128:9200 #配置节点地址数组
application:
name: search-service
上面给出的节点地址配置和旧版本的配置可能有所不同,我用网上的如下配置方式,无法成功启动spring-data-elasticsearch
下面为部分可以进行的配置选项
创建实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(indexName = "goods",shards = 1,replicas = 0)
public class Item implements Serializable {
@Id
Long id;
@Field(type = FieldType.Text,analyzer = "ik_max_word")
String title;
@Field(type = FieldType.Keyword)
String category;
@Field(type = FieldType.Keyword)
String brand;
@Field(type = FieldType.Double)
Double price;
@Field(type = FieldType.Keyword,index = false)//不会对图片地址查询,指定为false
String images;
}
可以注意到有关实体类的注释:
- 为需要使用索引库的实体类加上注解
@Document
部分属性如下indexName="索引库名"
shards = 分片数量(默认1)
replicas = 副本数量(默认1)
- 为id属性 添加
@Id
注释 - 各个字段加上注解并制定类型
@Field
部分属性如下type= FieldType.枚举
指定字段类型 Keyword不分词, Text分词 下面为可选类型,对应着elasticsearch的字段类型
- 为需要分词的字段添加分词器
analyzer="分词器名"
(ik分词器固定写法ik_max_word
) - 是否创建索引
index=boolean(默认true)
例如样例中的图片地址不需要创建索引
基于Spring Data的CRUD
自定义接口继承ElasticsearchRepository<类名,id类型>
public interface ItemRepository extends ElasticsearchRepository<Item,Long> {
}
下面通过文档可以发现两种建立查询的方式:
直接从方法名称派生查询
ElasticsearchRepository的父类已经写好了部分原生查询,这里有部分已被弃用的查询方法(例如:search
)就不演示了
编写测试类
注意:
测试之前要保证你的es中已经存在相应的索引库
@SpringBootTest
class EsDemoApplicationTests {
//注入jpa查询
@Autowired
private ItemRepository itemRepository;
@Test
public void testSaveAll2() {
List<Item> list = new ArrayList<>();
list.add(new Item(1L,"OPPOFindX2","手机","OPPO",4999d,"http://image.leyou.com/13123.jpg"));
list.add(new Item(2L,"OPPOFindX","手机","OPPO",3999d,"http://image.leyou.com/13123.jpg"));
list.add(new Item(3L,"OPPORENO","手机","OPPO",2999d,"http://image.leyou.com/13123.jpg"));
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"));
itemRepository.saveAll(list);
Iterable<Item> all = itemRepository.findAll();
all.forEach(System.out::println);
}
}
saveAll():
通过传入对象列表的方式保存多个文档
findAll():
查询索引库中所有文档
还有部分find
,delete
相关方法就不演示了
可以发现单单ElasticsearchRepository的方法是非常少的,无法满足我们的需求
但spring data会根据方法名称自动实现功能。
比如:你的方法名叫做:findByTitle,那么它就知道你是根据title查询,然后自动帮你完成,无需写实现类。
例如: 向接口中自定义两个方法
public interface ItemRepository extends ElasticsearchRepository<Item,Long> {
/**
* 不需要实现
*/
List<Item> findByTitle(String title);
/**
* 范围查item
* @param left
* @param right
* @return
*/
List<Item> findByPriceBetween(Double left,Double right);
}
其中提供了大量的自定义模板供我们使用
方法的返回值也可以为stream流对象
返回stream,有利于我们对返回数据进一步的操作
返回类型也可以是其他集合类型
自定义的查询
例:
/**
* match查询并设置operator
* @param title
* @param operator
* @return
*/
@Query("{\"match\": {\"title\":{ \"query\": \"?0\",\"operator\":\"?1\"}}}")
Item findByTitleOperator(String title,String operator);
自定义查询: 在@Query
中写出你的查询json,占位符?0
与?1
是方法的参数
调用方式与上一种一样,但是可以发现手写json还是非常麻烦的
ElasticsearchRestTemplate的使用
我们可以发现ElasticsearchRestTemplate使用高级REST客户端,继承了增删改查接口,其中还有创建HTTP请求的工厂对象
indexOperations 索引库相关操作
下面使用ElasticsearchRestTemplate对象indexOps
方法,创建indexOperations
的实现类对象并创建索引库
- 注入ElasticsearchRestTemplate
- 设置索引信息
indexOps()
传入类的字节码文件,返回IndexOperations
接口的实现DefaultIndexOperations
,这个类实现了索引的CRUD与http请求
create()
创建索引库indexOperations.createMapping()
创建映射indexOperations.putMapping(mapping);
将创建的映射写入索引库
@SpringBootTest
class EsDemoApplicationTests {
@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate
/**
* 创建索引库
*/
@Test
void textIndex() {
//设置索引信息(绑定实体类) 返回IndexOperations
IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Item.class);
//创建索引库
indexOperations.create();
//Creates the index mapping for the entity this IndexOperations is bound to.
//为该IndexOperations绑定到的实体创建索引映射。 有一个为给定类创建索引的重载,需要类的字节码文件
Document mapping = indexOperations.createMapping();
//writes a mapping to the index 将刚刚通过类创建的映射写入索引
indexOperations.putMapping(mapping);
}
}
通过indexOperations
还能判断索引库是否存在,删除索引库等等
有关Query的构造器
经过查看结构发现Query接口有一个抽象实现和三个实现
那我们在使用时真的要new NativeSearchQuery()
吗?
可以通过new NativeSearchQueryBuilder()
来构建NativeSearchQuery
对象
NativeSearchQuery
中有众多的方法来为我们实现复杂的查询与筛选等操作
其中的build()
返回NativeSearchQuery
,所以,在众多的筛选条件之后别忘了加上build()
例如查询withQuery
,过滤withFilter
,排序withSort
等等符合es语法的操作
QueryBuilders构造复杂查询条件
我们需要在这里传入一个QueryBuilder
,可以用QueryBuilders
构造QueryBuilder
对象
下面的查询实现,对应了es的各种查询
例
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", "OPPOFindX");
NativeSearchQuery query = nativeSearchQueryBuilder.withQuery(matchQueryBuilder).build();
DocumentOperations文档相关操作
delete()
删除文档
- 其中
IndexCoordinates
为封装索引库名称的不可变值对象, 用IndexCoordinates.of("索引库名")
来构造该对象 - 前4个重载返回的是影响条数String型,注意传入的id也是String
@Test
void testDelete1(){
String count = elasticsearchRestTemplate.delete(1 + "", IndexCoordinates.of("goods"));
System.out.println(count);
}
- 最后一个重载传入上面提到的
Query对象
,索引类的字节码
,索引库对象
@Test
void testDelete2(){
elasticsearchRestTemplate.delete(
new NativeSearchQueryBuilder().withQuery(
QueryBuilders.matchQuery("title", "OPPOFindX")
).build(),Item.class,IndexCoordinates.of("goods"));
SearchHits<Item> search = elasticsearchRestTemplate.search(new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchAllQuery()).build(), Item.class);
search.forEach(System.out::println);
}
save()
保存/新增文档
save()
新增/更新方法:可以传入集合,单个或者多个实体类对象,返回更新后的对象或者集合
@Test
void testSaveRest(){
List<Item> list = new ArrayList<>();
list.add(new Item(1L,"OPPOFindX2","手机","OPPO",4999d,"http://image.leyou.com/13123.jpg"));
list.add(new Item(2L,"OPPOFindX","手机","OPPO",3999d,"http://image.leyou.com/13123.jpg"));
list.add(new Item(3L,"OPPORENO","手机","OPPO",2999d,"http://image.leyou.com/13123.jpg"));
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"));
Iterable<Item> save = elasticsearchRestTemplate.save(list);
save.forEach(System.out::println);
}
SearchOperations查询相关操作
与DocumentOperations中的部分查询方法不同的是,SearchOperations返回的是下面两个对象
这两个对象应该是4.0新增的,两个对象也很好理解
search()
返回元数据
基本查询
@Test
void testSearch1() {
//利用构造器建造NativeSearchQuery 他可以添加条件,过滤,等复杂操作
NativeSearchQuery query = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchQuery("title", "OPPOFindX"))
.build();
//elasticsearchRestTemplate.search方法参数一,本机查询的构造,参数二index的类,可选参数三再次声明库名(可以多个)
SearchHits<Item> search = elasticsearchRestTemplate.search(query, Item.class);
search.forEach(searchHit-> System.out.println(searchHit.getContent()));
}
排序分页查询
SortBuilders.fieldSort("排序字段").order(SortOrder.ASC/DESC) :
分页后的排序
PageRequest.of(当前页,每页条数):
注意起始页为0
@Test
void testNativeSearchQueryBuilder2() {
NativeSearchQuery query = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchQuery("category", "手机"))
//添加分页 注意页码是从0开始的
//pageable的实现类PageRequest的静态方法of
//要排序就增加参数3 Sort.Direction.ASC升 Sort.Direction.DESC降
.withPageable(PageRequest.of(1,4))
//排序整体
//根据字段排序fieldSort("字段名") .order(SortOrder.ASC/DESC)
.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC))
.build();
//elasticsearchRestTemplate.search方法参数一,本机查询的构造,参数二index的类,可选参数三再次声明库名(可以多个)
SearchHits<Item> search = elasticsearchRestTemplate.search(query, Item.class);
search.forEach(searchHit-> System.out.println(searchHit.getContent()));
}
聚合查询
下面聚合查各品牌的产品数量:
AggregationBuilders
来建立聚合对象,可选多种聚合方式
例如字段聚合
:terms
中放聚合名,field
中放聚合字段
getAggregations()
从searchHits中获取聚合结果,聚合结果为Map,键为聚合名,值为聚合结果
@Test
void testAgg1(){
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
//聚合可以有多个,所以add
//terms词条聚合,传入聚合名称 field("聚合字段") size(结果集大小)
NativeSearchQuery query = nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("brands").field("brand"))
//结果集过滤 这里设置不需要结果集(不添加包含与不包含,会自动生成length为0数组)
.withSourceFilter(new FetchSourceFilterBuilder().build())
.build();
SearchHits<Item> hits = elasticsearchRestTemplate.search(query, Item.class);
System.out.println(hits);
//获取聚合结果集 因为结果为字符串类型 所以用ParsedStringTerms接收 还有ParsedLongTerms接收数字 ParsedDoubleTerms接收小数
Aggregations aggregations = hits.getAggregations();
assert aggregations != null;
ParsedStringTerms brands = aggregations.get("brands");
//获取桶
brands.getBuckets().forEach(bucket->{
//获取桶中的key 与 记录数
System.out.println(bucket.getKeyAsString()+" "+bucket.getDocCount());
});
}
上图为常见的聚合查询结果类,如果无法找到可以通过sout
的方式打印出类型
嵌套聚合查询
下面查出各品牌的产品数量后再查出各品牌产品均价:
添加子聚合 subAggregation
(添加方式和上面是一样的)
获取自聚合 在父聚合的桶中用getAggregations()
获取子聚合
@Test
void testAgg2(){
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
//聚合可以有多个,所以add
//terms词条聚合,传入聚合名称 field("聚合字段")
NativeSearchQuery query = nativeSearchQueryBuilder
.addAggregation(
AggregationBuilders
.terms("brands")
.field("brand")
//添加子聚合 subAggregation(添加方式是一样的) 值为桶中品牌均价
.subAggregation(AggregationBuilders.avg("price_avg").field("price"))
)
//结果集过滤 这里设置不需要结果集(不添加包含与不包含,会自动生成长为0数组)
.withSourceFilter(new FetchSourceFilterBuilder().build())
.build();
SearchHits<Item> hits = elasticsearchRestTemplate.search(query, Item.class);
System.out.println(hits);
//获取聚合结果集 因为结果为字符串类型 所以用ParsedStringTerms接收 还有ParsedLongTerms接收数字 ParsedDoubleTerms接收小数
Aggregations aggregations = hits.getAggregations();
assert aggregations != null;
ParsedStringTerms brands = aggregations.get("brands");
//获取桶brands
brands.getBuckets().forEach(bucket->{
//获取桶中的key 与 记录数
System.out.println(bucket.getKeyAsString()+" "+bucket.getDocCount());
//获取嵌套的桶price_avg
ParsedAvg price_avg = bucket.getAggregations().get("price_avg");
System.out.println(price_avg.getValue());
});
}
测试类代码集合
@SpringBootTest
class EsDemoApplicationTests {
//是使用高级REST客户端的ElasticsearchOperations接口的实现。
@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;
//注入jpa查询
@Autowired
private ItemRepository itemRepository;
/**
* 创建索引库
* indexOps返回了DefaultIndexOperations基于高级代理实现了IndexOperations接口
*/
@Test
void textIndex() {
//设置索引信息(绑定实体类) 返回IndexOperations
IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Item.class);
//创建索引库
indexOperations.create();
//Creates the index mapping for the entity this IndexOperations is bound to.
//为该IndexOperations绑定到的实体创建索引映射。 有一个为给定类创建索引的重载,需要类的字节码文件
//返回创建的索引
Document mapping = indexOperations.createMapping();
System.out.println(mapping);
//writes a mapping to the index
//将刚刚通过类创建的映射写入索引
indexOperations.putMapping(mapping);
//delete()
//Deletes the index this IndexOperations is bound to
//exists() Checks if the index this IndexOperations is bound to exists
}
/**
* save方法进行数据的新增,和修改 有相同id就是修改,无相同id就是新增
*/
@Test
void testSave() {
Item item=new Item(1L,"OPPOFindX2","手机","OPPO",4999d,"http://image.leyou.com/13123.jpg");
Item saveItem = itemRepository.save(item);
System.out.println(saveItem);
Iterable<Item> all = itemRepository.findAll();
all.forEach(System.out::println);
}
@Test
void test() {
Item item = itemRepository.findByTitleOperator("小米手机7","and");
System.out.println(item);
}
/**
* saveAll方法进行批量数据的新增,和修改 有相同id就是修改,无相同id就是新增
* findAll查所有
*/
@Test
public void testSaveAll() {
List<Item> list = new ArrayList<>();
list.add(new Item(1L,"OPPOFindX2","手机","OPPO",4999d,"http://image.leyou.com/13123.jpg"));
list.add(new Item(2L,"OPPOFindX","手机","OPPO",3999d,"http://image.leyou.com/13123.jpg"));
list.add(new Item(3L,"OPPORENO","手机","OPPO",2999d,"http://image.leyou.com/13123.jpg"));
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"));
itemRepository.saveAll(list);
Iterable<Item> all = itemRepository.findAll();
all.forEach(System.out::println);
}
/**
* delete相关方法删除
*/
/**
*findById
*/
@Test
void testFindById(){
Item byId = itemRepository.findById(2L).get();
System.out.println(byId);
}
@Test
void testFindByTitle() {
List<Item> items = itemRepository.findByTitle("OPPOFindX");
System.out.println(items);
}
@Test
void testFindByPriceBetween() {
List<Item> items = itemRepository.findByPriceBetween(1000d, 8000d);
items.forEach(System.out::println);
}
//elasticsearchRestTemplate
/**
* delete删除文档
*/
@Test
void testDelete1(){
String count = elasticsearchRestTemplate.delete(1 + "", IndexCoordinates.of("goods"));
System.out.println(count);
}
@Test
void testDelete2(){
elasticsearchRestTemplate.delete(
new NativeSearchQueryBuilder().withQuery(
QueryBuilders.matchQuery("title", "OPPOFindX")
).build(),Item.class,IndexCoordinates.of("goods"));
SearchHits<Item> search = elasticsearchRestTemplate.search(new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchAllQuery()).build(), Item.class);
search.forEach(System.out::println);
}
/**
* save
*/
@Test
void testSaveRest(){
List<Item> list = new ArrayList<>();
list.add(new Item(1L,"OPPOFindX2","手机","OPPO",4999d,"http://image.leyou.com/13123.jpg"));
list.add(new Item(2L,"OPPOFindX","手机","OPPO",3999d,"http://image.leyou.com/13123.jpg"));
list.add(new Item(3L,"OPPORENO","手机","OPPO",2999d,"http://image.leyou.com/13123.jpg"));
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"));
Iterable<Item> save = elasticsearchRestTemplate.save(list);
save.forEach(System.out::println);
}
/**
* 采用elasticsearchRestTemplate查询
*/
@Test
void testSearch1() {
//利用构造器建造NativeSearchQuery 他可以添加条件,过滤,等复杂操作
NativeSearchQuery query = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchQuery("title", "OPPOFindX"))
.build();
//elasticsearchRestTemplate.search方法参数一,本机查询的构造,参数二index的类,可选参数三再次声明库名(可以多个)
SearchHits<Item> search = elasticsearchRestTemplate.search(query, Item.class);
search.forEach(searchHit-> System.out.println(searchHit.getContent()));
}
/**
* 分页
*/
@Test
void testNativeSearchQueryBuilder2() {
NativeSearchQuery query = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchQuery("category", "手机"))
//添加分页 注意页码是从0开始的
//pageable的实现类PageRequest的静态方法of
//要排序就增加参数3 Sort.Direction.ASC升 Sort.Direction.DESC降
.withPageable(PageRequest.of(1,4))
//排序整体
//根据字段排序fieldSort("字段名") .order(SortOrder.ASC/DESC)
.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC))
.build();
//elasticsearchRestTemplate.search方法参数一,本机查询的构造,参数二index的类,可选参数三再次声明库名(可以多个)
SearchHits<Item> search = elasticsearchRestTemplate.search(query, Item.class);
search.forEach(searchHit-> System.out.println(searchHit.getContent()));
}
/**
* 聚合 品牌
*/
@Test
void testAgg1(){
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
//聚合可以有多个,所以add
//terms词条聚合,传入聚合名称 field("聚合字段") size(结果集大小)
NativeSearchQuery query = nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("brands").field("brand"))
//结果集过滤 这里设置不需要结果集(不添加包含与不包含,会自动生成长为0数组)
.withSourceFilter(new FetchSourceFilterBuilder().build())
.build();
SearchHits<Item> hits = elasticsearchRestTemplate.search(query, Item.class);
System.out.println(hits);
//获取聚合结果集 因为结果为字符串类型 所以用ParsedStringTerms接收 还有ParsedLongTerms接收数字 ParsedDoubleTerms接收小数
Aggregations aggregations = hits.getAggregations();
assert aggregations != null;
ParsedStringTerms brands = aggregations.get("brands");
//获取桶
brands.getBuckets().forEach(bucket->{
//获取桶中的key 与 记录数
System.out.println(bucket.getKeyAsString()+" "+bucket.getDocCount());
});
}
/**
* 聚合嵌套 品牌
*/
@Test
void testAgg2(){
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
//聚合可以有多个,所以add
//terms词条聚合,传入聚合名称 field("聚合字段")
NativeSearchQuery query = nativeSearchQueryBuilder
.addAggregation(
AggregationBuilders
.terms("brands")
.field("brand")
//添加子聚合 subAggregation(添加方式是一样的) 值为桶中品牌均价
.subAggregation(AggregationBuilders.avg("price_avg").field("price"))
)
//结果集过滤 这里设置不需要结果集(不添加包含与不包含,会自动生成长为0数组)
.withSourceFilter(new FetchSourceFilterBuilder().build())
.build();
SearchHits<Item> hits = elasticsearchRestTemplate.search(query, Item.class);
System.out.println(hits);
//获取聚合结果集 因为结果为字符串类型 所以用ParsedStringTerms接收 还有ParsedLongTerms接收数字 ParsedDoubleTerms接收小数
Aggregations aggregations = hits.getAggregations();
assert aggregations != null;
ParsedStringTerms brands = aggregations.get("brands");
//获取桶brands
brands.getBuckets().forEach(bucket->{
//获取桶中的key 与 记录数
System.out.println(bucket.getKeyAsString()+" "+bucket.getDocCount());
//获取嵌套的桶price_avg
ParsedAvg price_avg = bucket.getAggregations().get("price_avg");
System.out.println(price_avg.getValue());
});
}
}