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

This commit adds documentation for Java High Level REST Client's Update API.
This commit is contained in:
Tanguy Leroux 2017-07-05 12:16:42 +02:00 committed by GitHub
parent 7899dbef3b
commit fefcae3d45
4 changed files with 521 additions and 7 deletions

View File

@ -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:
@ -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();

View File

@ -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>>

View File

@ -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

View File

@ -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.