前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ES更新嵌套数组(使用Java API)

ES更新嵌套数组(使用Java API)

作者头像
allsmallpig
发布2022-01-06 15:18:24
2.5K0
发布2022-01-06 15:18:24
举报
文章被收录于专栏:allsmallpi博客allsmallpi博客

最近在做一个需求,一开始的时候以为用es脚本能搞定,耽搁了一天半时间。

后来用了Java client 的api来做,效率快多了。

代码语言:javascript
复制
package com.XXX.XXXX.XXX;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.assertj.core.util.Arrays;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class HestiaApplicationTests {

    @Resource
    protected RestHighLevelClient client;

    @Test
    public void contextLoads() {
    }

    /**
     * *先检索、再更新文档
     **/
    @Test
    public void search() throws IOException {

		try {
			SearchRequest searchRequest = new SearchRequest("zm_prod");
			SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
			// 第几页
			searchSourceBuilder.from(0);
			Map<String, Object> params = new HashMap<>();
			//课程标签:1.大班课;2.小班课;3.AI课;4.磨课
//        Script script = new Script(ScriptType.INLINE, "painless", "ctx._source.values.base_info.course_mark == 2", params);
//        searchSourceBuilder.query(QueryBuilders.scriptQuery(script));
//        searchSourceBuilder.query(QueryBuilders.matchQuery("_source.values.base_info.course_mark",2));


			searchSourceBuilder.query(QueryBuilders.termQuery("_id", 55074));
//			searchSourceBuilder.query(QueryBuilders.matchAllQuery());
			// 每页多少条数据
			searchSourceBuilder.size(1000);
			// 设置超时时间为2s
			searchSourceBuilder.timeout(new TimeValue(2000));

			// 设置request要搜索的索引和类型
//		searchRequest.indices("zm_prod").types("news");
			// 设置SearchSourceBuilder查询属性
			searchRequest.source(searchSourceBuilder);

			SearchResponse searchResponse = client.search(searchRequest);
			SearchHit[] searchHits = searchResponse.getHits().getHits();
			if (ArrayUtils.isEmpty(searchHits)) {
				log.info("searchHits = 666666666666666666666");
			}

			for (SearchHit hit : searchHits) {
				//文档的主键
				String id = hit.getId();
				String index = hit.getIndex();
				String type = hit.getType();
				String sourceAsString = hit.getSourceAsString();
				if(!sourceAsString.contains("course_mark")){
					continue;
				}
				//源文档内容
				Map<String, Object> sourceAsMap = hit.getSource();
//				String s = JSON.toJSONString(sourceAsMap);
				Map<String, Object> values = (Map)sourceAsMap.get("values");
				Map<String, Object>  base_info = (Map)values.get("base_info");

				Integer course_mark = (Integer) base_info.get("course_mark");
				String base_infostr = JSON.toJSONString(base_info);
				if(null!=course_mark){
					if(course_mark==1||course_mark==2||course_mark==3){
						log.info(" base_infostr = " + base_infostr);

                         //TODO 这个地方反向的在map里面添加字段,然后重新组装,然后更新当前的数据
						base_info.put("BBB",7777);
						values.put("base_info",base_info);

						UpdateRequest uRequest = new UpdateRequest()
								.index(index)
								.type(type)
								.id(id)
								.doc(XContentFactory.jsonBuilder()
										.startObject().field("values", values).endObject());
						BulkRequest blkRequest = new BulkRequest();
						blkRequest.add(uRequest);
                       // 执行
						BulkResponse bulkResponse = client.bulk(blkRequest);
//						for (UpdateRequest uprequest : list) {
//							bulkResponse.add(uprequest);
//						}

//						BulkResponse bulkResponse = bulkResponse.execute().actionGet();

						if (bulkResponse.hasFailures()) {
							System.out.println("批量错误!");
						}

					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
			log.error(ExceptionUtils.getMessage(e));
		}
    }

}

以下是参考别的博主的内容;

最近在学习ElasticSearch,前些天在工作中遇到一个难以解决的问题,问题正如标题所示在使用Java TransportClient更新ES复杂数据结构数组,最后请教大佬问题得以解决。此文章将详细描述问题并提供解决办法。

博主要更新的数据格式大致如下:

原数据:一个嵌套类型的数组 更新后的数据:将商场01对应的数据从数组删除

代码语言:javascript
复制
"list":[
    {
    "code": "9111364",
    "name": "企业01"
    },
    {
     "code": "900662",
    "name": "智能01"
   },
   {
   "code": "9000300",
   "name": "商场01"
    }
]

博主是ES小白,对于此类型的数据不知道如何正确使用 UpdateRequest进行更新。

于是乎使用如下方法,value表示更新的数据(也就是没有"商场01"的list数据),对于value的类型博主尝试过Object和List<>,甚至将list转成Json格式结果都不可以。

// XXXXXXXXX表示要更新的数据 // List value = XXXXXXXXX; // XXXXXXXXX表示要更新的数据 // Object value = XXXXXXXXX; List> value = XXXXXXXXX; // 这个好用 updateRequest.doc(XContentFactory.jsonBuilder() .startObject() .field("name", value) .field(flag, 1) .endObject()); 最后大佬告诉我要将List value转成List> value,也就是当使用updateRequest的时候,对于字段类型是对象数组的,ES是无法正常更新的,要将List中的泛型专程Map类型,Es才会识别。

// 将嵌套数组对象转Set格式(List也可以),否则无法进行更新(会报错) List> set = Lists.newArrayList(); Map map = Maps.newHashMap(); Class clazz; // 使用反射动态将Set中的属性值放入Map中 for (Object obj : setArry) { clazz = obj.getClass(); // 遍历当前对象的属性值 for (Field field : clazz.getDeclaredFields()) { field.setAccessible(true); String name = field.getName(); Object value = field.get(obj); map.put(name, value); } set.add(map); map = Maps.newHashMap(); 由于此种数组类型较多,博主使用反射,可以兼容每种数组类型。最后成功更新数据。

同时参考了

如果更新一条文档,而且知道文档id的前提下可以使用UpdateRequest即可实现,代码如下:

代码语言:javascript
复制
/**
     * 根据文档id更新
     * @throws IOException
     */
    @Test
    public void test() throws IOException {
        UpdateRequest request = new UpdateRequest("sub_bank1031","sub_bank","SvjgP24BndtcmnpzbiuL");
        request.doc("{\"aliasName\":\"中国农业发展银行林州市支行444\",\"bankType\":\"ADB\",\"bankTypeName\":\"中国农业发展银行\",\"cityId\":\"410500\",\"cityName\":\"安阳市\",\"createTime\":1515719190000,\"createUser\":\"system\",\"id\":\"000238a326b044e9ae10cfe4298f4c44\",\"isEnabled\":\"1\",\"name\":\"中国农业发展银行林州市支行\",\"provinceId\":\"410000\",\"provinceName\":\"河南省\",\"unionNumber\":\"203496100010\"}", XContentType.JSON);
        UpdateResponse resp = highLevelClient.update(request, RequestOptions.DEFAULT);
        println(resp.getResult());
    }

但是如果不知道文档id的情况如果还想使用UpdateRequest更新文档就需要先使用SearchRequest根据某个条件查询符合条件的文档,然后再循环更新文档即可。

代码语言:javascript
复制
    /**
    **先检索、再更新文档
    **/
   	@Test
	public void search() throws IOException{
		SearchRequest searchRequest = new SearchRequest("sub_bank1031");
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		searchSourceBuilder.query(QueryBuilders.matchQuery("_id", "SvjgP24BndtcmnpzbiuL"));
		searchSourceBuilder.size(2);
		searchRequest.source(searchSourceBuilder);
		SearchResponse searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT); 
		SearchHit[] searchHits = searchResponse.getHits().getHits();
	    for(SearchHit s:searchHits){
           String docId = s.getId();
    		UpdateRequest request = new UpdateRequest("sub_bank1031","sub_bank",docId);
		request.doc("{\"aliasName\":\"中国农业发展银行林州市支行444\",\"bankType\":\"ADB\",\"bankTypeName\":\"中国农业发展银行\",\"cityId\":\"410500\",\"cityName\":\"安阳市\",\"createTime\":1515719190000,\"createUser\":\"system\",\"id\":\"000238a326b044e9ae10cfe4298f4c44\",\"isEnabled\":\"1\",\"name\":\"中国农业发展银行林州市支行\",\"provinceId\":\"410000\",\"provinceName\":\"河南省\",\"unionNumber\":\"203496100010\"}", XContentType.JSON);
		UpdateResponse resp = highLevelClient.update(request, RequestOptions.DEFAULT);
		println(resp.getResult());              
	    }
	}

上面操作略显麻烦,需要多条http请求才能完成,要更新的文档数量很多时将大大降低系统响应速度,这时候我们可以使用es的UpdateByQueryRequest来实现该功能。

代码语言:javascript
复制
/**
     * 通过脚本更新文档
     * @throws IOException
     */
    @Test
    public void updateByQueryRequest() throws IOException {
        UpdateByQueryRequest request = new UpdateByQueryRequest("sub_bank1031");
        request.setDocTypes("sub_bank");
        request.setQuery(new TermQueryBuilder("cityId", "511000"));
        request.setSize(2);
        request.setScript(
                new Script(
                    ScriptType.INLINE, "painless",
                    "if (ctx._source.bankType == 'BOC') {ctx._source.aliasName='hello'}",
                    Collections.emptyMap()));    
        BulkByScrollResponse resp = highLevelClient.updateByQuery(request, RequestOptions.DEFAULT);
    }

PS:

pom文件es相关依赖如下:

代码语言:javascript
复制
  <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>6.8.0</version>
        </dependency>
        <!-- elasticsearch high level -->    
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.elasticsearch</groupId>
                    <artifactId>elasticsearch</artifactId>                
                </exclusion>
            </exclusions>
            <version>6.8.0</version>
        </dependency>
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-06-25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
Elasticsearch Service
腾讯云 Elasticsearch Service(ES)是云端全托管海量数据检索分析服务,拥有高性能自研内核,集成X-Pack。ES 支持通过自治索引、存算分离、集群巡检等特性轻松管理集群,也支持免运维、自动弹性、按需使用的 Serverless 模式。使用 ES 您可以高效构建信息检索、日志分析、运维监控等服务,它独特的向量检索还可助您构建基于语义、图像的AI深度应用。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档