Skip to content

Commit 112b5f1

Browse files
committed
Merge branch 'master' into ccr
* master: (24 commits) Watcher: Ensure mail message ids are unique per watch action (#30112) REST: Remove GET support for clear cache indices (#29525) SQL: Correct error message (#30138) Require acknowledgement to start_trial license (#30135) Fix a bug in FieldCapabilitiesRequest#equals and hashCode. (#30181) SQL: Add BinaryMathProcessor to named writeables list (#30127) Tests: Use buildDir as base for generated-resources (#30191) Fix SliceBuilderTests#testRandom failures Build: Fix deb version to use tilde with prerelease versions (#29000) Fix edge cases in CompositeKeyExtractorTests (#30175) Document time unit limitations for date histograms (#30177) Add support for field capabilities to the high-level REST client. (#29664) Remove licenses missed by the migration (#30128) [DOCS] Updates docker installation package details (#30110) Fix TermsSetQueryBuilder.doEquals() method (#29629) [Monitoring] Remove unhelpful Monitoring tests (#30144) [Test] Fix RenameProcessorTests.testRenameExistingFieldNullValue() (#29655) add copyright/scope configuration for intellij to Contributing Guide (#29688) [test] include oss tar in packaging tests (#30155) TEST: Update settings should go through cluster state (#29682) ...
2 parents 4bcecd3 + 707ba28 commit 112b5f1

File tree

95 files changed

+1868
-753
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+1868
-753
lines changed

CONTRIBUTING.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ We support development in the Eclipse and IntelliJ IDEs. For Eclipse, the
107107
minimum version that we support is [Eclipse Oxygen][eclipse] (version 4.7). For
108108
IntelliJ, the minimum version that we support is [IntelliJ 2017.2][intellij].
109109

110+
### Configuring IDEs And Running Tests
111+
110112
Eclipse users can automatically configure their IDE: `./gradlew eclipse`
111113
then `File: Import: Existing Projects into Workspace`. Select the
112114
option `Search for nested projects`. Additionally you will want to
@@ -144,6 +146,9 @@ For IntelliJ, go to
144146
For Eclipse, go to `Preferences->Java->Installed JREs` and add `-ea` to
145147
`VM Arguments`.
146148

149+
150+
### Java Language Formatting Guidelines
151+
147152
Please follow these formatting guidelines:
148153

149154
* Java indent is 4 spaces
@@ -155,6 +160,33 @@ Please follow these formatting guidelines:
155160
* IntelliJ: `Preferences/Settings->Editor->Code Style->Java->Imports`. There are two configuration options: `Class count to use import with '*'` and `Names count to use static import with '*'`. Set their values to 99999 or some other absurdly high value.
156161
* Don't worry too much about import order. Try not to change it but don't worry about fighting your IDE to stop it from doing so.
157162

163+
### License Headers
164+
165+
We require license headers on all Java files. You will notice that all the Java files in
166+
the top-level `x-pack` directory contain a separate license from the rest of the repository. This
167+
directory contains commercial code that is associated with a separate license. It can be helpful
168+
to have the IDE automatically insert the appropriate license header depending which part of the project
169+
contributions are made to.
170+
171+
#### IntelliJ: Copyright & Scope Profiles
172+
173+
To have IntelliJ insert the correct license, it is necessary to create to copyright profiles.
174+
These may potentially be called `apache2` and `commercial`. These can be created in
175+
`Preferences/Settings->Editor->Copyright->Copyright Profiles`. To associate these profiles to
176+
their respective directories, two "Scopes" will need to be created. These can be created in
177+
`Preferences/Settings->Appearances & Behavior->Scopes`. When creating scopes, be sure to choose
178+
the `shared` scope type. Create a scope, `apache2`, with
179+
the associated pattern of `!file[group:x-pack]:*/`. This pattern will exclude all the files contained in
180+
the `x-pack` directory. The other scope, `commercial`, will have the inverse pattern of `file[group:x-pack]:*/`.
181+
The two scopes, together, should account for all the files in the project. To associate the scopes
182+
with their copyright-profiles, go into `Preferences/Settings->Editor>Copyright` and use the `+` to add
183+
the associations `apache2/apache2` and `commercial/commercial`.
184+
185+
Configuring these options in IntelliJ can be quite buggy, so do not be alarmed if you have to open/close
186+
the settings window and/or restart IntelliJ to see your changes take effect.
187+
188+
### Creating A Distribution
189+
158190
To create a distribution from the source, simply run:
159191

160192
```sh
@@ -169,6 +201,8 @@ The archive distributions (tar and zip) can be found under:
169201
`./distribution/archives/(tar|zip)/build/distributions/`
170202

171203

204+
### Running The Full Test Suite
205+
172206
Before submitting your changes, run the test suite to make sure that nothing is broken, with:
173207

174208
```sh

buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/VagrantTestPlugin.groovy

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,15 @@ class VagrantTestPlugin implements Plugin<Project> {
3737
'ubuntu-1404',
3838
]
3939

40-
/** All onboarded archives by default, available for Bats tests even if not used **/
41-
static List<String> DISTRIBUTION_ARCHIVES = ['tar', 'rpm', 'deb', 'oss-rpm', 'oss-deb']
40+
/** All distributions to bring into test VM, whether or not they are used **/
41+
static List<String> DISTRIBUTIONS = [
42+
'archives:tar',
43+
'archives:oss-tar',
44+
'packages:rpm',
45+
'packages:oss-rpm',
46+
'packages:deb',
47+
'packages:oss-deb'
48+
]
4249

4350
/** Packages onboarded for upgrade tests **/
4451
static List<String> UPGRADE_FROM_ARCHIVES = ['rpm', 'deb']
@@ -117,13 +124,8 @@ class VagrantTestPlugin implements Plugin<Project> {
117124
upgradeFromVersion = Version.fromString(upgradeFromVersionRaw)
118125
}
119126

120-
DISTRIBUTION_ARCHIVES.each {
127+
DISTRIBUTIONS.each {
121128
// Adds a dependency for the current version
122-
if (it == 'tar') {
123-
it = 'archives:tar'
124-
} else {
125-
it = "packages:${it}"
126-
}
127129
project.dependencies.add(PACKAGING_CONFIGURATION,
128130
project.dependencies.project(path: ":distribution:${it}", configuration: 'default'))
129131
}

buildSrc/src/main/resources/checkstyle_suppressions.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,6 @@
535535
<suppress files="server[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]gateway[/\\]ReplicaShardAllocatorTests.java" checks="LineLength" />
536536
<suppress files="server[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]gateway[/\\]ReusePeerRecoverySharedTest.java" checks="LineLength" />
537537
<suppress files="server[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]get[/\\]GetActionIT.java" checks="LineLength" />
538-
<suppress files="server[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]IndexServiceTests.java" checks="LineLength" />
539538
<suppress files="server[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]IndexingSlowLogTests.java" checks="LineLength" />
540539
<suppress files="server[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]MergePolicySettingsTests.java" checks="LineLength" />
541540
<suppress files="server[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]SearchSlowLogTests.java" checks="LineLength" />

client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import org.elasticsearch.action.admin.indices.shrink.ResizeType;
4949
import org.elasticsearch.action.bulk.BulkRequest;
5050
import org.elasticsearch.action.delete.DeleteRequest;
51+
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesRequest;
5152
import org.elasticsearch.action.get.GetRequest;
5253
import org.elasticsearch.action.get.MultiGetRequest;
5354
import org.elasticsearch.action.index.IndexRequest;
@@ -75,6 +76,7 @@
7576
import org.elasticsearch.common.xcontent.XContentType;
7677
import org.elasticsearch.index.VersionType;
7778
import org.elasticsearch.index.rankeval.RankEvalRequest;
79+
import org.elasticsearch.rest.action.RestFieldCapabilitiesAction;
7880
import org.elasticsearch.rest.action.search.RestSearchAction;
7981
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
8082

@@ -536,6 +538,16 @@ static Request existsAlias(GetAliasesRequest getAliasesRequest) {
536538
return new Request(HttpHead.METHOD_NAME, endpoint, params.getParams(), null);
537539
}
538540

541+
static Request fieldCaps(FieldCapabilitiesRequest fieldCapabilitiesRequest) {
542+
Params params = Params.builder();
543+
params.withFields(fieldCapabilitiesRequest.fields());
544+
params.withIndicesOptions(fieldCapabilitiesRequest.indicesOptions());
545+
546+
String[] indices = fieldCapabilitiesRequest.indices();
547+
String endpoint = endpoint(indices, "_field_caps");
548+
return new Request(HttpGet.METHOD_NAME, endpoint, params.getParams(), null);
549+
}
550+
539551
static Request rankEval(RankEvalRequest rankEvalRequest) throws IOException {
540552
String endpoint = endpoint(rankEvalRequest.indices(), Strings.EMPTY_ARRAY, "_rank_eval");
541553
Params params = Params.builder();
@@ -712,6 +724,13 @@ Params withFetchSourceContext(FetchSourceContext fetchSourceContext) {
712724
return this;
713725
}
714726

727+
Params withFields(String[] fields) {
728+
if (fields != null && fields.length > 0) {
729+
return putParam("fields", String.join(",", fields));
730+
}
731+
return this;
732+
}
733+
715734
Params withMasterTimeout(TimeValue masterTimeout) {
716735
return putParam("master_timeout", masterTimeout);
717736
}

client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import org.elasticsearch.action.bulk.BulkResponse;
3131
import org.elasticsearch.action.delete.DeleteRequest;
3232
import org.elasticsearch.action.delete.DeleteResponse;
33+
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesRequest;
34+
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesResponse;
3335
import org.elasticsearch.action.get.GetRequest;
3436
import org.elasticsearch.action.get.GetResponse;
3537
import org.elasticsearch.action.get.MultiGetRequest;
@@ -501,6 +503,31 @@ public final void rankEvalAsync(RankEvalRequest rankEvalRequest, ActionListener<
501503
headers);
502504
}
503505

506+
/**
507+
* Executes a request using the Field Capabilities API.
508+
*
509+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-field-caps.html">Field Capabilities API
510+
* on elastic.co</a>.
511+
*/
512+
public final FieldCapabilitiesResponse fieldCaps(FieldCapabilitiesRequest fieldCapabilitiesRequest,
513+
Header... headers) throws IOException {
514+
return performRequestAndParseEntity(fieldCapabilitiesRequest, Request::fieldCaps,
515+
FieldCapabilitiesResponse::fromXContent, emptySet(), headers);
516+
}
517+
518+
/**
519+
* Asynchronously executes a request using the Field Capabilities API.
520+
*
521+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-field-caps.html">Field Capabilities API
522+
* on elastic.co</a>.
523+
*/
524+
public final void fieldCapsAsync(FieldCapabilitiesRequest fieldCapabilitiesRequest,
525+
ActionListener<FieldCapabilitiesResponse> listener,
526+
Header... headers) {
527+
performRequestAsyncAndParseEntity(fieldCapabilitiesRequest, Request::fieldCaps,
528+
FieldCapabilitiesResponse::fromXContent, listener, emptySet(), headers);
529+
}
530+
504531
protected final <Req extends ActionRequest, Resp> Resp performRequestAndParseEntity(Req request,
505532
CheckedFunction<Req, Request, IOException> requestConverter,
506533
CheckedFunction<XContentParser, Resp, IOException> entityParser,

client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import org.elasticsearch.action.bulk.BulkRequest;
5353
import org.elasticsearch.action.bulk.BulkShardRequest;
5454
import org.elasticsearch.action.delete.DeleteRequest;
55+
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesRequest;
5556
import org.elasticsearch.action.get.GetRequest;
5657
import org.elasticsearch.action.get.MultiGetRequest;
5758
import org.elasticsearch.action.index.IndexRequest;
@@ -89,6 +90,7 @@
8990
import org.elasticsearch.index.rankeval.RankEvalSpec;
9091
import org.elasticsearch.index.rankeval.RatedRequest;
9192
import org.elasticsearch.index.rankeval.RestRankEvalAction;
93+
import org.elasticsearch.rest.action.RestFieldCapabilitiesAction;
9294
import org.elasticsearch.rest.action.search.RestSearchAction;
9395
import org.elasticsearch.search.Scroll;
9496
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
@@ -108,11 +110,14 @@
108110
import java.lang.reflect.Constructor;
109111
import java.lang.reflect.Modifier;
110112
import java.util.ArrayList;
113+
import java.util.Arrays;
111114
import java.util.Collections;
112115
import java.util.HashMap;
116+
import java.util.HashSet;
113117
import java.util.List;
114118
import java.util.Locale;
115119
import java.util.Map;
120+
import java.util.Set;
116121
import java.util.StringJoiner;
117122
import java.util.function.Consumer;
118123
import java.util.function.Function;
@@ -128,6 +133,8 @@
128133
import static org.elasticsearch.search.RandomSearchRequestGenerator.randomSearchRequest;
129134
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
130135
import static org.hamcrest.CoreMatchers.equalTo;
136+
import static org.hamcrest.Matchers.hasEntry;
137+
import static org.hamcrest.Matchers.hasKey;
131138
import static org.hamcrest.Matchers.nullValue;
132139

133140
public class RequestTests extends ESTestCase {
@@ -1213,6 +1220,47 @@ public void testExistsAliasNoAliasNoIndex() {
12131220
}
12141221
}
12151222

1223+
public void testFieldCaps() {
1224+
// Create a random request.
1225+
String[] indices = randomIndicesNames(0, 5);
1226+
String[] fields = generateRandomStringArray(5, 10, false, false);
1227+
1228+
FieldCapabilitiesRequest fieldCapabilitiesRequest = new FieldCapabilitiesRequest()
1229+
.indices(indices)
1230+
.fields(fields);
1231+
1232+
Map<String, String> indicesOptionsParams = new HashMap<>();
1233+
setRandomIndicesOptions(fieldCapabilitiesRequest::indicesOptions,
1234+
fieldCapabilitiesRequest::indicesOptions,
1235+
indicesOptionsParams);
1236+
1237+
Request request = Request.fieldCaps(fieldCapabilitiesRequest);
1238+
1239+
// Verify that the resulting REST request looks as expected.
1240+
StringJoiner endpoint = new StringJoiner("/", "/", "");
1241+
String joinedIndices = String.join(",", indices);
1242+
if (!joinedIndices.isEmpty()) {
1243+
endpoint.add(joinedIndices);
1244+
}
1245+
endpoint.add("_field_caps");
1246+
1247+
assertEquals(endpoint.toString(), request.getEndpoint());
1248+
assertEquals(4, request.getParameters().size());
1249+
1250+
// Note that we don't check the field param value explicitly, as field names are passed through
1251+
// a hash set before being added to the request, and can appear in a non-deterministic order.
1252+
assertThat(request.getParameters(), hasKey("fields"));
1253+
String[] requestFields = Strings.splitStringByCommaToArray(request.getParameters().get("fields"));
1254+
assertEquals(new HashSet<>(Arrays.asList(fields)),
1255+
new HashSet<>(Arrays.asList(requestFields)));
1256+
1257+
for (Map.Entry<String, String> param : indicesOptionsParams.entrySet()) {
1258+
assertThat(request.getParameters(), hasEntry(param.getKey(), param.getValue()));
1259+
}
1260+
1261+
assertNull(request.getEntity());
1262+
}
1263+
12161264
public void testRankEval() throws Exception {
12171265
RankEvalSpec spec = new RankEvalSpec(
12181266
Collections.singletonList(new RatedRequest("queryId", Collections.emptyList(), new SearchSourceBuilder())),
@@ -1233,7 +1281,6 @@ public void testRankEval() throws Exception {
12331281
assertEquals(3, request.getParameters().size());
12341282
assertEquals(expectedParams, request.getParameters());
12351283
assertToXContentBody(spec, request.getEntity());
1236-
12371284
}
12381285

12391286
public void testSplit() throws IOException {

client/rest-high-level/src/test/java/org/elasticsearch/client/SearchIT.java

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
import org.apache.http.nio.entity.NStringEntity;
2828
import org.elasticsearch.ElasticsearchException;
2929
import org.elasticsearch.ElasticsearchStatusException;
30+
import org.elasticsearch.action.fieldcaps.FieldCapabilities;
31+
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesRequest;
32+
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesResponse;
3033
import org.elasticsearch.action.search.ClearScrollRequest;
3134
import org.elasticsearch.action.search.ClearScrollResponse;
3235
import org.elasticsearch.action.search.MultiSearchRequest;
@@ -96,14 +99,31 @@ public void indexDocuments() throws IOException {
9699
client().performRequest(HttpPut.METHOD_NAME, "/index/type/5", Collections.emptyMap(), doc5);
97100
client().performRequest(HttpPost.METHOD_NAME, "/index/_refresh");
98101

99-
StringEntity doc = new StringEntity("{\"field\":\"value1\"}", ContentType.APPLICATION_JSON);
102+
103+
StringEntity doc = new StringEntity("{\"field\":\"value1\", \"rating\": 7}", ContentType.APPLICATION_JSON);
100104
client().performRequest(HttpPut.METHOD_NAME, "/index1/doc/1", Collections.emptyMap(), doc);
101105
doc = new StringEntity("{\"field\":\"value2\"}", ContentType.APPLICATION_JSON);
102106
client().performRequest(HttpPut.METHOD_NAME, "/index1/doc/2", Collections.emptyMap(), doc);
103-
doc = new StringEntity("{\"field\":\"value1\"}", ContentType.APPLICATION_JSON);
107+
108+
StringEntity mappings = new StringEntity(
109+
"{" +
110+
" \"mappings\": {" +
111+
" \"doc\": {" +
112+
" \"properties\": {" +
113+
" \"rating\": {" +
114+
" \"type\": \"keyword\"" +
115+
" }" +
116+
" }" +
117+
" }" +
118+
" }" +
119+
"}}",
120+
ContentType.APPLICATION_JSON);
121+
client().performRequest("PUT", "/index2", Collections.emptyMap(), mappings);
122+
doc = new StringEntity("{\"field\":\"value1\", \"rating\": \"good\"}", ContentType.APPLICATION_JSON);
104123
client().performRequest(HttpPut.METHOD_NAME, "/index2/doc/3", Collections.emptyMap(), doc);
105124
doc = new StringEntity("{\"field\":\"value2\"}", ContentType.APPLICATION_JSON);
106125
client().performRequest(HttpPut.METHOD_NAME, "/index2/doc/4", Collections.emptyMap(), doc);
126+
107127
doc = new StringEntity("{\"field\":\"value1\"}", ContentType.APPLICATION_JSON);
108128
client().performRequest(HttpPut.METHOD_NAME, "/index3/doc/5", Collections.emptyMap(), doc);
109129
doc = new StringEntity("{\"field\":\"value2\"}", ContentType.APPLICATION_JSON);
@@ -713,6 +733,57 @@ public void testMultiSearch_failure() throws Exception {
713733
assertThat(multiSearchResponse.getResponses()[1].getResponse(), nullValue());
714734
}
715735

736+
public void testFieldCaps() throws IOException {
737+
FieldCapabilitiesRequest request = new FieldCapabilitiesRequest()
738+
.indices("index1", "index2")
739+
.fields("rating", "field");
740+
741+
FieldCapabilitiesResponse response = execute(request,
742+
highLevelClient()::fieldCaps, highLevelClient()::fieldCapsAsync);
743+
744+
// Check the capabilities for the 'rating' field.
745+
assertTrue(response.get().containsKey("rating"));
746+
Map<String, FieldCapabilities> ratingResponse = response.getField("rating");
747+
assertEquals(2, ratingResponse.size());
748+
749+
FieldCapabilities expectedKeywordCapabilities = new FieldCapabilities(
750+
"rating", "keyword", true, true, new String[]{"index2"}, null, null);
751+
assertEquals(expectedKeywordCapabilities, ratingResponse.get("keyword"));
752+
753+
FieldCapabilities expectedLongCapabilities = new FieldCapabilities(
754+
"rating", "long", true, true, new String[]{"index1"}, null, null);
755+
assertEquals(expectedLongCapabilities, ratingResponse.get("long"));
756+
757+
// Check the capabilities for the 'field' field.
758+
assertTrue(response.get().containsKey("field"));
759+
Map<String, FieldCapabilities> fieldResponse = response.getField("field");
760+
assertEquals(1, fieldResponse.size());
761+
762+
FieldCapabilities expectedTextCapabilities = new FieldCapabilities(
763+
"field", "text", true, false);
764+
assertEquals(expectedTextCapabilities, fieldResponse.get("text"));
765+
}
766+
767+
public void testFieldCapsWithNonExistentFields() throws IOException {
768+
FieldCapabilitiesRequest request = new FieldCapabilitiesRequest()
769+
.indices("index2")
770+
.fields("nonexistent");
771+
772+
FieldCapabilitiesResponse response = execute(request,
773+
highLevelClient()::fieldCaps, highLevelClient()::fieldCapsAsync);
774+
assertTrue(response.get().isEmpty());
775+
}
776+
777+
public void testFieldCapsWithNonExistentIndices() {
778+
FieldCapabilitiesRequest request = new FieldCapabilitiesRequest()
779+
.indices("non-existent")
780+
.fields("rating");
781+
782+
ElasticsearchException exception = expectThrows(ElasticsearchException.class,
783+
() -> execute(request, highLevelClient()::fieldCaps, highLevelClient()::fieldCapsAsync));
784+
assertEquals(RestStatus.NOT_FOUND, exception.status());
785+
}
786+
716787
private static void assertSearchHeader(SearchResponse searchResponse) {
717788
assertThat(searchResponse.getTook().nanos(), greaterThanOrEqualTo(0L));
718789
assertEquals(0, searchResponse.getFailedShards());

0 commit comments

Comments
 (0)