1
0
Эх сурвалжийг харах

Docs: HighLevelRestClient#multiGet (#29095)

Add documentation for HighLevelRestClient#multiGet.

Relates to #28389.
Nik Everett 7 жил өмнө
parent
commit
2f21dc7129

+ 207 - 1
client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/CRUDDocumentationIT.java

@@ -37,10 +37,14 @@ import org.elasticsearch.action.delete.DeleteRequest;
 import org.elasticsearch.action.delete.DeleteResponse;
 import org.elasticsearch.action.get.GetRequest;
 import org.elasticsearch.action.get.GetResponse;
+import org.elasticsearch.action.get.MultiGetItemResponse;
+import org.elasticsearch.action.get.MultiGetRequest;
+import org.elasticsearch.action.get.MultiGetResponse;
 import org.elasticsearch.action.index.IndexRequest;
 import org.elasticsearch.action.index.IndexResponse;
 import org.elasticsearch.action.support.ActiveShardCount;
 import org.elasticsearch.action.support.WriteRequest;
+import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
 import org.elasticsearch.action.support.replication.ReplicationResponse;
 import org.elasticsearch.action.update.UpdateRequest;
 import org.elasticsearch.action.update.UpdateResponse;
@@ -68,6 +72,11 @@ import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import static org.hamcrest.Matchers.arrayWithSize;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.hasKey;
+import static org.hamcrest.Matchers.not;
 import static java.util.Collections.emptyMap;
 import static java.util.Collections.singletonMap;
 
@@ -809,7 +818,7 @@ public class CRUDDocumentationIT extends ESRestHighLevelClientTestCase {
         {
             GetRequest request = new GetRequest("posts", "doc", "1");
             //tag::get-request-no-source
-            request.fetchSourceContext(new FetchSourceContext(false)); // <1>
+            request.fetchSourceContext(FetchSourceContext.DO_NOT_FETCH_SOURCE); // <1>
             //end::get-request-no-source
             GetResponse getResponse = client.get(request);
             assertNull(getResponse.getSourceInternal());
@@ -1066,4 +1075,201 @@ public class CRUDDocumentationIT extends ESRestHighLevelClientTestCase {
             // end::bulk-processor-options
         }
     }
+
+    public void testMultiGet() throws Exception {
+        RestHighLevelClient client = highLevelClient();
+
+        {
+            String mappings = "{\n" +
+            "    \"mappings\" : {\n" +
+            "        \"type\" : {\n" +
+            "            \"properties\" : {\n" +
+            "                \"foo\" : {\n" +
+            "                    \"type\": \"text\",\n" +
+            "                    \"store\": true\n" +
+            "                }\n" +
+            "            }\n" +
+            "        }\n" +
+            "    }\n" +
+            "}";
+
+            NStringEntity entity = new NStringEntity(mappings, ContentType.APPLICATION_JSON);
+            Response response = client().performRequest("PUT", "/index", Collections.emptyMap(), entity);
+            assertEquals(200, response.getStatusLine().getStatusCode());
+        }
+
+        Map<String, Object> source = new HashMap<>();
+        source.put("foo", "val1");
+        source.put("bar", "val2");
+        source.put("baz", "val3");
+        client.index(new IndexRequest("index", "type", "example_id")
+            .source(source)
+            .setRefreshPolicy(RefreshPolicy.IMMEDIATE));
+
+        {
+            // tag::multi-get-request
+            MultiGetRequest request = new MultiGetRequest();
+            request.add(new MultiGetRequest.Item(
+                "index",         // <1>
+                "type",          // <2>
+                "example_id"));  // <3>
+            request.add(new MultiGetRequest.Item("index", "type", "another_id"));  // <4>
+            // end::multi-get-request
+
+            // Add a missing index so we can test it.
+            request.add(new MultiGetRequest.Item("missing_index", "type", "id"));
+
+            // tag::multi-get-request-item-extras
+            request.add(new MultiGetRequest.Item("index", "type", "with_routing")
+                .routing("some_routing"));          // <1>
+            request.add(new MultiGetRequest.Item("index", "type", "with_parent")
+                .parent("some_parent"));            // <2>
+            request.add(new MultiGetRequest.Item("index", "type", "with_version")
+                .versionType(VersionType.EXTERNAL)  // <3>
+                .version(10123L));                  // <4>
+            // end::multi-get-request-item-extras
+            // tag::multi-get-request-top-level-extras
+            request.preference("some_preference");  // <1>
+            request.realtime(false);                // <2>
+            request.refresh(true);                  // <3>
+            // end::multi-get-request-top-level-extras
+
+            // tag::multi-get-execute
+            MultiGetResponse response = client.multiGet(request);
+            // end::multi-get-execute
+
+            // tag::multi-get-response
+            MultiGetItemResponse firstItem = response.getResponses()[0];
+            assertNull(firstItem.getFailure());              // <1>
+            GetResponse firstGet = firstItem.getResponse();  // <2>
+            String index = firstItem.getIndex();
+            String type = firstItem.getType();
+            String id = firstItem.getId();
+            if (firstGet.isExists()) {
+                long version = firstGet.getVersion();
+                String sourceAsString = firstGet.getSourceAsString();        // <3>
+                Map<String, Object> sourceAsMap = firstGet.getSourceAsMap(); // <4>
+                byte[] sourceAsBytes = firstGet.getSourceAsBytes();          // <5>
+            } else {
+                // <6>
+            }
+            // end::multi-get-response
+
+            assertTrue(firstGet.isExists());
+            assertEquals(source, firstGet.getSource());
+
+            MultiGetItemResponse missingIndexItem = response.getResponses()[2];
+            // tag::multi-get-indexnotfound
+            assertNull(missingIndexItem.getResponse());                // <1>
+            Exception e = missingIndexItem.getFailure().getFailure();  // <2>
+            ElasticsearchException ee = (ElasticsearchException) e;    // <3>
+            // TODO status is broken! fix in a followup
+            // assertEquals(RestStatus.NOT_FOUND, ee.status());        // <4>
+            assertThat(e.getMessage(),
+                containsString("reason=no such index"));               // <5>
+            // end::multi-get-indexnotfound
+
+            // tag::multi-get-execute-listener
+            ActionListener<MultiGetResponse> listener = new ActionListener<MultiGetResponse>() {
+                @Override
+                public void onResponse(MultiGetResponse response) {
+                    // <1>
+                }
+
+                @Override
+                public void onFailure(Exception e) {
+                    // <2>
+                }
+            };
+            // end::multi-get-execute-listener
+
+            // Replace the empty listener by a blocking listener in test
+            final CountDownLatch latch = new CountDownLatch(1);
+            listener = new LatchedActionListener<>(listener, latch);
+
+            // tag::multi-get-execute-async
+            client.multiGetAsync(request, listener); // <1>
+            // end::multi-get-execute-async
+
+            assertTrue(latch.await(30L, TimeUnit.SECONDS));
+        }
+        {
+            MultiGetRequest request = new MultiGetRequest();
+            // tag::multi-get-request-no-source
+            request.add(new MultiGetRequest.Item("index", "type", "example_id")
+                .fetchSourceContext(FetchSourceContext.DO_NOT_FETCH_SOURCE));  // <1>
+            // end::multi-get-request-no-source
+            MultiGetItemResponse item = unwrapAndAssertExample(client.multiGet(request));
+            assertNull(item.getResponse().getSource());
+        }
+        {
+            MultiGetRequest request = new MultiGetRequest();
+            // tag::multi-get-request-source-include
+            String[] includes = new String[] {"foo", "*r"};
+            String[] excludes = Strings.EMPTY_ARRAY;
+            FetchSourceContext fetchSourceContext =
+                    new FetchSourceContext(true, includes, excludes);
+            request.add(new MultiGetRequest.Item("index", "type", "example_id")
+                .fetchSourceContext(fetchSourceContext));  // <1>
+            // end::multi-get-request-source-include
+            MultiGetItemResponse item = unwrapAndAssertExample(client.multiGet(request));
+            assertThat(item.getResponse().getSource(), hasEntry("foo", "val1"));
+            assertThat(item.getResponse().getSource(), hasEntry("bar", "val2"));
+            assertThat(item.getResponse().getSource(), not(hasKey("baz")));
+        }
+        {
+            MultiGetRequest request = new MultiGetRequest();
+            // tag::multi-get-request-source-exclude
+            String[] includes = Strings.EMPTY_ARRAY;
+            String[] excludes = new String[] {"foo", "*r"};
+            FetchSourceContext fetchSourceContext =
+                    new FetchSourceContext(true, includes, excludes);
+            request.add(new MultiGetRequest.Item("index", "type", "example_id")
+                .fetchSourceContext(fetchSourceContext));  // <1>
+            // end::multi-get-request-source-exclude
+            MultiGetItemResponse item = unwrapAndAssertExample(client.multiGet(request));
+            assertThat(item.getResponse().getSource(), not(hasKey("foo")));
+            assertThat(item.getResponse().getSource(), not(hasKey("bar")));
+            assertThat(item.getResponse().getSource(), hasEntry("baz", "val3"));
+        }
+        {
+            MultiGetRequest request = new MultiGetRequest();
+            // tag::multi-get-request-stored
+            request.add(new MultiGetRequest.Item("index", "type", "example_id")
+                .storedFields("foo"));  // <1>
+            MultiGetResponse response = client.multiGet(request);
+            MultiGetItemResponse item = response.getResponses()[0];
+            String value = item.getResponse().getField("foo").getValue(); // <2>
+            // end::multi-get-request-stored
+            assertNull(item.getResponse().getSource());
+            assertEquals("val1", value);
+        }
+        {
+            // tag::multi-get-conflict
+            MultiGetRequest request = new MultiGetRequest();
+            request.add(new MultiGetRequest.Item("index", "type", "example_id")
+                .version(1000L));
+            MultiGetResponse response = client.multiGet(request);
+            MultiGetItemResponse item = response.getResponses()[0];
+            assertNull(item.getResponse());                          // <1>
+            Exception e = item.getFailure().getFailure();            // <2>
+            ElasticsearchException ee = (ElasticsearchException) e;  // <3>
+            // TODO status is broken! fix in a followup
+            // assertEquals(RestStatus.CONFLICT, ee.status());          // <4>
+            assertThat(e.getMessage(),
+                containsString("version conflict, current version [1] is "
+                    + "different than the one provided [1000]"));    // <5>
+            // end::multi-get-conflict
+        }
+
+    }
+
+    private MultiGetItemResponse unwrapAndAssertExample(MultiGetResponse response) {
+        assertThat(response.getResponses(), arrayWithSize(1));
+        MultiGetItemResponse item = response.getResponses()[0];
+        assertEquals("index", item.getIndex());
+        assertEquals("type", item.getType());
+        assertEquals("example_id", item.getId());
+        return item;
+    }
 }

+ 168 - 0
docs/java-rest/high-level/document/multi-get.asciidoc

@@ -0,0 +1,168 @@
+[[java-rest-high-document-multi-get]]
+=== Multi-Get API
+
+The `multiGet` API executes multiple <<java-rest-high-document-get,`get`>>
+requests in a single http request in parallel.
+
+[[java-rest-high-document-mulit-get-request]]
+==== Multi-Get Request
+
+A `MultiGetRequest` is built empty and you add `MultiGetRequest.Item`s to
+configure what to fetch:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[multi-get-request]
+--------------------------------------------------
+<1> Index
+<2> Type
+<3> Document id
+<4> Add another item to fetch
+
+==== Optional arguments
+
+`multiGet` supports the same optional arguments that the
+<<java-rest-high-document-get-request-optional-arguments,`get` API>> supports.
+You can set most of these on the `Item`:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[multi-get-request-no-source]
+--------------------------------------------------
+<1> Disable source retrieval, enabled by default
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[multi-get-request-source-include]
+--------------------------------------------------
+<1> Configure source inclusion for specific fields
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[multi-get-request-source-exclude]
+--------------------------------------------------
+<1> Configure source exclusion for specific fields
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[multi-get-request-stored]
+--------------------------------------------------
+<1> Configure retrieval for specific stored fields (requires fields to be
+stored separately in the mappings)
+<2> Retrieve the `foo` stored field (requires the field to be stored
+separately in the mappings)
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[multi-get-request-item-extras]
+--------------------------------------------------
+<1> Routing value
+<2> Parent value
+<3> Version
+<4> Version type
+
+{ref}/search-request-preference.html[`preference`],
+{ref}/docs-get.html#realtime[`realtime`]
+and
+{ref}/docs-get.html#get-refresh[`refresh`] can be set on the main request but
+not on any items:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[multi-get-request-top-level-extras]
+--------------------------------------------------
+<1> Preference value
+<2> Set realtime flag to `false` (`true` by default)
+<3> Perform a refresh before retrieving the document (`false` by default)
+
+[[java-rest-high-document-multi-get-sync]]
+==== Synchronous Execution
+
+After building the `MultiGetRequest` you can execute it synchronously with
+`multiGet`:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[multi-get-execute]
+--------------------------------------------------
+
+[[java-rest-high-document-multi-get-async]]
+==== Asynchronous Execution
+
+The asynchronous execution of a multi get request requires both the
+`MultiGetRequest` instance and an `ActionListener` instance to be passed to
+the asynchronous method:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[multi-get-execute-async]
+--------------------------------------------------
+<1> The `MultiGetRequest` to execute and the `ActionListener` to use when
+the execution completes.
+
+The asynchronous method does not block and returns immediately. Once the
+request completed the `ActionListener` is called back using the `onResponse`
+method if the execution successfully completed or using the `onFailure` method
+if it failed.
+
+A typical listener for `MultiGetResponse` looks like:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[multi-get-execute-listener]
+--------------------------------------------------
+<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-multi-get-response]]
+==== Multi Get Response
+
+The returned `MultiGetResponse` contains a list of `MultiGetItemResponse`s in
+`getResponses` in the same order that they were requested.
+`MultiGetItemResponse` contains *either* a
+<<java-rest-high-document-get-response, `GetResponse`>> if the get succeeded
+or a `MultiGetResponse.Failure` if it failed. A success looks just like a
+normal `GetResponse`.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[multi-get-response]
+--------------------------------------------------
+<1> `getFailure` returns null because there isn't a failure.
+<2> `getResponse` returns the `GetResponse`.
+<3> Retrieve the document as a `String`
+<4> Retrieve the document as a `Map<String, Object>`
+<5> Retrieve the document as a `byte[]`
+<6> Handle the scenario where the document was not found. Note that although
+the returned response has `404` status code, a valid `GetResponse` is
+returned rather than an exception thrown. Such response does not hold any
+source document and its `isExists` method returns `false`.
+
+When one of the subrequests as performed against an index that does not exist
+`getFailure` will contain an exception:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[multi-get-indexnotfound]
+--------------------------------------------------
+<1> `getResponse` is null.
+<2> `getFailure` isn't and contains an `Exception`.
+<3> That `Exception` is actually an `ElasticsearchException`
+<4> and it has a status of `NOT_FOUND`. It'd have been an HTTP 404 if this
+wasn't a multi get.
+<5> `getMessage` explains the actual cause, `no such index`.
+
+In case a specific document version has been requested, and the existing
+document has a different version number, a version conflict is raised:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/CRUDDocumentationIT.java[multi-get-conflict]
+--------------------------------------------------
+<1> `getResponse` is null.
+<2> `getFailure` isn't and contains an `Exception`.
+<3> That `Exception` is actuall and `ElasticsearchException`
+<4> and it has a status of `CONFLICT`. It'd have been an HTTP 409 if this
+wasn't a multi get.
+<5> `getMessage` explains the actual cause, `

+ 2 - 0
docs/java-rest/high-level/supported-apis.asciidoc

@@ -14,6 +14,7 @@ Single document APIs::
 [[multi-doc]]
 Multi-document APIs::
 * <<java-rest-high-document-bulk>>
+* <<java-rest-high-document-multi-get>>
 
 include::document/index.asciidoc[]
 include::document/get.asciidoc[]
@@ -21,6 +22,7 @@ include::document/exists.asciidoc[]
 include::document/delete.asciidoc[]
 include::document/update.asciidoc[]
 include::document/bulk.asciidoc[]
+include::document/multi-get.asciidoc[]
 
 == Search APIs