Skip to content

Commit

Permalink
Add Get Source API to the HLRC
Browse files Browse the repository at this point in the history
relates: #47678
  • Loading branch information
timoninmaxim committed Jan 11, 2020
1 parent e7cd44f commit 8a6fe9a
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -277,14 +277,26 @@ private static Request getStyleRequest(String method, GetRequest getRequest) {
static Request sourceExists(GetRequest getRequest) {
String endpoint = endpoint(getRequest.index(), "_source", getRequest.id());
Request request = new Request(HttpHead.METHOD_NAME, endpoint);
request.addParameters(sourceParams(getRequest).asMap());
return request;
}

static Request getSource(GetRequest getRequest) {
String endpoint = endpoint(getRequest.index(), "_source", getRequest.id());
Request request = new Request(HttpGet.METHOD_NAME, endpoint);
request.addParameters(sourceParams(getRequest).asMap());
return request;
}

private static Params sourceParams(GetRequest getRequest) {
Params parameters = new Params();
parameters.withPreference(getRequest.preference());
parameters.withRouting(getRequest.routing());
parameters.withRefresh(getRequest.refresh());
parameters.withRealtime(getRequest.realtime());
// Version params are not currently supported by the source exists API so are not passed
request.addParameters(parameters.asMap());
return request;
parameters.withFetchSourceContext(getRequest.fetchSourceContext());
// Version params are not currently supported by the _source API so are not passed
return parameters;
}

static Request multiGet(MultiGetRequest multiGetRequest) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@
import org.elasticsearch.common.CheckedConsumer;
import org.elasticsearch.common.CheckedFunction;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.ContextParser;
import org.elasticsearch.common.xcontent.DeprecationHandler;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
Expand Down Expand Up @@ -189,6 +191,7 @@

import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
Expand Down Expand Up @@ -860,6 +863,31 @@ public final Cancellable existsSourceAsync(GetRequest getRequest, RequestOptions
RestHighLevelClient::convertExistsResponse, listener, emptySet());
}

/**
* Retrieves the source field only of a document using GetSource API.
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-get.html#_source">Get Source API
* on elastic.co</a>
* @param getRequest the request
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @return the response
*/
public BytesReference getSource(GetRequest getRequest, RequestOptions options) throws IOException {
return performRequest(getRequest, RequestConverters::getSource, options, RestHighLevelClient::convertBytesResponse, emptySet());
}

/**
* Asynchronously retrieves the source field only of a document using GetSource API.
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-get.html#_source">Get Source API
* on elastic.co</a>
* @param getRequest the request
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @param listener the listener to be notified upon request completion
* @return cancellable that may be used to cancel the request
*/
public final Cancellable getSourceAsync(GetRequest getRequest, RequestOptions options, ActionListener<BytesReference> listener) {
return performRequestAsync(getRequest, RequestConverters::getSource, options, RestHighLevelClient::convertBytesResponse, listener, emptySet());
}

/**
* Index a document using the Index API.
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html">Index API on elastic.co</a>
Expand Down Expand Up @@ -1798,6 +1826,15 @@ protected static boolean convertExistsResponse(Response response) {
return response.getStatusLine().getStatusCode() == 200;
}

private static BytesReference convertBytesResponse(Response response) throws IOException {
if (response.getEntity() == null) {
throw new IllegalStateException("Response body expected but not returned");
}
try (InputStream s = response.getEntity().getContent()) {
return new BytesArray(s.readAllBytes());
}
}

/**
* Ignores deprecation warnings. This is appropriate because it is only
* used to parse responses from Elasticsearch. Any deprecation warnings
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,60 @@ public void testMultiGet() throws IOException {
}
}

public void testGetSource() throws IOException {
{
GetRequest getRequest = new GetRequest("index", "id");
ElasticsearchException exception = expectThrows(ElasticsearchException.class,
() -> execute(getRequest, highLevelClient()::getSource, highLevelClient()::getSourceAsync));
assertEquals(RestStatus.NOT_FOUND, exception.status());
assertEquals("Elasticsearch exception [type=index_not_found_exception, reason=no such index [index]]", exception.getMessage());
assertEquals("index", exception.getMetadata("es.index").get(0));
}
IndexRequest index = new IndexRequest("index").id("id");
String document = "{\"field1\":\"value1\",\"field2\":\"value2\"}";
index.source(document, XContentType.JSON);
index.setRefreshPolicy(RefreshPolicy.IMMEDIATE);
highLevelClient().index(index, RequestOptions.DEFAULT);
{
GetRequest getRequest = new GetRequest("index", "id");
BytesReference bytesResponse = execute(getRequest, highLevelClient()::getSource, highLevelClient()::getSourceAsync);
assertEquals(document, bytesResponse.utf8ToString());
}
{
GetRequest getRequest = new GetRequest("index", "does_not_exist");
ElasticsearchException exception = expectThrows(ElasticsearchException.class,
() -> execute(getRequest, highLevelClient()::getSource, highLevelClient()::getSourceAsync));
assertEquals(RestStatus.NOT_FOUND, exception.status());
assertEquals("Elasticsearch exception [type=resource_not_found_exception, reason=Document not found [index]/[does_not_exist]]", exception.getMessage());
}
{
GetRequest getRequest = new GetRequest("index", "id");
getRequest.fetchSourceContext(new FetchSourceContext(true, Strings.EMPTY_ARRAY, Strings.EMPTY_ARRAY));
BytesReference bytesResponse = execute(getRequest, highLevelClient()::getSource, highLevelClient()::getSourceAsync);
assertEquals(document, bytesResponse.utf8ToString());
}
{
GetRequest getRequest = new GetRequest("index", "id");
getRequest.fetchSourceContext(new FetchSourceContext(true, new String[]{"field1"}, Strings.EMPTY_ARRAY));
BytesReference bytesResponse = execute(getRequest, highLevelClient()::getSource, highLevelClient()::getSourceAsync);
assertEquals("{\"field1\":\"value1\"}", bytesResponse.utf8ToString());
}
{
GetRequest getRequest = new GetRequest("index", "id");
getRequest.fetchSourceContext(new FetchSourceContext(true, Strings.EMPTY_ARRAY, new String[]{"field1"}));
BytesReference bytesResponse = execute(getRequest, highLevelClient()::getSource, highLevelClient()::getSourceAsync);
assertEquals("{\"field2\":\"value2\"}", bytesResponse.utf8ToString());
}
{
GetRequest getRequest = new GetRequest("index", "id");
getRequest.fetchSourceContext(new FetchSourceContext(false));
ElasticsearchException exception = expectThrows(ElasticsearchException.class,
() -> execute(getRequest, highLevelClient()::getSource, highLevelClient()::getSourceAsync));
System.out.println(exception.getMessage());
assertEquals("Elasticsearch exception [type=action_request_validation_exception, reason=Validation Failed: 1: fetching source can not be disabled;]", exception.getMessage());
}
}

public void testIndex() throws IOException {
final XContentType xContentType = randomFrom(XContentType.values());
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -777,7 +777,6 @@ public void testApiNamingConventions() throws Exception {
"create",
"get_script_context",
"get_script_languages",
"get_source",
"indices.exists_type",
"indices.get_upgrade",
"indices.put_alias",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.ByteSizeUnit;
import org.elasticsearch.common.unit.ByteSizeValue;
Expand Down Expand Up @@ -1398,6 +1399,78 @@ public void onFailure(Exception e) {
}
}

public void testGetSource() throws Exception {
RestHighLevelClient client = highLevelClient();
{
Request createIndex = new Request("PUT", "/posts");
createIndex.setJsonEntity(
"{\n" +
" \"mappings\" : {\n" +
" \"properties\" : {\n" +
" \"message\" : {\n" +
" \"type\": \"text\",\n" +
" \"store\": true\n" +
" }\n" +
" }\n" +
" }\n" +
"}");
Response response = client().performRequest(createIndex);
assertEquals(200, response.getStatusLine().getStatusCode());

IndexRequest indexRequest = new IndexRequest("posts").id("1")
.source("user", "kimchy",
"postDate", new Date(),
"message", "trying out Elasticsearch");
IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);
assertEquals(DocWriteResponse.Result.CREATED, indexResponse.getResult());
}

// tag::get-source-request
GetRequest getSourceRequest = new GetRequest(
"posts", // <1>
"1"); // <2>

String[] includes = Strings.EMPTY_ARRAY;
String[] excludes = new String[]{"postDate"};
getSourceRequest.fetchSourceContext(new FetchSourceContext(true, includes, excludes));
// end::get-source-request
{
// tag::get-source-execute
BytesReference bytesResponse = client.getSource(getSourceRequest, RequestOptions.DEFAULT);
// end::get-source-execute
assertTrue(bytesResponse.utf8ToString().contains("user"));
assertFalse(bytesResponse.utf8ToString().contains("postDate"));
}
{
GetRequest request = new GetRequest("posts", "1");

// tag::get-source-execute-listener
ActionListener<BytesReference> listener = new ActionListener<BytesReference>() {
@Override
public void onResponse(BytesReference getResponse) {
// <1>
}

@Override
public void onFailure(Exception e) {
// <2>
}
};
// end::get-source-execute-listener

// Replace the empty listener by a blocking listener in test
final CountDownLatch latch = new CountDownLatch(1);
listener = new LatchedActionListener<>(listener, latch);

//tag::get-source-execute-async
client.getSourceAsync(request, RequestOptions.DEFAULT, listener); // <1>
//end::get-source-execute-async

assertTrue(latch.await(30L, TimeUnit.SECONDS));
}

}

public void testExists() throws Exception {
RestHighLevelClient client = highLevelClient();
// tag::exists-request
Expand Down
30 changes: 30 additions & 0 deletions docs/java-rest/high-level/document/get-source.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
--
:api: get-source
:request: GetRequest
:response: BytesReference
--

[id="{upid}-{api}"]
=== Get Source API

This API helps to get only the `_source` field of a document.

[id="{upid}-{api}-request"]
==== Get Request

Request `GetRequest` is the same like a Get API request:

["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests-file}[{api}-request]
--------------------------------------------------
<1> `FetchSourceContext` 's first argument `fetchSource` must be `true`, otherwise
`ElasticsearchException` get thrown
<2> Arguments `excludes` and `includes` are optional (see examples in Get API documentation)

include::../execution.asciidoc[]

[id="{upid}-{api}-response"]
==== Get Source Response

The returned +{response}+ represents a byte string of the source of requested document.
2 changes: 2 additions & 0 deletions docs/java-rest/high-level/supported-apis.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The Java High Level REST Client supports the following Document APIs:
Single document APIs::
* <<{upid}-index>>
* <<{upid}-get>>
* <<{upid}-get-source>>
* <<{upid}-exists>>
* <<{upid}-delete>>
* <<{upid}-update>>
Expand All @@ -28,6 +29,7 @@ Multi-document APIs::

include::document/index.asciidoc[]
include::document/get.asciidoc[]
include::document/get-source.asciidoc[]
include::document/exists.asciidoc[]
include::document/delete.asciidoc[]
include::document/update.asciidoc[]
Expand Down

0 comments on commit 8a6fe9a

Please sign in to comment.