mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-03-28 02:48:38 +00:00
Add support for field capabilities to the high-level REST client. (#29664)
This commit is contained in:
parent
cb7e3ffd75
commit
d40116d260
client/rest-high-level/src
main/java/org/elasticsearch/client
test/java/org/elasticsearch/client
docs/java-rest/high-level
server/src
main/java/org/elasticsearch/action/fieldcaps
test/java/org/elasticsearch/action/fieldcaps
@ -48,6 +48,7 @@ import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
|
||||
import org.elasticsearch.action.admin.indices.shrink.ResizeType;
|
||||
import org.elasticsearch.action.bulk.BulkRequest;
|
||||
import org.elasticsearch.action.delete.DeleteRequest;
|
||||
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesRequest;
|
||||
import org.elasticsearch.action.get.GetRequest;
|
||||
import org.elasticsearch.action.get.MultiGetRequest;
|
||||
import org.elasticsearch.action.index.IndexRequest;
|
||||
@ -75,6 +76,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.index.VersionType;
|
||||
import org.elasticsearch.index.rankeval.RankEvalRequest;
|
||||
import org.elasticsearch.rest.action.RestFieldCapabilitiesAction;
|
||||
import org.elasticsearch.rest.action.search.RestSearchAction;
|
||||
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
|
||||
|
||||
@ -536,6 +538,16 @@ public final class Request {
|
||||
return new Request(HttpHead.METHOD_NAME, endpoint, params.getParams(), null);
|
||||
}
|
||||
|
||||
static Request fieldCaps(FieldCapabilitiesRequest fieldCapabilitiesRequest) {
|
||||
Params params = Params.builder();
|
||||
params.withFields(fieldCapabilitiesRequest.fields());
|
||||
params.withIndicesOptions(fieldCapabilitiesRequest.indicesOptions());
|
||||
|
||||
String[] indices = fieldCapabilitiesRequest.indices();
|
||||
String endpoint = endpoint(indices, "_field_caps");
|
||||
return new Request(HttpGet.METHOD_NAME, endpoint, params.getParams(), null);
|
||||
}
|
||||
|
||||
static Request rankEval(RankEvalRequest rankEvalRequest) throws IOException {
|
||||
String endpoint = endpoint(rankEvalRequest.indices(), Strings.EMPTY_ARRAY, "_rank_eval");
|
||||
Params params = Params.builder();
|
||||
@ -712,6 +724,13 @@ public final class Request {
|
||||
return this;
|
||||
}
|
||||
|
||||
Params withFields(String[] fields) {
|
||||
if (fields != null && fields.length > 0) {
|
||||
return putParam("fields", String.join(",", fields));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
Params withMasterTimeout(TimeValue masterTimeout) {
|
||||
return putParam("master_timeout", masterTimeout);
|
||||
}
|
||||
|
@ -30,6 +30,8 @@ import org.elasticsearch.action.bulk.BulkRequest;
|
||||
import org.elasticsearch.action.bulk.BulkResponse;
|
||||
import org.elasticsearch.action.delete.DeleteRequest;
|
||||
import org.elasticsearch.action.delete.DeleteResponse;
|
||||
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesRequest;
|
||||
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesResponse;
|
||||
import org.elasticsearch.action.get.GetRequest;
|
||||
import org.elasticsearch.action.get.GetResponse;
|
||||
import org.elasticsearch.action.get.MultiGetRequest;
|
||||
@ -501,6 +503,31 @@ public class RestHighLevelClient implements Closeable {
|
||||
headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a request using the Field Capabilities API.
|
||||
*
|
||||
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-field-caps.html">Field Capabilities API
|
||||
* on elastic.co</a>.
|
||||
*/
|
||||
public final FieldCapabilitiesResponse fieldCaps(FieldCapabilitiesRequest fieldCapabilitiesRequest,
|
||||
Header... headers) throws IOException {
|
||||
return performRequestAndParseEntity(fieldCapabilitiesRequest, Request::fieldCaps,
|
||||
FieldCapabilitiesResponse::fromXContent, emptySet(), headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously executes a request using the Field Capabilities API.
|
||||
*
|
||||
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-field-caps.html">Field Capabilities API
|
||||
* on elastic.co</a>.
|
||||
*/
|
||||
public final void fieldCapsAsync(FieldCapabilitiesRequest fieldCapabilitiesRequest,
|
||||
ActionListener<FieldCapabilitiesResponse> listener,
|
||||
Header... headers) {
|
||||
performRequestAsyncAndParseEntity(fieldCapabilitiesRequest, Request::fieldCaps,
|
||||
FieldCapabilitiesResponse::fromXContent, listener, emptySet(), headers);
|
||||
}
|
||||
|
||||
protected final <Req extends ActionRequest, Resp> Resp performRequestAndParseEntity(Req request,
|
||||
CheckedFunction<Req, Request, IOException> requestConverter,
|
||||
CheckedFunction<XContentParser, Resp, IOException> entityParser,
|
||||
|
@ -52,6 +52,7 @@ import org.elasticsearch.action.admin.indices.shrink.ResizeType;
|
||||
import org.elasticsearch.action.bulk.BulkRequest;
|
||||
import org.elasticsearch.action.bulk.BulkShardRequest;
|
||||
import org.elasticsearch.action.delete.DeleteRequest;
|
||||
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesRequest;
|
||||
import org.elasticsearch.action.get.GetRequest;
|
||||
import org.elasticsearch.action.get.MultiGetRequest;
|
||||
import org.elasticsearch.action.index.IndexRequest;
|
||||
@ -89,6 +90,7 @@ import org.elasticsearch.index.rankeval.RankEvalRequest;
|
||||
import org.elasticsearch.index.rankeval.RankEvalSpec;
|
||||
import org.elasticsearch.index.rankeval.RatedRequest;
|
||||
import org.elasticsearch.index.rankeval.RestRankEvalAction;
|
||||
import org.elasticsearch.rest.action.RestFieldCapabilitiesAction;
|
||||
import org.elasticsearch.rest.action.search.RestSearchAction;
|
||||
import org.elasticsearch.search.Scroll;
|
||||
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
|
||||
@ -108,11 +110,14 @@ import java.io.InputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
@ -128,6 +133,8 @@ import static org.elasticsearch.index.alias.RandomAliasActionsGenerator.randomAl
|
||||
import static org.elasticsearch.search.RandomSearchRequestGenerator.randomSearchRequest;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasEntry;
|
||||
import static org.hamcrest.Matchers.hasKey;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
|
||||
public class RequestTests extends ESTestCase {
|
||||
@ -1213,6 +1220,47 @@ public class RequestTests extends ESTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testFieldCaps() {
|
||||
// Create a random request.
|
||||
String[] indices = randomIndicesNames(0, 5);
|
||||
String[] fields = generateRandomStringArray(5, 10, false, false);
|
||||
|
||||
FieldCapabilitiesRequest fieldCapabilitiesRequest = new FieldCapabilitiesRequest()
|
||||
.indices(indices)
|
||||
.fields(fields);
|
||||
|
||||
Map<String, String> indicesOptionsParams = new HashMap<>();
|
||||
setRandomIndicesOptions(fieldCapabilitiesRequest::indicesOptions,
|
||||
fieldCapabilitiesRequest::indicesOptions,
|
||||
indicesOptionsParams);
|
||||
|
||||
Request request = Request.fieldCaps(fieldCapabilitiesRequest);
|
||||
|
||||
// Verify that the resulting REST request looks as expected.
|
||||
StringJoiner endpoint = new StringJoiner("/", "/", "");
|
||||
String joinedIndices = String.join(",", indices);
|
||||
if (!joinedIndices.isEmpty()) {
|
||||
endpoint.add(joinedIndices);
|
||||
}
|
||||
endpoint.add("_field_caps");
|
||||
|
||||
assertEquals(endpoint.toString(), request.getEndpoint());
|
||||
assertEquals(4, request.getParameters().size());
|
||||
|
||||
// Note that we don't check the field param value explicitly, as field names are passed through
|
||||
// a hash set before being added to the request, and can appear in a non-deterministic order.
|
||||
assertThat(request.getParameters(), hasKey("fields"));
|
||||
String[] requestFields = Strings.splitStringByCommaToArray(request.getParameters().get("fields"));
|
||||
assertEquals(new HashSet<>(Arrays.asList(fields)),
|
||||
new HashSet<>(Arrays.asList(requestFields)));
|
||||
|
||||
for (Map.Entry<String, String> param : indicesOptionsParams.entrySet()) {
|
||||
assertThat(request.getParameters(), hasEntry(param.getKey(), param.getValue()));
|
||||
}
|
||||
|
||||
assertNull(request.getEntity());
|
||||
}
|
||||
|
||||
public void testRankEval() throws Exception {
|
||||
RankEvalSpec spec = new RankEvalSpec(
|
||||
Collections.singletonList(new RatedRequest("queryId", Collections.emptyList(), new SearchSourceBuilder())),
|
||||
@ -1233,7 +1281,6 @@ public class RequestTests extends ESTestCase {
|
||||
assertEquals(3, request.getParameters().size());
|
||||
assertEquals(expectedParams, request.getParameters());
|
||||
assertToXContentBody(spec, request.getEntity());
|
||||
|
||||
}
|
||||
|
||||
public void testSplit() throws IOException {
|
||||
|
@ -27,6 +27,9 @@ import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.nio.entity.NStringEntity;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.ElasticsearchStatusException;
|
||||
import org.elasticsearch.action.fieldcaps.FieldCapabilities;
|
||||
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesRequest;
|
||||
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesResponse;
|
||||
import org.elasticsearch.action.search.ClearScrollRequest;
|
||||
import org.elasticsearch.action.search.ClearScrollResponse;
|
||||
import org.elasticsearch.action.search.MultiSearchRequest;
|
||||
@ -96,14 +99,31 @@ public class SearchIT extends ESRestHighLevelClientTestCase {
|
||||
client().performRequest(HttpPut.METHOD_NAME, "/index/type/5", Collections.emptyMap(), doc5);
|
||||
client().performRequest(HttpPost.METHOD_NAME, "/index/_refresh");
|
||||
|
||||
StringEntity doc = new StringEntity("{\"field\":\"value1\"}", ContentType.APPLICATION_JSON);
|
||||
|
||||
StringEntity doc = new StringEntity("{\"field\":\"value1\", \"rating\": 7}", ContentType.APPLICATION_JSON);
|
||||
client().performRequest(HttpPut.METHOD_NAME, "/index1/doc/1", Collections.emptyMap(), doc);
|
||||
doc = new StringEntity("{\"field\":\"value2\"}", ContentType.APPLICATION_JSON);
|
||||
client().performRequest(HttpPut.METHOD_NAME, "/index1/doc/2", Collections.emptyMap(), doc);
|
||||
doc = new StringEntity("{\"field\":\"value1\"}", ContentType.APPLICATION_JSON);
|
||||
|
||||
StringEntity mappings = new StringEntity(
|
||||
"{" +
|
||||
" \"mappings\": {" +
|
||||
" \"doc\": {" +
|
||||
" \"properties\": {" +
|
||||
" \"rating\": {" +
|
||||
" \"type\": \"keyword\"" +
|
||||
" }" +
|
||||
" }" +
|
||||
" }" +
|
||||
" }" +
|
||||
"}}",
|
||||
ContentType.APPLICATION_JSON);
|
||||
client().performRequest("PUT", "/index2", Collections.emptyMap(), mappings);
|
||||
doc = new StringEntity("{\"field\":\"value1\", \"rating\": \"good\"}", ContentType.APPLICATION_JSON);
|
||||
client().performRequest(HttpPut.METHOD_NAME, "/index2/doc/3", Collections.emptyMap(), doc);
|
||||
doc = new StringEntity("{\"field\":\"value2\"}", ContentType.APPLICATION_JSON);
|
||||
client().performRequest(HttpPut.METHOD_NAME, "/index2/doc/4", Collections.emptyMap(), doc);
|
||||
|
||||
doc = new StringEntity("{\"field\":\"value1\"}", ContentType.APPLICATION_JSON);
|
||||
client().performRequest(HttpPut.METHOD_NAME, "/index3/doc/5", Collections.emptyMap(), doc);
|
||||
doc = new StringEntity("{\"field\":\"value2\"}", ContentType.APPLICATION_JSON);
|
||||
@ -713,6 +733,57 @@ public class SearchIT extends ESRestHighLevelClientTestCase {
|
||||
assertThat(multiSearchResponse.getResponses()[1].getResponse(), nullValue());
|
||||
}
|
||||
|
||||
public void testFieldCaps() throws IOException {
|
||||
FieldCapabilitiesRequest request = new FieldCapabilitiesRequest()
|
||||
.indices("index1", "index2")
|
||||
.fields("rating", "field");
|
||||
|
||||
FieldCapabilitiesResponse response = execute(request,
|
||||
highLevelClient()::fieldCaps, highLevelClient()::fieldCapsAsync);
|
||||
|
||||
// Check the capabilities for the 'rating' field.
|
||||
assertTrue(response.get().containsKey("rating"));
|
||||
Map<String, FieldCapabilities> ratingResponse = response.getField("rating");
|
||||
assertEquals(2, ratingResponse.size());
|
||||
|
||||
FieldCapabilities expectedKeywordCapabilities = new FieldCapabilities(
|
||||
"rating", "keyword", true, true, new String[]{"index2"}, null, null);
|
||||
assertEquals(expectedKeywordCapabilities, ratingResponse.get("keyword"));
|
||||
|
||||
FieldCapabilities expectedLongCapabilities = new FieldCapabilities(
|
||||
"rating", "long", true, true, new String[]{"index1"}, null, null);
|
||||
assertEquals(expectedLongCapabilities, ratingResponse.get("long"));
|
||||
|
||||
// Check the capabilities for the 'field' field.
|
||||
assertTrue(response.get().containsKey("field"));
|
||||
Map<String, FieldCapabilities> fieldResponse = response.getField("field");
|
||||
assertEquals(1, fieldResponse.size());
|
||||
|
||||
FieldCapabilities expectedTextCapabilities = new FieldCapabilities(
|
||||
"field", "text", true, false);
|
||||
assertEquals(expectedTextCapabilities, fieldResponse.get("text"));
|
||||
}
|
||||
|
||||
public void testFieldCapsWithNonExistentFields() throws IOException {
|
||||
FieldCapabilitiesRequest request = new FieldCapabilitiesRequest()
|
||||
.indices("index2")
|
||||
.fields("nonexistent");
|
||||
|
||||
FieldCapabilitiesResponse response = execute(request,
|
||||
highLevelClient()::fieldCaps, highLevelClient()::fieldCapsAsync);
|
||||
assertTrue(response.get().isEmpty());
|
||||
}
|
||||
|
||||
public void testFieldCapsWithNonExistentIndices() {
|
||||
FieldCapabilitiesRequest request = new FieldCapabilitiesRequest()
|
||||
.indices("non-existent")
|
||||
.fields("rating");
|
||||
|
||||
ElasticsearchException exception = expectThrows(ElasticsearchException.class,
|
||||
() -> execute(request, highLevelClient()::fieldCaps, highLevelClient()::fieldCapsAsync));
|
||||
assertEquals(RestStatus.NOT_FOUND, exception.status());
|
||||
}
|
||||
|
||||
private static void assertSearchHeader(SearchResponse searchResponse) {
|
||||
assertThat(searchResponse.getTook().nanos(), greaterThanOrEqualTo(0L));
|
||||
assertEquals(0, searchResponse.getFailedShards());
|
||||
|
@ -21,8 +21,13 @@ package org.elasticsearch.client.documentation;
|
||||
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.LatchedActionListener;
|
||||
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
|
||||
import org.elasticsearch.action.bulk.BulkRequest;
|
||||
import org.elasticsearch.action.bulk.BulkResponse;
|
||||
import org.elasticsearch.action.fieldcaps.FieldCapabilities;
|
||||
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesRequest;
|
||||
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesResponse;
|
||||
import org.elasticsearch.action.index.IndexRequest;
|
||||
import org.elasticsearch.action.index.IndexResponse;
|
||||
import org.elasticsearch.action.search.ClearScrollRequest;
|
||||
@ -93,6 +98,8 @@ import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
@ -157,6 +164,7 @@ public class SearchDocumentationIT extends ESRestHighLevelClientTestCase {
|
||||
|
||||
// tag::search-source-setter
|
||||
SearchRequest searchRequest = new SearchRequest();
|
||||
searchRequest.indices("posts");
|
||||
searchRequest.source(sourceBuilder);
|
||||
// end::search-source-setter
|
||||
|
||||
@ -699,6 +707,65 @@ public class SearchDocumentationIT extends ESRestHighLevelClientTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testFieldCaps() throws Exception {
|
||||
indexSearchTestData();
|
||||
RestHighLevelClient client = highLevelClient();
|
||||
// tag::field-caps-request
|
||||
FieldCapabilitiesRequest request = new FieldCapabilitiesRequest()
|
||||
.fields("user")
|
||||
.indices("posts", "authors", "contributors");
|
||||
// end::field-caps-request
|
||||
|
||||
// tag::field-caps-request-indicesOptions
|
||||
request.indicesOptions(IndicesOptions.lenientExpandOpen()); // <1>
|
||||
// end::field-caps-request-indicesOptions
|
||||
|
||||
// tag::field-caps-execute
|
||||
FieldCapabilitiesResponse response = client.fieldCaps(request);
|
||||
// end::field-caps-execute
|
||||
|
||||
// tag::field-caps-response
|
||||
assertThat(response.get().keySet(), contains("user"));
|
||||
Map<String, FieldCapabilities> userResponse = response.getField("user");
|
||||
|
||||
assertThat(userResponse.keySet(), containsInAnyOrder("keyword", "text")); // <1>
|
||||
FieldCapabilities textCapabilities = userResponse.get("keyword");
|
||||
|
||||
assertTrue(textCapabilities.isSearchable());
|
||||
assertFalse(textCapabilities.isAggregatable());
|
||||
|
||||
assertArrayEquals(textCapabilities.indices(), // <2>
|
||||
new String[]{"authors", "contributors"});
|
||||
assertNull(textCapabilities.nonSearchableIndices()); // <3>
|
||||
assertArrayEquals(textCapabilities.nonAggregatableIndices(), // <4>
|
||||
new String[]{"authors"});
|
||||
// end::field-caps-response
|
||||
|
||||
// tag::field-caps-execute-listener
|
||||
ActionListener<FieldCapabilitiesResponse> listener = new ActionListener<FieldCapabilitiesResponse>() {
|
||||
@Override
|
||||
public void onResponse(FieldCapabilitiesResponse response) {
|
||||
// <1>
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
// <2>
|
||||
}
|
||||
};
|
||||
// end::field-caps-execute-listener
|
||||
|
||||
// Replace the empty listener by a blocking listener for tests.
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
listener = new LatchedActionListener<>(listener, latch);
|
||||
|
||||
// tag::field-caps-execute-async
|
||||
client.fieldCapsAsync(request, listener); // <1>
|
||||
// end::field-caps-execute-async
|
||||
|
||||
assertTrue(latch.await(30L, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
public void testRankEval() throws Exception {
|
||||
indexSearchTestData();
|
||||
RestHighLevelClient client = highLevelClient();
|
||||
@ -794,7 +861,7 @@ public class SearchDocumentationIT extends ESRestHighLevelClientTestCase {
|
||||
MultiSearchResponse.Item firstResponse = response.getResponses()[0]; // <1>
|
||||
assertNull(firstResponse.getFailure()); // <2>
|
||||
SearchResponse searchResponse = firstResponse.getResponse(); // <3>
|
||||
assertEquals(3, searchResponse.getHits().getTotalHits());
|
||||
assertEquals(4, searchResponse.getHits().getTotalHits());
|
||||
MultiSearchResponse.Item secondResponse = response.getResponses()[1]; // <4>
|
||||
assertNull(secondResponse.getFailure());
|
||||
searchResponse = secondResponse.getResponse();
|
||||
@ -840,18 +907,35 @@ public class SearchDocumentationIT extends ESRestHighLevelClientTestCase {
|
||||
}
|
||||
|
||||
private void indexSearchTestData() throws IOException {
|
||||
BulkRequest request = new BulkRequest();
|
||||
request.add(new IndexRequest("posts", "doc", "1")
|
||||
CreateIndexRequest authorsRequest = new CreateIndexRequest("authors")
|
||||
.mapping("doc", "user", "type=keyword,doc_values=false");
|
||||
CreateIndexResponse authorsResponse = highLevelClient().indices().create(authorsRequest);
|
||||
assertTrue(authorsResponse.isAcknowledged());
|
||||
|
||||
CreateIndexRequest reviewersRequest = new CreateIndexRequest("contributors")
|
||||
.mapping("doc", "user", "type=keyword");
|
||||
CreateIndexResponse reviewersResponse = highLevelClient().indices().create(reviewersRequest);
|
||||
assertTrue(reviewersResponse.isAcknowledged());
|
||||
|
||||
BulkRequest bulkRequest = new BulkRequest();
|
||||
bulkRequest.add(new IndexRequest("posts", "doc", "1")
|
||||
.source(XContentType.JSON, "title", "In which order are my Elasticsearch queries executed?", "user",
|
||||
Arrays.asList("kimchy", "luca"), "innerObject", Collections.singletonMap("key", "value")));
|
||||
request.add(new IndexRequest("posts", "doc", "2")
|
||||
bulkRequest.add(new IndexRequest("posts", "doc", "2")
|
||||
.source(XContentType.JSON, "title", "Current status and upcoming changes in Elasticsearch", "user",
|
||||
Arrays.asList("kimchy", "christoph"), "innerObject", Collections.singletonMap("key", "value")));
|
||||
request.add(new IndexRequest("posts", "doc", "3")
|
||||
bulkRequest.add(new IndexRequest("posts", "doc", "3")
|
||||
.source(XContentType.JSON, "title", "The Future of Federated Search in Elasticsearch", "user",
|
||||
Arrays.asList("kimchy", "tanguy"), "innerObject", Collections.singletonMap("key", "value")));
|
||||
request.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
||||
BulkResponse bulkResponse = highLevelClient().bulk(request);
|
||||
|
||||
bulkRequest.add(new IndexRequest("authors", "doc", "1")
|
||||
.source(XContentType.JSON, "user", "kimchy"));
|
||||
bulkRequest.add(new IndexRequest("contributors", "doc", "1")
|
||||
.source(XContentType.JSON, "user", "tanguy"));
|
||||
|
||||
|
||||
bulkRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
||||
BulkResponse bulkResponse = highLevelClient().bulk(bulkRequest);
|
||||
assertSame(RestStatus.OK, bulkResponse.status());
|
||||
assertFalse(bulkResponse.hasFailures());
|
||||
}
|
||||
|
82
docs/java-rest/high-level/search/field-caps.asciidoc
Normal file
82
docs/java-rest/high-level/search/field-caps.asciidoc
Normal file
@ -0,0 +1,82 @@
|
||||
[[java-rest-high-field-caps]]
|
||||
=== Field Capabilities API
|
||||
|
||||
The field capabilities API allows for retrieving the capabilities of fields across multiple indices.
|
||||
|
||||
[[java-rest-high-field-caps-request]]
|
||||
==== Field Capabilities Request
|
||||
|
||||
A `FieldCapabilitiesRequest` contains a list of fields to get capabilities for,
|
||||
should be returned, plus an optional list of target indices. If no indices
|
||||
are provided, the request will be executed on all indices.
|
||||
|
||||
Note that fields parameter supports wildcard notation. For example, providing `text_*`
|
||||
will cause all fields that match the expression to be returned.
|
||||
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests}/SearchDocumentationIT.java[field-caps-request]
|
||||
--------------------------------------------------
|
||||
|
||||
[[java-rest-high-field-caps-request-optional]]
|
||||
===== Optional arguments
|
||||
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests}/SearchDocumentationIT.java[field-caps-request-indicesOptions]
|
||||
--------------------------------------------------
|
||||
<1> Setting `IndicesOptions` controls how unavailable indices are resolved and
|
||||
how wildcard expressions are expanded.
|
||||
|
||||
[[java-rest-high-field-caps-sync]]
|
||||
==== Synchronous Execution
|
||||
|
||||
The `fieldCaps` method executes the request synchronously:
|
||||
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests}/SearchDocumentationIT.java[field-caps-execute]
|
||||
--------------------------------------------------
|
||||
|
||||
[[java-rest-high-field-caps-async]]
|
||||
==== Asynchronous Execution
|
||||
|
||||
The `fieldCapsAsync` method executes the request asynchronously,
|
||||
calling the provided `ActionListener` when the response is ready:
|
||||
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests}/SearchDocumentationIT.java[field-caps-execute-async]
|
||||
--------------------------------------------------
|
||||
<1> The `FieldCapabilitiesRequest` to execute and the `ActionListener` to use when
|
||||
the execution completes.
|
||||
|
||||
The asynchronous method does not block and returns immediately. Once the request
|
||||
completes, 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 `FieldCapabilitiesResponse` is constructed as follows:
|
||||
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests}/SearchDocumentationIT.java[field-caps-execute-listener]
|
||||
--------------------------------------------------
|
||||
<1> Called when the execution is successfully completed.
|
||||
<2> Called when the whole `FieldCapabilitiesRequest` fails.
|
||||
|
||||
[[java-rest-high-field-caps-response]]
|
||||
==== FieldCapabilitiesResponse
|
||||
|
||||
For each requested field, the returned `FieldCapabilitiesResponse` contains its type
|
||||
and whether or not it can be searched or aggregated on. The response also gives
|
||||
information about how each index contributes to the field's capabilities.
|
||||
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests}/SearchDocumentationIT.java[field-caps-response]
|
||||
--------------------------------------------------
|
||||
<1> The `user` field has two possible types, `keyword` and `text`.
|
||||
<2> This field only has type `keyword` in the `authors` and `contributors` indices.
|
||||
<3> Null, since the field is searchable in all indices for which it has the `keyword` type.
|
||||
<4> The `user` field is not aggregatable in the `authors` index.
|
@ -32,11 +32,13 @@ The Java High Level REST Client supports the following Search APIs:
|
||||
* <<java-rest-high-search-scroll>>
|
||||
* <<java-rest-high-clear-scroll>>
|
||||
* <<java-rest-high-multi-search>>
|
||||
* <<java-rest-high-field-caps>>
|
||||
* <<java-rest-high-rank-eval>>
|
||||
|
||||
include::search/search.asciidoc[]
|
||||
include::search/scroll.asciidoc[]
|
||||
include::search/multi-search.asciidoc[]
|
||||
include::search/field-caps.asciidoc[]
|
||||
include::search/rank-eval.asciidoc[]
|
||||
|
||||
== Miscellaneous APIs
|
||||
|
@ -19,11 +19,14 @@
|
||||
|
||||
package org.elasticsearch.action.fieldcaps;
|
||||
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.io.stream.Writeable;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@ -36,6 +39,13 @@ import java.util.List;
|
||||
* Describes the capabilities of a field optionally merged across multiple indices.
|
||||
*/
|
||||
public class FieldCapabilities implements Writeable, ToXContentObject {
|
||||
private static final ParseField TYPE_FIELD = new ParseField("type");
|
||||
private static final ParseField SEARCHABLE_FIELD = new ParseField("searchable");
|
||||
private static final ParseField AGGREGATABLE_FIELD = new ParseField("aggregatable");
|
||||
private static final ParseField INDICES_FIELD = new ParseField("indices");
|
||||
private static final ParseField NON_SEARCHABLE_INDICES_FIELD = new ParseField("non_searchable_indices");
|
||||
private static final ParseField NON_AGGREGATABLE_INDICES_FIELD = new ParseField("non_aggregatable_indices");
|
||||
|
||||
private final String name;
|
||||
private final String type;
|
||||
private final boolean isSearchable;
|
||||
@ -52,7 +62,7 @@ public class FieldCapabilities implements Writeable, ToXContentObject {
|
||||
* @param isSearchable Whether this field is indexed for search.
|
||||
* @param isAggregatable Whether this field can be aggregated on.
|
||||
*/
|
||||
FieldCapabilities(String name, String type, boolean isSearchable, boolean isAggregatable) {
|
||||
public FieldCapabilities(String name, String type, boolean isSearchable, boolean isAggregatable) {
|
||||
this(name, type, isSearchable, isAggregatable, null, null, null);
|
||||
}
|
||||
|
||||
@ -69,7 +79,7 @@ public class FieldCapabilities implements Writeable, ToXContentObject {
|
||||
* @param nonAggregatableIndices The list of indices where this field is not aggregatable,
|
||||
* or null if the field is aggregatable in all indices.
|
||||
*/
|
||||
FieldCapabilities(String name, String type,
|
||||
public FieldCapabilities(String name, String type,
|
||||
boolean isSearchable, boolean isAggregatable,
|
||||
String[] indices,
|
||||
String[] nonSearchableIndices,
|
||||
@ -83,7 +93,7 @@ public class FieldCapabilities implements Writeable, ToXContentObject {
|
||||
this.nonAggregatableIndices = nonAggregatableIndices;
|
||||
}
|
||||
|
||||
FieldCapabilities(StreamInput in) throws IOException {
|
||||
public FieldCapabilities(StreamInput in) throws IOException {
|
||||
this.name = in.readString();
|
||||
this.type = in.readString();
|
||||
this.isSearchable = in.readBoolean();
|
||||
@ -107,22 +117,47 @@ public class FieldCapabilities implements Writeable, ToXContentObject {
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
builder.field("type", type);
|
||||
builder.field("searchable", isSearchable);
|
||||
builder.field("aggregatable", isAggregatable);
|
||||
builder.field(TYPE_FIELD.getPreferredName(), type);
|
||||
builder.field(SEARCHABLE_FIELD.getPreferredName(), isSearchable);
|
||||
builder.field(AGGREGATABLE_FIELD.getPreferredName(), isAggregatable);
|
||||
if (indices != null) {
|
||||
builder.field("indices", indices);
|
||||
builder.field(INDICES_FIELD.getPreferredName(), indices);
|
||||
}
|
||||
if (nonSearchableIndices != null) {
|
||||
builder.field("non_searchable_indices", nonSearchableIndices);
|
||||
builder.field(NON_SEARCHABLE_INDICES_FIELD.getPreferredName(), nonSearchableIndices);
|
||||
}
|
||||
if (nonAggregatableIndices != null) {
|
||||
builder.field("non_aggregatable_indices", nonAggregatableIndices);
|
||||
builder.field(NON_AGGREGATABLE_INDICES_FIELD.getPreferredName(), nonAggregatableIndices);
|
||||
}
|
||||
builder.endObject();
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static FieldCapabilities fromXContent(String name, XContentParser parser) throws IOException {
|
||||
return PARSER.parse(parser, name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static ConstructingObjectParser<FieldCapabilities, String> PARSER = new ConstructingObjectParser<>(
|
||||
"field_capabilities",
|
||||
true,
|
||||
(a, name) -> new FieldCapabilities(name,
|
||||
(String) a[0],
|
||||
(boolean) a[1],
|
||||
(boolean) a[2],
|
||||
a[3] != null ? ((List<String>) a[3]).toArray(new String[0]) : null,
|
||||
a[4] != null ? ((List<String>) a[4]).toArray(new String[0]) : null,
|
||||
a[5] != null ? ((List<String>) a[5]).toArray(new String[0]) : null));
|
||||
|
||||
static {
|
||||
PARSER.declareString(ConstructingObjectParser.constructorArg(), TYPE_FIELD);
|
||||
PARSER.declareBoolean(ConstructingObjectParser.constructorArg(), SEARCHABLE_FIELD);
|
||||
PARSER.declareBoolean(ConstructingObjectParser.constructorArg(), AGGREGATABLE_FIELD);
|
||||
PARSER.declareStringArray(ConstructingObjectParser.optionalConstructorArg(), INDICES_FIELD);
|
||||
PARSER.declareStringArray(ConstructingObjectParser.optionalConstructorArg(), NON_SEARCHABLE_INDICES_FIELD);
|
||||
PARSER.declareStringArray(ConstructingObjectParser.optionalConstructorArg(), NON_AGGREGATABLE_INDICES_FIELD);
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the field.
|
||||
*/
|
||||
|
@ -61,14 +61,18 @@ public final class FieldCapabilitiesRequest extends ActionRequest implements Ind
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> iff the results should be merged.
|
||||
*
|
||||
* Note that when using the high-level REST client, results are always merged (this flag is always considered 'true').
|
||||
*/
|
||||
boolean isMergeResults() {
|
||||
return mergeResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* if set to <code>true</code> the response will contain only a merged view of the per index field capabilities. Otherwise only
|
||||
* unmerged per index field capabilities are returned.
|
||||
* If set to <code>true</code> the response will contain only a merged view of the per index field capabilities.
|
||||
* Otherwise only unmerged per index field capabilities are returned.
|
||||
*
|
||||
* Note that when using the high-level REST client, results are always merged (this flag is always considered 'true').
|
||||
*/
|
||||
void setMergeResults(boolean mergeResults) {
|
||||
this.mergeResults = mergeResults;
|
||||
|
@ -21,20 +21,29 @@ package org.elasticsearch.action.fieldcaps;
|
||||
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.action.ActionResponse;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.common.xcontent.ToXContentFragment;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.XContentParserUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Response for {@link FieldCapabilitiesRequest} requests.
|
||||
*/
|
||||
public class FieldCapabilitiesResponse extends ActionResponse implements ToXContentFragment {
|
||||
private static final ParseField FIELDS_FIELD = new ParseField("fields");
|
||||
|
||||
private Map<String, Map<String, FieldCapabilities>> responseMap;
|
||||
private List<FieldCapabilitiesIndexResponse> indexResponses;
|
||||
|
||||
@ -114,10 +123,42 @@ public class FieldCapabilitiesResponse extends ActionResponse implements ToXCont
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.field("fields", responseMap);
|
||||
builder.field(FIELDS_FIELD.getPreferredName(), responseMap);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static FieldCapabilitiesResponse fromXContent(XContentParser parser) throws IOException {
|
||||
return PARSER.parse(parser, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final ConstructingObjectParser<FieldCapabilitiesResponse, Void> PARSER =
|
||||
new ConstructingObjectParser<>("field_capabilities_response", true,
|
||||
a -> new FieldCapabilitiesResponse(
|
||||
((List<Tuple<String, Map<String, FieldCapabilities>>>) a[0]).stream()
|
||||
.collect(Collectors.toMap(Tuple::v1, Tuple::v2))));
|
||||
|
||||
static {
|
||||
PARSER.declareNamedObjects(ConstructingObjectParser.constructorArg(), (p, c, n) -> {
|
||||
Map<String, FieldCapabilities> typeToCapabilities = parseTypeToCapabilities(p, n);
|
||||
return new Tuple<>(n, typeToCapabilities);
|
||||
}, FIELDS_FIELD);
|
||||
}
|
||||
|
||||
private static Map<String, FieldCapabilities> parseTypeToCapabilities(XContentParser parser, String name) throws IOException {
|
||||
Map<String, FieldCapabilities> typeToCapabilities = new HashMap<>();
|
||||
|
||||
XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);
|
||||
XContentParser.Token token;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser::getTokenLocation);
|
||||
String type = parser.currentName();
|
||||
FieldCapabilities capabilities = FieldCapabilities.fromXContent(name, parser);
|
||||
typeToCapabilities.put(type, capabilities);
|
||||
}
|
||||
return typeToCapabilities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
@ -19,7 +19,9 @@
|
||||
|
||||
package org.elasticsearch.action.fieldcaps;
|
||||
|
||||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.common.ValidationException;
|
||||
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
@ -80,7 +82,7 @@ public class FieldCapabilitiesRequestTests extends ESTestCase {
|
||||
|
||||
}
|
||||
|
||||
public void testFieldCapsRequestSerialization() throws IOException {
|
||||
public void testSerialization() throws IOException {
|
||||
for (int i = 0; i < 20; i++) {
|
||||
FieldCapabilitiesRequest request = randomRequest();
|
||||
BytesStreamOutput output = new BytesStreamOutput();
|
||||
@ -93,4 +95,11 @@ public class FieldCapabilitiesRequestTests extends ESTestCase {
|
||||
assertEquals(deserialized.hashCode(), request.hashCode());
|
||||
}
|
||||
}
|
||||
|
||||
public void testValidation() {
|
||||
FieldCapabilitiesRequest request = new FieldCapabilitiesRequest()
|
||||
.indices("index2");
|
||||
ActionRequestValidationException exception = request.validate();
|
||||
assertNotNull(exception);
|
||||
}
|
||||
}
|
||||
|
@ -19,42 +19,152 @@
|
||||
|
||||
package org.elasticsearch.action.fieldcaps;
|
||||
|
||||
import org.elasticsearch.action.admin.indices.close.CloseIndexResponse;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.test.AbstractStreamableXContentTestCase;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class FieldCapabilitiesResponseTests extends ESTestCase {
|
||||
private FieldCapabilitiesResponse randomResponse() {
|
||||
Map<String, Map<String, FieldCapabilities> > fieldMap = new HashMap<> ();
|
||||
int numFields = randomInt(10);
|
||||
for (int i = 0; i < numFields; i++) {
|
||||
String fieldName = randomAlphaOfLengthBetween(5, 10);
|
||||
int numIndices = randomIntBetween(1, 5);
|
||||
Map<String, FieldCapabilities> indexFieldMap = new HashMap<> ();
|
||||
for (int j = 0; j < numIndices; j++) {
|
||||
String index = randomAlphaOfLengthBetween(10, 20);
|
||||
indexFieldMap.put(index, FieldCapabilitiesTests.randomFieldCaps());
|
||||
}
|
||||
fieldMap.put(fieldName, indexFieldMap);
|
||||
}
|
||||
return new FieldCapabilitiesResponse(fieldMap);
|
||||
import static org.elasticsearch.test.XContentTestUtils.insertRandomFields;
|
||||
|
||||
public class FieldCapabilitiesResponseTests extends AbstractStreamableXContentTestCase<FieldCapabilitiesResponse> {
|
||||
|
||||
@Override
|
||||
protected FieldCapabilitiesResponse doParseInstance(XContentParser parser) throws IOException {
|
||||
return FieldCapabilitiesResponse.fromXContent(parser);
|
||||
}
|
||||
|
||||
public void testSerialization() throws IOException {
|
||||
for (int i = 0; i < 20; i++) {
|
||||
FieldCapabilitiesResponse response = randomResponse();
|
||||
BytesStreamOutput output = new BytesStreamOutput();
|
||||
response.writeTo(output);
|
||||
output.flush();
|
||||
StreamInput input = output.bytes().streamInput();
|
||||
FieldCapabilitiesResponse deserialized = new FieldCapabilitiesResponse();
|
||||
deserialized.readFrom(input);
|
||||
assertEquals(deserialized, response);
|
||||
assertEquals(deserialized.hashCode(), response.hashCode());
|
||||
@Override
|
||||
protected FieldCapabilitiesResponse createBlankInstance() {
|
||||
return new FieldCapabilitiesResponse();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FieldCapabilitiesResponse createTestInstance() {
|
||||
Map<String, Map<String, FieldCapabilities>> responses = new HashMap<>();
|
||||
|
||||
String[] fields = generateRandomStringArray(5, 10, false, true);
|
||||
assertNotNull(fields);
|
||||
|
||||
for (String field : fields) {
|
||||
Map<String, FieldCapabilities> typesToCapabilities = new HashMap<>();
|
||||
String[] types = generateRandomStringArray(5, 10, false, false);
|
||||
assertNotNull(types);
|
||||
|
||||
for (String type : types) {
|
||||
typesToCapabilities.put(type, FieldCapabilitiesTests.randomFieldCaps(field));
|
||||
}
|
||||
responses.put(field, typesToCapabilities);
|
||||
}
|
||||
return new FieldCapabilitiesResponse(responses);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FieldCapabilitiesResponse mutateInstance(FieldCapabilitiesResponse response) {
|
||||
Map<String, Map<String, FieldCapabilities>> mutatedResponses = new HashMap<>(response.get());
|
||||
|
||||
int mutation = response.get().isEmpty() ? 0 : randomIntBetween(0, 2);
|
||||
|
||||
switch (mutation) {
|
||||
case 0:
|
||||
String toAdd = randomAlphaOfLength(10);
|
||||
mutatedResponses.put(toAdd, Collections.singletonMap(
|
||||
randomAlphaOfLength(10),
|
||||
FieldCapabilitiesTests.randomFieldCaps(toAdd)));
|
||||
break;
|
||||
case 1:
|
||||
String toRemove = randomFrom(mutatedResponses.keySet());
|
||||
mutatedResponses.remove(toRemove);
|
||||
break;
|
||||
case 2:
|
||||
String toReplace = randomFrom(mutatedResponses.keySet());
|
||||
mutatedResponses.put(toReplace, Collections.singletonMap(
|
||||
randomAlphaOfLength(10),
|
||||
FieldCapabilitiesTests.randomFieldCaps(toReplace)));
|
||||
break;
|
||||
}
|
||||
return new FieldCapabilitiesResponse(mutatedResponses);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Predicate<String> getRandomFieldsExcludeFilter() {
|
||||
// Disallow random fields from being inserted under the 'fields' key, as this
|
||||
// map only contains field names, and also under 'fields.FIELD_NAME', as these
|
||||
// maps only contain type names.
|
||||
return field -> field.matches("fields(\\.\\w+)?");
|
||||
}
|
||||
|
||||
public void testToXContent() throws IOException {
|
||||
FieldCapabilitiesResponse response = createSimpleResponse();
|
||||
|
||||
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)
|
||||
.startObject();
|
||||
response.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
||||
builder.endObject();
|
||||
|
||||
String generatedResponse = BytesReference.bytes(builder).utf8ToString();
|
||||
assertEquals((
|
||||
"{" +
|
||||
" \"fields\": {" +
|
||||
" \"rating\": { " +
|
||||
" \"keyword\": {" +
|
||||
" \"type\": \"keyword\"," +
|
||||
" \"searchable\": false," +
|
||||
" \"aggregatable\": true," +
|
||||
" \"indices\": [\"index3\", \"index4\"]," +
|
||||
" \"non_searchable_indices\": [\"index4\"] " +
|
||||
" }," +
|
||||
" \"long\": {" +
|
||||
" \"type\": \"long\"," +
|
||||
" \"searchable\": true," +
|
||||
" \"aggregatable\": false," +
|
||||
" \"indices\": [\"index1\", \"index2\"]," +
|
||||
" \"non_aggregatable_indices\": [\"index1\"] " +
|
||||
" }" +
|
||||
" }," +
|
||||
" \"title\": { " +
|
||||
" \"text\": {" +
|
||||
" \"type\": \"text\"," +
|
||||
" \"searchable\": true," +
|
||||
" \"aggregatable\": false" +
|
||||
" }" +
|
||||
" }" +
|
||||
" }" +
|
||||
"}").replaceAll("\\s+", ""), generatedResponse);
|
||||
}
|
||||
|
||||
private static FieldCapabilitiesResponse createSimpleResponse() {
|
||||
Map<String, FieldCapabilities> titleCapabilities = new HashMap<>();
|
||||
titleCapabilities.put("text", new FieldCapabilities("title", "text", true, false));
|
||||
|
||||
Map<String, FieldCapabilities> ratingCapabilities = new HashMap<>();
|
||||
ratingCapabilities.put("long", new FieldCapabilities("rating", "long",
|
||||
true, false,
|
||||
new String[]{"index1", "index2"},
|
||||
null,
|
||||
new String[]{"index1"}));
|
||||
ratingCapabilities.put("keyword", new FieldCapabilities("rating", "keyword",
|
||||
false, true,
|
||||
new String[]{"index3", "index4"},
|
||||
new String[]{"index4"},
|
||||
null));
|
||||
|
||||
Map<String, Map<String, FieldCapabilities>> responses = new HashMap<>();
|
||||
responses.put("title", titleCapabilities);
|
||||
responses.put("rating", ratingCapabilities);
|
||||
return new FieldCapabilitiesResponse(responses);
|
||||
}
|
||||
}
|
||||
|
@ -20,16 +20,26 @@
|
||||
package org.elasticsearch.action.fieldcaps;
|
||||
|
||||
import org.elasticsearch.common.io.stream.Writeable;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.test.AbstractSerializingTestCase;
|
||||
import org.elasticsearch.test.AbstractWireSerializingTestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
public class FieldCapabilitiesTests extends AbstractWireSerializingTestCase<FieldCapabilities> {
|
||||
public class FieldCapabilitiesTests extends AbstractSerializingTestCase<FieldCapabilities> {
|
||||
private static final String FIELD_NAME = "field";
|
||||
|
||||
@Override
|
||||
protected FieldCapabilities doParseInstance(XContentParser parser) throws IOException {
|
||||
return FieldCapabilities.fromXContent(FIELD_NAME, parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FieldCapabilities createTestInstance() {
|
||||
return randomFieldCaps();
|
||||
return randomFieldCaps(FIELD_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -82,7 +92,7 @@ public class FieldCapabilitiesTests extends AbstractWireSerializingTestCase<Fiel
|
||||
}
|
||||
}
|
||||
|
||||
static FieldCapabilities randomFieldCaps() {
|
||||
static FieldCapabilities randomFieldCaps(String fieldName) {
|
||||
String[] indices = null;
|
||||
if (randomBoolean()) {
|
||||
indices = new String[randomIntBetween(1, 5)];
|
||||
@ -104,7 +114,7 @@ public class FieldCapabilitiesTests extends AbstractWireSerializingTestCase<Fiel
|
||||
nonAggregatableIndices[i] = randomAlphaOfLengthBetween(5, 20);
|
||||
}
|
||||
}
|
||||
return new FieldCapabilities(randomAlphaOfLengthBetween(5, 20),
|
||||
return new FieldCapabilities(fieldName,
|
||||
randomAlphaOfLengthBetween(5, 20), randomBoolean(), randomBoolean(),
|
||||
indices, nonSearchableIndices, nonAggregatableIndices);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user