如何在Spring Boot中通过RestHighLevelClient递归向Elasticsearch嵌套文档插入数据
Spring Boot 基于RestHighLevelClient向nested嵌套字段追加数据实现方案
前置说明
你当前的索引中companyaddress是nested嵌套类型,要实现追加数据无需每次全量查询再覆盖,直接用Elasticsearch的painless脚本更新即可,性能更高且避免并发冲突。
第一步:引入依赖(确认版本匹配)
确保你的pom.xml引入对应版本的ES客户端依赖,版本需和你部署的ES集群大版本完全一致:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> <!-- 版本和Spring Boot版本对应,确保ES客户端版本和集群版本一致 --> </dependency>
第二步:定义对应实体类
import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.annotations.FieldType; import java.util.List; @Document(indexName = "你的实际索引名") public class Company { @Field(type = FieldType.Long) private Long companyId; @Field(type = FieldType.Text, analyzer = "likely_analyzer", searchAnalyzer = "standard") private String companyName; @Field(type = FieldType.Nested) private List<CompanyAddress> companyaddress; // 省略getter、setter方法 } class CompanyAddress { @Field(type = FieldType.Text, analyzer = "likely_analyzer", searchAnalyzer = "standard") private String address3; @Field(type = FieldType.Long) private Long mainPhone1; // 省略getter、setter方法 }
第三步:核心追加数据实现(推荐脚本更新方式)
直接通过更新请求+脚本实现原子追加,无需先查询文档:
import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.action.update.UpdateResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.HashMap; import java.util.Map; @Service public class CompanyEsService { @Autowired private RestHighLevelClient restHighLevelClient; @Autowired private ObjectMapper objectMapper; /** * 向companyaddress字段追加新地址 * @param docId 目标文档ID * @param newAddress 待新增的地址对象 */ public void appendCompanyAddress(String docId, CompanyAddress newAddress) throws Exception { UpdateRequest updateRequest = new UpdateRequest("你的实际索引名", docId); // 构造painless执行脚本 Map<String, Object> params = new HashMap<>(); params.put("newAddress", objectMapper.convertValue(newAddress, Map.class)); Script script = new Script(ScriptType.INLINE, "painless", "if (ctx._source.companyaddress == null) {ctx._source.companyaddress = new ArrayList();} ctx._source.companyaddress.add(params.newAddress)", params); updateRequest.script(script); // 开启冲突重试,最多重试3次解决并发更新问题 updateRequest.retryOnConflict(3); // 执行更新请求 UpdateResponse response = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT); } }
注意事项
- 如果是新增文档,直接给
companyaddress赋值为包含首个元素的List即可,无需走追加逻辑 - 确保RestHighLevelClient的版本和ES服务端大版本一致,否则会出现兼容性问题
- 如果需要插入数据后立即查询可见,可以给updateRequest设置
setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE),但会牺牲写入性能,非必要不开启
内容的提问来源于stack exchange,提问作者Dorayya
相关产品推荐
相关产品推荐

