当前位置: 首页 > news >正文

SpringBoot集成ElasticSearch

Spring Boot 2.x 和 3.x 集成方式有什么区别?
ElasticsearchRepository 到底要不要继承?
ElasticsearchOperations 和 ElasticsearchRestTemplate 有何不同?

Spring Boot 2.x集成ES

maven依赖

    <!-- Spring Data Elasticsearch --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency>

配置文件(application.yml)

spring:elasticsearch:rest:uris: http://es-node1:9200,http://es-node2:9200,http://es-node3:9200username: elasticpassword: your-secure-passwordconnection-timeout: 1ssocket-timeout: 30sconnection-request-timeout: 1smax-in-flight-requests-per-route: 50max-in-flight-requests: 200

Java 配置类(核心:支持 HTTPS + 认证)
创建配置类,手动注册 RestClient 和 ElasticsearchRestTemplate Bean。

// ElasticsearchConfig.java
package com.example.demo.config;import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.util.StringUtils;import java.time.Duration;
import java.util.Arrays;@Configuration
public class ElasticsearchConfig {@Value("${spring.elasticsearch.rest.uris}")private String uris;@Value("${spring.elasticsearch.rest.username:}")private String username;@Value("${spring.elasticsearch.rest.password:}")private String password;@Value("${spring.elasticsearch.rest.connection-timeout:1s}")private Duration connectTimeout; // e.g., 1s@Value("${spring.elasticsearch.rest.socket-timeout:30s}")private Duration socketTimeout; // e.g., 30s@Value("${spring.elasticsearch.rest.connection-request-timeout:1s}")private Duration connectionRequestTimeout; // e.g., 1s@Value("${spring.elasticsearch.rest.max-in-flight-requests-per-route:50}")private int maxPerRoute;@Value("${spring.elasticsearch.rest.max-in-flight-requests:200}")private int maxTotal;/*** 构建生产级 RestClient*/@Beanpublic RestClient restClient() {// 1. 解析多个 ES 节点地址HttpHost[] hosts = Arrays.stream(uris.split(",")).map(String::trim).filter(s -> !s.isEmpty()).map(HttpHost::create).toArray(HttpHost[]::new);if (hosts.length == 0) {throw new IllegalArgumentException("Elasticsearch hosts cannot be empty");}// 2. 认证配置(如果启用了安全)final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();if (username != null && !username.trim().isEmpty()) {credentialsProvider.setCredentials(AuthScope.ANY,new UsernamePasswordCredentials(username, password));}// 3. 创建连接管理器(真正的连接池)PoolingAsyncClientConnectionManager connectionManager;try {IOReactorConfig ioReactorConfig = IOReactorConfig.custom().setConnectTimeout(Math.toIntExact(connectTimeout.toMillis())).build();connectionManager = new PoolingAsyncClientConnectionManager(new DefaultConnectingIOReactor(ioReactorConfig));} catch (IOReactorException e) {throw new RuntimeException("Failed to create IOReactor", e);}// 设置连接池大小connectionManager.setMaxTotal(maxTotal);connectionManager.setDefaultMaxPerRoute(maxPerRoute);// 4. 构建 RestClientRestClientBuilder builder = RestClient.builder(hosts).setHttpClientConfigCallback(httpClientBuilder -> {HttpAsyncClientBuilder asyncClientBuilder = httpClientBuilder.setConnectionManager(connectionManager).setDefaultCredentialsProvider(credentialsProvider)// 设置连接存活时间(Keep-Alive).setConnectionTimeToLive(connectTimeout)// 可选:自定义 Keep-Alive 策略.setKeepAliveStrategy((response, context) -> Duration.ofMinutes(5).toMillis());// 🔐 如果是 HTTPS 且自签名证书(仅测试环境!生产请用可信CA)/*if (uris.startsWith("https")) {try {SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, (chain, authType) -> true).build();asyncClientBuilder.setSSLContext(sslContext);asyncClientBuilder.setSSLStrategy(new SSLIOSessionStrategy(sslContext,(hostname, sslSession) -> true)); // 忽略主机名验证(仅测试)} catch (Exception e) {throw new RuntimeException("Failed to create SSL context", e);}}*/return asyncClientBuilder;}).setRequestConfigCallback(requestConfigBuilder ->requestConfigBuilder// 建立连接超时.setConnectTimeout(Math.toIntExact(connectTimeout.toMillis()))// 从连接池获取连接的超时(关键!防无限等待).setConnectionRequestTimeout(Math.toIntExact(connectionRequestTimeout.toMillis()))// 读取响应超时.setSocketTimeout(Math.toIntExact(socketTimeout.toMillis())));return builder.build();}@Beanpublic ElasticsearchOperations elasticsearchOperations(RestClient restClient) {RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());return new ElasticsearchRestTemplate(transport);}// 同时也可以提供 Reactive 版本(可选)@Beanpublic ReactiveElasticsearchOperations reactiveElasticsearchOperations(RestClient restClient) {RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());return new ReactiveElasticsearchTemplate(transport);}
}

实体类

// Product.java
package com.example.demo.entity;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 = "products")
public class Product {@Idprivate String id;@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")private String name;@Field(type = FieldType.Keyword)private String category;@Field(type = FieldType.Double)private Double price;@Field(type = FieldType.Integer)private Integer stock;// 构造函数public Product() {}public Product(String name, String category, Double price, Integer stock) {this.name = name;this.category = category;this.price = price;this.stock = stock;}// Getters and Setterspublic String getId() { return id; }public void setId(String id) { this.id = id; }public String getName() { return name; }public void setName(String name) { this.name = name; }public String getCategory() { return category; }public void setCategory(String category) { this.category = category; }public Double getPrice() { return price; }public void setPrice(Double price) { this.price = price; }public Integer getStock() { return stock; }public void setStock(Integer stock) { this.stock = stock; }@Overridepublic String toString() {return "Product{" +"id='" + id + '\'' +", name='" + name + '\'' +", category='" + category + '\'' +", price=" + price +", stock=" + stock +'}';}
}

Repository 接口

// ProductRepository.java
package com.example.demo.repository;import com.example.demo.entity.Product;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;import java.util.List;@Repository
public interface ProductRepository extends ElasticsearchRepository<Product, String> {List<Product> findByNameContaining(String name);List<Product> findByCategoryAndPriceBetween(String category, Double minPrice, Double maxPrice);
}

服务层

// ProductService.java
package com.example.demo.service;import com.example.demo.entity.Product;
import com.example.demo.repository.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class ProductService {@Autowiredprivate ProductRepository productRepository;@Autowired//@Qualifier("reactiveElasticsearchOperations")private ElasticsearchOperations elasticsearchOperations;//@Autowired//private ElasticsearchRestTemplate ElasticsearchRestTemplate;public Product save(Product product) {return productRepository.save(product);}public List<Product> findAll() {return productRepository.findAll();}public List<Product> searchByName(String name) {return productRepository.findByNameContaining(name);}public List<Product> findByCategoryAndPriceRange(String category, Double min, Double max) {return productRepository.findByCategoryAndPriceBetween(category, min, max);}public void deleteById(String id) {productRepository.deleteById(id);}/*** 使用 ElasticsearchOperations 执行复杂查询(如聚合)*/public void printCategoryAggregation() {// 构建原生查询(可自定义 DSL)NativeSearchQuery query = new NativeSearchQuery(Query.findAll());query.addAggregation(Aggregation.builder("by_category").terms("category.keyword") // 按 keyword 字段聚合.build());// 执行聚合查询SearchHits<Product> hits = elasticsearchOperations.search(query, Product.class);// 输出聚合结果hits.getAggregations().asMap().forEach((name, aggregation) -> {System.out.println("Aggregation: " + name);// 此处可解析 Terms、Histogram 等});}
}

启动类

// Application.java
package com.example.demo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;@SpringBootApplication
@EnableElasticsearchRepositories(basePackages = "com.example.demo.repository")
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}

ElasticsearchOperations 和 ElasticsearchRestTemplate 有何不同?

ElasticsearchOperations是接口,而ElasticsearchRestTemplate 是具体实现类。使用ElasticsearchOperations面向编程的思想,你可以有多个实现类,实际用时选择具体用哪一个。

ElasticsearchRepository 到底要不要继承?

上面配置中使用ProductRepository继承了ElasticsearchRepository

为什么不直接在service层使用ElasticsearchRestTemplate操作ES 。原因如下:

  • 继承ElasticsearchRepository会提供很多默认方法,就像mybatis-plus,提供基本了crud方法
  • 使用ElasticsearchRepository时底层还是使用ElasticsearchRestTemplate 处理的,没必要重复造轮子
  • 处理复杂查询时,service层可以同时使用ElasticsearchRestTemplate
  • 最佳实践就是同时使用,简单操作时使用ElasticsearchRepository,复杂查询时使用ElasticsearchRestTemplate

Spring Boot 3.x集成ES

去掉Java 配置类(核心:支持 HTTPS + 认证)这一步即可。
引入maven依赖,application.yml文件中配置连接信息、认证信息便会自动完成配置。

Spring Boot 2.x 和 3.x 集成方式有什么区别?

2.x版本不支持通过配置文件中的用户名和密码自动完成认证,必须通过配置类完成手动认证
3.x版本支持 application.yml 直接配置,在配置文件中配置密码会自动完成认证,无需再手写配置类。

配置信息解读

1. connection-timeout: 1s
连接建立超时时间

✅ 含义:客户端尝试与 Elasticsearch 节点建立 TCP 连接的最大等待时间。
📌 类比:打电话拨号后,对方多久没接就挂断。
💡 示例:
如果 ES 节点宕机或网络不通,1 秒内无法完成三次握手,则抛出 ConnectTimeoutException。
✅ 默认值:1s
✅ 推荐值:1s ~ 5s
❌ 太大(如 30s):线程长时间阻塞,容易导致雪崩
❌ 太小(如 100ms):在网络抖动时频繁失败
⚠️ 这个“连接”指的是从你的应用服务器到 ES 节点的 TCP 连接。

2. socket-timeout: 30s
套接字超时 / 读取超时(Socket Timeout)

✅ 含义:连接建立成功后,等待数据返回的最大时间。即:发送请求后,最多等多久没收到响应就超时。
📌 类比:电话接通了,但对方一直不说话,等多久你就挂电话。
💡 示例:
你查询一个大数据量的聚合,ES 处理了 35 秒还没返回结果 → 客户端抛出 SocketTimeoutException
✅ 默认值:30s
✅ 推荐值:10s ~ 60s(根据业务复杂度调整)
❌ 太大:请求堆积,线程池耗尽
❌ 太小:复杂查询被误判为失败
⚠️ 这是最常见的超时类型,尤其在聚合、排序、深分页场景下容易触发。

3. connection-request-timeout: 1s
获取连接请求超时

✅ 含义:当连接池满时,新请求等待空闲连接的最大时间。
📌 类比:银行大厅满了,你在门口排队等座位,最多等多久就放弃。
💡 示例:
连接池最大 100 个连接,当前全部被占用 → 新请求开始排队
如果 1 秒内没人释放连接 → 抛出 ConnectionPoolTimeoutException
✅ 推荐值:500ms ~ 2s
✅ 默认值:-1 (无限等待,⚠️ 危险!)
❌ 太大:线程长时间等待,拖垮整个服务
✅ 设置它能防止“雪崩效应”——一个慢请求拖死整个系统
⚠️ 这是你配置中最容易遗漏但最关键的一项!

4. max-in-flight-requests-per-route: 10
每个路由(节点)最大并发请求数

✅ 含义:对同一个 ES 节点(如 http://es-node1:9200),最多同时发送多少个请求。
💡 作用:
防止单个节点被压垮
控制客户端对每个节点的负载
📌 “飞行中请求” = 已发出但未收到响应的请求
✅ 默认值:10
✅ 推荐值:10 ~ 50(取决于节点性能)
❌ 太大:可能打满单个节点的线程池
❌ 太小:无法充分利用并发能力
🎯 比如你有 3 个 ES 节点,该值为 10,则每个节点最多处理 10 个并发请求。

5. max-in-flight-requests: 100
整个客户端最大并发请求数

✅ 含义:客户端总共允许多少个“飞行中”的请求(所有节点加起来)。
💡 作用:
全局控制客户端的并发压力
防止客户端自己资源耗尽(如线程、内存)
✅ 默认值:100
✅ 推荐值:50 * 节点数 或根据 QPS 和 RT 估算
❌ 太大:客户端可能 OOM 或 CPU 过高
❌ 太小:吞吐量上不去
📊 计算公式参考:

最大并发 ≈ QPS × 平均响应时间(秒)
例如:QPS=200,RT=200ms → 需要约 40 个并发连接。

🧩 四者关系图解
深色版本

[你的应用]│├─ connection-request-timeout: 等待连接池放回连接 → 超时则失败│▼
[连接池] ── connection-timeout: 建立 TCP 连接 → 超时则失败│▼
[ES 节点] ── socket-timeout: 等待响应数据 → 超时则失败│◄─── max-in-flight-requests-per-route: 每个节点最多并发数│◄─── max-in-flight-requests: 所有节点总并发上限

6、配置要求
Spring Boot ≥ 2.3在yml文件中配置即可完整自动配置。
Spring Boot ≤ 2.2必须在配置类中手动配置。


文章转载自:

http://lktWxajq.rmxgk.cn
http://FVqeVFOy.rmxgk.cn
http://DwKvFzbm.rmxgk.cn
http://Idn45D3g.rmxgk.cn
http://Np0Q3xDQ.rmxgk.cn
http://fgW1qRlA.rmxgk.cn
http://UbxsMYMU.rmxgk.cn
http://f7HSsef5.rmxgk.cn
http://PzVAareH.rmxgk.cn
http://jQoNsfjz.rmxgk.cn
http://S6mF3Erx.rmxgk.cn
http://vupHO1Wt.rmxgk.cn
http://G4BVG8ue.rmxgk.cn
http://MTkPRySb.rmxgk.cn
http://2ljHJTOw.rmxgk.cn
http://sSWti1FS.rmxgk.cn
http://FYz5Tpl3.rmxgk.cn
http://rcpsvBwA.rmxgk.cn
http://rGSsyQDD.rmxgk.cn
http://Q0fqruqE.rmxgk.cn
http://KmYJlmGb.rmxgk.cn
http://PwTqg657.rmxgk.cn
http://Glk9k3Hn.rmxgk.cn
http://Z1wXspgN.rmxgk.cn
http://tXLubZ6W.rmxgk.cn
http://ggk9Pe6b.rmxgk.cn
http://c3VUM6HA.rmxgk.cn
http://Lp09emIO.rmxgk.cn
http://hRBve40k.rmxgk.cn
http://xa8f2IJ0.rmxgk.cn
http://www.dtcms.com/a/377938.html

相关文章:

  • STL库——AVL树
  • 构建实时消息应用:Spring Boot + Vue 与 WebSocket 的有机融合
  • Aosp13 手机sim卡信号格显示修改
  • 小杰机器学习(five)——PyTorch、Tensor(torch库)、Tensor的基本属性、连续性、张量、随机树种子(seed)。
  • ARM 架构的异常模型(Exception Model)
  • 深度学习——基于 PyTorch 的 CBOW 模型实现自然语言处理
  • Spring Cloud Alibaba快速入门03-OpenFeign进阶用法
  • 【PyTorch】多对象分割
  • npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚
  • NodeJS 8 ,从 0 到 1:npm 包发布与更新全流程指南( 含多场景适配与踩坑总结 )
  • Debian 系统上安装与配置 MediaMTX
  • 【PyTorch训练】准确率计算(代码片段拆解)
  • 【Linux】线程池——详细讲解
  • Linux epoll 机制的核心控制函数——`epoll_ctl`
  • 粒子群优化(PSO)算法详解:从鸟群行为到强大优化工具
  • 从两分钟到毫秒级:一次真实看板接口性能优化实战(已上线)
  • Java入门级教程17——利用Java SPI机制制作验证码、利用Java RMI机制实现分布式登录验证系统
  • 【Redis】常用数据结构之List篇:从常用命令到典型使用场景
  • 掌握单元测试的利器:JUnit 注解从入门到精通
  • 【Vue2手录05】响应式原理与双向绑定 v-model
  • spring项目部署后为什么会生成 logback-spring.xml文件
  • Java 日期字符串万能解析工具类(支持多种日期格式智能转换)
  • 在VS2022的WPF仿真,为什么在XAML实时预览点击 ce.xaml页面控件,却不会自动跳转到具体代码,这样不方便我修改代码,
  • 【数组】区间和
  • Qt 基础编程核心知识点全解析:含 Hello World 实现、对象树、坐标系及开发工具使用
  • 解决推理能力瓶颈,用因果推理提升LLM智能决策
  • 【大前端】常用 Android 工具类整理
  • Gradle Task的理解和实战使用
  • 强大的鸿蒙HarmonyOS网络调试工具PageSpy 介绍及使用
  • C++/QT 1