Переглянути джерело

[Docs] Document Update API for Java High Level REST Client (#25536)

This commit adds documentation for Java High Level REST Client's Update API.
Tanguy Leroux 8 роки тому
батько
коміт
fefcae3d45

+ 268 - 4
client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/CRUDDocumentationIT.java

@@ -19,6 +19,8 @@
 
 package org.elasticsearch.client.documentation;
 
+import org.apache.http.HttpEntity;
+import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.ContentType;
 import org.apache.http.nio.entity.NStringEntity;
 import org.elasticsearch.ElasticsearchException;
@@ -48,7 +50,10 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.elasticsearch.common.xcontent.XContentFactory;
 import org.elasticsearch.common.xcontent.XContentType;
 import org.elasticsearch.index.VersionType;
+import org.elasticsearch.index.get.GetResult;
 import org.elasticsearch.rest.RestStatus;
+import org.elasticsearch.script.Script;
+import org.elasticsearch.script.ScriptType;
 import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
 
 import java.io.IOException;
@@ -57,6 +62,9 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 
+import static java.util.Collections.emptyMap;
+import static java.util.Collections.singletonMap;
+
 /**
  * This class is used to generate the Java CRUD API documentation.
  * You need to wrap your code between two tags like:
@@ -72,7 +80,7 @@ import java.util.Map;
  * --------------------------------------------------
  */
 public class CRUDDocumentationIT extends ESRestHighLevelClientTestCase {
-    
+
     public void testIndex() throws IOException {
         RestHighLevelClient client = highLevelClient();
 
@@ -80,8 +88,8 @@ public class CRUDDocumentationIT extends ESRestHighLevelClientTestCase {
             //tag::index-request-map
             Map<String, Object> jsonMap = new HashMap<>();
             jsonMap.put("user", "kimchy");
-            jsonMap.put("postDate",new Date());
-            jsonMap.put("message","trying out Elasticsearch");
+            jsonMap.put("postDate", new Date());
+            jsonMap.put("message", "trying out Elasticsearch");
             IndexRequest indexRequest = new IndexRequest("posts", "doc", "1")
                     .source(jsonMap); // <1>
             //end::index-request-map
@@ -211,7 +219,6 @@ public class CRUDDocumentationIT extends ESRestHighLevelClientTestCase {
                 }
             }
             // end::index-conflict
-
         }
         {
             // tag::index-optype
@@ -229,6 +236,263 @@ public class CRUDDocumentationIT extends ESRestHighLevelClientTestCase {
         }
     }
 
+    public void testUpdate() throws IOException {
+        RestHighLevelClient client = highLevelClient();
+        {
+            IndexRequest indexRequest = new IndexRequest("posts", "doc", "1").source("field", 0);
+            IndexResponse indexResponse = client.index(indexRequest);
+            assertSame(indexResponse.status(), RestStatus.CREATED);
+
+            XContentType xContentType = XContentType.JSON;
+            String script = XContentBuilder.builder(xContentType.xContent())
+                    .startObject()
+                        .startObject("script")
+                            .field("lang", "painless")
+                            .field("code", "ctx._source.field += params.count")
+                        .endObject()
+                    .endObject().string();
+            HttpEntity body = new NStringEntity(script, ContentType.create(xContentType.mediaType()));
+            Response response = client().performRequest(HttpPost.METHOD_NAME, "/_scripts/increment-field", emptyMap(), body);
+            assertEquals(response.getStatusLine().getStatusCode(), RestStatus.OK.getStatus());
+        }
+        {
+            //tag::update-request
+            UpdateRequest request = new UpdateRequest(
+                    "posts", // <1>
+                    "doc",  // <2>
+                    "1");   // <3>
+            //end::update-request
+            request.fetchSource(true);
+            //tag::update-request-with-inline-script
+            Map<String, Object> parameters = singletonMap("count", 4); // <1>
+
+            Script inline = new Script(ScriptType.INLINE, "painless", "ctx._source.field += params.count", parameters);  // <2>
+            request.script(inline);  // <3>
+            //end::update-request-with-inline-script
+            UpdateResponse updateResponse = client.update(request);
+            assertEquals(updateResponse.getResult(), DocWriteResponse.Result.UPDATED);
+            assertEquals(4, updateResponse.getGetResult().getSource().get("field"));
+
+            request = new UpdateRequest("posts", "doc", "1").fetchSource(true);
+            //tag::update-request-with-stored-script
+            Script stored =
+                    new Script(ScriptType.STORED, "painless", "increment-field", parameters);  // <1>
+            request.script(stored);  // <2>
+            //end::update-request-with-stored-script
+            updateResponse = client.update(request);
+            assertEquals(updateResponse.getResult(), DocWriteResponse.Result.UPDATED);
+            assertEquals(8, updateResponse.getGetResult().getSource().get("field"));
+        }
+        {
+            //tag::update-request-with-doc-as-map
+            Map<String, Object> jsonMap = new HashMap<>();
+            jsonMap.put("updated", new Date());
+            jsonMap.put("reason", "daily update");
+            UpdateRequest request = new UpdateRequest("posts", "doc", "1")
+                    .doc(jsonMap); // <1>
+            //end::update-request-with-doc-as-map
+            UpdateResponse updateResponse = client.update(request);
+            assertEquals(updateResponse.getResult(), DocWriteResponse.Result.UPDATED);
+        }
+        {
+            //tag::update-request-with-doc-as-xcontent
+            XContentBuilder builder = XContentFactory.jsonBuilder();
+            builder.startObject();
+            {
+                builder.field("updated", new Date());
+                builder.field("reason", "daily update");
+            }
+            builder.endObject();
+            UpdateRequest request = new UpdateRequest("posts", "doc", "1")
+                    .doc(builder);  // <1>
+            //end::update-request-with-doc-as-xcontent
+            UpdateResponse updateResponse = client.update(request);
+            assertEquals(updateResponse.getResult(), DocWriteResponse.Result.UPDATED);
+        }
+        {
+            //tag::update-request-shortcut
+            UpdateRequest request = new UpdateRequest("posts", "doc", "1")
+                    .doc("updated", new Date(),
+                         "reason", "daily update"); // <1>
+            //end::update-request-shortcut
+            UpdateResponse updateResponse = client.update(request);
+            assertEquals(updateResponse.getResult(), DocWriteResponse.Result.UPDATED);
+        }
+        {
+            //tag::update-request-with-doc-as-string
+            UpdateRequest request = new UpdateRequest("posts", "doc", "1");
+            String jsonString = "{" +
+                    "\"updated\":\"2017-01-01\"," +
+                    "\"reason\":\"daily update\"" +
+                    "}";
+            request.doc(jsonString, XContentType.JSON); // <1>
+            //end::update-request-with-doc-as-string
+            request.fetchSource(true);
+            // tag::update-execute
+            UpdateResponse updateResponse = client.update(request);
+            // end::update-execute
+            assertEquals(updateResponse.getResult(), DocWriteResponse.Result.UPDATED);
+
+            // tag::update-response
+            String index = updateResponse.getIndex();
+            String type = updateResponse.getType();
+            String id = updateResponse.getId();
+            long version = updateResponse.getVersion();
+            if (updateResponse.getResult() == DocWriteResponse.Result.CREATED) {
+                // <1>
+            } else if (updateResponse.getResult() == DocWriteResponse.Result.UPDATED) {
+                // <2>
+            } else if (updateResponse.getResult() == DocWriteResponse.Result.DELETED) {
+                // <3>
+            } else if (updateResponse.getResult() == DocWriteResponse.Result.NOOP) {
+                // <4>
+            }
+            // end::update-response
+
+            // tag::update-getresult
+            GetResult result = updateResponse.getGetResult(); // <1>
+            if (result.isExists()) {
+                String sourceAsString = result.sourceAsString(); // <2>
+                Map<String, Object> sourceAsMap = result.sourceAsMap(); // <3>
+                byte[] sourceAsBytes = result.source(); // <4>
+            } else {
+                // <5>
+            }
+            // end::update-getresult
+            assertNotNull(result);
+            assertEquals(3, result.sourceAsMap().size());
+            // tag::update-failure
+            ReplicationResponse.ShardInfo shardInfo = updateResponse.getShardInfo();
+            if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
+                // <1>
+            }
+            if (shardInfo.getFailed() > 0) {
+                for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
+                    String reason = failure.reason(); // <2>
+                }
+            }
+            // end::update-failure
+
+            // tag::update-execute-async
+            client.updateAsync(request, new ActionListener<UpdateResponse>() {
+                @Override
+                public void onResponse(UpdateResponse updateResponse) {
+                    // <1>
+                }
+
+                @Override
+                public void onFailure(Exception e) {
+                    // <2>
+                }
+            });
+            // end::update-execute-async
+        }
+        {
+            //tag::update-docnotfound
+            UpdateRequest request = new UpdateRequest("posts", "type", "does_not_exist").doc("field", "value");
+            try {
+                UpdateResponse updateResponse = client.update(request);
+            } catch (ElasticsearchException e) {
+                if (e.status() == RestStatus.NOT_FOUND) {
+                    // <1>
+                }
+            }
+            //end::update-docnotfound
+        }
+        {
+            // tag::update-conflict
+            UpdateRequest request = new UpdateRequest("posts", "doc", "1")
+                    .doc("field", "value")
+                    .version(1);
+            try {
+                UpdateResponse updateResponse = client.update(request);
+            } catch(ElasticsearchException e) {
+                if (e.status() == RestStatus.CONFLICT) {
+                    // <1>
+                }
+            }
+            // end::update-conflict
+        }
+        {
+            UpdateRequest request = new UpdateRequest("posts", "doc", "1").doc("reason", "no source");
+            //tag::update-request-no-source
+            request.fetchSource(true); // <1>
+            //end::update-request-no-source
+            UpdateResponse updateResponse = client.update(request);
+            assertEquals(updateResponse.getResult(), DocWriteResponse.Result.UPDATED);
+            assertNotNull(updateResponse.getGetResult());
+            assertEquals(3, updateResponse.getGetResult().sourceAsMap().size());
+        }
+        {
+            UpdateRequest request = new UpdateRequest("posts", "doc", "1").doc("reason", "source includes");
+            //tag::update-request-source-include
+            String[] includes = new String[]{"updated", "r*"};
+            String[] excludes = Strings.EMPTY_ARRAY;
+            request.fetchSource(new FetchSourceContext(true, includes, excludes)); // <1>
+            //end::update-request-source-include
+            UpdateResponse updateResponse = client.update(request);
+            assertEquals(updateResponse.getResult(), DocWriteResponse.Result.UPDATED);
+            Map<String, Object> sourceAsMap = updateResponse.getGetResult().sourceAsMap();
+            assertEquals(2, sourceAsMap.size());
+            assertEquals("source includes", sourceAsMap.get("reason"));
+            assertTrue(sourceAsMap.containsKey("updated"));
+        }
+        {
+            UpdateRequest request = new UpdateRequest("posts", "doc", "1").doc("reason", "source excludes");
+            //tag::update-request-source-exclude
+            String[] includes = Strings.EMPTY_ARRAY;
+            String[] excludes = new String[]{"updated"};
+            request.fetchSource(new FetchSourceContext(true, includes, excludes)); // <1>
+            //end::update-request-source-exclude
+            UpdateResponse updateResponse = client.update(request);
+            assertEquals(updateResponse.getResult(), DocWriteResponse.Result.UPDATED);
+            Map<String, Object> sourceAsMap = updateResponse.getGetResult().sourceAsMap();
+            assertEquals(2, sourceAsMap.size());
+            assertEquals("source excludes", sourceAsMap.get("reason"));
+            assertTrue(sourceAsMap.containsKey("field"));
+        }
+        {
+            UpdateRequest request = new UpdateRequest("posts", "doc", "id");
+            // tag::update-request-routing
+            request.routing("routing"); // <1>
+            // end::update-request-routing
+            // tag::update-request-parent
+            request.parent("parent"); // <1>
+            // end::update-request-parent
+            // tag::update-request-timeout
+            request.timeout(TimeValue.timeValueSeconds(1)); // <1>
+            request.timeout("1s"); // <2>
+            // end::update-request-timeout
+            // tag::update-request-retry
+            request.retryOnConflict(3); // <1>
+            // end::update-request-retry
+            // tag::update-request-refresh
+            request.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL); // <1>
+            request.setRefreshPolicy("wait_for");                            // <2>
+            // end::update-request-refresh
+            // tag::update-request-version
+            request.version(2); // <1>
+            // end::update-request-version
+            // tag::update-request-detect-noop
+            request.detectNoop(false); // <1>
+            // end::update-request-detect-noop
+            // tag::update-request-upsert
+            String jsonString = "{\"created\":\"2017-01-01\"}";
+            request.upsert(jsonString, XContentType.JSON);  // <1>
+            // end::update-request-upsert
+            // tag::update-request-scripted-upsert
+            request.scriptedUpsert(true); // <1>
+            // end::update-request-scripted-upsert
+            // tag::update-request-doc-upsert
+            request.docAsUpsert(true); // <1>
+            // end::update-request-doc-upsert
+            // tag::update-request-active-shards
+            request.waitForActiveShards(2); // <1>
+            request.waitForActiveShards(ActiveShardCount.ALL); // <2>
+            // end::update-request-active-shards
+        }
+    }
+
     public void testDelete() throws IOException {
         RestHighLevelClient client = highLevelClient();
 

+ 1 - 1
docs/java-rest/high-level/apis.asciidoc

@@ -6,7 +6,7 @@ The Java High Level REST Client supports the following APIs:
 * <<java-rest-high-document-index>>
 * <<java-rest-high-document-get>>
 * <<java-rest-high-document-delete>>
-* Update API
+* <<java-rest-high-document-update>>
 
 .Multi-document APIs
 * <<java-rest-high-document-bulk>>

+ 1 - 1
docs/java-rest/high-level/apis/_index.asciidoc

@@ -124,7 +124,7 @@ include-tagged::{doc-tests}/CRUDDocumentationIT.java[index-response]
 --------------------------------------------------
 <1> Handle (if needed) the case where the document was created for the first
 time
-<2> Handle (if needed) the case where the document was rewriten as it was
+<2> Handle (if needed) the case where the document was rewritten as it was
 already existing
 <3> Handle the situation where number of successful shards is less than
 total shards

+ 251 - 1
docs/java-rest/high-level/apis/update.asciidoc

@@ -1,4 +1,254 @@
 [[java-rest-high-document-update]]
 === Update API
 
-See https://github.com/elastic/elasticsearch/pull/25536
+[[java-rest-high-document-update-request]]
+==== Update Request
+
+An `UpdateRequest` requires the following arguments:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request]
+--------------------------------------------------
+<1> Index
+<2> Type
+<3> Document id
+
+The Update API allows to update an existing document by using a script
+or by passing a partial document.
+
+==== Updates with a script
+The script can be provided as an inline script:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request-with-inline-script]
+--------------------------------------------------
+<1> Script parameters provided as a `Map` of objects
+<2> Create an inline script using the `painless` language and the previous parameters
+<3> Sets the script to the update request
+
+Or as a stored script:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request-with-stored-script]
+--------------------------------------------------
+<1> Reference to a script stored under the name `increment-field` in the `painless` language
+<2> Sets the script in the update request
+
+==== Updates with a partial document
+When using updates with a partial document, the partial document will be merged with the
+existing document.
+
+The partial document can be provided in different ways:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request-with-doc-as-string]
+--------------------------------------------------
+<1> Partial document source provided as a `String` in JSON format
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request-with-doc-as-map]
+--------------------------------------------------
+<1> Partial document source provided as a `Map` which gets automatically converted
+to JSON format
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request-with-doc-as-xcontent]
+--------------------------------------------------
+<1> Partial document source provided as an `XContentBuilder` object, the Elasticsearch
+built-in helpers to generate JSON content
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request-shortcut]
+--------------------------------------------------
+<1> Partial document source provided as `Object` key-pairs, which gets converted to
+JSON format
+
+==== Upserts
+If the document does not already exist, it is possible to define some content that
+will be inserted as a new document using the `upsert` method:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request-upsert]
+--------------------------------------------------
+<1> Upsert document source provided as a `String`
+
+Similarly to the partial document updates, the content of the `upsert` document
+can be defined using methods that accept `String`, `Map`, `XContentBuilder` or
+`Object` key-pairs.
+
+==== Optional arguments
+The following arguments can optionally be provided:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request-routing]
+--------------------------------------------------
+<1> Routing value
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request-parent]
+--------------------------------------------------
+<1> Parent value
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request-timeout]
+--------------------------------------------------
+<1> Timeout to wait for primary shard to become available as a `TimeValue`
+<2> Timeout to wait for primary shard to become available as a `String`
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request-refresh]
+--------------------------------------------------
+<1> Refresh policy as a `WriteRequest.RefreshPolicy` instance
+<2> Refresh policy as a `String`
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request-retry]
+--------------------------------------------------
+<1> How many times to retry the update operation if the document to update has
+been changed by another operation between the get and indexing phases of the
+update operation
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request-no-source]
+--------------------------------------------------
+<1> Enable source retrieval, disabled by default
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request-source-include]
+--------------------------------------------------
+<1> Configure source inclusion for specific fields
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request-source-exclude]
+--------------------------------------------------
+<1> Configure source exclusion for specific fields
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request-version]
+--------------------------------------------------
+<1> Version
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request-detect-noop]
+--------------------------------------------------
+<1> Disable the noop detection
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request-scripted-upsert]
+--------------------------------------------------
+<1> Indicate that the script must run regardless of whether the document exists or not,
+ie the script takes care of creating the document if it does not already exist.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request-doc-upsert]
+--------------------------------------------------
+<1> Indicate that the partial document must be used as the upsert document if it
+does not exist yet.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-request-active-shards]
+--------------------------------------------------
+<1> Sets the number of shard copies that must be active before proceeding with
+the update operation.
+<2> Number of shard copies provided as a `ActiveShardCount`: can be `ActiveShardCount.ALL`,
+`ActiveShardCount.ONE` or `ActiveShardCount.DEFAULT` (default)
+
+[[java-rest-high-document-update-sync]]
+==== Synchronous Execution
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-execute]
+--------------------------------------------------
+
+[[java-rest-high-document-update-async]]
+==== Asynchronous Execution
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-execute-async]
+--------------------------------------------------
+<1> Called when the execution is successfully completed. The response is
+provided as an argument.
+<2> Called in case of failure. The raised exception is provided as an argument.
+
+[[java-rest-high-document-update-response]]
+==== Update Response
+
+The returned `UpdateResponse` allows to retrieve information about the executed
+ operation as follows:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-response]
+--------------------------------------------------
+<1> Handle the case where the document was created for the first time (upsert)
+<2> Handle the case where the document was updated
+<3> Handle the case where the document was deleted
+<4> Handle the case where the document was not impacted by the update,
+ie no operation (noop) was executed on the document
+
+When the source retrieval is enabled in the `UpdateRequest`
+through the fetchSource method, the response contains the
+source of the updated document:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-getresult]
+--------------------------------------------------
+<1> Retrieve the updated document as a `GetResult`
+<2> Retrieve the source of the updated document as a `String`
+<3> Retrieve the source of the updated document as a `Map<String, Object>`
+<4> Retrieve the source of the updated document as a `byte[]`
+<5> Handle the scenario where the source of the document is not present in
+the response (this is the case by default)
+
+It is also possible to check for shard failures:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-failure]
+--------------------------------------------------
+<1> Handle the situation where number of successful shards is less than
+total shards
+<2> Handle the potential failures
+
+When a `UpdateRequest` is performed against a document that does not exist,
+the response has `404` status code, an `ElasticsearchException` gets thrown
+which needs to be handled as follows:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-docnotfound]
+--------------------------------------------------
+<1> Handle the exception thrown because the document not exist
+
+If there is a version conflict, an `ElasticsearchException` will
+be thrown:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[update-conflict]
+--------------------------------------------------
+<1> The raised exception indicates that a version conflict error was returned.