Elasticsearch
创始人
2024-03-01 00:13:49
0

一、Spring Data
1、简介
Spring Data 是一个用于简化数据库、非关系型数据库、索引库访问,并支持云服务的开源框架。Spring Data 可以极大的简化JPA的写法,可以在几乎不用写实现的情况下,实现对数据库的访问和操作。除了 CRUD 之外,还包括如分页、排序等一下常用的功能。

2、Spring Data 的官网
https://spring.io/projects/spring-data

二、java 集成 Spring Data Elasticsearch 操作 es
1、pom依赖(spring boot 版本 2.4.1)

org.springframework.bootspring-boot-starter-data-elasticsearch

备注:
spring-data-elasticsearch 版本 4.1.1
elasticsearch 版本 7.11.1
elasticsearch-rest-high-level-client 版本 7.11.1
在这里插入图片描述

2、application.yml 配置文件

server:port: 8015spring:application:name: test-15-elasticsearchelasticsearch:rest:# es 连接地址,多个用逗号隔开uris: 192.168.3.56:9200,192.168.3.57:9200,192.168.3.58:9200username: spadgerpassword: spadger# 连接超时时间,单位毫秒,默认1sconnection-timeout: 1000# 读取超时时间,单位毫秒,默认30sread-timeout: 1000

3、Product 实体类代码

package com.test.elasticsearch.entity;import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;import java.io.Serializable;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;/*** indexName    指定索引名* shards       指定分片(无特殊配置,默认即可)* replicas     指定副本集(无特殊配置,默认即可)*/
@Data
@Document(indexName = "product", shards = 1, replicas = 1)
public class Product implements Serializable {private static final long serialVersionUID = 551589397625941751L;@Idprivate Long id;//商品唯一标识@Field(type = FieldType.Text)private String title;//商品名称@Field(type = FieldType.Keyword)private String category;//商品分类@Field(type = FieldType.Double)private Double price;//商品价格@Field(type = FieldType.Keyword, index = false)//index = false 表示该字段不能作为查询条件private String images;//图片地址}

4、ElasticsearchRestTemplate 客户端测试类

package com.test.elasticsearch;import com.test.elasticsearch.entity.Product;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.MatchPhraseQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
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.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
import org.springframework.data.elasticsearch.core.query.UpdateResponse;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;/*** 使用 Spring Data Elasticsearch 操作 es 索引库* ElasticsearchRestTemplate 客户端测试*/
@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)//不加这个注解 service层 就无法注入
@SpringBootTest
public class SpringDataESIndexTest {@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;/*** 创建索引*/@Testpublic void createIndex() {/*** 方式一:指定索引库名称创建索引(只会创建一个名为 product 的索引库,不会创建映射)* 存在问题:创建索引之后,删除索引,再重新创建的时候,会报错 "reason":"index [product/906Vi3zzRaKb1zJaIKzvtg] already exists"* 报错原因:分词器反复创建:先用standard分词器建的index,然后使用ik分词器又建索引出现这个错误,相当于对已有的 index 修改 mapping* 报错解决办法:不创建索引就好了。如果已经删除掉了 product 索引库,es里是没有 product 索引的。但实体类  Product 里有"indexName = “product”",你往索引里插入数据时,索引就自动存在了*/IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(IndexCoordinates.of("product"));boolean result = indexOperations.create();System.out.println("创建索引结果:" + result);boolean putMappingResult = indexOperations.putMapping(Product.class);System.out.println("索引映射添加结果:" + putMappingResult);/*** 方式二:指定实体类创建索引(创建一个名为 product 的索引库,同时会自动创建映射,映射关系就对应实体类 Product.class 的属性)* 存在问题:创建索引之后,删除索引,再重新创建的时候,会报错 "reason":"index [product/906Vi3zzRaKb1zJaIKzvtg] already exists"* 报错原因:分词器反复创建:先用standard分词器建的index,然后使用ik分词器又建索引出现这个错误,相当于对已有的 index 修改 mapping* 报错解决办法:不创建索引就好了。如果已经删除掉了 product 索引库,es里是没有 product 索引的。但实体类  Product 里有"indexName = “product”",你往索引里插入数据时,索引就自动存在了*/
//    IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Product.class);
//    boolean result = indexOperations.create();
//    System.out.println("创建索引结果:" + result);}/*** 根据索引名称判断索引是否存在*/@Testpublic void existsIndex() {//方式一:单纯的根据索引库名称进行判断boolean result01 = elasticsearchRestTemplate.indexOps(IndexCoordinates.of("product")).exists();System.out.println("索引是否存在:" + result01);//方式二:根据索引库对应的实体类,也就是加了 @Document(indexName = "product", shards = 1, replicas = 1) 注解的实体类进行判断boolean result02 = elasticsearchRestTemplate.indexOps(Product.class).exists();System.out.println("索引是否存在:" + result02);}/*** 根据索引名称删除索引库*/@Testpublic void deleteIndex() {boolean result = false;IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Product.class);System.out.println("索引是否存在:" + indexOperations.exists());if (indexOperations.exists()) {result = indexOperations.delete();}System.out.println("删除结果:" + result);System.out.println("索引是否存在:" + indexOperations.exists());}/*** 创建文档(索引库插入数据)* 注意:* ① 假如索引库 product 不存在,在添加文档的时候会自动创建 product 索引库,索引库信息会和 Product.class 中的各个属性一一对应* ② 创建文档的时候如果指定了id,则会使用指定的id,如果没有指定文档id,es默认会自动创建一个uuid作为文档id* ③ 创建文档的时候如果指定了id,并且该文档已经存在,则默认为更新操作*/@Testpublic void createDocument() {Product product = new Product();product.setId(1001L);product.setTitle("小米 S12");product.setImages("F:\\pictures\\yy测试下载图片.jpg");product.setPrice(3688.99);product.setCategory("手机");Product saveResult = elasticsearchRestTemplate.save(product);System.out.println("文档新增,指定id,创建结果:" + saveResult);Product product01 = new Product();product01.setTitle("一加 T3");product01.setImages("F:\\pictures\\yy测试下载图片.jpg");product01.setPrice(4666.88);product01.setCategory("手机");Product saveResult01 = elasticsearchRestTemplate.save(product01);System.out.println("文档新增,不指定id,创建结果:" + saveResult01);}/*** 批量创建文档(索引库批量插入数据)* 注意:* ① 假如索引库 product 不存在,在添加文档的时候会自动创建 product 索引库,索引库信息会和 Product.class 中的各个属性一一对应* ② 创建文档的时候如果指定了id,则会使用指定的id,如果没有指定文档id,es默认会自动创建一个uuid作为文档id* ③ 创建文档的时候如果指定了id,并且该文档已经存在,则默认为更新操作*/@Testpublic void createDocumentList() {List list = new ArrayList<>();Product product01 = new Product();product01.setId(1001L);product01.setTitle("小米 S12");product01.setImages("F:\\pictures\\yy测试下载图片.jpg");product01.setPrice(3688.99);product01.setCategory("手机");list.add(product01);Product product02 = new Product();product02.setId(1003L);product02.setTitle("一加 T3");product02.setImages("F:\\pictures\\yy测试下载图片.jpg");product02.setPrice(4666.88);product02.setCategory("手机");Product product03 = new Product();list.add(product02);product03.setId(1002L);product03.setTitle("S11");product03.setImages("F:\\pictures\\yy测试下载图片.jpg");product03.setPrice(2999.99);product03.setCategory("小米手机");list.add(product03);Iterable saveResult = elasticsearchRestTemplate.save(list);System.out.println("文档批量新增,创建结果:" + saveResult);}/*** 根据文档id判断文档是否存在*/@Testpublic void existsDocument() {boolean result = elasticsearchRestTemplate.exists("1001", Product.class);System.out.println("文档是否存在:" + result);}/*** 根据文档id删除文档*/@Testpublic void deleteDocument() {String result = elasticsearchRestTemplate.delete("j07wvIQBG2vb63j9iSAY", Product.class);System.out.println("根据文档id删除,结果::" + result);}/*** 根据查询条件批量删除文档*/@Testpublic void deleteDocumentByQueryCondition() {QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders.queryStringQuery("小米");NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(queryStringQueryBuilder);elasticsearchRestTemplate.delete(nativeSearchQuery, Product.class);System.out.println("根据查询条件批量删除文档!!!");}/*** 批量修改文档*/@Testpublic void updateDocumentList() {List list = new ArrayList<>();Product product01 = new Product();product01.setId(1003L);product01.setTitle("一加 T3");product01.setImages("F:\\pictures\\yy测试下载图片.jpg");product01.setPrice(4688.88);product01.setCategory("手机");list.add(product01);Product product03 = new Product();product03.setId(1004L);product03.setTitle("一加 T3 PRO");product03.setImages("F:\\pictures\\yy测试下载图片.jpg");product03.setPrice(5499.99);product03.setCategory("手机");list.add(product03);Iterable saveResult = elasticsearchRestTemplate.save(list);System.out.println("批量修改文档,结果:" + saveResult);}/*** 局部修改文档*/@Testpublic void updateDocument() {//ctx._source 为固定内容,title、price 为文档属性名称(字段名)String script = "ctx._source.title='小米 S12 PRO';ctx._source.price=3999.99";//根据文档id修改文档指定内容UpdateQuery updateQuery = UpdateQuery.builder("1001").withScript(script).build();IndexCoordinates indexCoordinates = IndexCoordinates.of("product");UpdateResponse updateResponse = elasticsearchRestTemplate.update(updateQuery, indexCoordinates);System.out.println("局部修改文档,结果:" + updateResponse);}/*** 查询文档 -- 查询全部*/@Testpublic void searchDocumentMatchAll() {MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(matchAllQueryBuilder);SearchHits searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Product.class);List list = new ArrayList<>();System.out.println("查询文档,查询全部,查询总数:" + searchHits.getTotalHits());searchHits.forEach(sh -> {list.add(sh.getContent());});System.out.println("查询文档,查询全部,结果集:" + list);}/*** 查询文档 -- 根据文档id查询*/@Testpublic void searchDocumentById() {Product product = elasticsearchRestTemplate.get("1001", Product.class);System.out.println("查询文档,根据文档id查询,结果集:" + product);}/*** 查询文档 -- 模糊查询*/@Testpublic void searchDocumentLike() {//QueryBuilders.queryStringQuery("小米") 这种查询方式不指定匹配的字段,默认根据文档中除id外的第一个字段进行匹配,并且只会通过这一个字段进行匹配,而且查询条件会被分词,根据分词后的结果进行匹配QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders.queryStringQuery("小米");NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(queryStringQueryBuilder);SearchHits searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Product.class);List list = new ArrayList<>();System.out.println("查询文档,模糊查询,查询总数:" + searchHits.getTotalHits());searchHits.forEach(sh -> {list.add(sh.getContent());});System.out.println("查询文档,模糊查询,结果集:" + list);}/*** 查询文档 -- 使用 match 查询 -- 模糊查询*/@Testpublic void searchDocumentMatch() {//QueryBuilders.matchQuery("title", "小米") 指定具体的匹配字段,查询条件会被分词,根据分词后的结果进行匹配MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", "小米");NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(matchQueryBuilder);SearchHits searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Product.class);List list = new ArrayList<>();System.out.println("查询文档,使用 match 查询,模糊查询,查询总数:" + searchHits.getTotalHits());searchHits.forEach(sh -> {list.add(sh.getContent());});System.out.println("查询文档,使用 match 查询,模糊查询,结果集:" + list);}/*** 查询文档 -- 使用 match 查询 -- 模糊查询之短语搜索* 备注:短语搜索是对条件不分词,但是文档中属性根据配置实体类时指定的分词类型进行分词,如果属性使用ik分词器,从分词后的索引数据中进行匹配。*/@Testpublic void searchDocumentMatchPhrase() {//QueryBuilders.matchPhraseQuery("title", "小米") 指定具体的匹配字段为 title,查询条件不分词,直接匹配MatchPhraseQueryBuilder matchPhraseQueryBuilder = QueryBuilders.matchPhraseQuery("title", "小米");NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(matchPhraseQueryBuilder);SearchHits searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Product.class);List list = new ArrayList<>();System.out.println("查询文档,使用 match 查询,模糊查询,查询总数:" + searchHits.getTotalHits());searchHits.forEach(sh -> {list.add(sh.getContent());});System.out.println("查询文档,使用 match 查询,模糊查询,结果集:" + list);}/*** 查询文档 -- 区间查询* 备注:短语搜索是对条件不分词,但是文档中属性根据配置实体类时指定的分词类型进行分词,如果属性使用ik分词器,从分词后的索引数据中进行匹配。*/@Testpublic void searchDocumentRange() {//QueryBuilders.rangeQuery("price") 根据 price 字段进行区间查询。gte():大于等于,lte():小于等于,gt():大于,lt():小于。RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("price").gte(4688.88D).lte(6000D);//gte(4688.88D) 和 gte(4688.88) 效果相同NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(rangeQueryBuilder);SearchHits searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Product.class);List list = new ArrayList<>();System.out.println("查询文档,区间查询,查询总数:" + searchHits.getTotalHits());searchHits.forEach(sh -> {list.add(sh.getContent());});System.out.println("查询文档,区间查询,结果集:" + list);}/*** 查询文档 -- 简单多条件查询* 实例:查询商品名称中包含 “米” 字,且价格大于等于 2555.88 的所有商品*/@Testpublic void searchDocumentMoreCondition() {//QueryBuilders.rangeQuery("price") 根据 price 字段进行区间查询。gte():大于等于,lte():小于等于,gt():大于,lt():小于。List queryBuilderList = new ArrayList<>();BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();queryBuilderList.add(QueryBuilders.matchQuery("title","米"));//商品名称 中要包含 “米” 字queryBuilderList.add(QueryBuilders.rangeQuery("price").gte(2555.88));//商品价格 要大于等于 2555.88
//    boolQueryBuilder.must().addAll(queryBuilderList);//逻辑 与(and -- 多个条件都要满足)boolQueryBuilder.should().addAll(queryBuilderList);//逻辑 或(or -- 多个条件满足其一即可)NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(boolQueryBuilder);SearchHits searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Product.class);List list = new ArrayList<>();System.out.println("查询文档,简单多条件查询,查询总数:" + searchHits.getTotalHits());searchHits.forEach(sh -> {list.add(sh.getContent());});System.out.println("查询文档,简单多条件查询,结果集:" + list);}/*** 查询文档 -- 复杂多条件查询* 实例:查询商品名称包含 “小米” 或者 “一加”,并且商品类型为 “手机” 的所有商品*/@Testpublic void searchDocumentMoreConditionOther() {//封装第一个查询条件List queryBuilderList01 = new ArrayList<>();BoolQueryBuilder boolQueryBuilder01 = QueryBuilders.boolQuery();queryBuilderList01.add(QueryBuilders.matchQuery("title","小米"));//商品名称 中要包含 “小米” 关键字queryBuilderList01.add(QueryBuilders.matchQuery("category","手机"));//商品类型 要是 “手机”boolQueryBuilder01.must().addAll(queryBuilderList01);//逻辑 与(and -- 多个条件都要满足)//封装第二个查询条件List queryBuilderList02 = new ArrayList<>();BoolQueryBuilder boolQueryBuilder02 = QueryBuilders.boolQuery();queryBuilderList02.add(QueryBuilders.matchQuery("title","一加"));//商品名称 中要包含 “一加” 关键字queryBuilderList02.add(QueryBuilders.matchQuery("category","手机"));//商品类型 要是 “手机”boolQueryBuilder02.must().addAll(queryBuilderList02);//逻辑 与(and -- 多个条件都要满足)//将 条件一 和 条件二 封装到 条件三 中,再使用 条件三 作为最后的查询条件List queryBuilderList03 = new ArrayList<>();BoolQueryBuilder boolQueryBuilder03 = QueryBuilders.boolQuery();queryBuilderList03.add(boolQueryBuilder01);queryBuilderList03.add(boolQueryBuilder02);boolQueryBuilder03.should().addAll(queryBuilderList03);//逻辑 或(or -- 多个条件满足其一即可)//使用 条件三 作为最后的查询条件进行查询NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(boolQueryBuilder03);SearchHits searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Product.class);List list = new ArrayList<>();System.out.println("查询文档,复杂多条件查询,查询总数:" + searchHits.getTotalHits());searchHits.forEach(sh -> {list.add(sh.getContent());});System.out.println("查询文档,复杂多条件查询,结果集:" + list);}/*** 查询文档 -- 分页与排序* 实例:查询商品名称中包含 “米” 字,且价格大于等于 2555.88 的所有商品*/@Testpublic void searchDocumentPageAndOrder() {MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();Query query = new NativeSearchQuery(matchAllQueryBuilder);//排序(Direction.ASC:升序;Direction.DESC:降序)query.addSort(Sort.by(Direction.ASC,"id"));//分页(起始页:0)query.setPageable(PageRequest.of(0,2));SearchHits searchHits = elasticsearchRestTemplate.search(query, Product.class);List list = new ArrayList<>();System.out.println("查询文档,分页与排序,查询总数:" + searchHits.getTotalHits() + ",当前页的数量:" + searchHits.getSearchHits().size());searchHits.forEach(sh -> {list.add(sh.getContent());});System.out.println("查询文档,分页与排序,结果集:" + list);}/*** 查询文档 -- 去重* 实例:查询商品名称中包含 “米” 字,且价格大于等于 2555.88 的所有商品* 注意:去重的字段不能是 text 类型*/@Testpublic void searchDocumentCollapse() {MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();boolQueryBuilder.must(matchAllQueryBuilder);nativeSearchQueryBuilder.withQuery(boolQueryBuilder);//根据商品类型 category 进行去重,去重的字段一定不能是 text 类型nativeSearchQueryBuilder.withCollapseField("category");SearchHits searchHits = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), Product.class);List list = new ArrayList<>();System.out.println("查询文档,去重,查询总数:" + searchHits.getTotalHits() + ",去重后的数量:" + searchHits.getSearchHits().size());searchHits.forEach(sh -> {list.add(sh.getContent());});System.out.println("查询文档,去重,结果集:" + list);}/*** 查询文档 -- 分组聚合* 实例:根据商品类型进行分类,查询所有类型对应的商品数量* 注意:作为聚合的字段不能是 text 类型*/@Testpublic void searchDocumentAggregations() {MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();boolQueryBuilder.must(matchAllQueryBuilder);nativeSearchQueryBuilder.withQuery(boolQueryBuilder);//AggregationBuilders.terms("product_count") 中 product_count 是分组后的结果集对应的 key,field("category") 中的 category 为分组的字段nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("product_count").field("category"));SearchHits searchHits = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), Product.class);Aggregations aggregations = searchHits.getAggregations();//分组聚合后的结果集对象ParsedStringTerms product_count = aggregations.get("product_count");Map map = new HashMap<>();System.out.println("查询文档,分组聚合,分组聚合后的结果集对象:" + product_count);for (Terms.Bucket bucket: product_count.getBuckets()) {map.put(bucket.getKeyAsString(),bucket.getDocCount());}System.out.println("查询文档,分组聚合,结果集:" + map);}}

5、User 实体类

package com.test.elasticsearch.entity;import java.util.Date;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
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
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Document(indexName = "user", shards = 1, replicas = 1)
public class User {@Id@Field(type = FieldType.Long)private Long id;@Field(type = FieldType.Text)private String name;@Field(type = FieldType.Keyword)private String sex;@Field(type = FieldType.Integer)private Integer age;@Field(type = FieldType.Keyword)private String role;@Field(type = FieldType.Date)private Date birthday;@Field(type = FieldType.Long)private Long worth;@Field(type = FieldType.Boolean)private boolean isDied;}

6、RestHighLevelClient 客户端测试类

package com.test.elasticsearch;import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.test.elasticsearch.entity.User;
import java.io.IOException;
import java.util.Date;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.FuzzyQueryBuilder;
import org.elasticsearch.index.query.IdsQueryBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.CardinalityAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.ParsedAvg;
import org.elasticsearch.search.aggregations.metrics.ParsedCardinality;
import org.elasticsearch.search.aggregations.metrics.ParsedMax;
import org.elasticsearch.search.aggregations.metrics.ParsedMin;
import org.elasticsearch.search.aggregations.metrics.ParsedStats;
import org.elasticsearch.search.aggregations.metrics.ParsedValueCount;
import org.elasticsearch.search.aggregations.metrics.StatsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
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.test.context.junit4.SpringJUnit4ClassRunner;/*** 使用 Spring Data Elasticsearch 操作 es 索引库* RestHighLevelClient 客户端测试*/
@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)//不加这个注解 service层 就无法注入
@SpringBootTest
public class SpringDataESIndexRestHighTest {@Autowiredprivate RestHighLevelClient restHighLevelClient;/*** 创建索引*/@Testpublic void restHighCreateIndex() throws IOException {//创建创建索引的请求对象CreateIndexRequest createIndexRequest = new CreateIndexRequest("user");//创建索引CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);//获取创建索引的响应状态boolean acknowledged = createIndexResponse.isAcknowledged();System.out.println("索引操作,创建索引,创建结果:" + acknowledged);}/*** 查询索引库的相关信息*/@Testpublic void restHighQueryIndexsInfo() throws IOException {GetIndexRequest getIndexRequest = new GetIndexRequest("user");GetIndexResponse getIndexResponse = restHighLevelClient.indices().get(getIndexRequest, RequestOptions.DEFAULT);//获取创建索引的响应状态//获取索引库的相关信息System.out.println("索引库的别名:" + getIndexResponse.getAliases());System.out.println("索引库的映射信息:" + JSON.toJSONString(getIndexResponse.getMappings()));System.out.println("索引库的配置信息:" + getIndexResponse.getSettings());System.out.println("索引库的默认配置信息:" + getIndexResponse.getDefaultSettings());System.out.println("不知道啥信息111:" + getIndexResponse.getIndices());System.out.println("不知道啥信息222:" + getIndexResponse.getDataStreams());}/*** 删除索引库*/@Testpublic void restHighDeleteIndex() throws IOException {GetIndexRequest getIndexRequest = new GetIndexRequest("user");System.out.println("索引操作,删除之前--判断索引是否存在,结果:" + restHighLevelClient.indices().exists(getIndexRequest,RequestOptions.DEFAULT));DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("user");AcknowledgedResponse acknowledgedResponse = restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);System.out.println("索引操作,删除索引,删除结果:" + acknowledgedResponse.isAcknowledged());System.out.println("索引操作,删除之后--判断索引是否存在,结果:" + restHighLevelClient.indices().exists(getIndexRequest,RequestOptions.DEFAULT));}/*** 索引库添加文档* 注意:* ① 如果索引库不存在,添加文档的时候,默认会自动创建索引库,前提是实体类中使用 @Document(indexName = "user", shards = 1, replicas = 1) 注解绑定了索引库* ② 如果映射关系没有创建,添加文档的时候,默认会根据实体类中 @Field(type = FieldType.Text) 注解绑定的属性自动创建映射关系*/@Testpublic void restHighAddDocument() throws IOException {IndexRequest indexRequest = new IndexRequest();indexRequest.index("user").id("1001");User user01 = new User();user01.setId(1001L);user01.setName("萧炎");user01.setSex("男");user01.setAge(18);user01.setRole("男主");//向es添加数据,必须将数据转换为json格式ObjectMapper objectMapper = new ObjectMapper();String user01Str = objectMapper.writeValueAsString(user01);indexRequest.source(user01Str, XContentType.JSON);//向索引库中插入数据IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);System.out.println("文档操作,添加文档,结果:" + indexResponse.getResult());}/*** 索引库查询文档*/@Testpublic void restHighGetDocument() throws IOException {GetRequest getRequest = new GetRequest();getRequest.index("user").id("1001");//根据文档id查询GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);System.out.println("文档操作,查询文档,结果:" + getResponse.getSourceAsString());}/*** 索引库修改文档*/@Testpublic void restHighUpdateDocument() throws IOException {UpdateRequest updateRequest = new UpdateRequest();updateRequest.index("user").id("1001");updateRequest.doc(XContentType.JSON,"id",1002L);UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);System.out.println("文档操作,修改文档,结果:" + updateResponse.getResult());}/*** 索引库删除文档*/@Testpublic void restHighDeleteDocument() throws IOException {GetRequest getRequest = new GetRequest();getRequest.index("user").id("1001");//根据文档id查询System.out.println("文档操作,删除之前 -- 判断文档是否存在,结果:" + restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT));DeleteRequest deleteRequest = new DeleteRequest();deleteRequest.index("user").id("1001");//根据文档id进行删除DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);System.out.println("文档操作,删除文档,结果:" + deleteResponse.getResult());System.out.println("文档操作,删除之后 -- 判断文档是否存在,结果:" + restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT));}/*** 索引库批量添加文档*/@Testpublic void restHighAddDocumentBatch() throws IOException {BulkRequest bulkRequest = new BulkRequest();bulkRequest.add(new IndexRequest().index("user").id("1001").source(XContentType.JSON,"name","萧炎","sex","男","age",18,"role","男主","birthday",new Date(1417251624000L),"worth",100000000L,"isDied",false));bulkRequest.add(new IndexRequest().index("user").id("1002").source(XContentType.JSON,"name","云韵","sex","女","age",25,"role","女二","birthday",new Date(867574824000L),"worth",55555555L,"isDied",false));bulkRequest.add(new IndexRequest().index("user").id("1003").source(XContentType.JSON,"name","萧熏儿","sex","女","age",18,"role","女一","birthday",new Date(1411981224000L),"worth",99999999L,"isDied",false));bulkRequest.add(new IndexRequest().index("user").id("1004").source(XContentType.JSON,"name","美杜莎","sex","女","age",25,"role","女一","birthday",new Date(858934824000L),"worth",99999999L,"isDied",false));bulkRequest.add(new IndexRequest().index("user").id("1005").source(XContentType.JSON,"name","药老","sex","男","age",55,"role","男二","birthday",new Date(-87145176000L),"worth",88888888L,"isDied",true));bulkRequest.add(new IndexRequest().index("user").id("1006").source(XContentType.JSON,"name","海波东","sex","男","age",45,"role","男三","birthday",new Date(240915624000L),"worth",66666666L,"isDied",false));bulkRequest.add(new IndexRequest().index("user").id("1007").source(XContentType.JSON,"name","石漠城萧鼎","sex","男","age",21,"role","男四","birthday",new Date(990349224000L),"worth",7895562L,"isDied",false));bulkRequest.add(new IndexRequest().index("user").id("1008").source(XContentType.JSON,"name","石漠城萧厉","sex","男","age",20,"role","男四","birthday",new Date(1026982824000L),"worth",6975898L,"isDied",false));bulkRequest.add(new IndexRequest().index("user").id("1009").source(XContentType.JSON,"name","萧战-萧族族主","sex","男","age",46,"role","男四","birthday",new Date(190198824000L),"worth",8546897L,"isDied",false));BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);System.out.println("文档操作,批量添加文档,耗时:" + bulkResponse.getTook());}/*** 索引库批量删除文档*/@Testpublic void restHighDeleteDocumentBatch() throws IOException {BulkRequest bulkRequest = new BulkRequest();bulkRequest.add(new DeleteRequest().index("user").id("1001"));bulkRequest.add(new DeleteRequest().index("user").id("1002"));bulkRequest.add(new DeleteRequest().index("user").id("1003"));bulkRequest.add(new DeleteRequest().index("user").id("1004"));bulkRequest.add(new DeleteRequest().index("user").id("1005"));bulkRequest.add(new DeleteRequest().index("user").id("1006"));BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);System.out.println("文档操作,批量删除文档,耗时:" + bulkResponse.getTook());}/*** 高级查询之全量查询*/@Testpublic void restHighSearchDocumentAll() throws IOException {SearchRequest searchRequest = new SearchRequest();searchRequest.indices("user");SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);SearchHits hits = searchResponse.getHits();System.out.println("文档操作,高级查询之全量查询,命中数量:" + hits.getTotalHits());System.out.println("文档操作,高级查询之全量查询,查询耗时:" + searchResponse.getTook());SearchHit[] result = hits.getHits();for (SearchHit searchHit: result) {System.out.println("文档操作,高级查询之全量查询,id:" + searchHit.getId() + ",内容:" + searchHit.getSourceAsString());}}/*** 高级查询之精确匹配* 注意:* ① QueryBuilders.termQuery(String name,String value):termQuery是精确匹配,即输入的查询内容是什么,就会按照什么取查询,不会解析查询内容,进行分词。这里的 name 是文档中的字段名,value 是要查询的内容。*/@Testpublic void restHighSearchDocumentTermQuery() throws IOException {SearchRequest searchRequest = new SearchRequest();searchRequest.indices("user");//根据年龄字段查询
//    searchRequest.source(new SearchSourceBuilder().query(QueryBuilders.termQuery("age",18)));//根据名称 name 字段精确匹配searchRequest.source(new SearchSourceBuilder().query(QueryBuilders.termQuery("name","炎")));//根据角色 role 字段精确匹配
//    searchRequest.source(new SearchSourceBuilder().query(QueryBuilders.termQuery("role","男主")));SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);SearchHits hits = searchResponse.getHits();System.out.println("文档操作,高级查询之精确匹配,命中数量:" + hits.getTotalHits());System.out.println("文档操作,高级查询之精确匹配,查询耗时:" + searchResponse.getTook());hits.forEach(p -> {System.out.println("文档操作,高级查询之精确匹配,查询结果,文档id:" + p.getId() + ",文档原生信息:" + p.getSourceAsString());});}/*** 高级查询之布尔查询*/@Testpublic void restHighSearchDocumentBoolQuery() throws IOException {SearchRequest searchRequest = new SearchRequest();searchRequest.indices("user");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();boolQueryBuilder.should(QueryBuilders.rangeQuery("age").gte(20));//年龄大于等于20boolQueryBuilder.should(QueryBuilders.rangeQuery("age").lte(45));//年龄小于等于45boolQueryBuilder.must(QueryBuilders.matchQuery("sex","女"));//性别为女searchSourceBuilder.query(boolQueryBuilder);searchRequest.source(searchSourceBuilder);SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);SearchHits hits = searchResponse.getHits();System.out.println("文档操作,高级查询之布尔查询,命中数量:" + hits.getTotalHits());System.out.println("文档操作,高级查询之布尔查询,查询耗时:" + searchResponse.getTook());hits.forEach(p -> {System.out.println("文档操作,高级查询之布尔查询,查询结果,文档id:" + p.getId() + ",文档原生信息:" + p.getSourceAsString());});}/*** 高级查询之日期查询*/@Testpublic void restHighSearchDocumentDateQuery() throws IOException {SearchRequest searchRequest = new SearchRequest();searchRequest.indices("user");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("birthday");
//    rangeQueryBuilder.gt("now-21y");//now-21y:表示当前时间减去21年rangeQueryBuilder.gt(1027158006000L);//可以直接填时间戳,毫秒值searchSourceBuilder.query(rangeQueryBuilder);searchRequest.source(searchSourceBuilder);SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);SearchHits hits = searchResponse.getHits();System.out.println("文档操作,高级查询之日期查询,命中数量:" + hits.getTotalHits());System.out.println("文档操作,高级查询之日期查询,查询耗时:" + searchResponse.getTook());hits.forEach(p -> {System.out.println("文档操作,高级查询之日期查询,查询结果,文档id:" + p.getId() + ",文档原生信息:" + p.getSourceAsString());});}/*** 高级查询之多个id查询*/@Testpublic void restHighSearchDocumentMoreIdsQuery() throws IOException {SearchRequest searchRequest = new SearchRequest();searchRequest.indices("user");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();IdsQueryBuilder idsQueryBuilder = QueryBuilders.idsQuery();idsQueryBuilder.addIds("1001","1002","1003");searchSourceBuilder.query(idsQueryBuilder);searchRequest.source(searchSourceBuilder);SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);SearchHits hits = searchResponse.getHits();System.out.println("文档操作,高级查询之多个id查询,命中数量:" + hits.getTotalHits());System.out.println("文档操作,高级查询之多个id查询,查询耗时:" + searchResponse.getTook());hits.forEach(p -> {System.out.println("文档操作,高级查询之多个id查询,查询结果,文档id:" + p.getId() + ",文档原生信息:" + p.getSourceAsString());});}/*** 高级查询之多条件组合查询*/@Testpublic void restHighSearchDocumentByConditionsMore() throws IOException {SearchRequest searchRequest = new SearchRequest();searchRequest.indices("user");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();//年龄必须是18岁,must 相当于 andboolQueryBuilder.must(QueryBuilders.matchQuery("age",18));//性别必须是男,must 相当于 and
//    boolQueryBuilder.must(QueryBuilders.matchQuery("sex","男"));//性别应该是男,should 相当于 orboolQueryBuilder.should(QueryBuilders.matchQuery("sex","男"));//性别应该是女,should 相当于 orboolQueryBuilder.should(QueryBuilders.matchQuery("sex","女"));searchSourceBuilder.query(boolQueryBuilder);searchRequest.source(searchSourceBuilder);//执行查询操作SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);SearchHits hits = searchResponse.getHits();System.out.println("文档操作,高级查询之多条件组合查询,命中数量:" + hits.getTotalHits());System.out.println("文档操作,高级查询之多条件组合查询,查询耗时:" + searchResponse.getTook());SearchHit[] result = hits.getHits();for (SearchHit searchHit: result) {System.out.println("文档操作,高级查询之多条件组合查询,id:" + searchHit.getId() + ",内容:" + searchHit.getSourceAsString());}}/*** 高级查询之模糊查询* 1、模糊查询 FuzzyQueryBuilder:QueryBuilders.fuzzyQuery(String name, Object value) 分词模糊查询,通过增加fuzziness 模糊属性,来查询* ① 输入的 name 会被分词* ② Fuzziness 参数会指定编辑次数,Fuzziness.ZERO 为绝对匹配,Fuzziness.ONE 为编辑一次(指修改一个字符),Fuzziness.TWO 为编辑两次(指修改两个字符),Fuzziness.AUTO 为默认推荐的方式* 2、Fuzziness 具体指什么?* QueryBuilders.fuzzyQuery("name", "萧").fuzziness() 方法是用来度量把一个单词转换为另一个单词需要的单字符编辑次数。单字符编辑方式如下:* ① 替换 一个字符到另一个字符: _f_ox -> _b_ox* ② 插入 一个新字符: sic -> sick* ③ 删除 一个字符:: b_l_ack -> back* ④ 换位 调整字符: _st_ar -> _ts_ar* 当然, 一个字符串的单次编辑次数依赖于它的长度。例如:对 hat 进行两次编辑可以得到 mad,所以允许对长度为3的字符串进行两次修改就太过了,Fuzziness 参数可以被设置成 AUTO,结果会在下面的最大编辑距离中:* ① Fuzziness.ZERO:适用于只有 1 或 2 个字符的字符串* ② Fuzziness.ONE:适用于 3、4或5个字符的字符串* ③ Fuzziness.TWO:适用于多于5个字符的字符串* 当然, 你可能发现编辑距离为 2 仍然是太过了,返回的结果好像并没有什么关联,把 Fuzziness 设置为 Fuzziness.ONE ,你可能会获得更好的结果和性能.*/@Testpublic void restHighSearchDocumentByConditionsLike() throws IOException {SearchRequest searchRequest = new SearchRequest();searchRequest.indices("user");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();//根据姓名 name 字段进行模糊匹配,不加 fuzziness() 方法表示默认,name 字段中要包含一个 “萧” 字算满足条件
//    FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders.fuzzyQuery("name", "萧");//根据姓名 name 字段进行模糊匹配,Fuzziness.AUTO 是默认配置,name 字段中要包含一个 “萧” 字算满足条件
//    FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders.fuzzyQuery("name", "萧").fuzziness(Fuzziness.AUTO);//根据姓名 name 字段进行模糊匹配,表示 name 字段在不做任何修改的前提下包含一个 “萧” 字则满足条件
//    FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders.fuzzyQuery("name", "萧").fuzziness(Fuzziness.ZERO);//根据姓名 name 字段进行模糊匹配,表示 name 字段如果修改一个字符能使 name 字段包含一个 “萧炎” 字则满足条件
//    FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders.fuzzyQuery("name", "萧炎").fuzziness(Fuzziness.ONE);//根据姓名 name 字段进行模糊匹配,表示 name 字段如果修改两个个字符能使 name 字段包含一个 “石漠” 字则满足条件FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders.fuzzyQuery("name", "石漠").fuzziness(Fuzziness.TWO);searchSourceBuilder.query(fuzzyQueryBuilder);searchRequest.source(searchSourceBuilder);//执行查询操作SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);SearchHits hits = searchResponse.getHits();System.out.println("文档操作,高级查询之模糊查询,命中数量:" + hits.getTotalHits());System.out.println("文档操作,高级查询之模糊查询,查询耗时:" + searchResponse.getTook());SearchHit[] result = hits.getHits();for (SearchHit searchHit: result) {System.out.println("文档操作,高级查询之模糊查询,id:" + searchHit.getId() + ",内容:" + searchHit.getSourceAsString());}}/*** 高级查询之范围查询*/@Testpublic void restHighSearchDocumentRange() throws IOException {SearchRequest searchRequest = new SearchRequest();searchRequest.indices("user");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();//指定根据 age 字段进行区间查询RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("age");//gte():大于等于,lte():小于等于,gt():大于,lt():小于。rangeQueryBuilder.gte(18);rangeQueryBuilder.lte(25);searchSourceBuilder.query(rangeQueryBuilder);searchRequest.source(searchSourceBuilder);//执行查询操作SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);SearchHits hits = searchResponse.getHits();System.out.println("文档操作,高级查询之范围查询,命中数量:" + hits.getTotalHits());System.out.println("文档操作,高级查询之范围查询,查询耗时:" + searchResponse.getTook());SearchHit[] result = hits.getHits();for (SearchHit searchHit: result) {System.out.println("文档操作,高级查询之范围查询,id:" + searchHit.getId() + ",内容:" + searchHit.getSourceAsString());}}/*** 高级查询之高亮查询*/@Testpublic void restHighSearchDocumentHighLight() throws IOException {SearchRequest searchRequest = new SearchRequest();searchRequest.indices("user");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("sex", "女");searchSourceBuilder.query(termQueryBuilder);//构建高亮对象HighlightBuilder highlightBuilder = new HighlightBuilder();//高亮样式highlightBuilder.preTags("");//前缀标签highlightBuilder.postTags("");//后缀标签//选择高亮字段highlightBuilder.field("name");highlightBuilder.requireFieldMatch(false);//多字段高亮显示时,需要设置为 falsehighlightBuilder.field("role");searchSourceBuilder.highlighter(highlightBuilder);searchRequest.source(searchSourceBuilder);//执行查询操作SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);SearchHits hits = searchResponse.getHits();System.out.println("文档操作,高级查询之高亮查询,命中数量:" + hits.getTotalHits());System.out.println("文档操作,高级查询之高亮查询,查询耗时:" + searchResponse.getTook());System.out.println("文档操作,高级查询之高亮查询,结果:" + searchResponse);hits.forEach(p -> {System.out.println("文档操作,高级查询之高亮查询,文档原生信息:" + p.getSourceAsString() + ",高亮信息:" + p.getHighlightFields());});}/*** 高级查询之查询结果字段过滤*/@Testpublic void restHighSearchDocumentResultFieldFilter() throws IOException {SearchRequest searchRequest = new SearchRequest();searchRequest.indices("user");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();searchSourceBuilder.query(matchAllQueryBuilder);//要排除的字段String[] excludes = {"age","role"};//要展示的字段String[] includes = {};searchSourceBuilder.fetchSource(includes,excludes);searchRequest.source(searchSourceBuilder);//执行查询操作SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);SearchHits hits = searchResponse.getHits();System.out.println("文档操作,高级查询之查询结果字段过滤,命中数量:" + hits.getTotalHits());System.out.println("文档操作,高级查询之查询结果字段过滤,查询耗时:" + searchResponse.getTook());System.out.println("文档操作,高级查询之查询结果字段过滤,结果:" + searchResponse);SearchHit[] result = hits.getHits();for (SearchHit searchHit: result) {System.out.println("文档操作,高级查询之查询结果字段过滤,id:" + searchHit.getId() + ",内容:" + searchHit.getSourceAsString());}}/*** 高级查询之查询结果排序*/@Testpublic void restHighSearchDocumentResultOrder() throws IOException {SearchRequest searchRequest = new SearchRequest();searchRequest.indices("user");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();searchSourceBuilder.query(matchAllQueryBuilder);//要排除的字段String[] excludes = {"sex","role"};//要展示的字段String[] includes = {"name","age"};searchSourceBuilder.fetchSource(includes,excludes);//按照年龄字段 age 排序,SortOrder.ASC 升序
//    searchSourceBuilder.sort("age", SortOrder.ASC);//按照年龄字段 age 排序,SortOrder.DESC 降序searchSourceBuilder.sort("age", SortOrder.DESC);searchRequest.source(searchSourceBuilder);//执行查询操作SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);SearchHits hits = searchResponse.getHits();System.out.println("文档操作,高级查询之查询结果排序,命中数量:" + hits.getTotalHits());System.out.println("文档操作,高级查询之查询结果排序,查询耗时:" + searchResponse.getTook());System.out.println("文档操作,高级查询之查询结果排序,结果:" + searchResponse);SearchHit[] result = hits.getHits();for (SearchHit searchHit: result) {System.out.println("文档操作,高级查询之查询结果排序,id:" + searchHit.getId() + ",内容:" + searchHit.getSourceAsString());}}/*** 高级查询之查询结果去重*/@Testpublic void restHighSearchDocumentResultCollapse() throws IOException {SearchRequest searchRequest = new SearchRequest();searchRequest.indices("user");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();searchSourceBuilder.query(matchAllQueryBuilder);//年龄 age 字段去重CardinalityAggregationBuilder cardinalityAggregationBuilderAgeCard = AggregationBuilders.cardinality("ageCard").field("age");searchSourceBuilder.aggregation(cardinalityAggregationBuilderAgeCard);//角色 role 字段去重CardinalityAggregationBuilder cardinalityAggregationBuilderRoleCard = AggregationBuilders.cardinality("roleCard").field("role");searchSourceBuilder.aggregation(cardinalityAggregationBuilderRoleCard);searchRequest.source(searchSourceBuilder);//执行查询操作SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);SearchHits hits = searchResponse.getHits();System.out.println("文档操作,高级查询之查询结果去重,命中数量:" + hits.getTotalHits());System.out.println("文档操作,高级查询之查询结果去重,查询耗时:" + searchResponse.getTook());Aggregations aggregations = searchResponse.getAggregations();ParsedCardinality parsedCardinalityAge = aggregations.get("ageCard");System.out.println("文档操作,高级查询之查询结果去重,年龄去重后的结果,key:" + parsedCardinalityAge.getName() + ",去重后的数量:" + parsedCardinalityAge.getValue());ParsedCardinality parsedCardinalityRole = aggregations.get("roleCard");System.out.println("文档操作,高级查询之查询结果去重,角色去重后的结果,key:" + parsedCardinalityRole.getName() + ",去重后的数量:" + parsedCardinalityRole.getValue());SearchHit[] result = hits.getHits();for (SearchHit searchHit: result) {System.out.println("文档操作,高级查询之查询结果去重,id:" + searchHit.getId() + ",内容:" + searchHit.getSourceAsString());}}/*** 高级查询之聚合查询* 注意:* ① Text 类型的字段是不允许进行聚合操作的,不能进行分组统计*/@Testpublic void restHighSearchDocumentAggregation() throws IOException {SearchRequest searchRequest = new SearchRequest();searchRequest.indices("user");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();//查询年龄 age 的最大值,最大值对应的key为 avgAgeAggregationBuilder aggregationBuilderMax = AggregationBuilders.max("maxAge").field("age");//查询年龄 age 的最小值,最小值对应的key为 avgAgeAggregationBuilder aggregationBuilderMin = AggregationBuilders.min("minAge").field("age");//查询年龄 age 的平均值,平均值对应的key为 avgAgeAggregationBuilder aggregationBuilderAvg = AggregationBuilders.avg("avgAge").field("age");//统计年龄 age 的数量,未去重AggregationBuilder aggregationBuilderAgeCount = AggregationBuilders.count("ageCount").field("age");//统计年龄 age 的数量,去重CardinalityAggregationBuilder cardinalityAggregationBuilderAgeCard = AggregationBuilders.cardinality("ageCard").field("age");//对年龄 age 字段进行统计,可以统计出最大值、最小值、平均值、数量、和......StatsAggregationBuilder statsAggregationBuilder = AggregationBuilders.stats("ageStatsResult").field("age");//根据年龄 age 进行分组,分组后的结果对应的key为 ageGroupAggregationBuilder aggregationBuilderAgeGroup = AggregationBuilders.terms("ageGroup").field("age");//根据性别 sex 进行分组,分组后的结果对应的key为 sexGroupAggregationBuilder aggregationBuilderSexGroup = AggregationBuilders.terms("sexGroup").field("sex");searchSourceBuilder.aggregation(aggregationBuilderMax);searchSourceBuilder.aggregation(aggregationBuilderMin);searchSourceBuilder.aggregation(aggregationBuilderAvg);searchSourceBuilder.aggregation(aggregationBuilderAgeCount);searchSourceBuilder.aggregation(cardinalityAggregationBuilderAgeCard);searchSourceBuilder.aggregation(statsAggregationBuilder);searchSourceBuilder.aggregation(aggregationBuilderAgeGroup);searchSourceBuilder.aggregation(aggregationBuilderSexGroup);searchSourceBuilder.sort("age", SortOrder.DESC);searchRequest.source(searchSourceBuilder);//执行查询操作SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);SearchHits hits = searchResponse.getHits();System.out.println("文档操作,高级查询之聚合查询,命中数量:" + hits.getTotalHits());System.out.println("文档操作,高级查询之聚合查询,查询耗时:" + searchResponse.getTook());Aggregations aggregations = searchResponse.getAggregations();ParsedMax parsedMax = aggregations.get("maxAge");System.out.println("文档操作,高级查询之聚合查询,最大值:" + parsedMax.getValue());ParsedMin parsedMin = aggregations.get("minAge");System.out.println("文档操作,高级查询之聚合查询,最小值:" + parsedMin.getValue());ParsedAvg parsedAvg = aggregations.get("avgAge");System.out.println("文档操作,高级查询之聚合查询,平均值:" + parsedAvg.getValue());ParsedValueCount parsedAgeCount = aggregations.get("ageCount");System.out.println("文档操作,高级查询之聚合查询,年龄未去重的数量:" + parsedAgeCount.getValue());ParsedCardinality parsedCardinalityAge = aggregations.get("ageCard");System.out.println("文档操作,高级查询之聚合查询,年龄去重后的数量:" + parsedCardinalityAge.getValue());ParsedStats ageStatsResult = aggregations.get("ageStatsResult");System.out.println("文档操作,高级查询之聚合查询,对年龄进行统计后的结果,统计个数(未去重):" + ageStatsResult.getCount());System.out.println("文档操作,高级查询之聚合查询,对年龄进行统计后的结果,年龄平均值:" + ageStatsResult.getAvg());System.out.println("文档操作,高级查询之聚合查询,对年龄进行统计后的结果,年龄最大值:" + ageStatsResult.getMax());System.out.println("文档操作,高级查询之聚合查询,对年龄进行统计后的结果,年龄最小值:" + ageStatsResult.getMin());System.out.println("文档操作,高级查询之聚合查询,对年龄进行统计后的结果,年龄之和:" + ageStatsResult.getSum());System.out.println("############# 年龄分组结果输出部分 ###############");Terms termsAgeGroup = aggregations.get("ageGroup");for (Terms.Bucket bucket : termsAgeGroup.getBuckets()) {System.out.println("文档操作,高级查询之聚合查询,年龄分组,key:" + bucket.getKeyAsString() + ",value:" + bucket.getDocCount());}System.out.println("############# 年龄分组结果输出部分 ###############");System.out.println("------------- 性别分组结果输出部分 ----------------");Terms termsSexGroup = aggregations.get("sexGroup");for (Terms.Bucket bucket : termsSexGroup.getBuckets()) {System.out.println("文档操作,高级查询之聚合查询,性别分组,key:" + bucket.getKeyAsString() + ",value:" + bucket.getDocCount());}System.out.println("------------- 性别分组结果输出部分 ----------------");SearchHit[] result = hits.getHits();for (SearchHit searchHit: result) {System.out.println("文档操作,高级查询之聚合查询,id:" + searchHit.getId() + ",内容:" + searchHit.getSourceAsString());}}}

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【Ctfer训练计划】——(三... 作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...