Skip to content

Commit

Permalink
Add Get Source API to the HLRC (elastic#50885)
Browse files Browse the repository at this point in the history
Relates to elastic#47678
  • Loading branch information
timoninmaxim authored and martijnvg committed Jan 23, 2020
1 parent 157b352 commit 814d5fb
Show file tree
Hide file tree
Showing 11 changed files with 582 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.client.core.GetSourceRequest;
import org.elasticsearch.client.core.MultiTermVectorsRequest;
import org.elasticsearch.client.core.TermVectorsRequest;
import org.elasticsearch.client.indices.AnalyzeRequest;
Expand Down Expand Up @@ -281,6 +282,14 @@ private static Request getStyleRequest(String method, GetRequest getRequest) {
}

static Request sourceExists(GetRequest getRequest) {
Params parameters = new Params();
parameters.withPreference(getRequest.preference());
parameters.withRouting(getRequest.routing());
parameters.withRefresh(getRequest.refresh());
parameters.withRealtime(getRequest.realtime());
parameters.withFetchSourceContext(getRequest.fetchSourceContext());
// Version params are not currently supported by the _source API so are not passed

String optionalType = getRequest.type();
String endpoint;
if (optionalType.equals(MapperService.SINGLE_MAPPING_NAME)) {
Expand All @@ -289,12 +298,20 @@ static Request sourceExists(GetRequest getRequest) {
endpoint = endpoint(getRequest.index(), optionalType, getRequest.id(), "_source");
}
Request request = new Request(HttpHead.METHOD_NAME, endpoint);
request.addParameters(parameters.asMap());
return request;
}

static Request getSource(GetSourceRequest getSourceRequest) {
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
parameters.withPreference(getSourceRequest.preference());
parameters.withRouting(getSourceRequest.routing());
parameters.withRefresh(getSourceRequest.refresh());
parameters.withRealtime(getSourceRequest.realtime());
parameters.withFetchSourceContext(getSourceRequest.fetchSourceContext());

String endpoint = endpoint(getSourceRequest.index(), "_source", getSourceRequest.id());
Request request = new Request(HttpGet.METHOD_NAME, endpoint);
request.addParameters(parameters.asMap());
return request;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.client.core.CountResponse;
import org.elasticsearch.client.core.GetSourceRequest;
import org.elasticsearch.client.core.GetSourceResponse;
import org.elasticsearch.client.core.MainRequest;
import org.elasticsearch.client.core.MainResponse;
import org.elasticsearch.client.core.MultiTermVectorsRequest;
Expand Down Expand Up @@ -860,6 +862,34 @@ 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 GetSourceResponse getSource(GetSourceRequest getRequest, RequestOptions options) throws IOException {
return performRequestAndParseEntity(getRequest, RequestConverters::getSource, options,
GetSourceResponse::fromXContent, 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(GetSourceRequest getRequest, RequestOptions options,
ActionListener<GetSourceResponse> listener) {
return performRequestAsyncAndParseEntity(getRequest, RequestConverters::getSource, options,
GetSourceResponse::fromXContent, 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.elasticsearch.client.core;

import org.elasticsearch.client.Validatable;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;

import java.io.IOException;

public final class GetSourceRequest implements Validatable, ToXContentObject {
private String routing;
private String preference;

private boolean refresh = false;
private boolean realtime = true;

private FetchSourceContext fetchSourceContext;

private String index;
private String id;

public GetSourceRequest(String index, String id) {
this.index = index;
this.id = id;
}

/**
* Controls the shard routing of the request. Using this value to hash the shard
* and not the id.
*/
public GetSourceRequest routing(String routing) {
if (routing != null && routing.length() == 0) {
this.routing = null;
} else {
this.routing = routing;
}
return this;
}

/**
* Sets the preference to execute the search. Defaults to randomize across shards. Can be set to
* {@code _local} to prefer local shards or a custom value, which guarantees that the same order
* will be used across different requests.
*/
public GetSourceRequest preference(String preference) {
this.preference = preference;
return this;
}

/**
* Should a refresh be executed before this get operation causing the operation to
* return the latest value. Note, heavy get should not set this to {@code true}. Defaults
* to {@code false}.
*/
public GetSourceRequest refresh(boolean refresh) {
this.refresh = refresh;
return this;
}

public GetSourceRequest realtime(boolean realtime) {
this.realtime = realtime;
return this;
}

/**
* Allows setting the {@link FetchSourceContext} for this request, controlling if and how _source should be returned.
* Note, the {@code fetchSource} field of the context must be set to {@code true}.
*/

public GetSourceRequest fetchSourceContext(FetchSourceContext context) {
this.fetchSourceContext = context;
return this;
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return null;
}

public String index() {
return index;
}

public String id() {
return id;
}

public String routing() {
return routing;
}

public String preference() {
return preference;
}

public boolean refresh() {
return refresh;
}

public boolean realtime() {
return realtime;
}

public FetchSourceContext fetchSourceContext() {
return fetchSourceContext;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.elasticsearch.client.core;

import org.elasticsearch.common.xcontent.XContentParser;

import java.io.IOException;
import java.util.Map;

public final class GetSourceResponse {

private final Map<String, Object> source;

public GetSourceResponse(Map<String, Object> source) {
this.source = source;
}

public static GetSourceResponse fromXContent(XContentParser parser) throws IOException {
return new GetSourceResponse(parser.map());
}

public Map<String, Object> getSource() {
return this.source;
}

@Override
public String toString() {
return source.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.core.GetSourceRequest;
import org.elasticsearch.client.core.GetSourceResponse;
import org.elasticsearch.client.core.MultiTermVectorsRequest;
import org.elasticsearch.client.core.MultiTermVectorsResponse;
import org.elasticsearch.client.core.TermVectorsRequest;
Expand Down Expand Up @@ -70,6 +72,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
Expand Down Expand Up @@ -456,6 +459,71 @@ public void testMultiGetWithTypes() throws IOException {
assertEquals("id2", secondResponse.getId());
}

public void testGetSource() throws IOException {
{
GetSourceRequest getRequest = new GetSourceRequest("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);
{
GetSourceRequest getRequest = new GetSourceRequest("index", "id");
GetSourceResponse response = execute(getRequest, highLevelClient()::getSource, highLevelClient()::getSourceAsync);
Map<String, Object> expectedResponse = new HashMap<>();
expectedResponse.put("field1", "value1");
expectedResponse.put("field2", "value2");
assertEquals(expectedResponse, response.getSource());
}
{
GetSourceRequest getRequest = new GetSourceRequest("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());
}
{
GetSourceRequest getRequest = new GetSourceRequest("index", "id");
getRequest.fetchSourceContext(new FetchSourceContext(true, Strings.EMPTY_ARRAY, Strings.EMPTY_ARRAY));
GetSourceResponse response = execute(getRequest, highLevelClient()::getSource, highLevelClient()::getSourceAsync);
Map<String, Object> expectedResponse = new HashMap<>();
expectedResponse.put("field1", "value1");
expectedResponse.put("field2", "value2");
assertEquals(expectedResponse, response.getSource());
}
{
GetSourceRequest getRequest = new GetSourceRequest("index", "id");
getRequest.fetchSourceContext(new FetchSourceContext(true, new String[]{"field1"}, Strings.EMPTY_ARRAY));
GetSourceResponse response = execute(getRequest, highLevelClient()::getSource, highLevelClient()::getSourceAsync);
Map<String, Object> expectedResponse = new HashMap<>();
expectedResponse.put("field1", "value1");
assertEquals(expectedResponse, response.getSource());
}
{
GetSourceRequest getRequest = new GetSourceRequest("index", "id");
getRequest.fetchSourceContext(new FetchSourceContext(true, Strings.EMPTY_ARRAY, new String[]{"field1"}));
GetSourceResponse response = execute(getRequest, highLevelClient()::getSource, highLevelClient()::getSourceAsync);
Map<String, Object> expectedResponse = new HashMap<>();
expectedResponse.put("field2", "value2");
assertEquals(expectedResponse, response.getSource());
}
{
GetSourceRequest getRequest = new GetSourceRequest("index", "id");
getRequest.fetchSourceContext(new FetchSourceContext(false));
ElasticsearchException exception = expectThrows(ElasticsearchException.class,
() -> execute(getRequest, highLevelClient()::getSource, highLevelClient()::getSourceAsync));
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
Loading

0 comments on commit 814d5fb

Please sign in to comment.