使用版本 ElasticSearch 7.17.3 springboot 2.7 Spring Data Elasticsearch 4.4.8 jdk不需要安装,会使用ES内置的JDK。
安装指定版本的ES,安装指定版本的Spring Boot,安装Spring Boot时选择依赖Spring Data Elasticsearch,spring boot指定了Spring Data Elasticsearch的版本。版本必须对应,否则Spring Data Elasticsearch和ES无法对应起来。
Spring Data Elasticsearch - Reference Documentation 查看版本对应关系。
看Spring Data Elasticsearch官方文档一定注意版本,版本不同,API差距很大,并且分清不同package下的同名类,很容易出错。
&& https://docs.spring.io/spring-data/elasticsearch/docs/4.4.8/reference/html/#preface.metadata && 将url路径中的current或具体版本号修改为Spring Data Elasticsearch版本的版本号就可以查看对应版本文档
下图是查看spring boot中使用Spring Data Elasticsearch的版本号
Elasticsearch是一个分布式全文搜索引擎,支持单节点模式(Single-Node Mode)和集群模式(Cluster Mode)部署,一 般来说,小公司的业务场景往往使用Single-Node Mode部署即可。以Single-Node Mode部署感受下ES,后续搭建分布式集群深入学习。
1. 虚拟机环境准备
操作系统:CentOS 7.x 64 bit
客户端连接工具:SecureCRT关闭虚拟机的防火墙
systemctl stop firewalld.service #停止firewallsystemctl disable firewalld.service #禁止firewall开机启动firewall-cmd --state # 查看防火墙
2. Elasticsearch Single-Node Mode部署
我们在虚拟机上部署Single-Node Mode Elasticsearch
下载Elasticsearch 地址: https://www.elastic.co/cn/downloads/elasticsearch 最新版本 。本课程使用7.3.0版本 。选择Linux版本下载
1.上传、解压tar.gz文件
cd /opt/lagou/software tar -zxvf elasticsearch-7.3.0-linux-x86_64.tar.gz -C ../servers
2.重命名
cd ../servers/ mv elasticsearch-7.3.0/ elasticsearch/
3 配置Elasticsearch
(1)编辑vim /opt/lagou/servers/elasticsearch/confifig/elasticsearch.yml
单机安装请取消注释:node.name: node-1,否则无法正常启动。
修改网络和端口,取消注释master节点,单机只保留一个node
node.name: node-1 network.host: 192.168.1.250 # # Set a custom port for HTTP: # http.port: 9200 cluster.initial_master_nodes: ["node-1"]
(2)按需修改vim /opt/lagou/servers/elasticsearch/confifig/jvm.options内存设置
vim /opt/lagou/servers/elasticsearch/config/jvm.options
根据实际情况修改占用内存,默认都是1G,单机1G内存,启动会占用700m+然后在安装kibana后,基本上无 法运行了,运行了一会就挂了报内存不足。 内存设置超出物理内存,也会无法启动,启动报错。
-Xms2g
-Xmx2g
Exception in thread "main" java.nio.file.AccessDeniedException: /opt/es/elasticsearch-7.17.3/config/jvm.options.d 虚拟机内存设置好,或设置大一点 1G内存肯定不行,至少4G
3.添加es用户,es默认root用户无法启动,需要改为其他用户
useradd estest#修改密码passwd estest改变es目录拥有者账号chown -R estest /opt/lagou/servers/elasticsearch/
4.修改/etc/sysctl.conf
ES因为需要大量的创建索引文件,需要大量的打开系统的文件,所以我们需要解除linux系统当中打开文件最大数目的限制,不然ES启动就会抛错
修改文件句柄数vim /etc/sysctl.conf末尾添加:vm.max_map_count=655360执行sysctl -p 让其生效sysctl -p
5.修改/etc/security/limits.conf
修改linux系统对文件描述符的限制级别vim /etc/security/limits.conf末尾添加:* soft nofile 65536* hard nofile 65536* soft nproc 4096* hard nproc 4096
6.启动es
切换刚刚新建的用户su estest启动命令/opt/lagou/servers/elasticsearch/bin/elasticsearch
7.配置完成:浏览器访问测试。 http://192.168.1.250:9200
8.Google商店安装head插件 就可以查看ES的运行状态或者使用Apipost自己调用接口。
我自己写的接口文件: es接口查询
(1)新建spring boot 项目,选择Spring Data Elasticserach
(2)新建repository实体类,映射Es中的index
package com.eb.fri.casebase.beanMappingESIndex;import lombok.Data; import org.springframework.data.annotation.Id; import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.annotations.FieldType;@Document(indexName = "case") @Data public class Case {@IdString id;//单位@Field(type = FieldType.Text, analyzer = "ik_max_word")//发布时间 fielddata允许排序@Field(type = FieldType.Date,pattern = "yyyy-MM-dd HH:mm:ss")String publish_time;//date类型的数据想要排序,不需要设置fieldata。只需要看下索引是date类型即可。date类型可以进行排序。Test类型可以进行分词。 }
(3)新建接口继承ElasticsearchRepository
package com.eb.fri.casebase.repository;import com.eb.fri.casebase.beanMappingESIndex.Case; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.elasticsearch.annotations.Query; import org.springframework.data.elasticsearch.core.SearchHit; import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;import java.util.List; import java.util.Optional;public interface ElasticsearchCaseRepository extends ElasticsearchRepository
{@OverrideOptional findById(String s);/*** 模糊查询分页实现** @param pageable* @return //*/@Query(value = " {\"fuzzy\": {\"article\": \"?0\"}}")Page findByArticleFussy(String kw, Pageable pageable);} (4)application.yml配置
spring:elasticsearch:uris: 192.168.1.250:9200connection-timeout: 10
(5)配置spring boot内置支持的logback日志
日志配置文件如果是下面文件名和位置,会被spring boot自动识别。
这句是开启Spring Data Elasticsearch的 查询语句日志。
%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n ${LOG_APP_HOME}/base.%d{yyyy-MM-dd}.log ${LOG_MAX_HISTORY} %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{500} - %msg%n (5)controller调用
简单的CRUD使继承自ElasticsearchRepository接口的接口,复杂查询使用NativeSearchQuery构造查询条件。
package com.eb.fri.casebase.controller;import com.alibaba.fastjson.JSONObject; import com.eb.fri.casebase.beanMappingESIndex.Case; import com.eb.fri.casebase.repository.ElasticsearchCaseRepository; import com.eb.fri.casebase.utils.SnowFlake; import org.elasticsearch.common.unit.Fuzziness; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryStringQueryBuilder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.elasticsearch.core.ElasticsearchOperations; import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; import org.springframework.data.elasticsearch.core.SearchHit; import org.springframework.data.elasticsearch.core.SearchHits; import org.springframework.data.elasticsearch.core.query.NativeSearchQuery; import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; import org.springframework.data.web.PageableDefault; import org.springframework.web.bind.annotation.*;import java.util.List;/*** @author liguofang* 对ES数据的查询 包括全文搜索、模糊搜索等*/ @RestController @RequestMapping(value = "/es") public class ESController {@AutowiredElasticsearchCaseRepository esrepo;@AutowiredElasticsearchOperations op;@ResponseBody@PostMapping(value = "/case/save")public String searchBy(@RequestBody Case caseObj) {caseObj.setId(SnowFlake.getID());Case res = esrepo.save(caseObj);return res.toString();}@GetMapping("/case/delete/{id}")public String deleteById(@PathVariable("id") Long id) {return "";}/*** 查询指定单位的文章,根据作者,文章内容等字段** @param pageable* @return*/@GetMapping("/case/searchDeptArticle")public SearchHits
searchDeptArticle(String dept, String fields, @PageableDefault(sort = {"publish_time"}, direction = Sort.Direction.DESC) Pageable pageable) {JSONObject props_json = JSONObject.parseObject(fields);BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();boolQuery.must(QueryBuilders.matchQuery("dept", dept));for (String k : props_json.keySet()) {boolQuery.should(QueryBuilders.matchQuery(k, props_json.getString(k)));}NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()//查询条件.withQuery(boolQuery)//分页.withPageable(pageable).build();SearchHits searchHits = op.search(nativeSearchQuery, Case.class);return searchHits;}}
查询表达式 | Elasticsearch: 权威指南 | Elastic 官方中文文档版本比较旧,新版本没有中文版
Fuzzy query | Elasticsearch Guide [7.17] | Elastic 指定版本
理解bool组合查询
下面的查询用于查找
title
字段匹配how to make millions
并且不被标识为spam
的文档。那些被标识为starred
或在2014之后的文档,将比另外那些文档拥有更高的排名。如果 两者 都满足。 即使数据中不满足should的数据也会查询出来,只不过评分低,排名靠后。{"bool": {"must": { "match": { "title": "how to make millions" }},"must_not": { "match": { "tag": "spam" }},"should": [{ "match": { "tag": "starred" }},{ "range": { "date": { "gte": "2014-01-01" }}}]} }
注意数据是否返回、对评分是否有影响。
must 满足条件才返回
文档 必须 匹配这些条件才能被查询返回。
must_not 不满足条件才返回
文档 必须不 匹配这些条件才能被查询返回。
should 不影响返回,只影响得分
如果满足这些语句中的任意语句,将增加
_score
,否则,无任何影响。它们主要用于修正每个文档的相关性得分。不影响数据是否查询返回。
filter 必须满足条件才返回
必须 匹配条件才会查询返回。这些语句对评分没有贡献,只是根据过滤标准来排除或包含文档。
将查询移到
bool
查询的filter
语句中,这样它就自动的转成一个不评分的 filter 了。{"bool": {"must": { "match": { "title": "how to make millions" }},"must_not": { "match": { "tag": "spam" }},"should": [{ "match": { "tag": "starred" }}],"filter": {"bool": { "must": [{ "range": { "date": { "gte": "2014-01-01" }}},{ "range": { "price": { "lte": 29.99 }}}],"must_not": [{ "term": { "category": "ebooks" }}]}}} }
关键区分:输入是否进行分词、索引内字段Test类型一定进行分词、针对全部字段匹配还是单个字段匹配。输入是否进行错别字修改
分词查询:输入单词会进行分词,索引内的字段数据会进行分词。然后进行单个字段匹配或者全部字段匹配。 给定相似度排序结果。 match queryforstring实现
模糊查询:输入单词修改某几个字,然后和索引内分词的单个字段进行匹配。只能单字段,不能全部字段。 fussy regex实现
精确匹配:term实现。输入单词不进行分词,必须和文段分词完全匹配才可以。term实现。
对于分词的理解: Elasticsearch入门到精通第二篇-查询分析_木秀林的博客-CSDN博客
开发流程
主要工作是开启Spring Data Elasticsearch日志后,对比输出的查询dsl和直接调用es的接口的dsl是否相同。 下面是es的官网中文文档
Spring Data Elasticsearch - Reference Documentation 4.4.8版本文档
Elasticsearch学习(7)—— 查询API - 叶枫啦啦的个人空间 - OSCHINA - 中文开源技术交流社区
如何使用Spring Data Elasticsearch
(1) 自定义映射索引的实体类
package com.eb.fri.casebase.beanMappingESIndex;import lombok.Data; import org.springframework.data.annotation.Id; import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.annotations.FieldType;@Document(indexName = "case") @Data public class Case {@IdString id;//单位@Field(type = FieldType.Text, analyzer = "ik_max_word")//发布时间 fielddata允许排序@Field(type = FieldType.Date,pattern = "yyyy-MM-dd HH:mm:ss")String publish_time;//date类型的数据想要排序,不需要设置fieldata。只需要看下索引是date类型即可。date类型可以进行排序。Test类型可以进行分词。 }
注解:@Document用来声明Java对象与ElasticSearch索引的关系indexName 索引名称(是字母的话必须是小写字母)type 索引类型shards 主分区数量,默认5replicas 副本分区数量,默认1createIndex 索引不存在时,是否自动创建索引,默认true不建议自动创建索引(自动创建的索引 是按着默认类型和默认分词器) 注解:@Id 表示索引的主键 注解:@Field 用来描述字段的ES数据类型,是否分词等配置,等于Mapping描述,其属性包括如下index 设置字段是否索引,默认是true,如果是false则该字段不能被查询store 标记原始字段值是否应该存储在 Elasticsearch 中,默认值为false,以便于快速检索。虽然store占用磁盘空间,但是减少了计算。type 数据类型(text、keyword、date、object、geo等)analyzer 对字段使用分词器,注意一般如果要使用分词器,字段的type一般是text。format 定义日期时间格式 注解:@CompletionField 定义关键词索引 要完成补全搜索analyzer 对字段使用分词器,注意一般如果要使用分词器,字段的type一般是text。searchAnalyzer 显示指定搜索时分词器,默认是和索引是同一个,保证分词的一致性。maxInputLength:设置单个输入的长度,默认为50 UTF-16 代码点
具体映射规则查看官网 Spring Data Elasticsearch - Reference Documentation
注意事项
(1) test类型的字段想排序 必须设置fieldata 但是springboot的api设置无效。必须es api执行才可以。
{"properties": {"publish_time": {"type": "text","fielddata": true}} }
(2)date类型可以进行排序。
(3)排序字段为_score _score才会有相似度分数值,如果排序字段为其他的字段,那么_score值为NaN
(2)自定义接口实现ElasticsearchRepository接口
首先实现映射索引的自定义实体类。
然后实现接口就可以使用一些关键词实现CRUD ES数据。常用来一些简单的操作,不能够实现复杂查询语句。因此,结合ElasticsearchOperations来查询。
package com.eb.fri.casebase.repository;import com.eb.fri.casebase.beanMappingESIndex.Case; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.elasticsearch.annotations.Query; import org.springframework.data.elasticsearch.core.SearchHit; import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;import java.util.List; import java.util.Optional;public interface ElasticsearchCaseRepository extends ElasticsearchRepository
{//继承来的方法@OverrideOptional findById(String s);//根据关键字实现查询指定的字段List > findByAuthor(String kw);/*** 分页实现** @param pageable* @return //*/@Query(value = "{\"match\": {\"article\": {\"query\": \"?0\"}}}")Page findByArticle(String kw, Pageable pageable);} (2)使用ElasticsearchOperations 结合Queries实现查询
构造查询语句的三种方式
CriteriaQuery 隔离具体DSL,根据语义进行构造查询语句
StringQuery 使用ES DSL JSON请求体
NativeSearchQuery ES所有原生API都进行了实现
通过 NativeSearchQueryBuilder.withQuery(QueryBuilder1).withFilter(QueryBuilder2).withSort(SortBuilder1).withXXXX().build(); 这样的方式来完成 NativeSearchQuery 的构建。
QueryBuilder 主要用来构建查询条件、过滤条件,SortBuilder 主要是构建排序。
要构建 QueryBuilder,我们可以使用工具类 QueryBuilders,里面有大量的方法用来完成各种各样的 QueryBuilder 的构建,字符串的、Boolean 型的、match 的、地理范围的等等。
要构建 SortBuilder,可以使用 SortBuilders 来完成各种排序。
然后就可以通过 NativeSearchQueryBuilder 来组合这些 QueryBuilder 和 SortBuilder,再组合分页的参数等等,最终就能得到一个 SearchQuery 了。
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery (QueryBuilders.queryStringQuery ("spring boot OR 书籍")).build ();
@GetMapping("/case/searchDeptArticle")public SearchHits
searchDeptArticle(String dept, String props, @PageableDefault(sort = {"publish_time"}, direction = Sort.Direction.DESC) Pageable pageable) {JSONObject props_json = JSONObject.parseObject(props);BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();boolQuery.must(QueryBuilders.matchQuery("dept", dept));for (String k : props_json.keySet()) {boolQuery.should(QueryBuilders.matchQuery(k, props_json.getString(k)));}NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()//查询条件.withQuery(boolQuery)//分页.withPageable(pageable).build();SearchHits searchHits = op.search(nativeSearchQuery, Case.class);return searchHits;} Query query = new NativeSearchQueryBuilder().addAggregation(terms("lastnames").field("lastname").size(10)) //.withQuery(QueryBuilders.matchQuery("firstname", firstName)).build();SearchHits
searchHits = operations.search(query, Person.class); ElasticSearch系列(六)springboot中使用QueryBuilders、NativeSearchQuery实现复杂查询_雨剑yyy的博客-CSDN博客
QueryBuilders使用
QueryBuilders是ES中的查询条件构造器。下面结合一些具体的查询场景,分析其常用方法。
假设ES中已经有title为 “总裁关心浦东开发开放” 的数据;
ik_smart分词结果:
{"tokens": [{"token": "总裁","start_offset": 3,"end_offset": 6,"type": "CN_WORD","position": 1},{"token": "关心","start_offset": 6,"end_offset": 8,"type": "CN_WORD","position": 2},{"token": "浦东","start_offset": 8,"end_offset": 10,"type": "CN_WORD","position": 3},{"token": "开发","start_offset": 10,"end_offset": 12,"type": "CN_WORD","position": 4},{"token": "开放","start_offset": 12,"end_offset": 14,"type": "CN_WORD","position": 5}] }
精确查询
精确,指的是查询关键字(或者关键字分词后),必须与目标分词结果完全匹配。1.指定字符串作为关键词查询,关键词支持分词
//查询title字段中,包含 ”开发”、“开放" 这个字符串的document;相当于把"浦东开发开放"分词了,再查询; QueryBuilders.queryStringQuery("开发开放").defaultField("title");//不指定feild,查询范围为所有feild QueryBuilders.queryStringQuery("青春");//指定多个feild QueryBuilders.queryStringQuery("青春").field("title").field("content");
2.以关键字“开发开放”,关键字不支持分词
QueryBuilders.termQuery("title", "开发开放") QueryBuilders.termsQuery("fieldName", "fieldlValue1","fieldlValue2...")
3.以关键字“开发开放”,关键字支持分词QueryBuilders.matchQuery("title", "开发开放") QueryBuilders.multiMatchQuery("fieldlValue", "fieldName1", "fieldName2", "fieldName3")
3.2 模糊查询
模糊,是指查询关键字与目标关键字可以模糊匹配。1.左右模糊查询,其中fuzziness的参数作用是在查询时,es动态的将查询关键词前后增加或者删除一个词,然后进行匹配QueryBuilders.fuzzyQuery("title", "开发开放").fuzziness(Fuzziness.ONE)2.前缀查询,查询title中以“开发开放”为前缀的document;QueryBuilders.prefixQuery("title", "开发开放")3.通配符查询,支持*和?,?表示单个字符;注意不建议将通配符作为前缀,否则导致查询很慢QueryBuilders.wildcardQuery("title", "开*放")QueryBuilders.wildcardQuery("title", "开?放")
注意,
在分词的情况下,针对fuzzyQuery、prefixQuery、wildcardQuery不支持分词查询,即使有这种doucment数据,也不一定能查出来,因为分词后,不一定有“开发开放”这个词;查询总结
title为 “总裁关心浦东开发开放” 的数据
查询关键词 开发开放 放 开 queryStringQuery 查询目标中含有开发、开放、开发开放的 无 无 matchQuery 同queryStringQuery 无 无 termQuery 无结果,因为它不支持分词 无 无 prefixQuery 无结果,因为它不支持分词 无 有,目标分词中以”开“开头的 fuzzyQuery 无结果,但是与fuzziness参数有关系 无 无 wildcardQuery 开发开放*无结果 开*,有 放*,无 3.3 范围查询
//闭区间查询 QueryBuilders.rangeQuery("fieldName").from("fieldValue1").to("fieldValue2");//开区间查询,默认是true,也就是包含 QueryBuilders.rangeQuery("fieldName").from("fieldValue1").to("fieldValue2").includeUpper(false).includeLower(false);//大于 QueryBuilders.rangeQuery("fieldName").gt("fieldValue"); //大于等于 QueryBuilders.rangeQuery("fieldName").gte("fieldValue"); //小于 QueryBuilders.rangeQuery("fieldName").lt("fieldValue"); //小于等于 QueryBuilders.rangeQuery("fieldName").lte("fieldValue");
3.4 组合查询boolQuery()QueryBuilders.boolQuery() QueryBuilders.boolQuery().must();//文档必须完全匹配条件,相当于and QueryBuilders.boolQuery().mustNot();//文档必须不匹配条件,相当于not QueryBuilders.boolQuery().should();//至少满足一个条件,这个文档就符合should,相当于or
具体demo如下:public void testBoolQuery() {NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.boolQuery().should(QueryBuilders.termQuery("title", "开发")).should(QueryBuilders.termQuery("title", "青春")).mustNot(QueryBuilders.termQuery("title", "潮头"))).withSort(SortBuilders.fieldSort("id").order(SortOrder.DESC)).withPageable(PageRequest.of(0, 50)).build();List
articleEntities = elasticsearchRestTemplate.queryForList(nativeSearchQuery, ArticleEntity.class);articleEntities.forEach(item -> System.out.println(item.toString())); } 以上是查询title分词中,包含“开发”或者“青春”,但不能包含“潮头”的document;也可以多个must组合。
SortBuilders排序
上述demo中,我们使用了排序条件://按照id字段降序
.withSort(SortBuilders.fieldSort("id").order(SortOrder.DESC))
注意排序时,有个坑,就是在以id排序时,比如降序,结果可能并不是我们想要的。因为根据id排序,es实际上会根据_id进行排序,但是_id是string类型的,排序后的结果会与整型不一致。建议:在创建es的索引mapping时,将es的id和业务的id分开,比如业务id叫做myId:
@Id @Field(type = FieldType.Long, store = true) private Long myId;@Field(type = FieldType.Text, store = true, analyzer = "ik_smart") private String title;@Field(type = FieldType.Text, store = true, analyzer = "ik_smart") private String content;
这样,后续排序可以使用myId进行排序。
分页
使用如下方式分页:@Test public void testPage() {NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchQuery("title", "青春")).withSort(SortBuilders.fieldSort("myId").order(SortOrder.DESC)).withPageable(PageRequest.of(0, 50)).build();AggregatedPage
page = elasticsearchRestTemplate.queryForPage(nativeSearchQuery, ArticleEntity.class);List articleEntities = page.getContent();articleEntities.forEach(item -> System.out.println(item.toString())); } 注意,如果不指定分页参数,es默认只显示10条。
高亮显示
查询title字段中的关键字,并高亮显示:@Test public void test() {String preTag = "";String postTag = "";NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchQuery("title", "开发")).withPageable(PageRequest.of(0, 50)).withSort(SortBuilders.fieldSort("id").order(SortOrder.DESC)).withHighlightFields(new HighlightBuilder.Field("title").preTags(preTag).postTags(postTag)).build();AggregatedPage
page = elasticsearchRestTemplate.queryForPage(nativeSearchQuery, ArticleEntity.class,new SearchResultMapper() {@Overridepublic AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) {List chunk = new ArrayList<>();for (SearchHit searchHit : response.getHits()) {if (response.getHits().getHits().length <= 0) {return null;}ArticleEntity article = new ArticleEntity();article.setMyId(Long.valueOf(searchHit.getSourceAsMap().get("id").toString()));article.setContent(searchHit.getSourceAsMap().get("content").toString());HighlightField title = searchHit.getHighlightFields().get("title");if (title != null) {article.setTitle(title.fragments()[0].toString());}chunk.add(article);}if (chunk.size() > 0) {return new AggregatedPageImpl<>((List ) chunk);}return null;}@Overridepublic T mapSearchHit(SearchHit searchHit, Class type) {return null;}});List articleEntities = page.getContent();articleEntities.forEach(item -> System.out.println(item.toString())); } 结果:
title=勇立潮头——总裁关心浦东开发开放40, content=外交部