简介面向Java开发者的Spring Boot整合Elasticsearch 7.2.0实战PDF文档围绕新版搜索引擎接入的常见问题展开。文档首先指出版本对应关系中的坑Spring Boot 2.1.X自带的spring-boot-starter-data-elasticsearch默认对应Elasticsearch 2.X而当前需要对接的已是7.2.0版本因此必须弃用旧依赖并改为使用Spring-data-elasticsearch。随后对比了transport与rest两种连接方式的特点说明官方为何建议采用rest并给出可复制的Maven依赖坐标、application.yml中的地址配置以及一个完整的RestHighLevelClient客户端配置类。文中对连接超时、Socket超时等参数也作了说明便于直接套用。文档以可直接运行的示例为主线完整给出了pom中的三项依赖、配置文件里的地址写法以及自定义客户端配置类的全部Java代码读者按步骤复制即可减少调试时间。这份PDF单文件大小约58KB内容精炼、步骤完整当前已有6768人学习下载。无论是正在集成Elasticsearch 7.2.0的新项目还是需要将旧版连接升级改造的老项目都能从其中获得切实可用的参考。1. SpringBoot整合Elasticsearch7.2.0为什么我放弃了官方 Starter做搜索需求时SpringBoot整合Elasticsearch7.2.0最让人头疼的不是ES本身而是版本对应关系。Spring Boot 2.1.X 的spring-boot-starter-data-elasticsearch锁定的 ES 客户端版本是 2.X可当时 ES 已经跑到 7.2.X 了。拿 2.X 的客户端去连 7.2.0 的服务端轻则接口调不通重则序列化直接报错。这个资源给的做法很干脆弃用 starter改用原生elasticsearch-rest-high-level-client把版本控制权完全收回到自己手里。这套方案适合所有用 Spring Boot 2.1.X 但想接 ES 7.x 新特性的团队也适合那些被 starter 版本绑架、想彻底搞懂连接原理的人。2. 依赖选型transport 与 rest 的分水岭2.1 两种连接方式的取舍ES 官方提供了两种 Java 客户端连接方式transport 和 rest。transport 走 TCP 协议只支持 Java 语言rest 走 HTTP API任何语言都能用。在 7.0 版本中 transport 已被标记为不建议使用到了 8.X 直接废弃。这意味着一件事如果你现在新写代码唯一正确的选择就是 rest 方式。rest 方式又分两种客户端elasticsearch-rest-client低层和elasticsearch-rest-high-level-client高层。低层客户端只负责 HTTP 通信索引、查询、删除这些操作全要自己拼 JSON高层客户端在低层之上封装了完整的 Java API增删改查都有对应方法。这个资源用的是高层客户端也是目前生产环境的主流做法。2.2 三个依赖各自的职责properties elasticsearch.version7.2.0/elasticsearch.version /properties dependency groupIdorg.elasticsearch/groupId artifactIdelasticsearch/artifactId version${elasticsearch.version}/version /dependency dependency groupIdorg.elasticsearch.client/groupId artifactIdelasticsearch-rest-client/artifactId version${elasticsearch.version}/version /dependency dependency groupIdorg.elasticsearch.client/groupId artifactIdelasticsearch-rest-high-level-client/artifactId version${elasticsearch.version}/version /dependency第一个依赖是 ES 核心库里面包含 Lucene 和 ES 自身的类第二个是低层 REST 客户端负责 HTTP 连接和请求发送第三个是高层客户端封装了索引、搜索、聚合等操作 API。三个版本必须一致都指向7.2.0。提示elasticsearch-rest-high-level-client传递依赖里已经包含了elasticsearch-rest-client理论上可以不显式声明低层客户端。但显式写出来有个好处版本冲突时一眼能看出问题在哪。2.3 application.yml 配置elasticsearch: ip: 192.168.52.132:9200这里配置的是 ES 服务的 HTTP 地址格式是ip:port。注意这个配置项不是 Spring Boot 内置的是自定义属性后面连接配置类里通过Value(${elasticsearch.ip})注入。端口默认是 9200ES 的 HTTP 对外服务端口9300 是 transport 的端口既然走 rest 方式就只关心 9200。如果 ES 部署在 Docker 里192.168.52.132换成宿主机 IP 即可如果在本机直接127.0.0.1:9200。地址可以配多个用逗号分隔连接类里会自动拆分成多个节点。3. 客户端连接配置RestHighLevelClient 的构建细节3.1 配置文件中的关键代码package com.dc.elastic.configuration; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClientBuilder; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.Arrays; import java.util.Objects; Configuration public class ElasticsearchRestClient { /** 超时时间设为5分钟 */ private static final int TIME_OUT 5 * 60 * 1000; private static final int ADDRESS_LENGTH 2; private static final String HTTP_SCHEME http; Value(${elasticsearch.ip}) String[] ipAddress; Bean public RestClientBuilder restClientBuilder() { System.err.println(ipAddress); HttpHost[] hosts Arrays.stream(ipAddress) .map(this::makeHttpHost) .filter(Objects::nonNull) .toArray(HttpHost[]::new); return RestClient.builder(hosts); } Bean(name highLevelClient) public RestHighLevelClient highLevelClient(Autowired RestClientBuilder restClientBuilder) { restClientBuilder.setRequestConfigCallback( new RestClientBuilder.RequestConfigCallback() { Override public RequestConfig.Builder customizeRequestConfig( RequestConfig.Builder requestConfigBuilder) { return requestConfigBuilder.setSocketTimeout(TIME_OUT); } }); return new RestHighLevelClient(restClientBuilder); } private HttpHost makeHttpHost(String s) { assert StringUtils.isNotEmpty(s); String[] address s.split(:); if (address.length ADDRESS_LENGTH) { String ip address[0]; int port Integer.parseInt(address[1]); System.err.println(ip port); return new HttpHost(ip, port, HTTP_SCHEME); } else { return null; } } }这段配置做了三件事。第一件事把 yml 里配置的elasticsearch.ip字符串数组解析成HttpHost数组。yml 里写的192.168.52.132:9200会自动按逗号拆分成 String[]每个元素再通过makeHttpHost方法拆成 ip 和 port组装成HttpHost对象。第二件事构建RestClient.builder(hosts)传入的 hosts 数组支持多个节点这样 ES 集群里挂掉一个节点客户端会自动把请求转发到其他可用节点这是 rest 方式天然具备的负载均衡能力。第三件事定制RequestConfig把 socket 超时时间设为 5 分钟。这个值很讲究——ES 的大聚合查询、深度分页耗时可能远超默认的 30 秒如果超时时间设太短业务方那边数据没查完这边连接就断了。5 分钟是一个偏保守但安全的取值。注意setSocketTimeout是 socket 读超时不是连接超时。连接超时用setConnectTimeout这里没设走的是 Apache HttpClient 的默认值1 秒。如果是跨机房调用建议把连接超时也显式调大。3.2 这段代码里藏着的三个细节第一个细节Value(${elasticsearch.ip}) String[] ipAddress这种注入方式要求 yml 里的值必须是逗号分隔的字符串Spring 会自动完成字符串到 String[] 的转换。如果有多个节点yml 里这样写elasticsearch: ip: 192.168.52.132:9200,192.168.52.133:9200第二个细节makeHttpHost里用assert StringUtils.isNotEmpty(s)做非空校验。但 assert 默认是关闭的生产环境 JVM 启动参数里如果没有-ea这行等于没写。更稳妥的做法是手动判空if (StringUtils.isEmpty(s)) { return null; }第三个细节配置类里用了System.err.println打印节点信息。生产环境不建议用这种方式输出日志走log.info或者直接删掉不然排查问题的时候控制台会被这些打印刷屏。4. 查询实战从 SearchRequest 到高亮返回4.1 完整的搜索接口代码RequestMapping(/test) public void test(RequestParam String keyword) { Integer pageIndex 1; Integer pageSize 5; String indexName vw_ods; MapString, Object data new HashMap(); data.put(clearacctname, keyword); ListMapString, Object result new ArrayList(); SearchRequest searchRequest new SearchRequest(indexName); queryBuilder(pageIndex, pageSize, data, indexName, searchRequest); try { SearchResponse response highLevelClient.search(searchRequest, RequestOptions.DEFAULT); for (SearchHit hit : response.getHits().getHits()) { MapString, Object map hit.getSourceAsMap(); map.put(id, hit.getId()); result.add(map); MapString, HighlightField highlightFields hit.getHighlightFields(); HighlightField highlight highlightFields.get(clearacctname); Text[] fragments highlight.fragments(); String fragmentString fragments[0].string(); System.out.println(高亮 fragmentString); } System.out.println(pageIndex: pageIndex); System.out.println(pageSize: pageSize); System.out.println(response.getHits().getTotalHits()); System.out.println(result.size()); } catch (IOException e) { e.printStackTrace(); } } private void queryBuilder(Integer pageIndex, Integer pageSize, MapString, Object query, String indexName, SearchRequest searchRequest) { if (query ! null !query.keySet().isEmpty()) { SearchSourceBuilder searchSourceBuilder new SearchSourceBuilder(); if (pageIndex ! null pageSize ! null) { searchSourceBuilder.size(pageSize); if (pageIndex 0) { pageIndex 0; } searchSourceBuilder.from((pageIndex - 1) * pageSize); } BoolQueryBuilder boolBuilder QueryBuilders.boolQuery(); query.keySet().forEach(key - { boolBuilder.must(QueryBuilders.matchQuery(key, query.get(key))); }); searchSourceBuilder.query(boolBuilder); HighlightBuilder highlightBuilder new HighlightBuilder(); HighlightBuilder.Field highlightTitle new HighlightBuilder.Field(title).preTags(strong).postTags(/strong); highlightTitle.highlighterType(unified); highlightBuilder.field(highlightTitle); searchSourceBuilder.highlighter(highlightBuilder); searchRequest.source(searchSourceBuilder); } }这段代码的查询逻辑是接收一个keyword参数去vw_ods索引里做matchQuery全文检索条件是clearacctname字段等于传入的关键词然后分页返回前 5 条同时对命中内容做高亮标记。执行分页时from (pageIndex - 1) * pageSize算出的是跳过多少条。比如第 1 页就是从第 0 条开始取 5 条第 2 页从第 5 条开始取 5 条这是 ES 标准的 from/size 分页方式。注意pageIndex 0时被强制赋为 0 这个细节——如果前端传了 0 或负数(pageIndex - 1) * pageSize得到负数ES 会直接报参数错误。这里给 0 其实也不严谨0 的话from变成-pageSize依然有问题。正确的防御应该是小于等于 0 时赋为 1。4.2 高亮处理的正确姿态代码里高亮部分有个很经典的坑new HighlightBuilder.Field(title)指定的是title字段但实际查询的是clearacctname字段。这意味着高亮结果里highlightFields.get(clearacctname)大概率拿到 null。高亮要想生效必须满足两个条件。第一查询字段必须跟高亮字段一致——查询clearacctname高亮也要写clearacctname。第二目标字段的 mapping 里要开启term_vector: with_positions_offsets或者 ES 7.x 默认的unified高亮器才能正常切词。正确的写法是HighlightBuilder highlightBuilder new HighlightBuilder(); HighlightBuilder.Field highlightField new HighlightBuilder.Field(clearacctname) .preTags(strong) .postTags(/strong) .highlighterType(unified); highlightBuilder.field(highlightField); searchSourceBuilder.highlighter(highlightBuilder);前端拿到返回结果里的clearacctname字段后直接把strong标签渲染成红色或者加粗字体即可不用自己再去做关键词匹配。5. 避坑指南版本冲突、空指针与集群连接失败5.1 现象NoNodeAvailableException客户端连不上 ES原因最常见的是 ES 服务没起或者起了但 9200 端口没对外开放。排查顺序先curl http://192.168.52.132:9200看有没有 JSON 返回没有就去看 ES 的elasticsearch.yml里network.host配置——如果设的是127.0.0.1外部机器访问必然拒绝。解决把 ES 的network.host改成0.0.0.0或者配置成具体的内网 IP然后重启 ES。Docker 部署的话-p 9200:9200端口映射不能少。5.2 现象Spring Boot 启动报NoSuchMethodError或者ClassNotFoundException原因项目里同时存在 Spring Data Elasticsearch 和原生 ES 客户端的兼容性问题。spring-boot-starter-data-elasticsearch传递依赖的 ES 版本是 2.X它的类跟原生 7.2.0 客户端的类冲突了。解决用exclusions把 starter 里的旧 ES 依赖全部排掉dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-elasticsearch/artifactId exclusions exclusion groupIdorg.elasticsearch/groupId artifactIdelasticsearch/artifactId /exclusion exclusion groupIdorg.elasticsearch.client/groupId artifactIdtransport/artifactId /exclusion /exclusions /dependency5.3 现象highLevelClient.search()抛出ElasticsearchStatusException提示all shards failed原因索引不存在或者查询的字段在 mapping 里不存在。调用SearchRequest(vw_ods)时如果vw_ods索引没有创建ES 会对所有分片执行查询全部失败。解决先用curl -X GET http://192.168.52.132:9200/_cat/indices确认索引存在。不存在就先建索引再查。如果索引存在但字段报错用curl -X GET http://192.168.52.132:9200/vw_ods/_mapping看字段类型keyword类型字段用matchQuery查不到预期结果的情况很常见可以换成termQuery加.keyword后缀。5.4 现象高亮结果highlight.fragments()[0]报数组越界原因查询没命中任何数据或者高亮字段名设置错误highlight.getFragments()返回空数组。这是代码原作者在test()方法里写死fragments[0]导致的问题。解决先判空再取HighlightField highlight hit.getHighlightFields().get(clearacctname); if (highlight ! null highlight.fragments() ! null highlight.fragments().length 0) { String fragmentString highlight.fragments()[0].string(); System.out.println(高亮 fragmentString); }5.5 现象elasticsearch.ip注入为 null连接构建时空指针原因Value(${elasticsearch.ip})如果 yml 里的 key 不存在或者缩进不对注入的就是 null。yml 里elasticsearch.ip这个 key 的层级关系必须严格对齐缩进错了 Spring 直接启动失败。解决在配置类里给默认值兜底Value(${elasticsearch.ip:127.0.0.1:9200}) String[] ipAddress;同时确认 yml 里没有把elasticsearch误写成elastic-search或者其他变体。6. 生产级验证从 curl 对照测试到超时与索引优化6.1 用 curl 对比验证查询结果代码写完不是结束最好跟 curl 直查 ES 的结果做交叉验证curl -X GET http://192.168.52.132:9200/vw_ods/_search?pretty \ -H Content-Type: application/json \ -d { query: { bool: { must: [ { match: { clearacctname: 测试关键词 } } ] } }, from: 0, size: 5, highlight: { fields: { clearacctname: { pre_tags: [strong], post_tags: [/strong] } } } }对比curl返回的 JSON 和 Java 代码里response.getHits()解析出来的字段是否一致。这个方法比看日志直观得多我每次排查查询结果对不上的时候都是先用 curl 打一遍确认 ES 侧返回正常再回头看 Java 代码的问题。6.2 超时参数的二次调优原配置里 socket 超时是 5 分钟这个值在绝大多数场景下是够的但生产环境建议再调细致一点。如果查询集中在简单的 keyword 精确匹配5 秒就够如果涉及多字段全文检索加聚合就要按最慢查询耗时乘 2 来定。我一般会这样处理private static final int CONNECT_TIME_OUT 10 * 1000; private static final int SOCKET_TIME_OUT 60 * 1000; restClientBuilder.setRequestConfigCallback(requestConfigBuilder - requestConfigBuilder.setConnectTimeout(CONNECT_TIME_OUT) .setSocketTimeout(SOCKET_TIME_OUT));连接超时 10 秒、读超时 60 秒是比较均衡的配置既不会因为网络抖动频繁报错也不会让慢查询拖死线程池。如果业务方反馈某个聚合查询经常超过 60 秒可以单独为该查询建一个带更长超时的客户端实例而不是全局调大——全局调大意味着所有慢查询都在消耗连接资源。6.3 RestHighLevelClient 用完后要不要关RestHighLevelClient实现了Closeable接口但绝对不能每次查询完就 close。这个客户端内部维护了连接池正确姿势是整个应用生命周期里只初始化一次Spring 容器销毁时再关PreDestroy public void closeClient() { try { if (highLevelClient ! null) { highLevelClient.close(); } } catch (IOException e) { log.error(关闭ES客户端异常, e); } }如果每次请求都 new 一个客户端再 close会频繁创建和销毁 HTTP 连接QPS 稍高一点就会把 ES 节点的连接数打满报too many open files。查问题的那几天我基本是 curl 和 Java 代码两头对照着看确认 ES 侧在做什么、Java 侧传了什么参数这套排查习惯帮我少走了很多弯路。后来每接一个新索引我都会强制走一遍这个流程先 curl 验证字段和查询语法再写 Java 代码最后用真实数据交叉验证返回结果。希望帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
AI芯片建模与仿真:从系统级到电路级的四层建模实战 1. 项目概述:为什么AI芯片建模与仿真不是“画个框图就完事”的事AI芯片建模与仿真,这六个字背后藏着整个智能硬件产业的底层逻辑。它不是数学建模竞赛里用MATLAB拟合曲线的“纸上谈兵”,也不是Wokwi平台上拖拽几个Arduino模块就能跑通的玩具级… · 2026/9/24 0:24:05
FPGA开发效率提升:ISE与Notepad++深度集成方案 1. 项目背景与需求解析在FPGA开发领域,Xilinx ISE 10.1作为经典开发环境,至今仍被许多老项目使用。但原生编辑器功能有限,开发者常需要切换到专业文本编辑器(如Notepad)进行代码编写。手动在两个软件间切换既影响效率&… · 2026/9/24 0:24:05
MATLAB深度强化学习实战:DQN、PPO、DDPG与TD3算法选型及训练避坑 简介:面向深度强化学习初学者及MATLAB仿真开发人员,案例程序聚焦环境构建、智能体训练和结果分析核心环节,通过具体实验演示深度神经网络与策略优化结合方式,帮助理解DQN、PPO、DDPG等主流算法原理与适用场景。资源共21个文件&… · 2026/9/24 1:06:07
深度强化学习云工作流调度:DDPG优先级调度实战解析 简介:一套基于深度强化学习的云工作流调度完整Python工程,面向对云工作流调度与智能优化算法感兴趣的开发者、毕业设计及课程设计学生。资源围绕数据预处理、模型构建、训练与评估完整流程展开,覆盖任务分配、资源利用率优化等核心问题&#… · 2026/9/24 1:06:07
用LSTM让《鹿鼎记》学会写小说:字符级文本生成实战 简介:基于金庸《鹿鼎记》全文数据的LSTM文本生成项目,提供了一套完整可运行的代码与说明,适合自然语言处理入门、毕业设计或课程设计参考。项目覆盖数据爬取到模型训练的全流程:GetLu.py负责抓取小说章节并保存为txt,W… · 2026/9/24 1:06:07
PCA+KMeans遥感变化检测:从数据预处理到参数避坑全指南 简介:这是一份面向遥感图像处理学习者的PCA-Kmeans变化检测小型工程包,适合对主成分分析降维、无监督聚类及地表覆盖变化识别感兴趣的初学者或研究人员。压缩包共14个文件,以Python脚本为主,分别承担主流程、PCA与K-means算法实现… · 2026/9/24 1:06:01
红外多目标检测数据集实战:三格式标签对齐与YOLO训练避坑指南 简介:本资源是一套面向计算机视觉初学者与YOLO目标检测实践者的红外多目标检测数据集及配套开发支持包,专为解决红外场景下小目标、低对比度目标的检测建模难题而设计。资源包含5000张真实场景红外图像,全部经LabelImg高质量标注,… · 2026/9/24 1:06:01
航拍小目标检测数据集实战:从VOC/YOLO格式校验到YOLOv8训练调优 简介:面向智慧牧场航拍场景的牛羊检测任务,该数据集提供了一千零二十一张航拍图像及对应的Pascal VOC与YOLO双格式标注文件,覆盖牛、母牛、羊三个类别,合计一万四千零四十七个标注框。得益于完整的标签数据,开发者可以… · 2026/9/24 1:06:01
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程 简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13
1D-CNN时间序列建模实战:从Conv1d原理到工业落地 简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26
柔软的L:汉语语流中被忽视的舌肌张力控制 1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44