1. 程式人生 > >elasticsearch(四)java 使用更新操作API

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);