Java ES(Elasticsearch)文档增删改查实战指南:从入门到最佳实践
目录导读
- Elasticsearch文档基础概念
- Java API客户端环境搭建
- 创建文档(增)的三种方式
- 读取文档(查)的多种姿势
- 更新文档(改)的核心方法
- 删除文档(删)的操作注意事项
- 增删改查综合案例实战
- 常见问题FAQ
Elasticsearch文档基础概念
Q:什么是Elasticsearch文档?
A:文档是ES中最基本的存储单元,以JSON格式存在,每个文档属于一个索引(类似数据库的表),并拥有唯一ID。

Q:Java ES开发需要什么?
A:需要引入Elasticsearch Java High-Level REST Client 或官方推荐的Java Client(7.x/8.x版本),连接ES集群进行CRUD操作。
Java API客户端环境搭建
Maven依赖示例(最新稳定版):
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.17.10</version>
</dependency>
客户端初始化代码:
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(new HttpHost("localhost", 9200, "http")));
创建文档(增)的三种方式
1 通过JSON字符串创建
IndexRequest request = new IndexRequest("index_name");
request.id("1"); // 指定ID,不指定则由ES自动生成
request.source("{\"title\":\"Java实战\",\"price\":59.9}", XContentType.JSON);
IndexResponse response = client.index(request, RequestOptions.DEFAULT);
2 通过Map对象创建
Map<String, Object> jsonMap = new HashMap<>();
jsonMap.put("title", "Spring Boot教程");
jsonMap.put("price", 45.0);
IndexRequest request = new IndexRequest("books").id("2").source(jsonMap);
client.index(request, RequestOptions.DEFAULT);
3 批量插入(Bulk)
Q:大量数据如何高效写入?
A:使用BulkRequest批量提交,减少网络交互。
BulkRequest bulkRequest = new BulkRequest();
for (int i = 0; i < 1000; i++) {
bulkRequest.add(new IndexRequest("books")
.id(String.valueOf(i))
.source("title", "Book " + i, "price", Math.random()*100));
}
BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
读取文档(查)的多种姿势
1 通过ID精确查询
GetRequest getRequest = new GetRequest("books", "1");
GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);
if (getResponse.isExists()) {
String json = getResponse.getSourceAsString();
System.out.println(json);
}
2 条件查询(Search API)
Q:如何按字段搜索文档?
A:构造SearchRequest配合QueryBuilder。
SearchRequest searchRequest = new SearchRequest("books");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.termQuery("title", "Java"));
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
3 分页与排序
searchSourceBuilder.from(0).size(10); // 分页
searchSourceBuilder.sort("price", SortOrder.DESC); // 按价格降序
更新文档(改)的核心方法
1 完全替换(Index)
IndexRequest request = new IndexRequest("books").id("1");
request.source("title", "新标题", "price", 99.0);
client.index(request, RequestOptions.DEFAULT); // 若ID存在则覆盖
2 部分更新(Update)
推荐使用方式,只修改指定字段:
UpdateRequest updateRequest = new UpdateRequest("books", "1");
updateRequest.doc("price", 88.8);
UpdateResponse updateResponse = client.update(updateRequest, RequestOptions.DEFAULT);
3 脚本更新(复杂逻辑)
UpdateRequest updateRequest = new UpdateRequest("books", "1");
Map<String, Object> params = Collections.singletonMap("newPrice", 70.0);
updateRequest.script(new Script(ScriptType.INLINE, "painless",
"ctx._source.price = params.newPrice", params));
client.update(updateRequest, RequestOptions.DEFAULT);
删除文档(删)的操作注意事项
1 根据ID删除
DeleteRequest deleteRequest = new DeleteRequest("books", "1");
DeleteResponse deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT);
2 按条件批量删除(Delete by Query)
DeleteByQueryRequest request = new DeleteByQueryRequest("books");
request.setQuery(QueryBuilders.rangeQuery("price").gte(100));
BulkByScrollResponse response = client.deleteByQuery(request, RequestOptions.DEFAULT);
重要提醒:
- 删除操作不可逆,建议先备份或使用软删除(添加is_deleted字段标记)
- 生产环境慎用delete_by_query,建议先测试条件
增删改查综合案例实战
场景:模拟电子商务书籍管理系统
// 1. 批量新增
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.add(new IndexRequest("ebooks").id("101").source("title","深入理解Java虚拟机","author","周志明","price",89.0));
bulkRequest.add(new IndexRequest("ebooks").id("102").source("title","Effective Java","author","Joshua Bloch","price",69.0));
client.bulk(bulkRequest, RequestOptions.DEFAULT);
// 2. 查询价格在50-100之间的书籍
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.query(QueryBuilders.rangeQuery("price").gte(50).lte(100));
SearchResponse resp = client.search(new SearchRequest("ebooks").source(builder), RequestOptions.DEFAULT);
// 3. 更新某本书价格
UpdateRequest update = new UpdateRequest("ebooks", "101");
update.doc("price", 79.0);
client.update(update, RequestOptions.DEFAULT);
// 4. 删除过时书籍
DeleteByQueryRequest delReq = new DeleteByQueryRequest("ebooks");
delReq.setQuery(QueryBuilders.termQuery("author", "Joshua Bloch"));
client.deleteByQuery(delReq, RequestOptions.DEFAULT);
常见问题FAQ
Q1:创建文档时ID冲突会怎样?
A:若使用相同ID创建新文档,旧文档会被覆盖(幂等),建议使用es自动生成的ID,或业务主键唯一。
Q2:为什么更新操作没有立即生效?
A:ES采用近实时搜索,默认refresh_interval为1秒,可手动调用request.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)强制刷新(影响性能)。
Q3:如何批量更新/删除大量文档?
A:使用Scroll API + BulkRequest分批次处理,避免内存溢出,示例:
SearchRequest scrollRequest = new SearchRequest("index");
Scroll scroll = new Scroll(TimeValue.timeValueMinutes(1));
scrollRequest.scroll(scroll);
SearchResponse scrollResp = client.search(scrollRequest, RequestOptions.DEFAULT);
String scrollId = scrollResp.getScrollId();
while (scrollResp.getHits().getHits().length > 0) {
// 处理当前批次,获取下一页
SearchScrollRequest scrollSearchReq = new SearchScrollRequest(scrollId);
scrollResp = client.scroll(scrollSearchReq, RequestOptions.DEFAULT);
}
Q4:连接池如何配置?
A:通过RestClientBuilder设置:
RestClientBuilder builder = RestClient.builder(new HttpHost("localhost", 9200));
builder.setRequestConfigCallback(cb -> cb.setConnectTimeout(5000).setSocketTimeout(30000));
builder.setHttpClientConfigCallback(cb -> cb.setMaxConnTotal(100).setMaxConnPerRoute(50));
Java操作ES文档时,建议始终保持幂等性设计,批量操作注意控制内存占用,删除操作务必加上测试条件,实际生产环境中,推荐使用Spring Data Elasticsearch进一步简化代码,但底层原理依然脱离不开本文介绍的RestHighLevelClient核心API。
掌握这些实战技巧,您已经可以应对90%的ES文档操作场景,遇到复杂需求时,请参考官方文档(客户端版本7.17+为成熟稳定版,8.x系列变动较大需注意)的API说明,必要时使用Elasticsearch SQL插件作为补充查询方案。