Spring Boot 集成 Elasticsearch 的完整指南(2025 年最新版)
本文介绍了2025年推荐的Spring Boot与Elasticsearch集成技术栈。主要内容包括: 技术栈选择:推荐Spring Boot 3.2+、Elasticsearch 8.10+及Spring Data Elasticsearch 5.2+组合,使用新的Elasticsearch Java API Client替代旧版REST Client。 开发配置: 提供Maven依赖配置示例
🧩 一、技术栈说明(2025 推荐)
| 组件 | 版本 | 说明 |
|---|---|---|
| Spring Boot | 3.2+ 或 3.3+ |
使用 Jakarta EE 9+(包名 jakarta.*) |
| Elasticsearch | 8.10+ 或 8.12+ |
官方推荐使用 Elasticsearch Java API Client(非 High Level REST Client) |
| Spring Data Elasticsearch | 5.2+ |
与 Spring Boot 3 兼容 |
⚠️ 注意:
- Elasticsearch 7.17 是最后一个支持 Transport Client 的版本
- Spring Boot 3 不再支持旧版 High Level REST Client
- 官方推荐使用新的 Elasticsearch Java API Client
📦 二、Maven 依赖配置
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Data Elasticsearch (自动集成 Java API Client) -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
</dependency>
<!-- Lombok(可选) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
✅ Spring Boot 3.2+ 会自动引入兼容的
co.elastic.clients:elasticsearch-java。
⚙️ 三、application.yml 配置
spring:
elasticsearch:
uris: http://localhost:9200
# 若需认证(如 Elastic Cloud)
# username: elastic
# password: your-password
connection-timeout: 1s
socket-timeout: 30s
🔐 如果使用 Elastic Cloud 或开启安全认证,请配置用户名密码。
📄 四、定义实体类(Document)
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 = "product") // 索引名
public class Product {
@Id
private 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;
// 构造函数、getter/setter 略
}
💡 提示:
@Document对应 ES 中的索引(index)@Field定义字段类型和分词器(如使用 IK 分词器需提前安装)
🗃️ 五、创建 Repository 接口
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ProductRepository extends ElasticsearchRepository<Product, String> {
// 自动实现 CRUD 和简单查询
// 方法命名查询(支持)
List<Product> findByCategory(String category);
List<Product> findByNameContaining(String name);
}
✅ 继承
ElasticsearchRepository后,自动获得:
save(),findById(),delete()findAll(),count()- 命名约定查询(如
findByXxx)
🧪 六、Service 层使用示例
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
public Product save(Product product) {
return productRepository.save(product);
}
public Optional<Product> findById(String id) {
return productRepository.findById(id);
}
public List<Product> searchByCategory(String category) {
return productRepository.findByCategory(category);
}
// 批量保存
public Iterable<Product> saveAll(List<Product> products) {
return productRepository.saveAll(products);
}
}
🔍 七、高级查询:使用 ElasticsearchTemplate 或 ElasticsearchOperations
对于复杂查询(如 bool、range、highlight),推荐使用 ElasticsearchOperations:
@Service
public class ProductSearchService {
@Autowired
private ElasticsearchOperations elasticsearchOperations;
public List<Product> searchProducts(String keyword, Double minPrice) {
Query query = NativeQuery.builder()
.withQuery(q -> q
.bool(b -> b
.must(m -> m.match(t -> t.field("name").query(keyword)))
.filter(f -> f.range(r -> r.field("price").gte(minPrice.toString())))
)
)
.build();
SearchHits<Product> hits = elasticsearchOperations.search(query, Product.class);
return hits.getSearchHits().stream()
.map(SearchHit::getContent)
.collect(Collectors.toList());
}
}
✅ 优势:直接使用 Elasticsearch DSL,灵活强大。
🧱 八、索引管理(可选)
8.1 自动创建索引(默认行为)
Spring Data Elasticsearch 会在第一次操作时自动创建索引(但不会自动设置 mapping)。
8.2 手动创建索引 + Mapping
@Component
public class IndexInitializer {
@EventListener(ApplicationReadyEvent.class)
public void initIndex() {
ElasticsearchRestTemplate template = ...; // 或注入 ElasticsearchOperations
if (!template.indexExists(Product.class)) {
template.createIndex(Product.class);
template.putMapping(Product.class);
}
}
}
💡 建议在生产环境提前用 Kibana 或脚本创建好索引模板,避免自动创建导致 mapping 不符合预期。
🧪 九、测试验证
-
启动 Elasticsearch(Docker 示例):
docker run -d --name es -p 9200:9200 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:8.12.0 -
启动 Spring Boot 应用
-
调用接口保存数据:
POST /products { "name": "iPhone 16", "category": "Electronics", "price": 7999.0, "stock": 100 } -
查看 ES 数据:
GET http://localhost:9200/product/_search
⚠️ 十、常见问题与注意事项
| 问题 | 解决方案 |
|---|---|
No qualifying bean of type 'ElasticsearchOperations' |
确保添加了 spring-data-elasticsearch 依赖 |
| 中文分词无效 | 安装 IK 分词器插件,并在 @Field 中指定 |
| 连接拒绝 | 检查 ES 是否运行,防火墙是否开放 9200 端口 |
Spring Boot 3 报错 javax.* 包不存在 |
升级到兼容 Jakarta EE 的客户端(Spring Data ES 5.2+ 已解决) |
| 性能慢 | 避免频繁小批量写入,使用 bulk 操作 |
📌 总结:最佳实践建议
- 优先使用
ElasticsearchRepository处理简单 CRUD - 复杂查询用
ElasticsearchOperations+ NativeQuery - 生产环境提前定义索引模板(Index Template)
- 敏感数据不要存 ES,ES 不是数据库!
- 监控集群状态(CPU、内存、JVM)
🔗 参考资料
🙌 感谢你读到这里!
🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。
💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友!
💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿
🔔 关注我,不错过下一篇干货!我们下期再见!✨
更多推荐



所有评论(0)