ES更新嵌套数组(使用Java API)
最近在做一個需求,一開始的時候以為用es腳本能搞定,耽擱了一天半時間。
后來用了Java client 的api來做,效率快多了。
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 {@Resourceprotected RestHighLevelClient client;@Testpublic void contextLoads() {}/*** *先檢索、再更新文檔**/@Testpublic 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);// 設置超時時間為2ssearchSourceBuilder.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對應的數據從數組刪除
博主是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即可實現,代碼如下:
/*** 根據文檔id更新* @throws IOException*/@Testpublic 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根據某個條件查詢符合條件的文檔,然后再循環更新文檔即可。
上面操作略顯麻煩,需要多條http請求才能完成,要更新的文檔數量很多時將大大降低系統響應速度,這時候我們可以使用es的UpdateByQueryRequest來實現該功能。
PS:
pom文件es相關依賴如下:
??<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>總結
以上是生活随笔為你收集整理的ES更新嵌套数组(使用Java API)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springcloud实践之断路器:Hy
- 下一篇: 《深入理解Java虚拟机》读后总结(一)