目录
spring-boot-starter-data-elasticsearch
1、概述
Spring Data Elasticsearch是Spring Data项目下的一个子模块。
查看 Spring Data的官网:http://projects.spring.io/spring-data/
Spring Data 的使命是给各种数据访问提供统一的编程接口,不管是关系型数据库(如MySQL),还是非关系数据库(如Redis),或者类似Elasticsearch这样的索引数据库。从而简化开发人员的代码,提高开发效率。
Spring Boot与Elasticsearch的对应版本:
引入依赖:
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.4.1</version><relativePath/><!-- lookup parent from repository --></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency></dependencies>
Elasticsearch的版本为7.16,所以选择2.4以上版本的SpringBoot。
2、配置
2.1、有密码
application.yml
es:address: 127.0.0.1
port:9200scheme: http
username: elastic
password:123456
@ConfigurationpublicclassElasticSearchConfigextendsAbstractElasticsearchConfiguration{@Value("${es.address}")String address;@Value("${es.port}")Integer port;@Value("${es.scheme}")String scheme;@Value("${es.username}")String username;@Value("${es.password}")String password;@OverridepublicRestHighLevelClientelasticsearchClient(){finalCredentialsProvider credentialsProvider =newBasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,newUsernamePasswordCredentials(username, password));RestClientBuilder restClientBuilder =RestClient.builder(newHttpHost(address, port, scheme)).setHttpClientConfigCallback(newRestClientBuilder.HttpClientConfigCallback(){@OverridepublicHttpAsyncClientBuildercustomizeHttpClient(HttpAsyncClientBuilder httpAsyncClientBuilder){return httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider);}});RestHighLevelClient esClient =newRestHighLevelClient(restClientBuilder);return esClient;}}
2.1、无密码
@ConfigurationpublicclassElasticSearchConfigextendsAbstractElasticsearchConfiguration{@Value("${es.address}")String address;@Value("${es.port}")Integer port;@Value("${es.scheme}")String scheme;@Value("${es.username}")String username;@Value("${es.password}")String password;@OverridepublicRestHighLevelClientelasticsearchClient(){RestClientBuilder builder =null;
builder =RestClient.builder(newHttpHost(address, port, scheme));RestHighLevelClient client =newRestHighLevelClient(builder);return client;}}
3、实体
@Document(indexName ="book", createIndex =true)publicclassBook{@Id@Field(type =FieldType.Long)privateLong id;@Field(type =FieldType.Keyword, store =true)privateString name;@Field(type =FieldType.Text, store =false, analyzer ="ik_smart")privateString describe;@Field(type =FieldType.Text, analyzer ="ik_smart")privateString author;@Field(type =FieldType.Double)privateDouble price;@Field(type =FieldType.Date, format =DateFormat.basic_date )privateDate createTime;publicLonggetId(){return id;}publicvoidsetId(Long id){this.id = id;}publicStringgetName(){return name;}publicvoidsetName(String name){this.name = name;}publicStringgetDescribe(){return describe;}publicvoidsetDescribe(String describe){this.describe = describe;}publicStringgetAuthor(){return author;}publicvoidsetAuthor(String author){this.author = author;}publicDoublegetPrice(){return price;}publicvoidsetPrice(Double price){this.price = price;}publicDategetCreateTime(){return createTime;}publicvoidsetCreateTime(Date createTime){this.createTime = createTime;}@OverridepublicStringtoString(){return"Book{"+"id="+ id +", name='"+ name +'\''+", describe='"+ describe +'\''+", author='"+ author +'\''+", price="+ price +", createTime="+ createTime +'}';}}
@Document
:作用在类,标记实体类为文档对象: -indexName
:索引名称,它可以包含一个SpEL模板表达式,如log-#{T(java.time.LocalDate).now().toString()}
-useServerConfiguration
:创建索引时是否使用服务器端设置,默认false。-shards
:主分片数量,默认1.-replicas
:副本分片数量,默认1.-refreshInterval
:创建索引时的刷新间隔,默认值为“1s”。-indexStoreType
:创建索引时的索引存储类型,默认"fs"。-createIndex
:是否创建索引,默认true。-versionType
:版本管理,默认VersionType.EXTERNAL@Id
:作用在成员变量,标记一个字段作为id主键。@Transient
:作用在成员变量,从Document中排除该字段。@GeoPointField
:作用在成员变量,标记该字段为GeoPoint类型。@GeoShapeField
:作用在成员变量,标记该字段为GeoShape类型。@Field
:作用在成员变量,标记为文档的字段,并指定字段映射属性 -name/value
:指定es中的field名称,默认为字段名称。-type
:字段类型,类型为枚举,默认为FieldType.AUTO。-index
:是否索引,默认为true。-format
:Date类型的格式化,枚举类型-pattern
:自定义格式化-store
:默认false-fielddata
:默认false-searchAnalyzer
:默认""-analyzer
:默认""-normalizer
:默认""-ignoreFields
:默认{}-includeInParent
:默认false-copyTo
:默认{}-ignoreAbove
:默认-1-coerce
:默认true-docValues
:默认true-ignoreMalformed
:默认false-indexOptions
:默认IndexOptions.none-indexPhrases
:默认false-indexPrefixes
:默认{}-norms
:默认true-nullValue
:默认""-positionIncrementGap
:默认-1-similarity
:默认Similarity.Default-termVector
:默认TermVector.none-scalingFactor
:默认1-maxShingleSize
:默认-1-storeNullValue
:默认false-positiveScoreImpact
:默认true-enabled
:默认true-eagerGlobalOrdinals
:默认false-nullValueType
:默认NullValueType.String
4、Respository
publicinterfaceBookRespositoryextendsElasticsearchRepository<Book,Long>{}
4.1、接口层次关系
CrudRepository:
提供以Id为参数的CRUD功能:
@NoRepositoryBeanpublicinterfaceCrudRepository<T, ID>extendsRepository<T, ID>{<SextendsT>Ssave(S entity);<SextendsT>Iterable<S>saveAll(Iterable<S> entities);Optional<T>findById(ID id);booleanexistsById(ID id);Iterable<T>findAll();Iterable<T>findAllById(Iterable<ID> ids);longcount();voiddeleteById(ID id);voiddelete(T entity);voiddeleteAll(Iterable<?extendsT> entities);voiddeleteAll();}
PagingAndSortingRepository:
在CRUD之上,提供分页和排序功能:
@NoRepositoryBeanpublicinterfacePagingAndSortingRepository<T, ID>extendsCrudRepository<T, ID>{Iterable<T>findAll(Sort sort);Page<T>findAll(Pageable pageable);}
ElasticsearchRepository:
大部分方法在7.x中已经废弃:
@NoRepositoryBeanpublicinterfaceElasticsearchRepository<T, ID>extendsPagingAndSortingRepository<T, ID>{@Deprecateddefault<SextendsT>Sindex(S entity){returnsave(entity);}@Deprecated<SextendsT>SindexWithoutRefresh(S entity);@DeprecatedIterable<T>search(QueryBuilder query);@DeprecatedPage<T>search(QueryBuilder query,Pageable pageable);Page<T>search(Query searchQuery);Page<T>searchSimilar(T entity,@NullableString[] fields,Pageable pageable);@Deprecatedvoidrefresh();}
4.2、增删改查
4.2.1、新增
@Testpublicvoidadd(){Book book =newBook();
book.setId(1l);
book.setAuthor("罗贯中");
book.setName("三国演义");
book.setPrice(42.56);
book.setCreateTime(newDate());
book.setDescribe("天下大势,分久必合,合久必分。");
bookRespository.save(book);}
4.2.2、修改
@Testpublicvoidupdate(){Book book =newBook();
book.setId(1l);
book.setAuthor("罗贯中");
book.setName("三国演义");
book.setPrice(55.55);
book.setCreateTime(newDate());
book.setDescribe("天下大势,分久必合,合久必分。");
bookRespository.save(book);}
4.2.3、批量新增
@Testpublicvoidadd_all(){List<Book> list =newArrayList<>();Book book1 =newBook();
book1.setId(2l);
book1.setAuthor("吴承恩");
book1.setName("西游记");
book1.setPrice(33.33);
book1.setCreateTime(newDate());
book1.setDescribe("大师兄!师傅又丢了!");
list.add(book1);Book book2 =newBook();
book2.setId(3l);
book2.setAuthor("曹雪芹");
book2.setName("红楼梦");
book2.setPrice(66.66);
book2.setCreateTime(newDate());
book2.setDescribe("一朝春尽红颜老,花落人亡两不知。");
list.add(book2);Book book3 =newBook();
book3.setId(4l);
book3.setAuthor("施耐庵");
book3.setName("水浒传");
book3.setPrice(35.22);
book3.setCreateTime(newDate());
book3.setDescribe("招安");
list.add(book3);
bookRespository.saveAll(list);}
4.2.4、删除
@Testpublicvoiddelete(){
bookRespository.deleteById(1l);}
4.2.5、根据ID查询
@TestpublicvoidfindById(){Optional<Book> optional = bookRespository.findById(2l);System.out.println(optional.get());}
4.2.6、查询所有
@TestpublicvoidfindAll(){Iterable<Book> all = bookRespository.findAll();
all.forEach(System.out::println);}
4.3、自定义方法
Spring Data 的另一个强大功能,是根据方法名称自动实现功能。
比如:方法名叫
findByName
,那么就是根据name查询,无需写实现类。
publicinterfaceBookRespositoryextendsElasticsearchRepository<Book,Long>{/**
* 根据书名查询
* @param name
* @return
*/List<Book>findByName(String name);}
@TestpublicvoidfindByName(){List<Book> list = bookRespository.findByName("红楼梦");
list.forEach(System.out::println);}
4.3.1、约定规则
当然,方法名称要遵循一定的约定:
And
:findByNameAndPrice
{"query":{"bool":{"must":[{"query_string":{"query":"?","fields":["name"]}},{"query_string":{"query":"?","fields":["price"]}}]}}}
Or
:findByNameOrPrice
{"query":{"bool":{"should":[{"query_string":{"query":"?","fields":["name"]}},{"query_string":{"query":"?","fields":["price"]}}]}}}
Is
:findByName
{"query":{"bool":{"must":[{"query_string":{"query":"?","fields":["name"]}}]}}}
Not
:findByNameNot
{"query":{"bool":{"must_not":[{"query_string":{"query":"?","fields":["name"]}}]}}}
Between
:findByPriceBetween
{"query":{"bool":{"must":[{"range":{"price":{"from":?,"to":?,"include_lower":true,"include_upper":true}}}]}}}
LessThan
:findByPriceLessThan
{"query":{"bool":{"must":[{"range":{"price":{"from":null,"to":?,"include_lower":true,"include_upper":false}}}]}}}
LessThanEqual
:findByPriceLessThanEqual
{"query":{"bool":{"must":[{"range":{"price":{"from":null,"to":?,"include_lower":true,"include_upper":true}}}]}}}
GreaterThan
:findByPriceGreaterThan
{"query":{"bool":{"must":[{"range":{"price":{"from":?,"to":null,"include_lower":false,"include_upper":true}}}]}}}
GreaterThanEqual
:findByPriceGreaterThan
{"query":{"bool":{"must":[{"range":{"price":{"from":?,"to":null,"include_lower":true,"include_upper":true}}}]}}}
Before
:findByPriceBefore
{"query":{"bool":{"must":[{"range":{"price":{"from":null,"to":?,"include_lower":true,"include_upper":true}}}]}}}
After
:findByPriceAfter
{"query":{"bool":{"must":[{"range":{"price":{"from":?,"to":null,"include_lower":true,"include_upper":true}}}]}}}
Like
:findByNameLike
{"query":{"bool":{"must":[{"query_string":{"query":"?*","fields":["name"]},"analyze_wildcard":true}]}}}
StartingWith
:findByNameStartingWith
{"query":{"bool":{"must":[{"query_string":{"query":"?*","fields":["name"]},"analyze_wildcard":true}]}}}
EndingWith
:
findByNameEndingWith
{"query":{"bool":{"must":[{"query_string":{"query":"*?","fields":["name"]},"analyze_wildcard":true}]}}}
Contains/Containing
:findByNameContaining
{"query":{"bool":{"must":[{"query_string":{"query":"*?*","fields":["name"]},"analyze_wildcard":true}]}}}
In
(when annotated as FieldType.Keyword):findByNameIn(Collection<String>names)
{"query":{"bool":{"must":[{"bool":{"must":[{"terms":{"name":["?","?"]}}]}}]}}}
In
:findByNameIn(Collection<String>names)
{"query":{"bool":{"must":[{"query_string":{"query":"\"?\" \"?\"","fields":["name"]}}]}}}
NotIn
(when annotated as FieldType.Keyword):findByNameNotIn(Collection<String>names)
{"query":{"bool":{"must":[{"bool":{"must_not":[{"terms":{"name":["?","?"]}}]}}]}}}
NotIn
:findByNameNotIn(Collection<String>names)
{"query":{"bool":{"must":[{"query_string":{"query":"NOT(\"?\" \"?\")","fields":["name"]}}]}}}
Near
:findByStoreNear
Not Supported Yet !
True
:findByAvailableTrue
{"query":{"bool":{"must":[{"query_string":{"query":"true","fields":["available"]}}]}}}
False
:findByAvailableFalse
{"query":{"bool":{"must":[{"query_string":{"query":"false","fields":["available"]}}]}}}
OrderBy
:findByAvailableTrueOrderByNameDesc
{"query":{"bool":{"must":[{"query_string":{"query":"true","fields":["available"]}}]}},"sort":[{"name":{"order":"desc"}}]}
4.3.2、示例
按照价格区间查询:
List<Book>findByPriceBetween(Double from,Doubleto);
@TestpublicvoidfindByPriceBetween(){List<Book> list = bookRespository.findByPriceBetween(20.00,60.00);
list.forEach(System.out::println);}
查询书名为三国演义或红楼梦,或者作者为吴承恩的书籍:
List<Book>findByNameInOrAuthorIn(List<String> names,List<String> authors);
@TestpublicvoidfindByNameInOrAuthorIn(){List<String> names =newArrayList<>();
names.add("三国演义");
names.add("红楼梦");List<String> authors =newArrayList<>();
authors.add("吴承恩");List<Book> list = bookRespository.findByNameInOrAuthorIn(names, authors);
list.forEach(System.out::println);}
4.4、QueryBuilder查询(4.0后废弃)
基本方式是使用Respository的各种search方法,然后用QueryBuilder构建查询。4.0后已经废弃,推荐使用注解查询、ElasticsearchRestTemlate或者上面的方法名查询。
@Testpublicvoidbash_search(){MatchQueryBuilder builder =QueryBuilders.matchQuery("author","吴承恩");Iterable<Book> books = bookRespository.search(builder);
books.forEach(System.out::println);}
4.4.1、分页查询
@Testpublicvoidpage_search(){NativeSearchQueryBuilder queryBuilder =newNativeSearchQueryBuilder();
queryBuilder.withQuery(QueryBuilders.matchAllQuery());//初始化分页参数int page =0;int size =2;
queryBuilder.withPageable(PageRequest.of(0,2));Page<Book> books = bookRespository.search(queryBuilder.build());//总条数System.out.println(books.getTotalElements());//总页数System.out.println(books.getTotalPages());//每页大小System.out.println(books.getSize());//当前页System.out.println(books.getNumber());//数据
books.getContent().forEach(System.out::println);}
4.4.2、排序查询
@Testpublicvoidsort_search(){NativeSearchQueryBuilder queryBuilder =newNativeSearchQueryBuilder();
queryBuilder.withQuery(QueryBuilders.matchAllQuery());
queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC));Page<Book> books = bookRespository.search(queryBuilder.build());
books.getContent().forEach(System.out::println);}
4.4.3、桶聚合
@Testpublicvoidbucket_agg(){NativeSearchQueryBuilder queryBuilder =newNativeSearchQueryBuilder();//不查询任何字段
queryBuilder.withSourceFilter(newFetchSourceFilter(newString[]{""},null));//添加一个terms聚合,名称为name_agg,字段为name
queryBuilder.addAggregation(AggregationBuilders.terms("name_agg").field("name"));//查询AggregatedPage<Book> books =(AggregatedPage<Book>) bookRespository.search(queryBuilder.build());//解析ParsedStringTerms agg=(ParsedStringTerms) books.getAggregation("name_agg");List<?extendsTerms.Bucket> buckets = agg.getBuckets();for(Terms.Bucket bucket : buckets){System.out.println(bucket.getKeyAsString()+":"+ bucket.getDocCount());}}
4.4.4、嵌套聚合
@Testpublicvoidavg_agg(){NativeSearchQueryBuilder queryBuilder =newNativeSearchQueryBuilder();//不查询任何字段
queryBuilder.withSourceFilter(newFetchSourceFilter(newString[]{""},null));//添加一个terms聚合,名称为name_agg,字段为name
queryBuilder.addAggregation(AggregationBuilders.terms("name_agg").field("name").subAggregation(AggregationBuilders.avg("price_avg").field("price")));//查询AggregatedPage<Book> books =(AggregatedPage<Book>) bookRespository.search(queryBuilder.build());//获取聚合ParsedStringTerms name_agg =(ParsedStringTerms) books.getAggregation("name_agg");//获取桶List<?extendsTerms.Bucket> buckets = name_agg.getBuckets();//遍历for(Terms.Bucket bucket : buckets){System.out.println(bucket.getKeyAsString()+":"+ bucket.getDocCount());//获取子聚合ParsedAvg price_avg =(ParsedAvg) bucket.getAggregations().asMap().get("price_avg");System.out.println(price_avg.getValue());}}
4.4.5、其他查询
等值查询:
QueryBuilders.termQuery("name","小李")
范围查询:
QueryBuilders.rangeQuery("age").gte(18).lte(50);
模糊查询:
QueryBuilders.boolQuery().must(QueryBuilders.wildcardQuery("name","*小李*"));
多条件查询:
QueryBuilders.boolQuery().must(QueryBuilders.termQuery("name","小李")).must(QueryBuilders.rangeQuery("age").gte(10).lte(50));
must查询:
List<String> list =Arrays.asList("北京","上海","杭州");QueryBuilders.boolQuery().must(QueryBuilders.termQuery("name","李明")).must(QueryBuilders.termsQuery("address", list)).must(QueryBuilders.rangeQuery("age").gte(10).lte(50));
should查询:
QueryBuilders.boolQuery().should(QueryBuilders.wildcardQuery("name","*小李*")).should(QueryBuilders.termQuery("address","北京"));
bool组合查询:
QueryBuilders.boolQuery().must(QueryBuilders.termQuery("sex","男")).should(QueryBuilders.wildcardQuery("name","*小李*")).should(QueryBuilders.termQuery("address","北京")).minimumShouldMatch(1);
有值查询:
QueryBuilders.boolQuery().must(QueryBuilders.existsQuery("name")).mustNot(QueryBuilders.existsQuery("tag"));
4.5、注解查询
4.5.1、@Query
使用@Query注解查询,设置为注释参数的String必须是有效的Elasticsearch JSON查询。
JSON字符串中使用
?idnex
进行参数占位,
?
表示该位置为参数,
index
表示参数下标,从0开始。
根据作者查询:
/**
* {
* "query": {
* "match": {
* "author": "曹雪芹"
* }
* }
* }
* @param name
* @return
*/@Query("{\n"+" \"match\": {\n"+" \"author\": \"?0\"\n"+" }\n"+"}")List<SearchHit<Book>>listBookByName(String name);
@Testpublicvoidannotation_test1(){List<SearchHit<Book>> list = bookRespository.listBookByName("曹雪芹");for(SearchHit<Book> hit : list){System.out.println(hit.getScore());System.out.println(hit.getContent());}}
根据价格范围查询:
/**
* {
* "query": {
* "range": {
* "price": {
* "gte": 10,
* "lte": 40
* }
* }
* }
* }
* @param from
* @param to
* @return
*/@Query("{\n"+" \"range\": {\n"+" \"price\": {\n"+" \"gte\": \"?0\",\n"+" \"lte\": \"?1\"\n"+" }\n"+" }\n"+"}")List<SearchHit<Book>>listBookByPriceRange(Double from,Doubleto);
@Testpublicvoidannotation_test2(){List<SearchHit<Book>> list = bookRespository.listBookByPriceRange(10d,40d);for(SearchHit<Book> hit : list){System.out.println(hit.getScore());System.out.println(hit.getContent());}}
4.5.2、@Highlight
@Highlight注解用于设置高亮查询,子注解@HighlightField用于指定高亮字段,@HighlightParameters用于配置高亮选项。
根据作者查询,并高亮作者:
/**
* {
* "query": {
* "match": {
* "author": "罗贯中"
* }
* },
* "highlight": {
* "pre_tags": ["<span style='color:red'>"],
* "post_tags": ["</span>"],
* "fields": {
* "author": {}
* }
* }
* }
*/@Query("{\n"+" \"match\": {\n"+" \"author\": \"?0\"\n"+" }\n"+"}")@Highlight(
fields ={@HighlightField(name ="author")},
parameters =@HighlightParameters(preTags ="<span style='color:red'>", postTags ="</span>"))List<SearchHit<Book>>listBookByNameHighlight(String name);
@Testpublicvoidannotation_highlight(){List<SearchHit<Book>> list = bookRespository.listBookByNameHighlight("罗贯中");for(SearchHit<Book> hit : list){System.out.println(hit.getScore());System.out.println(hit.getContent());List<String> hitHighlightField = hit.getHighlightField("author");
hitHighlightField.forEach(System.out::println);}}
1.2039728
Book{id=1, name='三国演义', describe='天下大势,分久必合,合久必分。', author='罗贯中', price=55.55, createTime=Fri Oct 27 08:00:00 CST 2023}
<span style='color:red'>罗贯中</span>
5、ElasticsearchOperations接口
ElasticsearchOperations是Spring Data Elasticsearch抽象出来的操作接口,有两个实现类:
- ElasticsearchTemplate
- ElasticsearchRestTemplate
5.1、ElasticsearchTemplate
ElasticsearchTemplate底层依赖于Transport Client,在4.0版本后已被标记为废弃。
配置:
@ConfigurationpublicclassTransportClientConfigextendsElasticsearchConfigurationSupport{@BeanpublicClientelasticsearchClient()throwsUnknownHostException{Settings settings =Settings.builder().put("cluster.name","elasticsearch").build();TransportClient client =newPreBuiltTransportClient(settings);
client.addTransportAddress(newTransportAddress(InetAddress.getByName("127.0.0.1"),9300));return client;}@Bean(name ={"elasticsearchOperations","elasticsearchTemplate"})publicElasticsearchTemplateelasticsearchTemplate()throwsUnknownHostException{returnnewElasticsearchTemplate(elasticsearchClient());}}
5.2、ElasticsearchRestTemplate
ElasticsearchRestTemplate底层依赖于High Level REST Client,所以配置也使用AbstractElasticsearchConfiguration,无须再次配置。
ElasticsearchRestTemplate中定义了一系列方法:
IndexOperations
:定义索引级别上的操作,如创建或删除索引
publicIndexOperationsindexOps(Class<?> clazz);publicIndexOperationsindexOps(IndexCoordinates index);
DocumentOperations
:定义了基于实体id存储、更新和检索实体的操作。
publicStringdoIndex(IndexQuery query,IndexCoordinates index);public<T>Tget(String id,Class<T> clazz,IndexCoordinates index);public<T>List<T>multiGet(Query query,Class<T> clazz,IndexCoordinates index);protectedbooleandoExists(String id,IndexCoordinates index);publicvoidbulkUpdate(List<UpdateQuery> queries,BulkOptions bulkOptions,IndexCoordinates index);publicStringdelete(String id,@NullableString routing,IndexCoordinates index);publicvoiddelete(Query query,Class<?> clazz,IndexCoordinates index);@Deprecatedpublicvoiddelete(DeleteQuery deleteQuery,IndexCoordinates index);publicUpdateResponseupdate(UpdateQuery query,IndexCoordinates index);publicList<IndexedObjectInformation>doBulkOperation(List<?> queries,BulkOptions bulkOptions,IndexCoordinates index);
SearchOperations
:定义使用查询搜索多个实体的操作
publiclongcount(Query query,@NullableClass<?> clazz,IndexCoordinates index);public<T>SearchHits<T>search(Query query,Class<T> clazz,IndexCoordinates index);public<T>SearchScrollHits<T>searchScrollStart(long scrollTimeInMillis,Query query,Class<T> clazz,IndexCoordinates index);public<T>SearchScrollHits<T>searchScrollContinue(@NullableString scrollId,long scrollTimeInMillis,Class<T> clazz,IndexCoordinates index);publicvoidsearchScrollClear(List<String> scrollIds);publicSearchResponsesuggest(SuggestBuilder suggestion,IndexCoordinates index);
5.3、返回值类型
- SearchHit<T>-
Id
-Score
-Sort Values
-Highlight fields
-Inner hits
(this is an embedded SearchHits object containing eventually returned inner hits)- The retrieved entity of type - SearchHits<T>:-
Number of total hits
-Total hits relation
-Maximum score
-A list of SearchHit<T> objects
-Returned aggregations
- SearchPage<T>: Defines a Spring Data Page that contains a SearchHits element and can be used for paging access using repository methods.
- SearchScrollHits<T>: Returned by the low level scroll API functions in ElasticsearchRestTemplate, it enriches a SearchHits with the Elasticsearch scroll id.
- SearchHitsIterator<T>: An Iterator returned by the streaming functions of the SearchOperations interface.
5.4、IndexOperations(索引操作)
5.4.1、初始化索引
@TestpublicvoidcreateIndex(){IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Student.class);//是否存在if(!indexOperations.exists()){//根据绑定的实体类注解获取设置信息Document settings = indexOperations.createSettings();//创建索引
indexOperations.create(settings);//或者直接调用无参的create(),内部自动创建settings// indexOperations.create();//根据实体类注解获取映射关系Document mapping = indexOperations.createMapping();//将mapping添加到索引中
indexOperations.putMapping(mapping);}}
5.4.2、删除索引
@TestpublicvoiddeleteIndex(){IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Student.class);if(indexOperations.exists()){
indexOperations.delete();}}
5.4.3、获取索引信息
@TestpublicvoidcreateIndex(){IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Student.class);//是否存在if(!indexOperations.exists()){//根据绑定的实体类注解获取设置信息Document settings = indexOperations.createSettings();//创建索引
indexOperations.create(settings);//或者直接调用无参的create(),内部自动创建settings// indexOperations.create();//根据实体类注解获取映射关系Document mapping = indexOperations.createMapping();//将mapping添加到索引中
indexOperations.putMapping(mapping);}}
5.4.4、别名操作
@TestpublicvoidaliasTest(){IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Student.class);//一系列别名操作AliasActions actions =newAliasActions();//新增别名
actions.add(newAliasAction.Add(AliasActionParameters.builder().withAliases("a").withIndices("student").build()));//删除别名
actions.add(newAliasAction.Remove(AliasActionParameters.builder().withAliases("a").withIndices("student").build()));boolean flag = indexOperations.alias(actions);System.out.println(flag);//通过别名查询,返回key为包含该别名的index的mapMap<String,Set<AliasData>> map = indexOperations.getAliases("a");Set<AliasData> data = map.get("student");
data.forEach(e ->System.out.println(e.getAlias()));//通过index查询,返回返回key为包含该别名的index的mapMap<String,Set<AliasData>> map1 = indexOperations.getAliasesForIndex("student");Set<AliasData> data1 = map1.get("student");
data1.forEach(e ->System.out.println(e.getAlias()));}
5.4.5、索引模板操作
@TestpublicvoidtemplateTest(){IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Student.class);//新增模板PutTemplateRequest request =PutTemplateRequest.builder("my-template","pattern1","pattern2").withSettings(Document.create().append("index.number_of_shards",3)).withMappings(Document.parse("{\n"+" \"_source\": {\n"+" \"enabled\": false\n"+" }\n"+"}")).withOrder(1).withVersion(1).build();
indexOperations.putTemplate(request);//获取模板if(indexOperations.existsTemplate("my-template")){TemplateData template = indexOperations.getTemplate("my-template");System.out.println(template.getSettings().toJson());System.out.println(template.getMapping().toJson());}//删除模板if(indexOperations.existsTemplate("my-template")){boolean flag = indexOperations.deleteTemplate("my-template");System.out.println(flag);}}
5.5、增删改查
5.5.1、新增单个文档
@Testpublicvoidadd(){Student student =newStudent();
student.setAge(23);
student.setData("123");
student.setDesc("华为手机");
student.setId("1");
student.setName("张三");Student save = elasticsearchRestTemplate.save(student);System.out.println(save);}
5.5.2、批量新增文档
@TestpublicvoidaddAll(){List<Student> list =newArrayList<>();
list.add(newStudent("2","李四","苹果手机","1",22));
list.add(newStudent("3","王五","oppo手机","2",24));
list.add(newStudent("4","赵六","voio手机","3",25));
list.add(newStudent("5","田七","小米手机","4",26));Iterable<Student> result = elasticsearchRestTemplate.save(list);System.out.println(result);}
5.5.3、修改(全量替换)
@Testpublicvoidupdate(){Student student =newStudent();
student.setId("1");
student.setAge(23);
student.setData("99");
student.setDesc("华为手机AND苹果手机");
student.setName("张三");Student save = elasticsearchRestTemplate.save(student);System.out.println(save);}
5.5.4、修改(部分修改)
@Testpublicvoidupdate2(){//脚本更新String script ="ctx._source.age = 27;ctx._source.desc = 'oppo手机and苹果电脑'";UpdateResponse update = elasticsearchRestTemplate.update(UpdateQuery.builder("3").withScript(script).build(),IndexCoordinates.of("student"));System.out.println(update.getResult());//部分文档更新UpdateResponse update1 = elasticsearchRestTemplate.update(UpdateQuery.builder("3").withDocument(Document.create().append("age",99)).build(),IndexCoordinates.of("student"));System.out.println(update1.getResult());}
5.5.5、根据主键查询
/**
* 根据主键查查询
*/@TestpublicvoidsearchById(){Student student = elasticsearchRestTemplate.get("3",Student.class);System.out.println(student);}
5.5.6、根据主键删除
@TestpublicvoiddeleteById(){String id = elasticsearchRestTemplate.delete("5",Student.class);System.out.println(id);}
6、Query接口
在SearchOperations中定义的几乎所有方法都使用Query参数,该参数定义了要执行的查询以进行搜索。Query是一个接口,Spring Data Elasticsearch提供了三个实现:
CriteriaQuery
StringQuery
NativeSearchQuery
6.1、CriteriaQuery
基于CriteriaQuery的查询允许创建查询来搜索数据,而无需了解Elasticsearch查询的语法或基础知识。它们允许用户通过简单地链接和组合指定搜索文档必须满足的条件的条件对象来构建查询。
@TestpublicvoidcriteriaQuery(){Criteria criteria =newCriteria("author").matches("吴承恩");Query query =newCriteriaQuery(criteria);SearchHits<Book> hits = elasticsearchRestTemplate.search(query,Book.class,IndexCoordinates.of("book"));List<SearchHit<Book>> list = hits.getSearchHits();for(SearchHit<Book> hit : list){System.out.println(hit.getContent());}}
Criteria
代表一个查询条件,可以绑定一个字段,也可以是一个空条件。CriteriaEntry
代表一个条件项,如果不止一个条件项,则条件项中的项组合在bool-must查询
中,包含如下类型: -EQUALS
-CONTAINS
-STARTS_WITH
-ENDS_WITH
-EXPRESSION
-BETWEEN
-FUZZY
-MATCHES
-MATCHES_ALL
-IN
-NOT_IN
-WITHIN
-BBOX
-LESS
-LESS_EQUAL
-GREATER
-GREATER_EQUAL
-EXISTS
-GEO_INTERSECTS
-GEO_IS_DISJOINT
-GEO_WITHIN
-GEO_CONTAINS
CriteriaChain
代表一系列条件链,可以通过or()
和and()
将Criteria组合到条件链中。条件链是LinkedList,所以是有序的,且条件链中的所有条件都处在同一级别,嵌套查询需要使用subCrteria。
6.1.1、简单查询
@Testpublicvoidsimple_criteria(){//EQUALS 等值查询Criteria criteria =newCriteria("price").is(33.33);//EXISTS 存在查询
criteria =newCriteria("name").exists();//BETWEEN 范围查询
criteria =newCriteria("price").between(20.0,40.0);//CONTAINS 包含查询 支持keyword和text类型
criteria =newCriteria("describe").contains("师傅");//ENDS_WITH 以..结尾 支持keyword和text类型
criteria =newCriteria("name").endsWith("记");//STARTS_WITH 以..开始 支持keyword和text类型
criteria =newCriteria("name").startsWith("西");//EXPRESSION 支持es的原生expression查询
criteria =newCriteria("name").expression("*游记");//FUZZY 模糊查询
criteria =newCriteria("name").fuzzy("东游记");//MATCH 匹配查询 默认使用OR运算符
criteria =newCriteria("describe").matches("丢了");//MATCH_ALL 匹配查询 默认使用AND运算符
criteria =newCriteria("describe").matchesAll("丢了");//IN 多值查询 仅支持keyword类型
criteria =newCriteria("name").in("三国演义","西游记");//NOT_IN 仅支持keyword类型
criteria =newCriteria("name").notIn("三国演义");//LESS <
criteria =newCriteria("price").lessThan(40.0);//LESS_EQUAL <=
criteria =newCriteria("price").lessThanEqual(35.22);//GREATER >
criteria =newCriteria("price").greaterThan(50.0);//GREATER_EQUAL >=
criteria =newCriteria("price").greaterThanEqual(55.55);Query query =newCriteriaQuery(criteria);SearchHits<Book> hits = elasticsearchRestTemplate.search(query,Book.class,IndexCoordinates.of("book"));List<SearchHit<Book>> list = hits.getSearchHits();for(SearchHit<Book> hit : list){System.out.println(hit.getContent());}}
6.1.2、组合查询
就是构建条件链
And逻辑:
@Testpublicvoidand_criteria(){//条件:(20.0 < price < 80.0) && (name=三国演义)//组合条件时,默认情况下使用AND逻辑:Criteria criteria =newCriteria("price").greaterThan(20.0).lessThan(80.0);//等价于
criteria =newCriteria("price").greaterThan(20.0).and("price").lessThan(80.0);//条件:(20.0 < price < 80.0) && (name=三国演义) && (author=罗贯中)
criteria =newCriteria("price").between(20.0,80.0).and("name").is("三国演义").and("author").is("罗贯中");Query query =newCriteriaQuery(criteria);SearchHits<Book> hits = elasticsearchRestTemplate.search(query,Book.class,IndexCoordinates.of("book"));List<SearchHit<Book>> list = hits.getSearchHits();for(SearchHit<Book> hit : list){System.out.println(hit.getContent());}}
or逻辑:
@Testpublicvoidor_criteria(){//条件:(name=三国演义) OR (author=曹雪芹)Criteria criteria =newCriteria("name").is("三国演义").or("author").matches("曹雪芹");//条件:(name=三国演义) OR (name=西游记)
criteria =newCriteria("name").matches("三国演义").or("name").matches("西游记");Query query =newCriteriaQuery(criteria);SearchHits<Book> hits = elasticsearchRestTemplate.search(query,Book.class,IndexCoordinates.of("book"));List<SearchHit<Book>> list = hits.getSearchHits();for(SearchHit<Book> hit : list){System.out.println(hit.getContent());}}
and和or逻辑组合:
@Testpublicvoidand_or_criteria(){//条件:(name=三国演义) && (author=罗贯中) || (name=西游记)Criteria criteria =newCriteria("name").is("三国演义").and("author").matches("罗贯中").or("name").is("西游记");Query query =newCriteriaQuery(criteria);SearchHits<Book> hits = elasticsearchRestTemplate.search(query,Book.class,IndexCoordinates.of("book"));List<SearchHit<Book>> list = hits.getSearchHits();for(SearchHit<Book> hit : list){System.out.println(hit.getContent());}}
6.1.3、嵌套查询
如果要创建嵌套查询,则需要为此使用子查询。subCriteria()使用AND逻辑连接条件。
可以简单的理解为:每一个subCriteria()就开启了一个
()
,这个
()
和父条件之间使用AND连接。
@Testpublicvoidsub_criteria(){//示例一//条件: (20.0 < price < 80.0) && (name=三国演义 || author=吴承恩)Criteria criteria =newCriteria("price").between(20.0,80.0).subCriteria(//添加子查询条件,默认and连接newCriteria()//空条件.or("name").is("三国演义")//以为第一个是空条件,所以此处or或and都可以.or("author").is("吴承恩")//此处必须为or);//上面构建的条件最原始的形态是:(20.0 < price < 80.0) && (空条件 || name=三国演义 || author=吴承恩)//示例二//条件:(name=三国演义 && author=罗贯中) || (name=西游记 && author=吴承恩)
criteria =newCriteria("name").is("三国演义").subCriteria(newCriteria("author").is("罗贯中")).or(newCriteria("name").is("西游记").subCriteria(newCriteria("author").is("吴承恩")));//上面构建的条件最原始的形态是:(name=三国演义 && (author=罗贯中)) || (name=西游记 && (author=吴承恩))//因为subCriteria使用and连接,所以只能这样写,非常反人类Query query =newCriteriaQuery(criteria);SearchHits<Book> hits = elasticsearchRestTemplate.search(query,Book.class,IndexCoordinates.of("book"));List<SearchHit<Book>> list = hits.getSearchHits();for(SearchHit<Book> hit : list){System.out.println(hit.getContent());}}
6.1.4、GEO查询
略…
不推荐使用CriteriaQuery进行GEO查询。
6.2、StringQuery
将JSON字符串作为一个Elasticsearch查询。
6.2.1、简单查询
@Testpublicvoidstring_query1(){/**
* {
* "query": {
* "match": {
* "author": "吴承恩"
* }
* }
* }
*/Query query =newStringQuery("{\n"+" \"match\": {\n"+" \"author\": \"吴承恩\"\n"+" }\n"+"}");SearchHits<Book> hits = elasticsearchRestTemplate.search(query,Book.class,IndexCoordinates.of("book"));List<SearchHit<Book>> list = hits.getSearchHits();for(SearchHit<Book> hit : list){System.out.println(hit.getContent());}}
Book{id=2, name='西游记', describe='大师兄!师傅又丢了!', author='吴承恩', price=33.33, createTime=FriOct2708:00:00CST2023}
6.2.2、复杂查询
@Testpublicvoidstring_query2(){/**
* {
* "query": {
* "bool": {
* "must": [
* {
* "range": {
* "price": {
* "gte": 20.0,
* "lte": 80.0
* }
* }
* }
* ],
* "should": [
* {
* "terms": {
* "name": [
* "三国演义",
* "西游记"
* ]
* }
* }
* ],
* "must_not": [
* {
* "match": {
* "author": "曹雪芹"
* }
* }
* ]
* }
* }
* }
*/Query query =newStringQuery("{\n"+" \"bool\": {\n"+" \"must\": [\n"+" {\n"+" \"range\": {\n"+" \"price\": {\n"+" \"gte\": 20.0,\n"+" \"lte\": 80.0\n"+" }\n"+" }\n"+" }\n"+" ],\n"+" \"should\": [\n"+" {\n"+" \"terms\": {\n"+" \"name\": [\n"+" \"三国演义\",\n"+" \"西游记\"\n"+" ]\n"+" }\n"+" }\n"+" ],\n"+" \"must_not\": [\n"+" {\n"+" \"match\": {\n"+" \"author\": \"曹雪芹\"\n"+" }\n"+" }\n"+" ]\n"+" }\n"+"}");SearchHits<Book> hits = elasticsearchRestTemplate.search(query,Book.class,IndexCoordinates.of("book"));List<SearchHit<Book>> list = hits.getSearchHits();for(SearchHit<Book> hit : list){System.out.println(hit.getContent());}}
Book{id=1, name='三国演义', describe='天下大势,分久必合,合久必分。', author='罗贯中', price=55.55, createTime=FriOct2708:00:00CST2023}Book{id=2, name='西游记', describe='大师兄!师傅又丢了!', author='吴承恩', price=33.33, createTime=FriOct2708:00:00CST2023}Book{id=4, name='水浒传', describe='招安', author='施耐庵', price=35.22, createTime=FriOct2708:00:00CST2023}
6.2.3、分页查询
@Testpublicvoidstring_query3(){/**
* {
* "query": {
* "range": {
* "price": {
* "gte": 20.0,
* "lte": 80.0
* }
* }
* },
* "from": 0,
* "size": 2
* }
*/Query query =newStringQuery("{\n"+" \"range\": {\n"+" \"price\": {\n"+" \"gte\": 20.0,\n"+" \"lte\": 80.0\n"+" }\n"+" }\n"+"}",PageRequest.of(0,2));SearchHits<Book> hits = elasticsearchRestTemplate.search(query,Book.class,IndexCoordinates.of("book"));List<SearchHit<Book>> list = hits.getSearchHits();for(SearchHit<Book> hit : list){System.out.println(hit.getContent());}}
Book{id=1, name='三国演义', describe='天下大势,分久必合,合久必分。', author='罗贯中', price=55.55, createTime=FriOct2708:00:00CST2023}Book{id=2, name='西游记', describe='大师兄!师傅又丢了!', author='吴承恩', price=33.33, createTime=FriOct2708:00:00CST2023}
6.2.4、排序查询
@Testpublicvoidstring_query4(){/**
* {
* "query": {
* "range": {
* "price": {
* "gte": 20.0,
* "lte": 80.0
* }
* }
* },
* "sort": [
* {
* "price": {
* "order": "desc"
* }
* }
* ],
* "from": 0,
* "size": 2
* }
*/Query query =newStringQuery("{\n"+" \"range\": {\n"+" \"price\": {\n"+" \"gte\": 20.0,\n"+" \"lte\": 80.0\n"+" }\n"+" }\n"+"}",PageRequest.of(0,2),Sort.by(Sort.Direction.DESC,"price"));SearchHits<Book> hits = elasticsearchRestTemplate.search(query,Book.class,IndexCoordinates.of("book"));List<SearchHit<Book>> list = hits.getSearchHits();for(SearchHit<Book> hit : list){System.out.println(hit.getContent());List<Object> sortValues = hit.getSortValues();
sortValues.forEach(System.out::println);}}
Book{id=3, name='红楼梦', describe='一朝春尽红颜老,花落人亡两不知。', author='曹雪芹', price=66.66, createTime=FriOct2708:00:00CST2023}66.66Book{id=1, name='三国演义', describe='天下大势,分久必合,合久必分。', author='罗贯中', price=55.55, createTime=FriOct2708:00:00CST2023}55.55
6.2.5、高亮查询
@Testpublicvoidstring_query4(){/**
* {
* "query": {
* "match": {
* "describe": "师傅"
* }
* },
* "highlight": {
* "pre_tags": ["<strong>"],
* "post_tags": ["</strong>"],
* "fields": {
* "describe": {}
* }
* }
* }
*/Query query =newStringQuery("{\n"+" \"match\": {\n"+" \"describe\": \"师傅\"\n"+" }\n"+"}");HighlightQuery highlightQuery =newHighlightQuery(newHighlightBuilder().field("describe").preTags("<strong>").postTags("</strong>"));
query.setHighlightQuery(highlightQuery);SearchHits<Book> hits = elasticsearchRestTemplate.search(query,Book.class,IndexCoordinates.of("book"));List<SearchHit<Book>> list = hits.getSearchHits();for(SearchHit<Book> hit : list){System.out.println(hit.getContent());List<String> highlightField = hit.getHighlightField("describe");
highlightField.forEach(System.out::println);}}
Book{id=2, name='西游记', describe='大师兄!师傅又丢了!', author='吴承恩', price=33.33, createTime=FriOct2708:00:00CST2023}<strong>师傅</strong>又丢了!
6.3、NativeSearchQuery
NativeSearchQuery是在具有复杂查询或无法使用Criteria API表示的查询时使用的类,例如在构建查询和使用聚合时。它允许使用Elasticsearch库中所有不同的QueryBuilder实现,因此被命名为“原生”。
6.3.1、简单查询
@Testpublicvoidnative_query1(){/**
* {
* "query": {
* "match": {
* "author": "曹雪芹"
* }
* }
* }
*/NativeSearchQuery query =newNativeSearchQuery(QueryBuilders.matchQuery("author","曹雪芹"));SearchHits<Book> hits = elasticsearchRestTemplate.search(query,Book.class,IndexCoordinates.of("book"));List<SearchHit<Book>> list = hits.getSearchHits();for(SearchHit<Book> hit : list){System.out.println(hit.getContent());}}
Book{id=3, name='红楼梦', describe='一朝春尽红颜老,花落人亡两不知。', author='曹雪芹', price=66.66, createTime=FriOct2708:00:00CST2023}
6.3.2、复杂查询
@Testpublicvoidnative_query2(){/**
* {
* "query": {
* "bool": {
* "must": [
* {
* "range": {
* "price": {
* "gte": 20.0,
* "lte": 80.0
* }
* }
* }
* ],
* "should": [
* {
* "terms": {
* "name": [
* "三国演义",
* "西游记"
* ]
* }
* }
* ],
* "must_not": [
* {
* "match": {
* "author": "曹雪芹"
* }
* }
* ]
* }
* }
* }
*/NativeSearchQuery query =newNativeSearchQuery(QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("price").gte(20.0).lte(80.0)).should(QueryBuilders.termsQuery("name","三国演义","西游记")).mustNot(QueryBuilders.matchQuery("author","曹雪芹")));SearchHits<Book> hits = elasticsearchRestTemplate.search(query,Book.class,IndexCoordinates.of("book"));List<SearchHit<Book>> list = hits.getSearchHits();for(SearchHit<Book> hit : list){System.out.println(hit.getContent());}}
Book{id=1, name='三国演义', describe='天下大势,分久必合,合久必分。', author='罗贯中', price=55.55, createTime=FriOct2708:00:00CST2023}Book{id=2, name='西游记', describe='大师兄!师傅又丢了!', author='吴承恩', price=33.33, createTime=FriOct2708:00:00CST2023}Book{id=4, name='水浒传', describe='招安', author='施耐庵', price=35.22, createTime=FriOct2708:00:00CST2023}
6.3.3、分页查询
@Testpublicvoidnative_query3(){/**
* {
* "query": {
* "range": {
* "price": {
* "gte": 20.0,
* "lte": 80.0
* }
* }
* },
* "from": 0,
* "size": 2
* }
*/NativeSearchQuery query =newNativeSearchQuery(QueryBuilders.rangeQuery("price").gte(20.0).lte(80.0));
query.setPageable(PageRequest.of(0,2));SearchHits<Book> hits = elasticsearchRestTemplate.search(query,Book.class,IndexCoordinates.of("book"));List<SearchHit<Book>> list = hits.getSearchHits();for(SearchHit<Book> hit : list){System.out.println(hit.getContent());}}
Book{id=1, name='三国演义', describe='天下大势,分久必合,合久必分。', author='罗贯中', price=55.55, createTime=FriOct2708:00:00CST2023}Book{id=2, name='西游记', describe='大师兄!师傅又丢了!', author='吴承恩', price=33.33, createTime=FriOct2708:00:00CST2023}
6.3.4、排序查询
@Testpublicvoidnative_query4(){/**
* {
* "query": {
* "range": {
* "price": {
* "gte": 20.0,
* "lte": 80.0
* }
* }
* },
* "sort": [
* {
* "price": {
* "order": "desc"
* }
* }
* ],
* "from": 0,
* "size": 2
* }
*/NativeSearchQuery query =newNativeSearchQuery(QueryBuilders.rangeQuery("price").gte(20.0).lte(80.0)).addSort(Sort.by(Sort.Direction.DESC,"price")).setPageable(PageRequest.of(0,2));SearchHits<Book> hits = elasticsearchRestTemplate.search(query,Book.class,IndexCoordinates.of("book"));List<SearchHit<Book>> list = hits.getSearchHits();for(SearchHit<Book> hit : list){System.out.println(hit.getContent());List<Object> sortValues = hit.getSortValues();
sortValues.forEach(System.out::println);}}
Book{id=3, name='红楼梦', describe='一朝春尽红颜老,花落人亡两不知。', author='曹雪芹', price=66.66, createTime=FriOct2708:00:00CST2023}66.66Book{id=1, name='三国演义', describe='天下大势,分久必合,合久必分。', author='罗贯中', price=55.55, createTime=FriOct2708:00:00CST2023}55.55
6.3.5、高亮查询
@Testpublicvoidnative_query5(){/**
* {
* "query": {
* "match": {
* "describe": "师傅"
* }
* },
* "highlight": {
* "pre_tags": ["<strong>"],
* "post_tags": ["</strong>"],
* "fields": {
* "describe": {}
* }
* }
* }
*/NativeSearchQuery query =newNativeSearchQuery(QueryBuilders.matchQuery("describe","师傅"));
query.setHighlightQuery(newHighlightQuery(newHighlightBuilder().field("describe").preTags("<strong>").postTags("</strong>")));SearchHits<Book> hits = elasticsearchRestTemplate.search(query,Book.class,IndexCoordinates.of("book"));List<SearchHit<Book>> list = hits.getSearchHits();for(SearchHit<Book> hit : list){System.out.println(hit.getContent());List<String> highlightField = hit.getHighlightField("describe");
highlightField.forEach(System.out::println);}}
Book{id=2, name='西游记', describe='大师兄!师傅又丢了!', author='吴承恩', price=33.33, createTime=FriOct2708:00:00CST2023}<strong>师傅</strong>又丢了!
6.3.5、聚合查询
@Testpublicvoidnative_query6(){/**
* {
* "size": 0,
* "aggs": {
* "name_count": {
* "terms": {
* "field": "name"
* }
* }
* }
* }
*/NativeSearchQuery query =newNativeSearchQuery(QueryBuilders.matchAllQuery());
query.addAggregation(AggregationBuilders.terms("name_agg").field("name"));SearchHits<Book> hits = elasticsearchRestTemplate.search(query,Book.class,IndexCoordinates.of("book"));Aggregations aggregations = hits.getAggregations();ParsedStringTerms terms = aggregations.get("name_agg");List<?extendsTerms.Bucket> buckets = terms.getBuckets();
buckets.forEach(e ->System.out.println(e.getKeyAsString()+":"+ e.getDocCount()));}
三国演义:1
水浒传:1
红楼梦:1
西游记:1
版权归原作者 吴声子夜歌 所有, 如有侵权,请联系我们删除。