elasticsearch(四)java 使用更新操作API
1,完整程式碼示例及解析
package com.example.elasticsearch.document; import org.apache.http.HttpHost; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.DocWriteResponse; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.support.ActiveShardCount; import org.elasticsearch.action.support.WriteRequest; import org.elasticsearch.action.support.replication.ReplicationResponse; import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.action.update.UpdateResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.Strings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.get.GetResult; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.search.fetch.subphase.FetchSourceContext; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * Created with IntelliJ IDEA. * * @Author: Weichang Zhong * @Date: 2018/11/7 * @Time: 14:14 * @Description: */ public class SynUpdateRequest { public static void main(String[] args) { try (RestHighLevelClient client = new RestHighLevelClient( RestClient.builder( new HttpHost("127.0.0.1", 9200, "http") ) )) { UpdateRequest request = new UpdateRequest ("posts", "doc", "31"); // UpdateRequest request = new UpdateRequest("posts", "type", "does_not_exist").doc("field", "value"); // jsonMap和jsonString只是兩種不同的傳參方式,可以相互轉換使用,效果相同 // jsonMap內容會自動轉換成json格式 Map<String, Object> jsonMap = new HashMap<>(); jsonMap.put("updated", new Date()); jsonMap.put("reason", "daily update"); jsonMap.put("test", "test update"); request.doc(jsonMap); // true,表明如果文件不存在,則新更新的文件內容作為新的內容插入文件,這個和scriptedUpsert的區別是:更新文件的兩種不同方式,有的使用doc方法更新有的使用指令碼更新 request.docAsUpsert(true); // 為true,表明無論文件是否存在,指令碼都會執行(如果不存在時,會建立一個新的文件) request.scriptedUpsert(true); // 如果文件不存在,使用upsert方法,會根據更新內容建立新的文件 // 需要更新的內容,以json字串方式提供 String jsonString = "{\"created\":\"2017-01-01\"}"; request.upsert(jsonString, XContentType.JSON); // 等待主分片可用的超時時間 request.timeout(TimeValue.timeValueMinutes(300)); //WAIT_UNTIL 一直保持請求連線中,直接當所做的更改對於搜尋查詢可見時的刷新發生後,再將結果返回 request.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL); // 如果更新的過程中,文件被其它執行緒進行更新的話,會產生衝突,這個為設定更新失敗後重試的次數 request.retryOnConflict(3); // 是否將文件內容作為結果返回,預設是禁止的 request.fetchSource(true); // 設定希望在返回結果中返回的欄位值 String[] includes = new String[]{"updated", "r*"}; String[] excludes = Strings.EMPTY_ARRAY; // request.fetchSource(new FetchSourceContext(false, includes, excludes)); // NO OPeration,空操作檢查,預設情況為true,只有原來的source和新的source存在不同的欄位情況下才會重建索引,如果一模一樣是不會觸發重建索引的,如果將detect_noop=false不管內容有沒有變化都會重建索引,這一點可以通過version的值的變化來發現 request.detectNoop(true); // 設定在更新操作執行之前,要求活動狀態的分片副本數;單機不要設定,否則會報錯:超時 // request.waitForActiveShards(2); // request.waitForActiveShards(ActiveShardCount.ALL); UpdateResponse updateResponse = client.update(request, RequestOptions.DEFAULT); if (updateResponse.getResult() == DocWriteResponse.Result.CREATED) { System.out.println("文件建立成功!"); }else if(updateResponse.getResult() == DocWriteResponse.Result.UPDATED) { // 任何一個欄位的更新,都算更新操作,即使只是日期欄位的值變化 System.out.println("文件更新成功!"); }else if (updateResponse.getResult() == DocWriteResponse.Result.DELETED) { System.out.println("文件刪除成功!"); } else if (updateResponse.getResult() == DocWriteResponse.Result.NOOP) { // 如果request.detectNoop(true);中設定為false,則這個永遠不會進入 System.out.println("文件無變化!"); } String index = updateResponse.getIndex(); String type = updateResponse.getType(); String id = updateResponse.getId(); long version = updateResponse.getVersion(); System.out.println("index:" + index + "; type:" + type + "; id:" + id + ",version:" + version); ReplicationResponse.ShardInfo shardInfo = updateResponse.getShardInfo(); if (shardInfo.getTotal() != shardInfo.getSuccessful()) { System.out.println("未完全執行所有分片,總分片數為:" + shardInfo.getTotal() + ",執行的分片數為:"+ shardInfo.getSuccessful()); } // fetchSource 如果設定需要返回結果中包含內容了,如果沒有設定返回內容,則result 等於null GetResult result = updateResponse.getGetResult(); if(result == null) { System.out.println("無內容結果返回"); }else if (result.isExists()) { // 此例中如果文件不存在,且這樣設定:request.scriptedUpsert(true);、request.docAsUpsert(false);,則會建立一個空內容的文件,因為指令碼中沒有內容,而禁止doc建立新文件 String sourceAsString = result.sourceAsString(); System.out.println(sourceAsString); Map<String, Object> sourceAsMap = result.sourceAsMap(); } }catch (ElasticsearchException e) { if (e.status() == RestStatus.NOT_FOUND) { // 如果不使用request.upsert方法,且request.scriptedUpsert(false);和request.docAsUpsert(false);都設定為false,則文件不存在時提示沒有找到文件 System.out.println("文件不存在"); }else if(e.status() == RestStatus.CONFLICT) { System.out.println("需要刪除的文件版本與現在文件衝突!"); } } catch (Exception e) { e.printStackTrace(); } } }
2,此程式碼示例執行情況說明:
1)以下情況
a.如果將request.docAsUpsert(true) 和request.scriptedUpsert(true)註釋掉或都設定為false,
b.如果將request.docAsUpsert(true) 設定為faluse,而request.scriptedUpsert(true)為true
且文件不存在,則創建出來的文件內容為:
{"created":"2017-01-01"},
即只有request.upsert(jsonString, XContentType.JSON)中的jsonString內容被建立,而request.doc(jsonMap)中的jsonMap內容沒被建立
2)此例中如果文件不存在,且這樣設定:request.scriptedUpsert(true);、request.docAsUpsert(false);,則會建立一個空內容的文件,因為指令碼中沒有內容,而禁止通過doc秋冬裝建立新文件
3)如果不使用request.upsert方法,且request.scriptedUpsert(false);和request.docAsUpsert(false);都設定為false,
則文件不存在時提示沒有找到文件,而不會建立新的文件
4)如果request.docAsUpsert(true)和request.scriptedUpsert(true)都設定為true,且
request.doc(jsonMap)被註釋掉時,會報錯如下:
org.elasticsearch.action.ActionRequestValidationException:
Validation Failed: 1: script or doc is missing;2: doc must be specified if doc_as_upsert is enabled;
即如果開啟動了doc_as_upsert方法,則必須使用doc方法傳入需要更新的內容
5)注:單機不要使用如下方法,否則會報超時異常
// request.waitForActiveShards(2);
// request.waitForActiveShards(ActiveShardCount.ALL);