From 06364cf6f00feb5ed7494c90b5ac72bdf0703949 Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Wed, 3 May 2017 18:49:08 -0400 Subject: [PATCH 01/44] You had one job Netty logging guard In pre-release versions of Elasticsearch 5.0.0, users were subject to log messages of the form "your platform does not.*reliably.*potential system instability". This is because we disable Netty from being unsafe, and Netty throws up this scary info-level message when unsafe is unavailable, even if it was unavailable because the user requested that it be unavailabe. Users were rightly confused, and concerned. So, we contributed a guard to Netty to prevent this log message from showing up when unsafe was explicitly disabled. This guard shipped with all versions of Netty that shipped starting with Elasticsearch 5.0.0. Unfortunately, this guard was lost in an unrelated refactoring and now with the 4.1.10.Final upgrade, users will again see this message. This commit is a hack around this until we can get a fix upstream again. Relates #24469 --- .../transport/netty4/Netty4InternalESLogger.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/Netty4InternalESLogger.java b/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/Netty4InternalESLogger.java index 91bbe1c1a9b..3d509db6561 100644 --- a/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/Netty4InternalESLogger.java +++ b/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/Netty4InternalESLogger.java @@ -101,7 +101,11 @@ class Netty4InternalESLogger extends AbstractInternalLogger { @Override public void info(String msg) { - logger.info(msg); + if (!("Your platform does not provide complete low-level API for accessing direct buffers reliably. " + + "Unless explicitly requested, heap buffer will always be preferred to avoid potential system " + + "instability.").equals(msg)) { + logger.info(msg); + } } @Override From 2edd4d11f24ccbfd572dff61934e514e5ec342c5 Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Wed, 3 May 2017 18:51:50 -0400 Subject: [PATCH 02/44] Revise issue template This commit revises the issue template, hoping to make it clearer that following the guidelines is a really good thing to do. Relates #24470 --- .github/ISSUE_TEMPLATE.md | 43 +++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 7822d8ef2b3..ea89d18ca8a 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,27 +1,40 @@ + + **Elasticsearch version**: **Plugins installed**: [] -**JVM version**: +**JVM version** (`java -version`): -**OS version**: +**OS version** (`uname -a` if on a Unix-like system): **Description of the problem including expected versus actual behavior**: @@ -33,8 +46,8 @@ request block and provide responses for all of the below items. **Provide logs (if relevant)**: **Describe the feature**: From 4862544934e0b9e3a5d8e4d37fb14ab70fbf7202 Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Wed, 3 May 2017 20:11:41 -0400 Subject: [PATCH 03/44] Increase logging in IndexRecoveryIT#rerouteTest This test started failing but the logging here is insufficient to discern what is happening. This commit increases the logging level on this test until the failure can be understood. --- .../indices/recovery/IndexRecoveryIT.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/src/test/java/org/elasticsearch/indices/recovery/IndexRecoveryIT.java b/core/src/test/java/org/elasticsearch/indices/recovery/IndexRecoveryIT.java index a21f7757eac..5fb59245935 100644 --- a/core/src/test/java/org/elasticsearch/indices/recovery/IndexRecoveryIT.java +++ b/core/src/test/java/org/elasticsearch/indices/recovery/IndexRecoveryIT.java @@ -240,6 +240,16 @@ public class IndexRecoveryIT extends ESIntegTestCase { validateIndexRecoveryState(nodeBRecoveryState.getIndex()); } + @TestLogging( + "_root:DEBUG," + + "org.elasticsearch.action.bulk:TRACE," + + "org.elasticsearch.action.get:TRACE," + + "org.elasticsearch.cluster.service:TRACE," + + "org.elasticsearch.discovery:TRACE," + + "org.elasticsearch.indices.cluster:TRACE," + + "org.elasticsearch.indices.recovery:TRACE," + + "org.elasticsearch.index.seqno:TRACE," + + "org.elasticsearch.index.shard:TRACE") public void testRerouteRecovery() throws Exception { logger.info("--> start node A"); final String nodeA = internalCluster().startNode(); From 45dd3780e27893d6b6221772df84d79d1d59b1d7 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Wed, 3 May 2017 20:58:23 -0400 Subject: [PATCH 04/44] CONSOLEify remaining _cat docs Relates to #18160 --- docs/build.gradle | 3 -- docs/reference/cat/snapshots.asciidoc | 21 +++++++-- docs/reference/cat/templates.asciidoc | 23 +++++++--- docs/reference/cat/thread_pool.asciidoc | 60 ++++++++++++++++--------- 4 files changed, 73 insertions(+), 34 deletions(-) diff --git a/docs/build.gradle b/docs/build.gradle index 7effa7401b0..699cda15872 100644 --- a/docs/build.gradle +++ b/docs/build.gradle @@ -38,9 +38,6 @@ buildRestTests.expectedUnconvertedCandidates = [ 'reference/aggregations/metrics/percentile-rank-aggregation.asciidoc', 'reference/aggregations/metrics/scripted-metric-aggregation.asciidoc', 'reference/aggregations/metrics/tophits-aggregation.asciidoc', - 'reference/cat/snapshots.asciidoc', - 'reference/cat/templates.asciidoc', - 'reference/cat/thread_pool.asciidoc', 'reference/cluster/allocation-explain.asciidoc', 'reference/cluster/nodes-info.asciidoc', 'reference/cluster/nodes-stats.asciidoc', diff --git a/docs/reference/cat/snapshots.asciidoc b/docs/reference/cat/snapshots.asciidoc index 3d34cd51e6d..5677a0f2a7c 100644 --- a/docs/reference/cat/snapshots.asciidoc +++ b/docs/reference/cat/snapshots.asciidoc @@ -5,15 +5,30 @@ The `snapshots` command shows all snapshots that belong to a specific repository To find a list of available repositories to query, the command `/_cat/repositories` can be used. Querying the snapshots of a repository named `repo1` then looks as follows. -[source,sh] +[source,js] +-------------------------------------------------- +GET /_cat/snapshots/repo1?v&s=id +-------------------------------------------------- +// CONSOLE +// TEST[s/^/PUT \/_snapshot\/repo1\/snap1?wait_for_completion=true\n/] +// TEST[s/^/PUT \/_snapshot\/repo1\/snap2?wait_for_completion=true\n/] +// TEST[s/^/PUT \/_snapshot\/repo1\n{"type": "fs", "settings": {"location": "repo\/1"}}\n/] + +Which looks like: + +[source,txt] -------------------------------------------------- -% curl 'localhost:9200/_cat/snapshots/repo1?v' id status start_epoch start_time end_epoch end_time duration indices successful_shards failed_shards total_shards snap1 FAILED 1445616705 18:11:45 1445616978 18:16:18 4.6m 1 4 1 5 snap2 SUCCESS 1445634298 23:04:58 1445634672 23:11:12 6.2m 2 10 0 10 -------------------------------------------------- +// TESTRESPONSE[s/FAILED/SUCCESS/ s/14456\d+/\\d+/ s/\d+(\.\d+)?(m|s|ms)/\\d+(\\.\\d+)?(m|s|ms)/] +// TESTRESPONSE[s/\d+:\d+:\d+/\\d+:\\d+:\\d+/] +// TESTRESPONSE[s/1 4 1 5/\\d+ \\d+ \\d+ \\d+/] +// TESTRESPONSE[s/2 10 0 10/\\d+ \\d+ \\d+ \\d+/] +// TESTRESPONSE[_cat] Each snapshot contains information about when it was started and stopped. Start and stop timestamps are available in two formats. The `HH:MM:SS` output is simply for quick human consumption. -The epoch time retains more information, including date, and is machine sortable if the snapshot process spans days. \ No newline at end of file +The epoch time retains more information, including date, and is machine sortable if the snapshot process spans days. diff --git a/docs/reference/cat/templates.asciidoc b/docs/reference/cat/templates.asciidoc index 51ab34d0546..bc221d13552 100644 --- a/docs/reference/cat/templates.asciidoc +++ b/docs/reference/cat/templates.asciidoc @@ -3,14 +3,25 @@ The `templates` command provides information about existing templates. -[source, sh] +[source,js] -------------------------------------------------- -% curl 'localhost:9200/_cat/templates?v=true' -name template order version -template0 te* 0 -template1 tea* 1 -template2 teak* 2 7 +GET /_cat/templates?v&s=name -------------------------------------------------- +// CONSOLE +// TEST[s/^/PUT _template\/template0\n{"index_patterns": "te*", "order": 0}\n/] +// TEST[s/^/PUT _template\/template1\n{"index_patterns": "tea*", "order": 1}\n/] +// TEST[s/^/PUT _template\/template2\n{"index_patterns": "teak*", "order": 2, "version": 7}\n/] + +which looks like + +[source,txt] +-------------------------------------------------- +name index_patterns order version +template0 [te*] 0 +template1 [tea*] 1 +template2 [teak*] 2 7 +-------------------------------------------------- +// TESTRESPONSE[s/\*/\\*/ s/\[/\\[/ s/\]/\\]/ _cat] The output shows that there are three existing templates, with template2 having a version value. diff --git a/docs/reference/cat/thread_pool.asciidoc b/docs/reference/cat/thread_pool.asciidoc index 7da1aa5ce0f..721d85e46a0 100644 --- a/docs/reference/cat/thread_pool.asciidoc +++ b/docs/reference/cat/thread_pool.asciidoc @@ -4,35 +4,43 @@ The `thread_pool` command shows cluster wide thread pool statistics per node. By default the active, queue and rejected statistics are returned for all thread pools. -[source,sh] +[source,js] -------------------------------------------------- -% curl 192.168.56.10:9200/_cat/thread_pool -0EWUhXe bulk 0 0 0 -0EWUhXe fetch_shard_started 0 0 0 -0EWUhXe fetch_shard_store 0 0 0 -0EWUhXe flush 0 0 0 -0EWUhXe force_merge 0 0 0 -0EWUhXe generic 0 0 0 -0EWUhXe get 0 0 0 -0EWUhXe index 0 0 0 -0EWUhXe listener 0 0 0 -0EWUhXe management 1 0 0 -0EWUhXe refresh 0 0 0 -0EWUhXe search 0 0 0 -0EWUhXe snapshot 0 0 0 -0EWUhXe warmer 0 0 0 +GET /_cat/thread_pool -------------------------------------------------- +// CONSOLE + +Which looks like: + +[source,txt] +-------------------------------------------------- +node-0 bulk 0 0 0 +node-0 fetch_shard_started 0 0 0 +node-0 fetch_shard_store 0 0 0 +node-0 flush 0 0 0 +node-0 force_merge 0 0 0 +node-0 generic 0 0 0 +node-0 get 0 0 0 +node-0 index 0 0 0 +node-0 listener 0 0 0 +node-0 management 1 0 0 +node-0 refresh 0 0 0 +node-0 search 0 0 0 +node-0 snapshot 0 0 0 +node-0 warmer 0 0 0 +-------------------------------------------------- +// TESTRESPONSE[s/\d+/\\d+/ _cat] The first column is the node name -[source,sh] +[source,txt] -------------------------------------------------- node_name -0EWUhXe +node-0 -------------------------------------------------- The second column is the thread pool name -[source,sh] +[source,txt] -------------------------------------------------- name bulk @@ -54,7 +62,7 @@ warmer The next three columns show the active, queue, and rejected statistics for each thread pool -[source,sh] +[source,txt] -------------------------------------------------- active queue rejected 0 0 0 @@ -76,12 +84,20 @@ active queue rejected The cat thread pool API accepts a `thread_pool_patterns` URL parameter for specifying a comma-separated list of regular expressions to match thread pool names. -[source,sh] +[source,js] +-------------------------------------------------- +GET /_cat/thread_pool/generic?v&h=id,name,active,rejected,completed +-------------------------------------------------- +// CONSOLE + +which looks like: + +[source,js] -------------------------------------------------- -% curl 'localhost:9200/_cat/thread_pool/generic?v&h=id,name,active,rejected,completed' id name active rejected completed 0EWUhXeBQtaVGlexUeVwMg generic 0 0 70 -------------------------------------------------- +// TESTRESPONSE[s/0EWUhXeBQtaVGlexUeVwMg/[\\w-]+/ s/\d+/\\d+/ _cat] Here the host columns and the active, rejected and completed suggest thread pool statistics are displayed. From 48031a2c5a98866f6ee1cf0492f2cfca10259f32 Mon Sep 17 00:00:00 2001 From: Ali Beyad Date: Wed, 3 May 2017 22:58:43 -0400 Subject: [PATCH 05/44] [DOCS] Fixes the documentation on leading forward slashes in the (#24478) [DOCS] Fixes the documentation on leading forward slashes in the base_path of S3 repositories Closes #23435 --- docs/plugins/repository-s3.asciidoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/plugins/repository-s3.asciidoc b/docs/plugins/repository-s3.asciidoc index 58ca5dab2d7..a0fe757ab40 100644 --- a/docs/plugins/repository-s3.asciidoc +++ b/docs/plugins/repository-s3.asciidoc @@ -168,6 +168,9 @@ The following settings are supported: Specifies the path within bucket to repository data. Defaults to value of `repositories.s3.base_path` or to root directory if not set. + Previously, the base_path could take a leading `/` (forward slash). + However, this has been deprecated and setting the base_path now should + omit the leading `/`. `access_key`:: From d0e71510adf6cea814c04a75bfa8c2bd0ef109bc Mon Sep 17 00:00:00 2001 From: Adrien Grand Date: Thu, 4 May 2017 10:27:50 +0200 Subject: [PATCH 06/44] Enforce at most one type. (#24428) This is a follow-up to #24317, which did the hard work but was merged in such a way that it exposes the setting while still allowing indices to have multiple types by default in order to give time to people who test against master to add this setting to their index settings. --- .../java/org/elasticsearch/index/mapper/MapperService.java | 6 ++---- .../org/elasticsearch/index/mapper/MapperServiceTests.java | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/index/mapper/MapperService.java b/core/src/main/java/org/elasticsearch/index/mapper/MapperService.java index cca285198ef..bd65d123f81 100755 --- a/core/src/main/java/org/elasticsearch/index/mapper/MapperService.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/MapperService.java @@ -99,12 +99,10 @@ public class MapperService extends AbstractIndexComponent implements Closeable { public static final Setting INDEX_MAPPING_SINGLE_TYPE_SETTING; static { Function defValue = settings -> { - // TODO: uncomment this - /*boolean singleType = true; + boolean singleType = true; if (settings.getAsVersion(IndexMetaData.SETTING_VERSION_CREATED, null) != null) { singleType = Version.indexCreated(settings).onOrAfter(Version.V_6_0_0_alpha1_UNRELEASED); - }*/ - boolean singleType = false; + } return Boolean.valueOf(singleType).toString(); }; INDEX_MAPPING_SINGLE_TYPE_SETTING = Setting.boolSetting("index.mapping.single_type", defValue, Property.IndexScope, Property.Final); diff --git a/core/src/test/java/org/elasticsearch/index/mapper/MapperServiceTests.java b/core/src/test/java/org/elasticsearch/index/mapper/MapperServiceTests.java index 4d467d641d9..cc853b5b9e5 100644 --- a/core/src/test/java/org/elasticsearch/index/mapper/MapperServiceTests.java +++ b/core/src/test/java/org/elasticsearch/index/mapper/MapperServiceTests.java @@ -310,7 +310,6 @@ public class MapperServiceTests extends ESSingleNodeTestCase { containsString("cannot have nested fields when index sort is activated")); } - @AwaitsFix(bugUrl="https://github.com/elastic/elasticsearch/pull/24317#issuecomment-297624290") public void testForbidMultipleTypes() throws IOException { String mapping = XContentFactory.jsonBuilder().startObject().startObject("type").endObject().endObject().string(); MapperService mapperService = createIndex("test").mapperService(); From 9a3ab3e8000be059ccf4edeee53b62ddb5913fc6 Mon Sep 17 00:00:00 2001 From: Dimitrios Liappis Date: Thu, 4 May 2017 12:04:53 +0300 Subject: [PATCH 07/44] Tests: Switch to Fedora-25 for packaging tests Switch the Fedora Vagrant box for packaging tests to Fedora-25 as Fedora-24 will become EOL one month after Fedora-26 is out. Relates #24466 --- Vagrantfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Vagrantfile b/Vagrantfile index a818d666655..00cc9bd638f 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -56,8 +56,8 @@ Vagrant.configure(2) do |config| config.vm.box = "elastic/oraclelinux-7-x86_64" rpm_common config end - config.vm.define "fedora-24" do |config| - config.vm.box = "elastic/fedora-24-x86_64" + config.vm.define "fedora-25" do |config| + config.vm.box = "elastic/fedora-25-x86_64" dnf_common config end config.vm.define "opensuse-13" do |config| From 14e57bf9f8902e6d3ec85e115c11bfc2ffdbb04a Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Thu, 4 May 2017 11:44:54 +0200 Subject: [PATCH 08/44] Add cross cluster support to `_field_caps` (#24463) To support kibana this commit adds an internal optimization to support the cross cluster syntax for indices on the `_field_caps` API. Closes #24334 --- .../FieldCapabilitiesIndexResponse.java | 7 +- .../fieldcaps/FieldCapabilitiesRequest.java | 29 +++- .../fieldcaps/FieldCapabilitiesResponse.java | 29 ++++ .../TransportFieldCapabilitiesAction.java | 144 ++++++++++++------ ...TransportFieldCapabilitiesIndexAction.java | 45 ++---- .../action/search/TransportSearchAction.java | 30 +--- .../transport/RemoteClusterAware.java | 4 + .../transport/RemoteClusterConnection.java | 19 ++- .../transport/RemoteClusterService.java | 39 ++++- .../RemoteClusterConnectionTests.java | 5 +- .../test/multi_cluster/30_field_caps.yaml | 66 ++++++++ .../test/remote_cluster/10_basic.yaml | 48 ++++++ .../test/field_caps/10_basic.yaml | 6 +- 13 files changed, 347 insertions(+), 124 deletions(-) create mode 100644 qa/multi-cluster-search/src/test/resources/rest-api-spec/test/multi_cluster/30_field_caps.yaml diff --git a/core/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesIndexResponse.java b/core/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesIndexResponse.java index de520ee6274..1e468624516 100644 --- a/core/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesIndexResponse.java +++ b/core/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesIndexResponse.java @@ -22,6 +22,7 @@ package org.elasticsearch.action.fieldcaps; import org.elasticsearch.action.ActionResponse; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Writeable; import java.io.IOException; import java.util.Map; @@ -29,7 +30,7 @@ import java.util.Map; /** * Response for {@link FieldCapabilitiesIndexRequest} requests. */ -public class FieldCapabilitiesIndexResponse extends ActionResponse { +public class FieldCapabilitiesIndexResponse extends ActionResponse implements Writeable { private String indexName; private Map responseMap; @@ -41,6 +42,10 @@ public class FieldCapabilitiesIndexResponse extends ActionResponse { FieldCapabilitiesIndexResponse() { } + FieldCapabilitiesIndexResponse(StreamInput input) throws IOException { + this.readFrom(input); + } + /** * Get the index name diff --git a/core/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesRequest.java b/core/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesRequest.java index 7eab9112162..ce1ba282899 100644 --- a/core/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesRequest.java +++ b/core/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesRequest.java @@ -19,6 +19,7 @@ package org.elasticsearch.action.fieldcaps; +import org.elasticsearch.Version; import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionRequestValidationException; import org.elasticsearch.action.IndicesRequest; @@ -38,13 +39,14 @@ import java.util.Set; import static org.elasticsearch.common.xcontent.ObjectParser.fromList; -public class FieldCapabilitiesRequest extends ActionRequest - implements IndicesRequest.Replaceable { +public final class FieldCapabilitiesRequest extends ActionRequest implements IndicesRequest.Replaceable { public static final ParseField FIELDS_FIELD = new ParseField("fields"); public static final String NAME = "field_caps_request"; private String[] indices = Strings.EMPTY_ARRAY; private IndicesOptions indicesOptions = IndicesOptions.strictExpandOpen(); private String[] fields = Strings.EMPTY_ARRAY; + // pkg private API mainly for cross cluster search to signal that we do multiple reductions ie. the results should not be merged + private boolean mergeResults = true; private static ObjectParser PARSER = new ObjectParser<>(NAME, FieldCapabilitiesRequest::new); @@ -56,16 +58,39 @@ public class FieldCapabilitiesRequest extends ActionRequest public FieldCapabilitiesRequest() {} + /** + * Returns true iff the results should be merged. + */ + boolean isMergeResults() { + return mergeResults; + } + + /** + * if set to true the response will contain only a merged view of the per index field capabilities. Otherwise only + * unmerged per index field capabilities are returned. + */ + void setMergeResults(boolean mergeResults) { + this.mergeResults = mergeResults; + } + @Override public void readFrom(StreamInput in) throws IOException { super.readFrom(in); fields = in.readStringArray(); + if (in.getVersion().onOrAfter(Version.V_5_5_0_UNRELEASED)) { + mergeResults = in.readBoolean(); + } else { + mergeResults = true; + } } @Override public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); out.writeStringArray(fields); + if (out.getVersion().onOrAfter(Version.V_5_5_0_UNRELEASED)) { + out.writeBoolean(mergeResults); + } } public static FieldCapabilitiesRequest parseFields(XContentParser parser) throws IOException { diff --git a/core/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesResponse.java b/core/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesResponse.java index 9ff2cf3850b..3e2dc46a01d 100644 --- a/core/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesResponse.java +++ b/core/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesResponse.java @@ -19,6 +19,7 @@ package org.elasticsearch.action.fieldcaps; +import org.elasticsearch.Version; import org.elasticsearch.action.ActionResponse; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; @@ -27,6 +28,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import java.io.IOException; import java.util.Collections; +import java.util.List; import java.util.Map; /** @@ -34,9 +36,20 @@ import java.util.Map; */ public class FieldCapabilitiesResponse extends ActionResponse implements ToXContent { private Map> responseMap; + private List indexResponses; FieldCapabilitiesResponse(Map> responseMap) { + this(responseMap, Collections.emptyList()); + } + + FieldCapabilitiesResponse(List indexResponses) { + this(Collections.emptyMap(), indexResponses); + } + + private FieldCapabilitiesResponse(Map> responseMap, + List indexResponses) { this.responseMap = responseMap; + this.indexResponses = indexResponses; } /** @@ -53,6 +66,13 @@ public class FieldCapabilitiesResponse extends ActionResponse implements ToXCont return responseMap; } + + /** + * Returns the actual per-index field caps responses + */ + List getIndexResponses() { + return indexResponses; + } /** * * Get the field capabilities per type for the provided {@code field}. @@ -66,6 +86,11 @@ public class FieldCapabilitiesResponse extends ActionResponse implements ToXCont super.readFrom(in); this.responseMap = in.readMap(StreamInput::readString, FieldCapabilitiesResponse::readField); + if (in.getVersion().onOrAfter(Version.V_6_0_0_alpha1_UNRELEASED)) { + indexResponses = in.readList(FieldCapabilitiesIndexResponse::new); + } else { + indexResponses = Collections.emptyList(); + } } private static Map readField(StreamInput in) throws IOException { @@ -76,6 +101,10 @@ public class FieldCapabilitiesResponse extends ActionResponse implements ToXCont public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); out.writeMap(responseMap, StreamOutput::writeString, FieldCapabilitiesResponse::writeField); + if (out.getVersion().onOrAfter(Version.V_6_0_0_alpha1_UNRELEASED)) { + out.writeList(indexResponses); + } + } private static void writeField(StreamOutput out, diff --git a/core/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java b/core/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java index a7f268eaf5d..6491b8ce4c7 100644 --- a/core/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java +++ b/core/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java @@ -20,6 +20,7 @@ package org.elasticsearch.action.fieldcaps; import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.OriginalIndices; import org.elasticsearch.action.support.ActionFilters; import org.elasticsearch.action.support.HandledTransportAction; import org.elasticsearch.cluster.ClusterState; @@ -27,18 +28,27 @@ import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.CountDown; import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.RemoteClusterAware; +import org.elasticsearch.transport.RemoteClusterService; +import org.elasticsearch.transport.Transport; +import org.elasticsearch.transport.TransportException; +import org.elasticsearch.transport.TransportRequestOptions; +import org.elasticsearch.transport.TransportResponseHandler; import org.elasticsearch.transport.TransportService; +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.AtomicInteger; -import java.util.concurrent.atomic.AtomicReferenceArray; -public class TransportFieldCapabilitiesAction - extends HandledTransportAction { +public class TransportFieldCapabilitiesAction extends HandledTransportAction { private final ClusterService clusterService; private final TransportFieldCapabilitiesIndexAction shardAction; + private final RemoteClusterService remoteClusterService; + private final TransportService transportService; @Inject public TransportFieldCapabilitiesAction(Settings settings, TransportService transportService, @@ -50,71 +60,97 @@ public class TransportFieldCapabilitiesAction super(settings, FieldCapabilitiesAction.NAME, threadPool, transportService, actionFilters, indexNameExpressionResolver, FieldCapabilitiesRequest::new); this.clusterService = clusterService; + this.remoteClusterService = transportService.getRemoteClusterService(); + this.transportService = transportService; this.shardAction = shardAction; } @Override protected void doExecute(FieldCapabilitiesRequest request, final ActionListener listener) { - ClusterState clusterState = clusterService.state(); - String[] concreteIndices = - indexNameExpressionResolver.concreteIndexNames(clusterState, request); - final AtomicInteger indexCounter = new AtomicInteger(); - final AtomicInteger completionCounter = new AtomicInteger(concreteIndices.length); - final AtomicReferenceArray indexResponses = - new AtomicReferenceArray<>(concreteIndices.length); - if (concreteIndices.length == 0) { + final ClusterState clusterState = clusterService.state(); + final Map remoteClusterIndices = remoteClusterService.groupIndices(request.indicesOptions(), + request.indices(), idx -> indexNameExpressionResolver.hasIndexOrAlias(idx, clusterState)); + final OriginalIndices localIndices = remoteClusterIndices.remove(RemoteClusterAware.LOCAL_CLUSTER_GROUP_KEY); + final String[] concreteIndices = indexNameExpressionResolver.concreteIndexNames(clusterState, localIndices); + final int totalNumRequest = concreteIndices.length + remoteClusterIndices.size(); + final CountDown completionCounter = new CountDown(totalNumRequest); + final List indexResponses = Collections.synchronizedList(new ArrayList<>()); + final Runnable onResponse = () -> { + if (completionCounter.countDown()) { + if (request.isMergeResults()) { + listener.onResponse(merge(indexResponses)); + } else { + listener.onResponse(new FieldCapabilitiesResponse(indexResponses)); + } + } + }; + if (totalNumRequest == 0) { listener.onResponse(new FieldCapabilitiesResponse()); } else { + ActionListener innerListener = new ActionListener() { + @Override + public void onResponse(FieldCapabilitiesIndexResponse result) { + indexResponses.add(result); + onResponse.run(); + } + + @Override + public void onFailure(Exception e) { + // TODO we should somehow inform the user that we failed + onResponse.run(); + } + }; for (String index : concreteIndices) { - FieldCapabilitiesIndexRequest indexRequest = - new FieldCapabilitiesIndexRequest(request.fields(), index); - shardAction.execute(indexRequest, - new ActionListener () { + shardAction.execute(new FieldCapabilitiesIndexRequest(request.fields(), index), innerListener); + } + + // this is the cross cluster part of this API - we force the other cluster to not merge the results but instead + // send us back all individual index results. + for (Map.Entry remoteIndices : remoteClusterIndices.entrySet()) { + String clusterAlias = remoteIndices.getKey(); + OriginalIndices originalIndices = remoteIndices.getValue(); + Transport.Connection connection = remoteClusterService.getConnection(remoteIndices.getKey()); + FieldCapabilitiesRequest remoteRequest = new FieldCapabilitiesRequest(); + remoteRequest.setMergeResults(false); // we need to merge on this node + remoteRequest.indicesOptions(originalIndices.indicesOptions()); + remoteRequest.indices(originalIndices.indices()); + remoteRequest.fields(request.fields()); + transportService.sendRequest(connection, FieldCapabilitiesAction.NAME, remoteRequest, TransportRequestOptions.EMPTY, + new TransportResponseHandler() { @Override - public void onResponse(FieldCapabilitiesIndexResponse result) { - indexResponses.set(indexCounter.getAndIncrement(), result); - if (completionCounter.decrementAndGet() == 0) { - listener.onResponse(merge(indexResponses)); - } + public FieldCapabilitiesResponse newInstance() { + return new FieldCapabilitiesResponse(); } @Override - public void onFailure(Exception e) { - indexResponses.set(indexCounter.getAndIncrement(), e); - if (completionCounter.decrementAndGet() == 0) { - listener.onResponse(merge(indexResponses)); + public void handleResponse(FieldCapabilitiesResponse response) { + for (FieldCapabilitiesIndexResponse res : response.getIndexResponses()) { + indexResponses.add(new FieldCapabilitiesIndexResponse(RemoteClusterAware.buildRemoteIndexName(clusterAlias, + res.getIndexName()), res.get())); } + onResponse.run(); + } + + @Override + public void handleException(TransportException exp) { + onResponse.run(); + } + + @Override + public String executor() { + return ThreadPool.Names.SAME; } }); } + } } - private FieldCapabilitiesResponse merge(AtomicReferenceArray indexResponses) { + private FieldCapabilitiesResponse merge(List indexResponses) { Map> responseMapBuilder = new HashMap<> (); - for (int i = 0; i < indexResponses.length(); i++) { - Object element = indexResponses.get(i); - if (element instanceof FieldCapabilitiesIndexResponse == false) { - assert element instanceof Exception; - continue; - } - FieldCapabilitiesIndexResponse response = (FieldCapabilitiesIndexResponse) element; - for (String field : response.get().keySet()) { - Map typeMap = responseMapBuilder.get(field); - if (typeMap == null) { - typeMap = new HashMap<> (); - responseMapBuilder.put(field, typeMap); - } - FieldCapabilities fieldCap = response.getField(field); - FieldCapabilities.Builder builder = typeMap.get(fieldCap.getType()); - if (builder == null) { - builder = new FieldCapabilities.Builder(field, fieldCap.getType()); - typeMap.put(fieldCap.getType(), builder); - } - builder.add(response.getIndexName(), - fieldCap.isSearchable(), fieldCap.isAggregatable()); - } + for (FieldCapabilitiesIndexResponse response : indexResponses) { + innerMerge(responseMapBuilder, response.getIndexName(), response.get()); } Map> responseMap = new HashMap<>(); @@ -131,4 +167,16 @@ public class TransportFieldCapabilitiesAction return new FieldCapabilitiesResponse(responseMap); } + + private void innerMerge(Map> responseMapBuilder, String indexName, + Map map) { + for (Map.Entry entry : map.entrySet()) { + final String field = entry.getKey(); + final FieldCapabilities fieldCap = entry.getValue(); + Map typeMap = responseMapBuilder.computeIfAbsent(field, f -> new HashMap<>()); + FieldCapabilities.Builder builder = typeMap.computeIfAbsent(fieldCap.getType(), key -> new FieldCapabilities.Builder(field, + key)); + builder.add(indexName, fieldCap.isSearchable(), fieldCap.isAggregatable()); + } + } } diff --git a/core/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesIndexAction.java b/core/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesIndexAction.java index 5bab7276860..e7db685b4a8 100644 --- a/core/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesIndexAction.java +++ b/core/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesIndexAction.java @@ -41,34 +41,19 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -public class TransportFieldCapabilitiesIndexAction - extends TransportSingleShardAction { private static final String ACTION_NAME = FieldCapabilitiesAction.NAME + "[index]"; - protected final ClusterService clusterService; private final IndicesService indicesService; @Inject - public TransportFieldCapabilitiesIndexAction(Settings settings, - ClusterService clusterService, - TransportService transportService, - IndicesService indicesService, - ThreadPool threadPool, - ActionFilters actionFilters, - IndexNameExpressionResolver - indexNameExpressionResolver) { - super(settings, - ACTION_NAME, - threadPool, - clusterService, - transportService, - actionFilters, - indexNameExpressionResolver, - FieldCapabilitiesIndexRequest::new, - ThreadPool.Names.MANAGEMENT); - this.clusterService = clusterService; + public TransportFieldCapabilitiesIndexAction(Settings settings, ClusterService clusterService, TransportService transportService, + IndicesService indicesService, ThreadPool threadPool, ActionFilters actionFilters, + IndexNameExpressionResolver indexNameExpressionResolver) { + super(settings, ACTION_NAME, threadPool, clusterService, transportService, actionFilters, indexNameExpressionResolver, + FieldCapabilitiesIndexRequest::new, ThreadPool.Names.MANAGEMENT); this.indicesService = indicesService; } @@ -86,11 +71,8 @@ public class TransportFieldCapabilitiesIndexAction } @Override - protected FieldCapabilitiesIndexResponse shardOperation( - final FieldCapabilitiesIndexRequest request, - ShardId shardId) { - MapperService mapperService = - indicesService.indexServiceSafe(shardId.getIndex()).mapperService(); + protected FieldCapabilitiesIndexResponse shardOperation(final FieldCapabilitiesIndexRequest request, ShardId shardId) { + MapperService mapperService = indicesService.indexServiceSafe(shardId.getIndex()).mapperService(); Set fieldNames = new HashSet<>(); for (String field : request.fields()) { fieldNames.addAll(mapperService.simpleMatchToIndexNames(field)); @@ -98,10 +80,7 @@ public class TransportFieldCapabilitiesIndexAction Map responseMap = new HashMap<>(); for (String field : fieldNames) { MappedFieldType ft = mapperService.fullName(field); - FieldCapabilities fieldCap = new FieldCapabilities(field, - ft.typeName(), - ft.isSearchable(), - ft.isAggregatable()); + FieldCapabilities fieldCap = new FieldCapabilities(field, ft.typeName(), ft.isSearchable(), ft.isAggregatable()); responseMap.put(field, fieldCap); } return new FieldCapabilitiesIndexResponse(shardId.getIndexName(), responseMap); @@ -113,9 +92,7 @@ public class TransportFieldCapabilitiesIndexAction } @Override - protected ClusterBlockException checkRequestBlock(ClusterState state, - InternalRequest request) { - return state.blocks().indexBlockedException(ClusterBlockLevel.METADATA_READ, - request.concreteIndex()); + protected ClusterBlockException checkRequestBlock(ClusterState state, InternalRequest request) { + return state.blocks().indexBlockedException(ClusterBlockLevel.METADATA_READ, request.concreteIndex()); } } diff --git a/core/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java b/core/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java index 91a23bf6a6f..501504631bc 100644 --- a/core/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java +++ b/core/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java @@ -178,35 +178,17 @@ public class TransportSearchAction extends HandledTransportAction remoteClusterIndices; - final ClusterState clusterState = clusterService.state(); - if (remoteClusterService.isCrossClusterSearchEnabled()) { - final Map> groupedIndices = remoteClusterService.groupClusterIndices(searchRequest.indices(), - // empty string is not allowed - idx -> indexNameExpressionResolver.hasIndexOrAlias(idx, clusterState)); - List remove = groupedIndices.remove(RemoteClusterAware.LOCAL_CLUSTER_GROUP_KEY); - String[] indices = remove == null ? Strings.EMPTY_ARRAY : remove.toArray(new String[remove.size()]); - localIndices = new OriginalIndices(indices, searchRequest.indicesOptions()); - Map originalIndicesMap = new HashMap<>(); - for (Map.Entry> entry : groupedIndices.entrySet()) { - String clusterAlias = entry.getKey(); - List originalIndices = entry.getValue(); - originalIndicesMap.put(clusterAlias, - new OriginalIndices(originalIndices.toArray(new String[originalIndices.size()]), searchRequest.indicesOptions())); - } - remoteClusterIndices = Collections.unmodifiableMap(originalIndicesMap); - } else { - remoteClusterIndices = Collections.emptyMap(); - localIndices = new OriginalIndices(searchRequest); - } + final ClusterState clusterState = clusterService.state(); + final Map remoteClusterIndices = remoteClusterService.groupIndices(searchRequest.indicesOptions(), + searchRequest.indices(), idx -> indexNameExpressionResolver.hasIndexOrAlias(idx, clusterState)); + OriginalIndices localIndices = remoteClusterIndices.remove(RemoteClusterAware.LOCAL_CLUSTER_GROUP_KEY); if (remoteClusterIndices.isEmpty()) { executeSearch((SearchTask)task, timeProvider, searchRequest, localIndices, Collections.emptyList(), (clusterName, nodeId) -> null, clusterState, Collections.emptyMap(), listener); } else { - remoteClusterService.collectSearchShards(searchRequest, remoteClusterIndices, - ActionListener.wrap((searchShardsResponses) -> { + remoteClusterService.collectSearchShards(searchRequest.indicesOptions(), searchRequest.preference(), searchRequest.routing(), + remoteClusterIndices, ActionListener.wrap((searchShardsResponses) -> { List remoteShardIterators = new ArrayList<>(); Map remoteAliasFilters = new HashMap<>(); BiFunction clusterNodeLookup = processRemoteShards(searchShardsResponses, diff --git a/core/src/main/java/org/elasticsearch/transport/RemoteClusterAware.java b/core/src/main/java/org/elasticsearch/transport/RemoteClusterAware.java index 42ab7315234..b07c7fe3605 100644 --- a/core/src/main/java/org/elasticsearch/transport/RemoteClusterAware.java +++ b/core/src/main/java/org/elasticsearch/transport/RemoteClusterAware.java @@ -159,4 +159,8 @@ public abstract class RemoteClusterAware extends AbstractComponent { throw new IllegalArgumentException("port must be a number", e); } } + + public static final String buildRemoteIndexName(String clusterAlias, String indexName) { + return clusterAlias + REMOTE_CLUSTER_INDEX_SEPARATOR + indexName; + } } diff --git a/core/src/main/java/org/elasticsearch/transport/RemoteClusterConnection.java b/core/src/main/java/org/elasticsearch/transport/RemoteClusterConnection.java index 5c7e072f650..e4f0d0d4af7 100644 --- a/core/src/main/java/org/elasticsearch/transport/RemoteClusterConnection.java +++ b/core/src/main/java/org/elasticsearch/transport/RemoteClusterConnection.java @@ -152,7 +152,7 @@ final class RemoteClusterConnection extends AbstractComponent implements Transpo /** * Fetches all shards for the search request from this remote connection. This is used to later run the search on the remote end. */ - public void fetchSearchShards(SearchRequest searchRequest, final String[] indices, + public void fetchSearchShards(ClusterSearchShardsRequest searchRequest, ActionListener listener) { if (connectedNodes.isEmpty()) { // just in case if we are not connected for some reason we try to connect and if we fail we have to notify the listener @@ -160,18 +160,15 @@ final class RemoteClusterConnection extends AbstractComponent implements Transpo // we can't proceed with a search on a cluster level. // in the future we might want to just skip the remote nodes in such a case but that can already be implemented on the caller // end since they provide the listener. - connectHandler.connect(ActionListener.wrap((x) -> fetchShardsInternal(searchRequest, indices, listener), listener::onFailure)); + connectHandler.connect(ActionListener.wrap((x) -> fetchShardsInternal(searchRequest, listener), listener::onFailure)); } else { - fetchShardsInternal(searchRequest, indices, listener); + fetchShardsInternal(searchRequest, listener); } } - private void fetchShardsInternal(SearchRequest searchRequest, String[] indices, + private void fetchShardsInternal(ClusterSearchShardsRequest searchShardsRequest, final ActionListener listener) { final DiscoveryNode node = nodeSupplier.get(); - ClusterSearchShardsRequest searchShardsRequest = new ClusterSearchShardsRequest(indices) - .indicesOptions(searchRequest.indicesOptions()).local(true).preference(searchRequest.preference()) - .routing(searchRequest.routing()); transportService.sendRequest(node, ClusterSearchShardsAction.NAME, searchShardsRequest, new TransportResponseHandler() { @@ -224,7 +221,13 @@ final class RemoteClusterConnection extends AbstractComponent implements Transpo }; } - @Override + Transport.Connection getConnection() { + DiscoveryNode discoveryNode = nodeSupplier.get(); + return transportService.getConnection(discoveryNode); + } + + + @Override public void close() throws IOException { connectHandler.close(); } diff --git a/core/src/main/java/org/elasticsearch/transport/RemoteClusterService.java b/core/src/main/java/org/elasticsearch/transport/RemoteClusterService.java index 92dce9d53f1..91a5cebbcd2 100644 --- a/core/src/main/java/org/elasticsearch/transport/RemoteClusterService.java +++ b/core/src/main/java/org/elasticsearch/transport/RemoteClusterService.java @@ -24,10 +24,12 @@ import org.elasticsearch.Version; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.OriginalIndices; import org.elasticsearch.action.admin.cluster.shards.ClusterSearchShardsGroup; +import org.elasticsearch.action.admin.cluster.shards.ClusterSearchShardsRequest; import org.elasticsearch.action.admin.cluster.shards.ClusterSearchShardsResponse; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchShardIterator; import org.elasticsearch.action.support.GroupedActionListener; +import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.common.Booleans; @@ -176,6 +178,25 @@ public final class RemoteClusterService extends RemoteClusterAware implements Cl return remoteClusters.get(remoteCluster).isNodeConnected(node); } + public Map groupIndices(IndicesOptions indicesOptions, String[] indices, Predicate indexExists) { + Map originalIndicesMap = new HashMap<>(); + if (isCrossClusterSearchEnabled()) { + final Map> groupedIndices = groupClusterIndices(indices, indexExists); + for (Map.Entry> entry : groupedIndices.entrySet()) { + String clusterAlias = entry.getKey(); + List originalIndices = entry.getValue(); + originalIndicesMap.put(clusterAlias, + new OriginalIndices(originalIndices.toArray(new String[originalIndices.size()]), indicesOptions)); + } + if (originalIndicesMap.containsKey(LOCAL_CLUSTER_GROUP_KEY) == false) { + originalIndicesMap.put(LOCAL_CLUSTER_GROUP_KEY, new OriginalIndices(Strings.EMPTY_ARRAY, indicesOptions)); + } + } else { + originalIndicesMap.put(LOCAL_CLUSTER_GROUP_KEY, new OriginalIndices(indices, indicesOptions)); + } + return originalIndicesMap; + } + /** * Returns true iff the given cluster is configured as a remote cluster. Otherwise false */ @@ -183,8 +204,9 @@ public final class RemoteClusterService extends RemoteClusterAware implements Cl return remoteClusters.containsKey(clusterName); } - public void collectSearchShards(SearchRequest searchRequest, Map remoteIndicesByCluster, - ActionListener> listener) { + public void collectSearchShards(IndicesOptions indicesOptions, String preference, String routing, + Map remoteIndicesByCluster, + ActionListener> listener) { final CountDown responsesCountDown = new CountDown(remoteIndicesByCluster.size()); final Map searchShardsResponses = new ConcurrentHashMap<>(); final AtomicReference transportException = new AtomicReference<>(); @@ -195,7 +217,10 @@ public final class RemoteClusterService extends RemoteClusterAware implements Cl throw new IllegalArgumentException("no such remote cluster: " + clusterName); } final String[] indices = entry.getValue().indices(); - remoteClusterConnection.fetchSearchShards(searchRequest, indices, + ClusterSearchShardsRequest searchShardsRequest = new ClusterSearchShardsRequest(indices) + .indicesOptions(indicesOptions).local(true).preference(preference) + .routing(routing); + remoteClusterConnection.fetchSearchShards(searchShardsRequest, new ActionListener() { @Override public void onResponse(ClusterSearchShardsResponse clusterSearchShardsResponse) { @@ -240,6 +265,14 @@ public final class RemoteClusterService extends RemoteClusterAware implements Cl return connection.getConnection(node); } + public Transport.Connection getConnection(String cluster) { + RemoteClusterConnection connection = remoteClusters.get(cluster); + if (connection == null) { + throw new IllegalArgumentException("no such remote cluster: " + cluster); + } + return connection.getConnection(); + } + @Override protected Set getRemoteClusterNames() { return this.remoteClusters.keySet(); diff --git a/core/src/test/java/org/elasticsearch/transport/RemoteClusterConnectionTests.java b/core/src/test/java/org/elasticsearch/transport/RemoteClusterConnectionTests.java index 1ce73aee905..f7ab29c95c5 100644 --- a/core/src/test/java/org/elasticsearch/transport/RemoteClusterConnectionTests.java +++ b/core/src/test/java/org/elasticsearch/transport/RemoteClusterConnectionTests.java @@ -385,7 +385,10 @@ public class RemoteClusterConnectionTests extends ESTestCase { failReference.set(x); responseLatch.countDown(); }); - connection.fetchSearchShards(request, new String[]{"test-index"}, shardsListener); + ClusterSearchShardsRequest searchShardsRequest = new ClusterSearchShardsRequest(new String[]{"test-index"}) + .indicesOptions(request.indicesOptions()).local(true).preference(request.preference()) + .routing(request.routing()); + connection.fetchSearchShards(searchShardsRequest, shardsListener); responseLatch.await(); assertNull(failReference.get()); assertNotNull(reference.get()); diff --git a/qa/multi-cluster-search/src/test/resources/rest-api-spec/test/multi_cluster/30_field_caps.yaml b/qa/multi-cluster-search/src/test/resources/rest-api-spec/test/multi_cluster/30_field_caps.yaml new file mode 100644 index 00000000000..d3922ca46cb --- /dev/null +++ b/qa/multi-cluster-search/src/test/resources/rest-api-spec/test/multi_cluster/30_field_caps.yaml @@ -0,0 +1,66 @@ +--- +"Get simple field caps from remote cluster": + - skip: + version: " - 5.99.99" + reason: this uses a new API that has been added in 6.0.0 + + - do: + indices.create: + index: field_caps_index_2 + body: + mappings: + t: + properties: + text: + type: text + keyword: + type: keyword + number: + type: double + geo: + type: geo_point + object: + type: object + properties: + nested1 : + type : text + index: true + nested2: + type: float + doc_values: true + + - do: + field_caps: + index: 'field_caps_index_2,my_remote_cluster:field_*' + fields: [text, keyword, number, geo] + + - match: {fields.text.text.searchable: true} + - match: {fields.text.text.aggregatable: false} + - is_false: fields.text.text.indices + - is_false: fields.text.text.non_searchable_indices + - is_false: fields.text.text.non_aggregatable_indices + - match: {fields.keyword.keyword.searchable: true} + - match: {fields.keyword.keyword.aggregatable: true} + - is_false: fields.text.keyword.indices + - is_false: fields.text.keyword.non_searchable_indices + - is_false: fields.text.keyword.non_aggregatable_indices + - match: {fields.number.double.searchable: true} + - match: {fields.number.double.aggregatable: true} + - match: {fields.number.double.indices: ["field_caps_index_2", "my_remote_cluster:field_caps_index_1"]} + - is_false: fields.number.double.non_searchable_indices + - is_false: fields.number.double.non_aggregatable_indices + - match: {fields.number.long.searchable: true} + - match: {fields.number.long.aggregatable: true} + - match: {fields.number.long.indices: ["my_remote_cluster:field_caps_index_3"]} + - is_false: fields.number.long.non_searchable_indices + - is_false: fields.number.long.non_aggregatable_indices + - match: {fields.geo.geo_point.searchable: true} + - match: {fields.geo.geo_point.aggregatable: true} + - match: {fields.geo.geo_point.indices: ["field_caps_index_2", "my_remote_cluster:field_caps_index_1"]} + - is_false: fields.geo.geo_point.non_searchable_indices + - is_false: fields.geo.geo_point.non_aggregatable_indices + - match: {fields.geo.keyword.searchable: true} + - match: {fields.geo.keyword.aggregatable: true} + - match: {fields.geo.keyword.indices: ["my_remote_cluster:field_caps_index_3"]} + - is_false: fields.geo.keyword.non_searchable_indices + - is_false: fields.geo.keyword.on_aggregatable_indices diff --git a/qa/multi-cluster-search/src/test/resources/rest-api-spec/test/remote_cluster/10_basic.yaml b/qa/multi-cluster-search/src/test/resources/rest-api-spec/test/remote_cluster/10_basic.yaml index 5c68a591142..c3162383843 100644 --- a/qa/multi-cluster-search/src/test/resources/rest-api-spec/test/remote_cluster/10_basic.yaml +++ b/qa/multi-cluster-search/src/test/resources/rest-api-spec/test/remote_cluster/10_basic.yaml @@ -1,6 +1,54 @@ --- "Index data and search on the old cluster": + - do: + indices.create: + index: field_caps_index_1 + body: + mappings: + t: + properties: + text: + type: text + keyword: + type: keyword + number: + type: double + geo: + type: geo_point + object: + type: object + properties: + nested1 : + type : text + index: false + nested2: + type: float + doc_values: false + - do: + indices.create: + index: field_caps_index_3 + body: + mappings: + t: + properties: + text: + type: text + keyword: + type: keyword + number: + type: long + geo: + type: keyword + object: + type: object + properties: + nested1 : + type : long + index: false + nested2: + type: keyword + doc_values: false - do: indices.create: index: test_index diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/field_caps/10_basic.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/field_caps/10_basic.yaml index cef72b6e3fe..be2fd820a12 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/field_caps/10_basic.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/field_caps/10_basic.yaml @@ -76,7 +76,7 @@ setup: --- "Get simple field caps": - skip: - version: " - 5.3.99" + version: " - 5.99.99" # temporarily disabled until bwc code is backported and propagated reason: this uses a new API that has been added in 5.4.0 - do: @@ -117,7 +117,7 @@ setup: --- "Get nested field caps": - skip: - version: " - 5.3.99" + version: " - 5.99.99" # temporarily disabled until bwc code is backported and propagated reason: this uses a new API that has been added in 5.4.0 - do: @@ -148,7 +148,7 @@ setup: --- "Get prefix field caps": - skip: - version: " - 5.3.99" + version: " - 5.99.99" # temporarily disabled until bwc code is backported and propagated reason: this uses a new API that has been added in 5.4.0 - do: From c4eea8571365446b75fb3ac3b5d3fb3454501c3d Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Thu, 4 May 2017 11:51:47 +0200 Subject: [PATCH 09/44] Use V_5_5_UNRELEASED constant consitently on both request and response --- .../action/fieldcaps/FieldCapabilitiesResponse.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesResponse.java b/core/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesResponse.java index 3e2dc46a01d..00c424e1fe7 100644 --- a/core/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesResponse.java +++ b/core/src/main/java/org/elasticsearch/action/fieldcaps/FieldCapabilitiesResponse.java @@ -86,7 +86,7 @@ public class FieldCapabilitiesResponse extends ActionResponse implements ToXCont super.readFrom(in); this.responseMap = in.readMap(StreamInput::readString, FieldCapabilitiesResponse::readField); - if (in.getVersion().onOrAfter(Version.V_6_0_0_alpha1_UNRELEASED)) { + if (in.getVersion().onOrAfter(Version.V_5_5_0_UNRELEASED)) { indexResponses = in.readList(FieldCapabilitiesIndexResponse::new); } else { indexResponses = Collections.emptyList(); @@ -101,7 +101,7 @@ public class FieldCapabilitiesResponse extends ActionResponse implements ToXCont public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); out.writeMap(responseMap, StreamOutput::writeString, FieldCapabilitiesResponse::writeField); - if (out.getVersion().onOrAfter(Version.V_6_0_0_alpha1_UNRELEASED)) { + if (out.getVersion().onOrAfter(Version.V_5_5_0_UNRELEASED)) { out.writeList(indexResponses); } From 01872f364904cc3ec953745db6792ce0d5df1a04 Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Thu, 4 May 2017 13:29:03 +0200 Subject: [PATCH 10/44] Add version for 5.4.1 and bwc indices for 5.4.0 --- .../main/java/org/elasticsearch/Version.java | 4 ++++ .../test/resources/indices/bwc/index-5.4.0.zip | Bin 0 -> 385816 bytes .../test/resources/indices/bwc/repo-5.4.0.zip | Bin 0 -> 189447 bytes 3 files changed, 4 insertions(+) create mode 100644 core/src/test/resources/indices/bwc/index-5.4.0.zip create mode 100644 core/src/test/resources/indices/bwc/repo-5.4.0.zip diff --git a/core/src/main/java/org/elasticsearch/Version.java b/core/src/main/java/org/elasticsearch/Version.java index a7f01ef5528..21b0af5f882 100644 --- a/core/src/main/java/org/elasticsearch/Version.java +++ b/core/src/main/java/org/elasticsearch/Version.java @@ -80,6 +80,8 @@ public class Version implements Comparable { public static final Version V_5_3_2_UNRELEASED = new Version(V_5_3_2_ID_UNRELEASED, org.apache.lucene.util.Version.LUCENE_6_4_2); public static final int V_5_4_0_ID_UNRELEASED = 5040099; public static final Version V_5_4_0_UNRELEASED = new Version(V_5_4_0_ID_UNRELEASED, org.apache.lucene.util.Version.LUCENE_6_5_0); + public static final int V_5_4_1_ID_UNRELEASED = 5040199; + public static final Version V_5_4_1_UNRELEASED = new Version(V_5_4_1_ID_UNRELEASED, org.apache.lucene.util.Version.LUCENE_6_5_0); public static final int V_5_5_0_ID_UNRELEASED = 5050099; public static final Version V_5_5_0_UNRELEASED = new Version(V_5_5_0_ID_UNRELEASED, org.apache.lucene.util.Version.LUCENE_6_5_0); public static final int V_6_0_0_alpha1_ID_UNRELEASED = 6000001; @@ -104,6 +106,8 @@ public class Version implements Comparable { return V_6_0_0_alpha1_UNRELEASED; case V_5_5_0_ID_UNRELEASED: return V_5_5_0_UNRELEASED; + case V_5_4_1_ID_UNRELEASED: + return V_5_4_1_UNRELEASED; case V_5_4_0_ID_UNRELEASED: return V_5_4_0_UNRELEASED; case V_5_3_2_ID_UNRELEASED: diff --git a/core/src/test/resources/indices/bwc/index-5.4.0.zip b/core/src/test/resources/indices/bwc/index-5.4.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..e8473b3aa30bb25e1d777f3320d0f7f1e62dde96 GIT binary patch literal 385816 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

VSnop??DX6! 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
*H{0u>}=J82vwz`8 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

rS2`r*Di7z`} zUfA+)JLj+{O}4i2%(lKgDJ@Werl`;x8|Rp1Icn5q;Z{Gxb_AUd^EP0B680|I^XP`W zrSq$h4YbSdaQX#c`UT%=?1whPvB5Yw-P=o?SEiZ>>>*fcMht!!C0ytwPQ2m9Re^xe zFI+c57=M9y)?4i@eOijiusg#}=DZ_0z9J5UW83*#N?fL>oqb3)zN7`dUEs#jV_F6Yiui zu`azIRY<95beDSeJlSj35MoKb9Nz!6*7!~Nw9qIODCs6@o^rne z+qafyY?O;Ihg^;zvW{Fy9k_Wdwli@=lMAkp(H(KP6T4n)*RjI!rf7f9gmWHRy=YfgN3KPr{+n@~beYp9TM1SCng1D_B6L^lK zWM?0EBNAT>Uzxm&d;&n7gs~;_ZYcTZOF-?F+VUswWo@qeX7j%O$g0crM2Mszo>ihg zl`2U-Aei-u4cydmN+cx{0kI9On4wz!^ukX{8$JG|Q$AZSZ$jMod)fZfY$N}~^CqwP z^-qsK8|W4}x+_Zgs8``5YLM^t3T>s8HQ@F265wDZt| z5thI2#>a@-eD0Tf?)in0((E8B8&UZhk}ZY&C%)a0Z5S>)W#V+8XHywJgsocmOv*IA zYB?MWJ!?dP5~STR_X>7RmZfuVN>aD-JXVM4{Fd@Fk zGf7bae#l5t-hWSb&yr+Y7W6QI*&tkDbL8bcIq-p9&5j=Lk6w$DcHu41Y2agYGj1qZ z8^N=+LY9MZv?89`C%B^pcK-0uL7<|@5nPl{DTnOyCF>f)9;c>UA4~BfSg2&1#7VSEDf-MHQ_O`qlu;e zHiVJs!-7~k3mFNw3)qYvWK8}N2>c>&>Of8NvBlOMLWN{-B7`Zx_(444j76eP8s-`a8s?al%tY5Qw4Yx8=u^Nmer z{buFiA}syh_zfG*Yys@=B?Vv->H-=e|1C8kRar%MZ-KTgRQ*Tw(=TKyg&+N6giu=4 zFp?L~)v>qtZjWjjtHkAgP~)Pw?;$W+Ok|KKMiRd@kqe5Iy#W|VtLav) z>R3N+p}c}eHux_{gh=fi2nju3^Fz(3K|TdNetow1-MJi51A37Qh~8u`qU3IfXcbpw z9U&cim%18Lrz}5wrguOR$r6M$L) zL~~(RBne0lMN`beY&$2q z$ku|uSiImDrCrM#=*#I+e0?-aMF)Ppbq#C4)e#y0-cPuZs&N;_1b%mmeBHVP-_YQT zDU*Wf*rGp*YOrA@s??bq=Y?93-BFW9W7lgOEn=(Pk)~oi(YEo*%yhwbgq`b943i3u zT%~*6X8vICe{q@pfadUOEK7&b02h1UQx{d;Uec)Yp}&x8#T%?r?$kkJ;$^e@SL1r2 zs52LtcpFyCeLW321bsd$=Ja_jwBT^f+89FKj>K`S*+8X94tMnNS*s3Ril=}A1kqXO z5oQ$?I@wms=W!1=2l5XL&ZzevI6jYs@dee4wr_qE=LGnKD1$;X2Tg`Kz?Ti6-O02C zd7eZRpx=3_oHR%Ae|jQ!hz}mkQdPToztOZolry=uvXFQ)fmqu7#^0C`I(PbUcw5xcK%j;_Hktnj5%Z2jD;;R(1s%?E7YX; z3U+$2{N7i~muRGp10B_vI_A_A1muYU2*6di6Y|zaJ#O3y!zzT!gyXE|il5>`j#-;B zlVsC3@lnC`NQ2=&XEX>?Iqm!`5Bq9)K=aLoLPlK{Tii6pFX-Z@;nty<@C%v11-$^y zRatWG2%Lgr75Bg8TwYQ51W7i}xJWQkWtOfAWn}uW7NW(nH+(wZ>yW#ji%ZsF7A(-W z(O?ZC*P&-ra$}Rl!g?xUFYx4E2tsjTX`!)saF zcB!7LUamfIzS~9B{cjtY^SX>QAVrJ0)iT-_Cc{%E`^EF#;x|Ko*FDOfvx&TP~*e<;tF( zn*d9zxO$pM2fo zdhPxCz(Gk!$$v{gCv{ce%L4O?5)8Vsq}sd}6GD<)bkvB_g?J^B;$XMvkS%abrB0@^ zi7j_~H6fjwaY^%GDDY3BxWBLoRMu<9Cs53BQrDTHHeIB%8DU+qfOU{yHq!n8f#_AS zM|I%dkn(N})M)kR`8TV{O3)sZuPa&U%yLJJ2`8i*q-rhACrhmd<|myuX()VjPC6oxjgI zTpeynV-v_0Z>jnMAye#v{YymKx&6O%?kdc*$*#YtlW;lYJ7D0%#qt=OVaHp33}f+s zKaW#W*lA-nu%t1xLYMBFVp z$;UE zvm1;;dj-5e)=#E=Q`@J1y)qE`UiPGN3ob4~E)s@idT`L|4dz@106Wu3*+?}o>P3@B z7@{V6HKj4ir=VK177)zu>A; zf;i#~|7MW}b`s(N4wuq6GZ;q(N~W4LH>r^sk`(PG9LEbQVx6Y#Xtc5g=l3={W#1nM zeW4B>>A?&#JOq`qJrJPzHRMDk=fFYyaR^z~nNhHNgvCQY)jfxPNr`J9Y4xRA7)lO_ z1S#oWJ!27Pm*?GQYY8t^`60F_{*pGVgpgew6pmd2QmbX~T3AAbDAG6tP9@1NS#lM( zP`ic!bdJ^VvHFrv;iAEml^_ay_Cg$%?~pS|(mrPg#6c&=1Uty{8RF~Z4>N6EISnnm zEIA62Inm=(te#XJ7m(Wa%UZ_%eC1M+<9ELFZUmlI|x6^Jpa>& zz(PO;c``eiiSlu|0kFi<$ibY1;{JuaqH(jRlaT@&tim>T;)t40eh`c!*^KeSZ+3bE zMv6X1#i>hMw=ynMVbfkR3PDMnW{KZtY{MT647b@u^RZ1ln zpitU5L0bh#b9>YI7~$i%q&MLc!^inijOLZ1dQ=0hjvRl?ux^ciGSZyg%B7_osdQ0r zISZgvQof=cmzm-O6Im>bZ8-^q2h7IyOi!y)&7JG~*7~AkiV+Zc*q?M_-dp$+CY6OnE>NV1&5@s->>5wdz(1v`%1zZ z)QNf4X%GuyGfD;a_Wjgqw4=T1F3`^KDdr&sUF%mjE>P|Inf-L~X&StAegY!92?n*@ zFFRTZdqdZHps%6lr+b8CGHaS$Tya{8Ia8MaektCKWoX1they(6~ z1~;aF1es(8O6ImN=!f*xMPa+BucG4Zv3JuNcd}?7shYFElgfC$TN(V8##sH$Suf(l z=3nDsjuF+*e_pUV=d4a2iiAHk2-WXJ;EEQW0x5l6bV+#w+ue>=? z;n0VMV6WH*Ypf1x3>XS`q1fK?vDdNE$M+I(7W?_$`Y5iIb!Ym}%4OiIy zNxLy2#CAy4U`Q`cRg|+&D3KuFtEAwO$WTO;AQg705p9E6sO}N?4$=QCPRTnZ(;)yI zH!D8tUZAI79j)gmJ;9v2gsq^Q?_#(xqYlH6L<{&&F923mdMF7&7=Wn^qMe25r;oRpc%kjkdJ7n zOJT_CF~*PItnb@xW!12H3xH2!1!aD}F+b!id=mJjJ8={!UCDvKSuS%TNFS369g`fv z^`V2xRMZ`9P<==uA>zaNf&+_2t{J@_wj!!+?=2y?0^wWZ1dLY+Q{BWtQ=zRS^Ykn|7cmo$#+B+R{ zDMj^$&;z)-7lAz7k3FVw|CO8vhv}@3$2b|m1#Y-en;7G4-7Nyv<~Z?8{%+pILGj9E zjcf{F3iu}4M7b+sF*XI6N*_{ugTP?85>hRv(#F40rmxx2r+%Oe=PUpzz| z$`cse6@IBPBqf`3D{cy8C(FXkA{v%jin2Rf`hR+DOqR{3u>+}2%OCfuE}I35af4q( zst;3d6MQMUQvUu>=J?2gq`2hq_0$j{mSisM9O4bQ6GYHDu&twZsn!taHp=}LXOh9w z5D?urr4B}TzE1weI{PGl)=?&(1A6yQfsG*>GMo$S%_|DxvX4z@IMRv^^oi3QI{*D1 zpB+;ul6BMKVgHX8>0eZ76iQgz0(zLcJenwc5_bc!WW^JOZ=k3JVC=nBf<+Je5eT}W zE{3h97YXmOV6S6z!ra!sw=eg63@x`btk^>tcCrnoMvS(UZklP_8L ztwQf6#aaATt|CT>AvK^r!G8#!FK+!e(^d$F+X~F64|b1#cVrK? zB+H(lY}(DE%6nqZKK#%3Z?V!cc+wDT!TVVWUR;$PrC`UelM)Auvac}VBusxM3s%CRB0F^kyJ-ul652vXfSNX3@d2|K6f~1rhs8kW#%>C;x z-u(yhS3&<@N|)`n-EhWsdcM^M<{@5~L)44W<)C3a@#5_EwEFDI__aan;G=fMDv3l8uGv&__sx9O5m;Wt9BYha5NC{-9+N5~%Flp)cZZF?V&dEP1jee6su zK?;Wo^?Pn_T}?uMLi%b-ltzr8uKx#!jP)c#|TYdcG8YY9HqzqYCcKlNaH zg&!VWf^$#LPft$?POeTbFNsg8tLmE_&PDtkt~GC@xSyX~_r;yKwHshRHrM|-UrT(4 z`o9(45qQ6YpSrL8>p(o-86HNL6LF*HL|3 z^;*(R2Eh(C2<+kl#^aCl2D0054>+i~8L%4Z=!R*HN(j+k_@~kg;4pVMjbl2-$e=&I zDwqv9V0+XC4{71%zx=u{@|;shLiqBpM)wG|KuH{c4-LsPzzw$RV<#+bjRrItX-ohM z!SO6EV8B2tyDPRO-;)p9C*F3-BkXlKu%7C1mD&apGt_*)og!Y)X)F%?OXB|{Mlpwwp+PQE*JL= z3WTVIU%~KDP=eK@T{e$sQ&)}Rpt)^Z>o#fEs2(p1YZRRp z+V-k!$9`S7geR^xt@0z6x7`IY12o(zT&PX>wDN-VRAq#qj0G1+d67{PI~T0n{^YvA zVGM;(lRf{wKh&41-wSVQhAnutSn_|A^O2pe*7JKgU6!~(;JrE3pnS7RdqWGHwI7~w&yH1pNvDG`BPC8rXN17Z&j*FH)cjE{;X{}5w}_Z?t2Ml z?01o9)5YA#fMVm~i7Z$k^H%VNtk^!fLtVRmN9;+0=&?~YJ( za2)m5PXLjy+p+5qwPe%2sGMVq22J;LWvr60wb(hz}Zf=_WebvdN zmnx;~eq5i?a;gUr6(1+U*QTE5dgp+>G_S`r@^~Q^1O-x3T~$wdQ5)xAR)P^rg5M#4 zhZBh#>E)KZANL3}n-1v;^a$UsNs+;jpZL*+KDu@Pda!)a!|3n1K55h~Rpq5dAHG`) z^r)iYg<1Z6MPo)$_7lc|gSfzeT4qDyze-e$N@&@1QY^GmkFho%?W^xC#+T>68)3*d z<*v2QsfwTlSTd9WZ4&iO#*<)4?uctDl>AGl?2f`b4a?w!J@=d52juVk-1IH zMWzur3>bIaqn!1hEB-YoLH^=54trfvc{LL9)#b+VvgG8yN6R1xgR!TB0Nrvu&MWqbmQCZ}r?cV%*&2}6kKcZ=S=PHr9AAz8S%iuFk*7fA~*1#0)|7T4k}_fFIyWaJDt*qM%pG;1^b|@ z6_TGA+JFB$f3?p1+D=&u?IGP3A=cc9G;!_(v1+~w3c}cQfbKt{lNZ8+Btaps=SXzA zGKf?iOr}W2DLa5$s!;rgH$BZ)vGVjV*Hk(bsoV2<@ zG+p8e(-}o9*k|3n!uh&K=`MJxjl z^(87MgNY2`T`;g>gQzPg@fln>Qzp-jcG<0M7MHwJa|Evw0Jr41b`$4L`V$8yzRlN5 zmpwCn1=1*(LcpG*;?gpvfmcbscx<}7pO;UmESY3U?boI9q7rVK1>ln28d(40!QXo9 zGqz6HGUd+2AAl%6h2abb5dW&9Fr0z06$r%Oe?tbr>JVyTxw}%Gv3xnG^$VrtY+FgD zwHz9D*>f&t`i5qGe7^DL>a(mCjhtV@5atOLxZgsk=Sg8!GPRRLgm=_dVncIKQ!X1z zuDF*McN9BB%#xd<{uRAO5&+XR@6QV#{q)GjH%{6}SFTJc)E$B8O}uzjgTPgb#j8-{ zSz;wI8O<`)4t^-6lt+{aUPcvFh`6RB!&d8_J!@?1Ce=<`wW+-NuK5>l!0in%pHBjd zys^4o1j0irjocv8qJya48&8NLEK|G9AWx}MUVT^8*ENYS%pDeX2Y+XM;+lx`xEq+` zembxMp-&>r;)}PF>iGAPp?wfIAegqE49pFS>21?#BGy=2LhUd+{hjFoXCXYy9NvCy z)65OWRI*cb@~=BDC%;(;(`nRN@j@cd$vQq*;xvl!Yk&{B2L^^6EXH$*JOZ)b8)g+% zg>X*6vE_xUkRdY89p2tKC$_aQ*?exy&vDHD^ci^N7!0{@1Z5JTiGz>;^oN^U4~{^q zU&aPeae*5&whJ|)g4fR~tJqezwIFQhFst1{iLadZ#9eWPw%uDwvHONI0#E1O2|aVuC*N%In%{H1 zzVpkED9Ed$Dg970$4Y~$P!fC+#v()#9Kz63K!!3guB#9gYptO;UnY+j&GBg2&_A4~ zf5Py{s|zTqsxIQRyXSXY;GKdQVmr=>G>M`_+Is}-6pS*&2S}CbK@(G|@#@-aA)iyl zHW#@b5z|p9?jLov!i>&2LXO}6#qzh6pIsHk_B{C7L)B0XJp5_MbP-np!)qYyJpxoc zVbmZ=TDFuu9+5nqPMX9nWx&K0;3|)D*+8%fd|qVNzU_~G^5^oVIZ6AMIuxEm2JXF4 z>?cm=aJnIkN+nn4=$FtgO~fHDM$)WEmsPLx7Ry?l)rpeub--aC=z5SwdHmm*mT3>2 z`)Gy5z7k=GUnf>_T_A3!K1GE_V^AlI$pNmKLs~~#tpGoYM&aqaOQ^}Eh+DK$ zktrHT>$#aCUyv^9pQvmNoV#S%$%V`2+#q_K8GZKnW9b>YsEwR>Rg-8YrB2jF!?N`> z82D5i>E|q#Odwun$C3(vxa9VCa@#ZJQ^OJMe~2^6H~n>g`rz6rH}45NG4~yS&Q4WV zfxxz!RL`v@VV_Y@K@SVpHa8;efqqX zQ?19OTVqd=7~)4^a8TI&jS%f~3dW+48w4Y%AcSaFWIKR*W%*uK+G}w*JECHi9Kau- zB$->!F4{wRX3e#2FN|_@UA+n{{CNal2JuO}q`{Ivx<1hpMnB5r#WR=w!km$)gSX>|BStBdGRB19^Ue8}}TkNDWYo z@Vc8!fx4Ujd<;I@wJGAh^&P@Y9tXe`krA!qWviegFdh)$K@8VM8$yeIl~mfU1NI{= z45Ur`fWx2AzeA{`N#FW>A?#KE{!6+1z$+znkhuUxHjTvzm)#gNjVl2_st>`V+XkQ{ zLujJpYj-BunON8v(nxtGPN&Y))(u_8)1{lHj&UxTasTLB$Jc!F&3Pm1@jC~e{C3M0>%T8dv8`LY;WYyNDQXk%G+Hl)Nm!(cgjc)a`O*%T)LSf; z17blWlvArqOncO>mJR!%o0m20uRe6)k)CHg&kc#ctmI3NS5stgv*B=ZmUXQ0Onbq2b z*ON`Np6R^l_h-Dl(-Pb7?0#EJT}IQ7VcoV4#!m zos=Z9cvuk#b!h@lu7s0yBuhcOfEP$HizR)i_Rvbkq4reaY3=!?M^QQmo+aF7N*%wS zgsnsXz&s2TTpKb=-7;NPEtH3ZA_YIhleFz10dE83x0SHhKO)x9({uLO!Iih`@9c%( zFNhQ=+$2fT>m?)-fOIJ0pIkw7;dXBzT8NkYZiloZDe7>QWMysedil%h;GuiYWD6Ui zTb6$7Yss}NL+Bc`i5DW)N#3GBEf7W|LCE5Xl~hp&-zMNP-R`7V!}AJ5No$uRu2_Z) zb3Kbz?f&tUYwKH=Qah)rn*-QB0-e&*BwUV66LMQ97_)}jz&Q?ICW#XqOIDSW7|aT# zAtMqfgxMg0S~-~W3G-7o&SRfDz}+>3J#jdD9B$+vhnx5Sq&C!Hs}OQE1^`AV>nbM` zL1Q_rag_aGzo@K<2ynbC0q3&fC0=*v<4+i0ef-_ce{hbS=!IqqcqkPMR6*3q1Q;b@ zWGVrE7{!qRiRlch-LW{^l?;lyJW7*Tqb{s(1m^;Dai~KT)aJd#D{uGG&t-ObRw0eT zk7{ZKCy3OKz&$C(<7cx9fm+1Ev%`tBltRPv*_A?ql9J8>OY2*Je=%OF%ej={ z+~9d?#N0Fgy!pp_X_QKzN@?OAhMR>G2qUPQfyaymjV`-Roo$c$qD-IL(aCqF3J|H5 zdx?1!-f*F#ZNrmp(Zr#5?0Z&+Uu_}O=xeb*ra&~wc=#t6y0a3lF@#4cIBq7fb0(>f z*-?m;GBSI6xhM}R)K6g0Kg=ue7yFl;J^A~cGnO0T=c>-V6Qf|2h>bwPS_lw;7Y7K< z`8Q@z;Kyn!g|&8{nV)gBiF4(&lIctdMImwVn`yON;>;_sVgKOcE3Q6&gJQ^i!|xb- z5oZJ}W#B}}85%^LGZy=L8d}}l^f$#L&hcelS2EaQ8DgNQiNgjIUo96RUxRK{0*7B#I)IO+AvX6jk1bjCPz{wz~ zSl|dF4zrof_6Q4Rr!!FMjJ7lZe%Y(##aG$@1eV%cMNP> zHI8Unse+B|4tw9OZ?=%geYP*QV^0YBUY-Xg?E)nHY60vzL zQn7q>^RNBW_wOI3zV}m$pS$$uc$wI_pvcG_g6RZY_)aVXQ^18PKE$R z#?$m+mcbLrt5SYrM^RYLb_nx%mU7{65y{#M^>=(8&VPOG>Rr0^bU;;xtdYH#|F%(2$EozqyQUBr!i{+93LAq#^#TJ5_e0Pu82b~2@M?2BYbdtJLcx4jLXfhyIdoBt zC}ozHc9FmbUV;CFZe99Q@YE{3`H^>jU%Bu7)d*f}(+^>BA_OD|dz3-0z5w8fA{z@9 z0frR`%3T~$$;Z!%V*&+S0TuM!&HEEK{IU7ZZ(rYhY|o@qpHt`WNP zrshxaK70vY*f5cRgh%1npO>XWRrXq}5293S(IGVHE-1XZa9Na6#<>xXS`x6fiEu~@ zgm}xQmGMV%zb~Ks!<03DpV0qiq(NsZkoK?9crzKJ^*tD8VXL3RE}?c^)?Ea?(JW9V z{i+UQAroY>jWi(0A|S|ZkA1&4`qP39Q}d3GU)}NVXGh^i$*;5~$qWGa&yU7PEo27w zRS4Y!z+{^~$@C;eMt4vyGWxk~nS8PB4_Ynv)P$?>%*X$YF8w%g?lr-|JD>Q8mcCF6 zFQee;124EG28Jn6axI?7zyp3JPZ>9K>f2nxlD|-5Mv@w~I&v5uF2=u-nan+Zr|+pP zud(_zFG1HYM}R`&)dbes2F|Zju)0xb^$T@Fq;yg2l9Vz5Ay3NIS{;5_st{43S1P6W zJFsz=W^|uT^CygMMDOeyfu~iJ)wl%OY9ZR(@$maFaOMzLXAot@H4&yVX-c=-v}~Qv zRMhxb2E1VmCqMtS92?YrvdzElvxn(>iwoEj2(^-pc-ISd!&rz`Lj{2q3I3Ff9s$l= zrO#V@CQdF=NLuBJ6wk{sc%$8k}CB4IjTkfj6EMy}QYm1>s-GI6;f&X$H!-du)dobM!HM`5Ui%e@R&lGEY>m&GzVQ^H$+T^NgoF|EU ztim==B&h@rkJ-k{%lILF8-;Wgj}kWylxOYSQM+g6;2Xb@*NJC=DCi=Dr{KuaF6ktQ%3rKPPXfCvjCZ)a0&Y%K3h?!USeMqWECVgRf96&A z7sq$0El-V|`U>+=&IAsRawoY4$ltsX5bfNQ=2YSaQUjMp8bsZCce|@yW^^doen(f5 z)fTgBe0XU*@Z$dMPS33dv!T&ecWt)f-OS^pMlqf^eUeK3jRv(*umvzoqf&=RzHrVE zkC()OuwSRPcR4-!a70amHq1N+XB(;?y6N@uSZ&>0M|h|A)W`5J1>4)(-_zUQ*S8t( z!5!%C?ZH{szOB9e16#X$db@iDy8C+i!5`V&+t-6P*KP*C*8~0;{Gzw75C7rbz5(#7 z{(k(2E41t8fdQP&?dk6A@9yu$JA406=PghCzbRO;_c#7e9FKt}{EwrSHD; z*0l!#{^YQGLHvFfUH}ZBa4*DeO{RufyB49KuF_6LmRf@aH8YlS3c0}|yTIr2EQ)~i zddU(z_V8dZrv1l0bUJowgAYnun(#i_dyl%t{)<{ zNH}133ZNANPNc&SF&eU_D68NMXa%aQ)7d{vY@P0Sm^-oUsh_XyZeMr8{j~#cDs2&S z?GRqPA?e3`XGDnXbyd04(=-^t!8GnXV(5hG_Upa&)iE)1GKW{9a z{I^j4!ImeltQ&h_^Cu@@hFFX@OEz<+5Gv(WK-JJ0Tp^y=;dt~>wn@@e_UQvormq~8 zdYqEpVNm#WU;k%+WIo>4-F}*P7rOD{2^c39XGsKWkb02}#!kSL1|D$Uq$oG%6Iz5a zu2>`w1vzC_2j00^VRY|}jXy(Q{^KY6mj9FcC;inY@G7t!VIz^EfM*FfI6cf)RQjN2 z!q_PQ!9`yqm9!(tdP`G?r4*VRC!*&oACIv0+AMnN5DS*3)O#|ee2g7 zi>2L8un@Q+C=vJSCcu9oQdLXI_KP4OIf zqbtCONA8e6ZK6_A+T%}K9UA%-h(3w&L5vCC8uBx`U?ggRk`*`7-_DtR_}3I1?Zahk>|?mLqkNw+YZh z0(KT9*7JLz%Orb{=@YlNxfGJ3+FFv7`7u)pB~=99aBcIS-tVxVP&F%eOuo|rR^mQX zv6TWIP$s@a4mY=wNhorWR0(u>ZE6W$q|Xc6l}fK9;B#^fHs$Te)k?|UPyc!2_;XL6 z@eotrZf^ID7|{#WfY=gPx;owjJUAdXaQ6`gQKMETHrfMazcnVvdGzL(k|PS@d2k*O zcK(Xn1fu5)b&~(|-Fu&5@e+8ApU99r1cM*1uH%61wXQ*+k6~;Y0qoQap-QkRMJn3H zQ%7C;SVUm!(yFs5nZUjlUl2!(>puJ`{M`)AZv6;!*RqlcUN!(Bw-GATOdC2)Ci3bEebK#!Stl-G8Ln~N+>~nb;iWTN{Y4V(S(4=IR zOGd6hIxOmxPUXLie>NQq+;(*SrxQC*9EK5IrSG|x3c@l92|ElE8N6Tc5E?`=d>~2Y zj6W`mSlfi5IJc}1w|5Vx>KpE~es+1wgX1=^c2540+uJc8=PWNkRa+tYbV`*RWwdf} zS%+zjK-4|?vel`OWxQUeiK(`BmHFx{|Il#OIQrA)c6K!JqH)ll`E>b{$5)b(H>vIs52?l)d<{)8&If0ph5>x zu7%Z}lxw8YqF+=!oi6n;5UU5Af;W~1? z@HmXEBcn)XCF_9dvwEJSjZ^aLLIo+)(B+GI)jT}-1Cl=DxtITXBb$F@HsLrYD}3kh z?=%K)h*YT#*hZ@7fe&1TP#EHK!?2Xa=G%g{vQgm9YC5&0f?ZOG%cov1yT4`}v1I1Q zCm(zF^}BYNe%waAgUk?IAz}Scb-l13g4ZBG|A-7Bj1vfhDBGh_1%(c^O_4Nbf-;rO znNa&`@Gbx#>Yw*2Z{LP$B%eNhPN{XRNv}mhcY5@1)3&mAPMZ_=uoe)kJiGRKD&9;ue^}p{2>qxp$N;int z$@Sa=1Z)xkMH=YnLA$_i zhsgT33G{ob=|7`&04ZRHU<#5URO%H1Zbv97FS~RZL5Sy<>fF+}o>@r@0x>FWY}q{X zyD7VFJ@{Fbze+cB7({F&QjN?I{nl5X&z? zhI{=A^SQTwdo*w=?)!UZ?Cih`hv60xe?0;B2LcI^RL9>=#imnGhOiB)gl#f@yUP;y z>A4ntz^rg)Q^B%XaVx$lAVuWWkI34o-y_{~1+m_%pVDt7(g#Sxoe3Y;V876)EfN6` zA)Gi;boiL*q#}_wh*M>$-k6ER6eY!Qm|atxzde2Gg-@q_gxvkabi#YbV7dbM0u5S+ z4`Mh56Opl16@%2tZP(^H{9OTFr$A9CSjzI4TPGVflY0W|{!`2>UOYrUd*4UX>!wVl zFeHstlw-Iz03hXYDu|IN3}HoOhtQxguaS9U$+R!cOLXZ2s;EtA>w_v`_H93^NxP?R z`=GdKME4l}D%~ms{)<%A2hn3yv@4@AKM{q0BUKKkQ|->h%^i_Q%r4+aJKQ{tAfmt< zK=3~I*Mso~|2}qyV(2T<_dhN5)~qEX#~8S&-82S-{i~3%w3Wyps*B56rChY&iE|Tv zn@p~D@R>>Aa4S6c6!V@B-updz^Y%iEtj;)pYd?f2s;l~;M*h2mX<~6T728Fvs$Pc- zk#cONN2cmh@->>ah&vwd2&fA+c%3Ntp65-E5pPl)$$Yr}(ZJ0|ckKaAtW;?f6kMQT zPg6%D_rm}p0WHtO3O){#FZ5|FVzpi^O!L&LHAt->Kk^Fn`0U)GSI)fk**Wi;U$(q6 zMvKA{+;22-){yIPXC{NIXeYoTZFYrLATsOCdWTh!7uh=n`c6TJcnuZcNq_cxr=R~| z?luPf(3gAef93={dQ^3-NJXR?Xye4kD)49u1!~~z2O6&9I@k_vwCwQMyn>OZethTZ@y#^;_w!%|57@!^aFggHN}UH|jdc_nK1`&PNh%E;I)~mT zb^46?wtQF~bm8^zI4A$X;|Dld`}Dn|(?9B8s@>{CN%Z{4X1<>YRV@HWrVk=Fh;Z{R zV`ikLHd~n2me9x?ZJ}Z?monpZL^u~u{$-i?h2EcbuO-Qjyme*TycR-@me#~qqIJRm z5jso5wo?h!i|Q|-0ZBF-u_xlbE}7dawZ+A$kRy3Jas}n#tlZ)sj;@z%%hkH##BJx- zjoN%1o+%Q)MQGwgtLg+A6nkkD8M${n`WE3bsXeRl0(_t{sXKXEJ720w24dGoJ-Gk# zWA9>;ICg2md}vH@U^CtnCIg28^jb7}6i@(S_4A`Hp=p7x&6M@{+!AwV)T3l}FjG$T zVfYG}#|BEh<9_`OFKrHe`N!S8^B4Uxx(@Dcs969v@%Iq0SL?@-_z;fM5wT>mi8=iK|mmh#&4=ofa#YL6jz{pT3mh|gx>0jyc|9tB(32wcS1 zWE}YrJ4y+4B%-m$%4MCb>^3?|sj+oZG2zPx=DtrB8f-J>jIBc+LaPGA zniFWn<{bfsVHaNaJ%ol;$u^@br?V*2(SRZsF$6tU`@CVuv&!`$zoBZO&et`km2+`} z!9#51y;IY~IRdT-h)Sr6QjIr$=dJAmL&n(Q)dMwZcZc*GZZUoo#qS6Bf)_{c=JvP8 zdozsSt<0OBeTaF?DDJNri zu_jP~NuOW%ZsFz8)!#jK|Fqpto!$WVwbU#pV>5nz|4DEca{F&n>7#$>KIQBsHFDpt!2`~!qcF~JBF7pk7D}Ac znOq*WRNz*`tX@;uZ0cgUdmtz|@)~@8pV9L)bn?Cv%IBY-`|IsNDNJwXGHakJUlpE* zZs6Za{Hux^aXR7=DOVBblq9o$jase}r;GFE9iLFkOOLz)|1jD9P>ZnU>_6QvtH({a zZO23c(oUl6C19(_08sYg)n>rzf@_lF#-Y7zD+c&FVJR9ibQW2hHfbq*0v&DvoE87# zt>3H8PCLTAy5Os4xvKzJ{;jr2D2MAoU;)330Cx*DhzQg{G~+bML}7M-$L-K$<62|M zYEc;`U56u&+m`>{*mOAX?k;Q1`=dy}$I_D{YsJTjR3denh)<$6w;mv%v|SkRNyRp` zT$#>j1nmi?J)`STu;S8{!wuvZ@(x88ZQi(j=!W$-EjWp+L>T;W#46yLCQ+!zU{-7C zYBLJEVe}|GNQxE%S#?I^7P$OMx24F6a#(GW@j!I&M!E^K9|XbUxkg(kjYXjn5h2Wo@p*!>PB)(^K1jaNfG? z!c)c3i_2el7Ql3EZ48GkbjyITp=pC(`{5K8p{ z!bP%AVu@*jC0&O%U+QA{MH#cjqYhOHV{kGq_tm7vtLtxmE&J}J#XJA1uRjSRn^53y zv9HHM)OBQV?_?NQi<5Y9Xd)x`+HG2k-ObJLL~%hp-5CU*R-ru6=!yh?omANQ#s9t;q#ZJML2Jy_AOQ<=o@pVbmw-`7Xti_nB~-Lz}forERyb@6EOXaChXV*5Z_KGKr$HnxTaFYdjedT zB4N&Q14*qfozk``*jiH}r24O%3Eg-0`!nxlAEV5iN4X(P`Wr;G{EaYx{McC+ zxQ`|2P#u>>!ke+HKcNhvf^wc6Nm|TqP2S}!NF44|n=5&}68Q9-{2h7BzqrHshdsFB zyDg86X%tK)VBd{}Xi*~kDFvgGh`2bRr@=?@*phf4EGaM}Wv|J{HyBf;&e$|UC0;vh z3Y43ZmuLPc`J`HS*E9D`Bh=7IO`?mnwEM^yn?kA6q))NrH(s-iY*<7HgIZz z!AK-r9Br{24g@;NMzc}O=5>1HMqqa&K(QVR3MN(`EuFl;zi``^i+`X^B_KanSK(9Q z{zO?^$p-RB2CuOS#iNBp-eWS9)y`r@6t%V+m<5#}?7Oa6k9~6wkF#;#uH#DI{8w)A zYokkbr2=|hr*oII`5R^}IzPL?PaPqB4uLIZ9J!M&rT;spEi$E&`+_S)or zS^mB0ghp` z_ynnz_Xg_9p^bl&zTOF)6 ze>7;F<<2X)afU{L{N zN9Ti+(VJu{W2apZX9hDmTRGtJ=b1afR$c*HnRY}e{A=jp)4xofdC2qQQW}{=2fxMn z2f;Kb6

mdkMq_$(>|yG94UAM4FPy1Q|{|9QVpoZ9$8l2u=oXAdoCsvW^OoAA9kk zx*Mr04oi>1^p;Ug;-6}&fI4hpkgK1k4wAYY4iQhsOl33CvRG&eh;%vD!`1i-z*4-e zob%Jxox65kxX|DI>!tF!$E(sA&|C|+7j z!_k|}-ytxkWT~9VBaIu<>UgHW>O3^;_DEk3&0iLN_SCWmKTtjNM9id0!lTXW3o>2ScAGC>Vuqq(Z@bDZTsWL&n)Pz?&?=|)!|Y|s)r7}& zb^t=uGeLBS7dc|5&~Y_*X}yOX>@up-F_qh4_cFO%HXqYHFg%r{=IQ1GpGWR<+6{YN zdVA{p&>DpP8KsH)A8H*B7``11l>S z)&2Se32q?*{8&w;lCX`{C?X=`#HZ)b8+MZLKV zfFBUG1CP6VVB!8{e=`CnZ~QI1xBtWUBn*BfCY&YV++R)oaTY*XWCpLDRKZ9^PQVz~ z%Qb>r8&8oeWxeraXZpI!-QRxqgFS0c?Yl(3?a8F;k8Lw4cyVPiGWGBhg+^UFlkK8b0u1yjK(DAEjP2vxl zs6g)hz<;Aq_3WBK)DU;1^<_&3U#}I50=`&UEjIY{H0b?_S75GVI+H*4NZ;JwPEQ(0 zRcECz*h&=u>N6;`J$&dm4C#rLQ3M|}4WXGtG~_Z0MMYjPDgeOPsVj)hQn=ED^F;W_ zt%qLQUp#)IeA2$@^|?~G2DqcdBw)g~lkl;i$SDSjPuSo|G{O{D7P95#O1smlRk_3B z!~m(Xo5P=9?!Wa`-Dj%|cFpKVZre1g2I-!Q&%Y5PBoGJ1(uW` z60zl_oLqt}S19>1e8db;CjJjYvU|MinG3&p{{;$1Ozwr?M^WG_>6dEj#lZ5C=b+W6 z#^P*tfbVg#+a1Zyti;)7x0t%Doa;2)AK$(bxp|Cr@!7wvUoQOB@@+q<5g!j*Nr(X( z1&u+gH_jX)wR0UE9Ws61Y)+=6`b4LYr%u(h3{Qr=F);R~5l_z@`WbrsnX{Rlh90O! zhGN%7LsZ5LXaWH{jskSNfP%YzQjD8R74vCJR@(027ekg(Nvoq#&ynzk$_HZ8_WfXf ziuBlVO6`ZORcD_^DwB@8dp7s>RQ~Sk?&;~?4F0LV7iU&`dwOvub!+d|-rj+p-oCy8 ze6n#r-s_6bGVaBv9&ZN!a-h3sE8Z^KyA^MS1;2-P#csx#Sg`8mfu8CH$gX zIcLM;iuay@SI&i71UNss1)3$0%!Q}%B;Egm6Gnc4D$>kJS(MVSR+bR43*t6mR?%q= zmktiY;%`(rQXwmRp2FW9H3kdNQ^Z^UDfL5ZG2ZI?)2S zYAXcofv~wS#NbXxDhHP+m=zIOUT7*QHAS_sVB%PU+9gQE|2=km|GI|qoC)N;$z5~o z%@da(jl4<+ejR5EG+Zj?CK9UW!GmO#v$M^^Elatbeq}r+=5lg;UnF#Jm|Yot#|B?mLx~Y z!L!(Sz0gH^=~wK^(ofgFT{}s(WZ_pmP{r6Ef@g8XJK3vYkbr87^0C=H?T@bW8lsYHJE#yVKf)qQ4PeH_Mh(>OI;kAtq)^03>o<5d( zjQ`vZDDo|Wk1iA+gYkLT*aQNRA--!kVGp95u+AEgdzk#3wp?syD+E?1Ua*ZTk(dYn}!d1%<><~<%T_XYr z#tw5h*0Pjo<>@;G!B8d4 zTtsM`@D&0kh5<^z#h7UqnECB(OhLxQi#jy|g`bt;jUiNq)D6uy9rgZuYP;xe%TUeX zpMQd1pumq4@gXP@5n3-AO~6YBCc&742sH?B#h2OD36-MVSqzz@K}%PgPLxZqz8}uQ zkvQ8&2{!H{9A8qcpZeOAf5s9T1uR;V#6g_K18R@GKq13-z-T)-myjpuW@SZMUo7iZ zW};D>UuWmzxk7wWz>e?#ee=Dn?)wotk88iM9f4OrOhPuoRWg|VFp2sN3YW;39Gq`u z=Ao9=C6gsxF}Vd{ZoY5I z#$E_9k#Og{2C3&4sxb)-WpFr1B_AWUbwrF>t+6c~aa!4Kc~a}=NAP?MUjFvyO%rbskv5)!O(l>U_;_}`ERsp&>{3UB&E`Zbl7b;7R4cDl zU9FV7efsPYTHC{S8U*XHB-glRBnVqSBjY13x=AqgO$z)$1v@v0R{`YWh_{8EKB?Yf z>rDExc1}VO^s{l25}z4uwH|fsrAnEnvoHMpi0I&F$6I|K;1z#Rz6Sxmh)SBp7d2Dr zL}4NXVEjTFk%rel2zf<=%^%|klkG_lJ8t!hjn=Mr2*blj&fZq7{a)}(VMk1BDekwt za|~uk@|3Z0aV_>F08{)YN$?N>JBC-C5i2bWVJ$za5EXT@bUQO2WHUL@E`@!?FjKke z9wzpB6}s`w7yp_6&0G+7REE;w?dw%Pqu9T6a)StOD)cFBS`$0tVJ3}!zrp8=>)Ad@ zWo|3p#jaR4NB7v}+|BuS$3OV=_`jtvgIgrv+_F$`45luG7o?J{M_~ekKbL@Kxk=i* z$Jb?KsmuzgDkG6}bV*!}9%#5vw)LCM2M)hImrZ)|aQnO8jQSgIiLb8EMJTCG=&4L@ zt!@S2H{LE%*%UgvG0PRpJsMv?(HX|4y;l-?8$qi z-xudzwCo@;I1jE8b59uZo zhRAqokNek`?90-%lIge3dP4Sl%T##zY)T_HNTh#EsRv?$9Uzbxg5PkK)QN#aPO3o}V)JlGxKD2Or@GwSc6-t1&4&X?wo}MCJX~O$o_Mf-Os8w^_~duD zY*m)OT?oT36D!w71lRUH1yiDAqe9mNnDhUbwpK!Aal#~Cev^0|0{&ng6}L$F^^82)m&zCiEB zGuFARFc63c#2GtJnn_z$Bg1_4^o>tXVlvO1?mPX#13yt8mubPVe2?IB!cO5FaTN($ zgP_$XfmyZ*T_v?w;fi?q&ZN|q$og6A|Dvn)+qremez*S3(VL0epFaH8hbLi%=!Z%X z&4IB{JuguO_JdaApQnn(lAcbPfL&6?l6G-YFE0i1m2@>w+A)%;(Q~CQCrsM1VCuA) z-7oJXF~l43a;hfIhHBcnF_?)4LZCoF$YmPDaYLw!U&wZG+PMN*3@56AQ7ixc(%`3) zxz$~-zFxR7DSe<1s(GJ)twkWrG7^&8chV!KvetPFJr z)@=N?@?Y}mz9$ayqtA9MdsZ}^fZSY1QNY;wT9}%u!lo0ds)uTaP@&hFOzGwFu&TX7 zD~RPIwsyZ_I-wHho_QhE)3aig*Mv0S#y+nnmGYA!K3<%$4qB9&ZnO)9AXPhf7bsE^_M6{PN%q=^|-7{}>@Xec- zeQ<$4Km6s9UIv4AR}C(@oL)w~a5aK=i&#)1@>DIVfG?4AeoiW=aXX4^m&&aW+N0vM zT`p~?yIdie|8p>WTc>@$isYaFz`Y;XC=*6CisayQzM)JLa$Pj&TPpTD3cB$=`RZst8y4OM+f zfkQ;>B8||%!PDKzqQWP$cm;WHn~+mvb+AG{gY3HGY=wRzp+he|cllfF+keT`210 z-M_WxdLSf1#SOA}4@`Zin!2BWu_$PR0QX!vi=dq=?NDkJNmZHCE^*koM)P*ka2NYz zy7N2IffmWzpE};K%)5KO4n=lW^0*sXpl0s=QDYgL4KTU}s6viiEZE{YkHjpC@iI&h z00g4^f#Is5=i6rMtnRV$u{8*N!3b<|BUCSLti$$?A~S@C$d%d=N5-Iv zYb4B=Thz`fMFaMzPH3kLH)&e?Ne|w>bVK(y*QOmZa?6HOAiQ~;)Wi)DssGetJIA06 zJiOGxqIU7UDJPdBa&-k#eknI;>=IA8KJ#K>P@G)d`Rz-b^4f(z^S%6 zw2p@~DE(SJh-&I3FHo^N$Yg|tphw|LXx39U*}N{ZpwJl-`jsAwDxk$ju%mpuGU4f` zKGD8}ojQBu%;)tB+t;-Mt1D>0dmHK7NX^_8$Y_S7V$3h04rxcuWs+M3eyc(d7HSiz z7{7>jtMl2wnwv?#-g;!i$*<(6n$|tGUc7%iR?B$~t#st~LU>LsL`18v)DDv3DjVCY z;KrC{XO^YzQiYTW)oU2QgLrYmgZ3BV^9Bb0j$Mr_muXkOhShvuQyDNJ2@>HiAnY^> zRZD@{RC(C$grG|wcY1gpd0At0F}3=`!}fdh({-CR>oz)H4$pj7aPPVqhhh5H0GBRD z>V#j{KvO7Sk&%~47F(A|7GP>(sbIk^ZI=Z&Qt4s1GLKF=(@6Sb?fq+i_mh?{HbeU- zQ)co-hv7!{UP7Jdol2YLJQ%9}yasq%tBt2smD6n^VbtsqxKk{-JbAq^Av5abmYdG7 z-t3>Z%hi8wMfX+`Lvq&$%54Z;O{?Q}jjU}2tAK9;L1#4!tR-`ayNns9UK)!_FQPUroAg5NeU53@@IGugiHrhc1D_&}^Gu7nZC zm?T)z%kvI>ZxQ-WIk}bD){rvvn z8e!d|b+1k@#@CP=MF5?x8V6DP#$ap7WH?K~i5Zk@Xj8adiiEGo^@b%8fu++QGR}vu zR!T0v+qXZk>{PC1)7tNL%P!r@SD-c9N%R#+vuGP>B=Su)-oS_oiYc*0EVHv@(vnOk zbF~MV3U!z`T-R`#I#<5ecD0sEysyJ`ZDsuem_D(tN!T>1ncoAAY~bPPXqQqeEod~6 zGRte?CPT?c(h{w-?ErDTRR+D1IrizrPk!i{dPjcZzI_DxE(|+60iyaR!2u$+pFn_T zB9)wpPE_QVE$s@uGL=vYlzP6&leCks7gtVwUHma=LCLE|8)e0vX z_J7)b0&bL?L9w65L(ReyV@Eb{@YWrX(d}ys%WW|a%Uz0Q(k5P~M<5^0aQ*ttO|xt7 z-|)=$AKdWxoW(z!J^|Cwh9(h-1Z+M|jUR^zEqtLHt`yUV+=7loTxNOcG6r0tm(T*_cwUE|ks) ztR5Z5DC$b8w+_3p#cM|l)~sLg*luNCLG*g4VI|TcmRx`+O0-FE09chC2m(=*5W;3r zAS5^Z5|>G-7v*)~U|Qy8YUJ{0S27gu`ltq+4iB7;SoYcrk1QG(vvhn*|2tii-~N-+fk-uU&rpA!t zX|KQUHsK|B>eEkn_pg3TKY#p(q6urrbOv>n7|%*_j5J7zmry}Sicm>Hx%>gA*(2*> znKBBe&Lr}NcrMot(zVK4C!TLN&g;os{bi;7f!C5X-+6sRI`-=Xh&GV`zgbZlWGdJIT>U-a>Ar1Z9m{H*>Wd9_}L_(8z zKcSv?8ih3|Hi|V2>tBs{J#63YCKJOP#|2;M)a`wAZhUY&z zu;&2Rx%H<>c%B}g_uI@JfFQ~Xqp%CKs_HL5e988A@e-|pQIpWJxlU*=o4ES)y=IH?Bj`It8YS-Xe$(zxnkb$@t9RiAxq!hb#mA>ohHy;gJDluS9e9d_EWt}PYlS-q z)YnGQ9-RtBh}b%WSlu;pkmQ%9ygp-xmBr+8m9kuyUg#8$W!3VBrd);c)Q0repI`g! zrP>A#bK7lWS#(MR=C6mV&e57%pCXYP1WKS>0cS*)^yL$}C`Y4DstQtJfah8_Ja@m; zv3|>k!7209GcrlSj+Z^Vv6?a+OAw)|g<~Nfj75o1gXnHDkQ}wLz0;dzX*61A#2EJE zy&XQme@$$=)idUeSFerFj$Zej`^6W3IyH%ayu-uCqw#B78aR^)%}Km;S)3tM*e6Z7 zgC~xwJkFelWs_)G8gVXDn0Uu%W^j9Hc&imj9?}Q+!BD5M)9Q{Zt=_0k;j_|)J6Nbl_t8O?@GsYc ziW~2`@2B>Ya1GMXBm|=KQ0r);mUB_gsdy47J5<| zk1DFy@dEjz$ELr9INYl8$oP1}_MMHrzG+(yz0`UC^n)<+G?TIg!YD0Joj6*BS!>D2 z+vD($B4s<(?3AgiAmF4GCb1`McMCIhb(ewt18!#5pD*wKQ?IK=qu?aqvoVbL%QHp}L0pHzg#oru;!xgl9;llkM`1*&30F zL-X#R18@!AW4H3FaN*jqpFWtr<<=+Wjaz=ckx(NA7v4yy6Gp1A-F0YnaoiBe={13{ zK+xu}x!c5PSv01!I3#0%?18ItJiq*brFzR0{rUTR_bEorm_(s}IRYC!3Zm9x7?oOu z9A}_-Id>{y?NkI!W@UTX>P~{dN8PEAoW9;j*XK{wT)3AJ|2()Pt%&WvbWb(?rg}^{ z0hldtPt{5KASz3DczGc&w?k?S8ujj6*{say_7SdD#zUeTe>{Xv4m3XvPGCBgGgP931v#5w7Q}I;EMXRtLj$u zU70wiVfqb3bm}CtJ!B9v zV?}p3ELW?f;q=jAD3IQ;V<=pG_6$2XPBzXwVVe|&$5!FyL0pa1@%Is6Ke2h{-wTi# z0tv28E2(mU(`KD818x< z80f{P3U~M5Q-txE!@c-xvRmd|8EwSC-|Q%ESLZPSXe&Pg7c04XYz0z z{vPZ9Z}M>2*p`oZLeX}I%8|+BxVCl{m-9a+5A*S2ijThdZNtuqE~)*ACxzP7#c$v> zy-=VKdmkU{{N)VX!sS&~suh0)Q_sND`N9DpP%z5i z|2fRS3bKxlF1@^9=J{l7A=_ydsq}5i;ik}2FOEIXvui;S{_^S33;v^<1+P8>obWuP zLc)ra@O1pE@d3m?!ze7S%&a9da|OL3WoZjV^=3oBSyV+M9d7B*!&&~zAKpP`MI@TNz+XyMpprSS1*st(0Z)IRyy+;ktjVk^Xuh!Dzgyo09) zn#PeFAD;NT5GKH9A#?$-vtC2Qo)@Ns@q{N+j^%}pE*U?x5*eNc9e?kEm!G)dq2Lpr z=*za+uI2Eu9*7}+pwclVi4&)B1pwf+40o;y@aIrVC0ofEPM92FwLcdUWds3}!m|_^ zW?DX+^qjNq9xG$ZbM#+M9$y)r53W}HBuwdsYWYhc>OMj}zy|PtkP0ErOAsm{m@K2# zvh4C)&I2bKacBp8sq@%lDOHFU^M;+`lT*QJ)||6nI)@nXG{)nW~(3<{+&6KxmBMeS@+$9#NfCa`|!DzoxvTeUoT zcT)CSV$Ll$5%HEM`s)PhO~mHb9unHX#e*?#K~fS9lVF5YVr3GH)+v#7aODY`j31Qg zVmyb&5PlPHGr~dsBI%-Aw`-c3iI0lRxe3dAAtYZ({&Qq7K5F$E5p57HA`YU-Qrhiw zu_YG2Nt$$X6Qxw#U#N_#0Q=cG!{xYpp7hIQTefWfVExUnO&~BNe;^eOK?c`}uMu$p zXdyrie0=IfL}+O1bY`<%Jcq+z?=o`u;do^zDb7aR*-v}JefHhLD9&8Nx9bAq=b{Yp zpCo(`DE`jxEyR%wp&oyFb_jJSb19uwBos0mdkNTFl*|z6Nfn%>&Wl{UEdCBbEa{Rv3njl(FMW$J zoN2E=^xdI1+qOui-a0w?{?|GL9Jct&igDoMu@JX1!v!Emd?Bs5!y_z2N*w}@-XG#| zgIZsSbqFsN24~&!_Yc4P{M@1~y3U%5x2@&=(+kyXCD9MV^?Zl~0eQ|>Y8n}w@xu+! zDTO+cSF&RO^QrX$MXKGW2QS^_ zBtx;c2q+DY@XETNG9S^q*jZJ|UdU_ohEg1-wQzy{=-~q|wLbF2f5OJI>S-Tsv-VLd zlY^^{!}Jwo+N>J<`C2)^*P;zD2xKmy0#k=x=IV?JEE2hhmnnw@9TpIk4^aeos_(?f z4@h?&KZ(iyC_le;<7cPgRr@H7!fm7`&T52q3SLkOfjBVOjX2-A}C6 zop|D=J*7UVGV&WQ%1F@b#M5eEfaO#)5KG<%R|YNUf=PMQRMJRf7LTFq4F!!Zll%B^ zyW!-aeRuu3_ODU(JmHbszM%(yMj3(%*U-eBN~jZ2Nw~rsgQ4m$eFzOZ5?o!IM4dAk z-6aXv7cI(lrDMaK+iLAgllG{dJ?{GO;O2Xw^&c*T;Tv&np|=w1BpS52l|rH*?O3J2 z)e{J_rRijwJm-=Z+jGK_Hmc4Z8%9!*pYzD0A5z~z-iqDu-nw_5rjY0lGMYG(2-C#; zvnZqWF(TdwiCm(BfZ`(A=_?k}cA?%OV#U~PVv${5&?<{TI(}3@&>bJm-ZuXZ+ny7j z?U~cYTsKmS(sz=Y_<9<32j0;`ZV*l+Tte9VBJ0&v~1G?Ie*IoX2RDcUdIiOi0LT@8~pg65^82 z!HaU!>f^&AezCsi?B5T+elU1p>Zn8W9=?i?8)G9-WD zq-3RqUbqH<3>0ugQ1uD`eG?M9-Q@8HSQ($7V9#|4(_yuJKDc;%=H*vkN_O1x?+(fC zIhDNocVW};iXGdIdvn85N0vm$z@rsYG z+qX=kc;M-YFQ!bMM>(_kEdqltAyejp@OmjijnlE8U^31`k`(PGgSEi-h|ChTUYU!k z9mUWI6ki2=QjPB})$jGcUQT>>)6?BP$#-|NRlu zB*4Ztw|aRL?+3iB+wTEf9-5PnKZaWoOR#SBpu0g5TGGtVBE7*oxR*uS9T(K&ZV;hW} za*m-ClrJ3CP5=1gw0~Y7b0?qur?)kRikK0Z?(XjLP`8ZaySJ2QA7^1yc zhre^Sl>{Nx#NlBOX?8kmviVb)Qi$nP8$4~kunHy(qWD>P&{LtINdwaaco}Jf7T| z(4Nx|{`|mQPv2$y@kSytmw`X;%sEV>wbf%k!YJW6I)2?GA-_wg?Ci`J?6#=EA9A`B zeokQA@Wke`ca=w6`E579pYz@5TSbMHZxF__=L5(+8lvs5!TKPydI@5rmfb5h zclc87Jlmkj1f}6a*B`RoW?T7>@anwcwBW(&rX71%$zggoX_ip*CZXyujP0+X)Zk7q z7S}A6DcCU(+U_Ml zFbOKb747x`L=~22`NBk^Gg=U~MMd0{Lc-Dc*CE4`JXg&a{3Y_tJ-^?1?;AU@gW6(0 zgggpU)*(&&)z!3h_?%`6a;O1aj|`ED78SF-R4S)fDWgpol6Y+eFOx7l`0_1y>5Vg= z@4sB5-#IVA-1K9yks%6=!pCcKnFNRmoE8nk)G!h08C{9Gw7H^H$9MUxeo0$M>I}x& zBxtvi+uQ3!g$KA&>k=^T~n*@b2#cjy?@HNob_1_2lN( z$4Ml_Nv(MHVzeByD(xO$MkI76l4WLBheEz}xPoEd+!G4L57}LpgOLkYM(?j$0K-3# zu?28-oj^mwXc)?nu!e`4v}J5)La;zW1_f=#Wd3>w7)vWzgAhzYthp@7d_WGQoHpktcrW#v!q zJoUh4_43no`~RHz@e^yBt4WQ#DDV^2q&mrm6zq@MD)^7#sUHrTyfYdT8#2aJhh59j zD1!EKXeQ+n1utE)v^;ZfQ_|@220f?mT zA5$;D^@B!6-fFDuD5TEw!<{iphTXxE$CBKPqo^>Q_nD=8V-(Ud-^RA-_&hvUd_-2T=)$LUm7 zr1^P927O}ADCUx%K<;XajHdh(Xk>HI`gqS5#%@=u<_Fq#zPY z+fL%;s6Y_suFQJJOdR!(t{?vAwLQ=*5VO2O#LN0rXbrZXKtaZj#2X_?HmR}fR`TK; zud9v4m#OS3X68;ZSOdtPhLH0cPJaCo?b8 ztwOyjnv!*-3c9>XD%Gt)hMxfWBbzBS-7)3{_?A1@zhH(Y?EqH|;LWRbP(6PKK3kN; zkj$;drH^EEutn`IXToX?J58m4Db8u{oIx3W0YqS!<60e5j&sbJde6g-XMUt(2)hxF z#)X0r)H?h%nV&1&&<%nC(jZB1a7R=TZ&2jzkcu;kf;A&Ae>mbQ2*QByO?$^XX3F8; zUfg@W=XX`l^XAd?jElGBlJTFXXbJM%Dn z6&2w8Tp#6ZD!FasO&hHN%ST^22M@zFWKy%ZdK5lgVPu0u3T$A>T;g!WE?-irH+lF) zo~b>dmH3DNx^ckSzIXM-AKw|j8M!BRmq-#>cM(K`f;I%$P-qWK^%1F@vG^@Dh^7I* z=Va<7PIEe{0ur3GW);&-O=vNlaL?f0vcF>%6TC~y|w#Rqu(^WR@bUKsK2JrCbJ zN;~&a!tAelA^LWJ16m2w1;X@5aIPrwek-sI=U`7!ld}g5rhJ#Ls0buG#*G>$3{_pJ z)IZ1IUk%6UFOOx{ocZ>jzgL_E0LfYl)!a&~6YnEn%aJNtd+jAO><_t>5@XEnNQl@h zZ7d(m*ljZSGB{cwEvvt)8~LT*pndJj^OIh@{D3A{RntSlN>c%Je2)T22^feZtCs`d zXKVL}J9)N<+wIZCtX69_>E#&a;o%jY8`lP3-;?hPJhXnpD9f(Szj=EI$ewYOWdJ{} zAXAA{Y(7ju)=e0G>^2>>d6{;uC1Wx;a?Yqe&Ns+B#L8RG*+;%eowz9LzsvfzZ^kXv zXp~O(5a}?fp1TZz`ynh!#|Lo_p)Ns55f69_MXkf5m^CPpn257_BwGmt`W;fUgUcxuMUi}#XDmF# z0CJ0G>Ge}j98F`kM0WoxPd}4Ot^&qI0YiR-x{XvPT1CbvRC0?*a{UD>S2F4L*+cGj zp46f>;xB(Wx^gGstCjLoZ|VDtxbDVuZOhlq^$yN+YmplK0jsaaLRAAKOgw^8ZKxeY zlQ|Ew5Q?>hN-llM!ZtV+A-@HmT#YA_yWe^9)hgP`Db(JYYP+~m{vd;J*9gi90BYK3 zb=+_jycT>IWh5})X|6h;*JRst;heK8>S`;8LqX;B2U^Z=S<}^fcIG4T_Ho~_#J4Uz z1tTq0_}fX-#q1|YSmP+PS}{pbG9Acnr0W>%2bbL!htFo~pMZVo42*#zM^4(-0 zGx$In{{3CDR+3)x>`}gCsk!CjlQ42_3|`oM51GoOV9#My2y+~Y4-yP!m`YQZtDube zLT0HzkZ)s`Z2iNKdg(K(=8Ty=LftZ#UV7mTt~N$&Y4LrW^hRD`+r1$BeqcHu` z8te=ks+WX`&^a1(o`_dKS3AK~%QN0mKod)MGJOTB&*9<;RawJq3Z!RVfvMZica^5^ zIXzqX_PE2nF*aDIA4Drh;W{1&Q&UwaLpTdBlo~`$@w}uB$ct8H6Idm_c)_I37x1@K zaB}B{8<)(M9cdZ0Tm9|iSB^gY>QR`%y+*1~84JhP@!tX95y4Za3?W8D@n;XDsf3zq zU}@|=r`E4zi%ndW79A#fko9Z6`}AGI+nT&#?i^3%xuY&^qKrjAoQgMp zM;#tPn>^)_IwMH~m#HkcRe|tPJiG)Kb+>Bw%o+7?#|~a<)$R?q+)bu0Z^TnBbsQ~< zNyn3`9~m=sJeD@vg&I#uVkx*CW}(^#j04`j>zJ5(NM|th{_x>fvjg(W6DBqa zAFRd#^$>M$6ZQ*AVF;HJEAhKP>SVFn1x!=MDbU%N!8Vh!Gje^3)(O(>|0I{*u&p$i zwRPrE)*V0vw8E-WFqW=@sHfq|i*0g7MeH~#uPA9{cPLCjlPs%e#q~)^ynndV<16Qt zEsbNVPk(|wx97pf|9J?&X&)aS2)%eDL}gJhJz9l4INVqtD@rBBXuG}L?vsX%JROHw zEG)(|8#syl05or(-~pEiT6OUKZ-1SgDO6!!QlKWmhXfXv7blKnh<_hbfewj?Q_pe> zlyQqvY;i{-Z83|(bq6xs+VI$9-9O!mjqqIQBYm?KqdajU{rK1>;U@%Y)nqJABqBR% zD@7HKj4PD8*yry}w#udcfLHi~({c=#foVxf;G)bsiv zd_WmKdIc}N>MTl2d|@yVG3jJ3T}kV*#o5WN5YS2B2lhbR<2z2RJ0`t#^E%J;{N^SC z{pNaX8U?E3O~cFlD72eF7}wDu*R+>&9Ufh&q+y3L8hONRuBHw@Eq!x(?TvHBhBrUg zteG)>+M^4O!SolgSv>9@0`-om&8_!VlPfP(o8%sf-ik5@e*?m*LRvjOyek4`xT&&J0TSM8!!#*4lvAy%&^UnT`*I#%8*EEv7* z`Eo{^F?8f|eZ#Kcwh_0#_~tIbi%);jH-ocy=IoO&_7Mf5Pa)8rXu)!Hw7PNB5J}dS zjmVP)4J&3Qcx_WAYsoV@HergBDJj#r3ljVIvB%%pPbp=gV5D3Sgp}f}Bri*`vl{7t6RZNf zl*zapUOxEzYmX4m?@6F{GsnZL;LT8r1gAnbLrtPB&@>UR8(P>}3giTp^34`L&ad`C zm&ih|y=-SE;sJ{)ZD59WcrwcxWN@w%onFI+Hbx0T=sPrhyk#|^_P`XC0kGKzMV zK)3*&&gb?)wVdGw+7>bQ`uJXUq2$OF>>h#H5lqXK-W*G*2o`|@CgYVIU;O&ub0>Z{ z@ptpUgofw;B-{?K?g1O(RdPm+{H^$KlC9U-U?GGzlQVd)508B`@p6GcK<*UqOdgTO zWa}t7N+Nvl8D8fxXK_>M$i~yT$9~P-zi2Y|w|?N+9)^KMo+S_sK+}c){p2fyQyKU_ zgr@Duwvw3Za2d*SHcRhyh06vt{wgtU$0Q$q`0<0cezfn)^P9ZmKWczis^CW9I%JlB z+YgQ7_d&1{f2EH|I}KkV2c2dvOA~bYm>oiAu)s7XC3;Z^FSEeQx|Y~3UM+r?J9*i0 zQCFKt(Wy)8JOY+p;pvj` z$|tV3az48BPu8=4Ou65E`uxgRZSmvx2~AunOkamg7jr-a@IHZ3>GooIiZYk0Q*Q`_ zl4@1L7*(XRX*~Okmyi7O6zsY41J2J=$GPsl>xS62<8TX44DNLe(gZ$jItQf(&+>S6rl}Gz3TY=ZH!_OK z@GUw=yVVi2r=w-DHRy{~-pB>E=FSu1g&W5x)n9I(dsTU9(q4F(kBGGrAo^LfjxUFy zL0b4i7mVVC^?H^);}hi*Y?c`yp{!Dsk(xOR@z-PU?xw$f z$-Nf*^1{UvcN`eggMHOZV2B>53_|7$j=@zh3F@sty#~=uz`bPhZfm;Bk#s9dZ9-N= zBbLen{~urf0p>*Y|BK@@lVp-jb~79L?y|e|79hPTExq?13#RvE(+euS*n3CVT^1D! zVpkL?f(qDsK|rdA9hIv7=Ooa;Cc~&n9I8Rxn)) z%|V;MrqMP357AxcQ?kJYwSV?LU+yM!3-OOA!9U_Uh+C z`t0a++cu9Sw5=oc2)7Yh-lRa=AnZyQhF@x6Ur1tGkZleL1VOe+=MKu*wlY`XBR1KP zejm-39IO?jTJMe*RsX#9<&6j+)$ZY+BX)3oMC?YSr4>AhRcGa;9Fd6JSx{Bhm` zgl;?q@8RsCbc%-{xCS>Qn`e<56NPajTjg*?y#iyd8cRobIZ-f^+em8mx!1f;GJ3`w z+xOh6=-H=UnYw8=0X~3Gj^io)L`utlEfA4}9YzU=p;_RS*K>F@$Tn#B5spY}3C0pS zv-k3RHSLN`eYeqiSO4|X@&l{5CjUyLn>Qcs!GBHTib6#A2*6z82jiFKY;4xw=NI_Y z3Wb#&O~&Fnom=kJ4C2WWev1d5^c}xzd0X4KyT{x#`ML+YBgD3T2s?&Cz2aqL21B9) zC*Ulqsi{MH^xO>MdZ?sC~+=I;S?`2Ca)eq9(Um?nO zaF1{<+-$_`B9IXd2)zF$7m9ITSi>|0bI}sZCd#`w;#x$yvkk0;-`(fGdZ@biw)_*b z|LHmHUdX-v5KIpddqj(oUS5bea-5Kl-#745hPtgBw<~K_ciL(;Wi4uj%;1wZn}95S z_NMV%Y5Y#{H`o}qJ|c(VhfqK^$6Z106ewxf_%;*~F`9&sm9kJEOtX_hjiWE=7pN=F zh+Ez)%r2x|IJxP?dj>vzO!Zn9sn;WiyLtHc;%M4C1V6PmsBbyf6B~Vdu}EEts4IG% zmQ`>C-6D3{rxH#efS1DW?V0B`U!S5*y5lG3p4UH#C{I03>gLGdUg2^4%I+p$Yg(yY zTs?~4*O<5-N@k>)N>!SO+PP|Hs;D~&Lo+ECpBNcWBd7PQnbyMN$j? zLpp^@r%vPZVnnQkL}rM;BjY#ZEZXN12CKnJk{>Ws%0`Y1ZWPZJ{l;Fs@$u*~I@2KF8lCZ6HXP67qQ0Oa7Q4(_?4Ezi$>4~apX|B0-XGra{pxiP{U;ihq(i-& zXQ_-X;g7VlC|{Ay8vHy#G43wZUF@*0FBs5=LA4fC(+^)UZPqjAU!MH*``7eD9_X6Z zOF(?2Mh`efrvk#2$uM>RhP&7yBJOYVQb(9w$p+Q6Oh7N=>4aJlbD&vKxp~X*MTTj8 zsmD|Om8pYQo{P31i-t8oJ3uRggS$<@-2zxq&W>o57GuV2)x6}O> z_X&f!KBYSy-AKBGzaMTxE=|9aZ#nVQ^RnpUGlrCpEggW`PPg|6@MQpZ*8oIr9VFo~ zq%)jh=8V3qk|m6b`tZbs%}Z=2G@3fc)sJ7;(9v(caLZOaZxP*oq#-cv7H3^ z3A9Hdg{jjifV_AK0=52wyL^ka%#Y+e2|Rx2W2+3wgeY%PuDeWAIhS_s#*If`PEY^H zcI=L=?+=?oVF>O)DdPw|;(v%8l7&Rf-q}K1iu+fgE0)fU_K(ABrx$$L_cHYkt>pmDz!3lya6-zzG&i z4pCWH)24#fhPB7+=mx}8F?Ft(op!I z&4sD>8A#B{t@H71Dy2NZP*!T6Uh$ixR>f8LaTMT}b0HPDI9z1`X&tbD=@UYfrdvGH!R)`~pY}u;y z)VwyPU!o2aoCH#%@P5mVOV@8@Em--7zxUxkBR|;&sj!#<#+M8uAs~i0i9qZU`-x}K zuvS|y*u2c3O2c89%$`UlSq#Wf@J_g|s4n9@H)>v=^{-2xK5%1gR(1)(kYp(M6~&ge z!c>R~KSh`oiQhN5_2yCMP?NA^mT)uvvXz%`<584NQ4IqHu10Pwdg}JG@o%=Z9ra#w zy<*O_S6ymh2%4HCKlef%yloV0DMA@161+}Amm+7;ph4khvtq?)+^zA2m?e`oQqu1N z;R~q3_ig#+({t%%lUIiiZRW53Wtt5C=rTN-+J)zNw~oSg5m1_+c#h;R1oKs~JE_%$ zS;j;yrm4A1N7^soYv6Yw@ecEyJwxLj*v_3Z&^y_<`eF;hM<@$m`mLi{@JRo9gaogF z(JSEdq>9aD(yK*kja=vjqdNYNTfMQb_dH`Ze8JeM1<^SlR|V2i{jw5^}9Hf`Xp z*8Tm>%(K@GLiB5h*n)P5wwMf>_DHI&F|8={M-!5g#^Bb6Yk{Dx%4TZfhRe(dr=FPj z_xJlfk3XN@o%{6rBQpmfhHwPXOzM#Y=$)bkC`O=?5o|aa4-iRgA3IRzs`%VcL>y7& z+&)KN0V077#?SI;RWUnv<+VW0I8cdMC}m{VjVmJ6?(G`lc9uG;)wHT zK2wv1yaE$XR?b91%&5{Y4(8>}`TEV*FDcz_JkWLWhC}^~XU9HGAi>`NdaPc-4nl)_ z6+Di)$)>Jg)s>2%uo4%@IC70$9LRZtYWy%0@H>uO+THfSmRs&DQHpP59vj;}4IW8s zWSB?raP=^XAtXv`WH|2CZMLYM&y_Rd35`F&Dce)_zATu<1|?qqi0hcQExR!7oy6R% z&atWg2n<^>5cUY(!B5TiU^sZpIZ`O0u-OxpK6|WW5(}#wmox5udo;c)pu$^bf2^A` zUDtKnnWsxm&HbtYs9QXUN2uJlN7J6~>CK#=ky`QdMarbD`kb@sC`wIizb2;AX*5c} zB!Qoobs_2|gZ)K9F;-Ph%I#LEXvp|(zyYPAb%-M^P@uu-1Dh~(F>($~=<~W_-do}7 z*a?x`!#A*4R@n~11rmUu-umR;mtSUo_2|T(CZA*d_Yo>Z>EE`~rDzA|I~ZC{$6Y6O z9@WW>E>|vNaQ5;00<5}GXSZkAk2H_Vq=_S4oA%q*P0wC>Z}OzaKUqX(NbodC3`3(~ z>H@Tb-$}r39ECC@8WOk%s7GPfCPMn8S&+;rs|B&IYL05hG^MPr=C8T!lc6ggnlZd< zPIP$xI4==-y&H_a{R?Ju4xv~XL0iYQoh7@anQ9~u<~bzQKD$X-un6iFPKDfav4KGK zwETX@!A2;#kNmXTv}1r&U9 zUz!&Svy?{XAsTca>ms~q<#wLknVLs`EdBkW-&?JRQTor58tqHpa7@~cj^z+L&Y?=a zn8{Odl+r*-oi!NzYImkjzY@V$xBw5oW8Q&l6!2@R{^!5xh@YDA2BBN90s#WKD-ddG z=4FwuR$>o`yUHfH%#Qnhc|e=uu(%>aNqppToznE}`;-y)eBJ-ZgliUm`}{9w#uM7k z5wY&kP={nLjWL1OK!hL)5;~rMhm=Karlboyi>VwpQq0P#%(T!vp70+Dutm@NWa_IA z-21ZcU?+7 z*{4!eS*}HwXJb_tCrw;``inW|e9Gw~<}7wCfZKfZUg26&8wQb3hyO46j5tzPXY>#LV zqQNBWS|SPvT<{Pi$_|FZUR}Y@PuD6;d0AGq$^eHEz{}s=Hnw)6<+;sM_G8Q57;7Qo zW?>5*ILe;UP|NnQy%S_89&>A`__kaiD(jw>{04yAV>q^^IV!M&IwZyhq{m}dSd=a z$mA;guYTi`={KI*w9t^8@lw@y!>7(IgAh_DP>#Wvc{e~aX9q2jE>D7&YVBeAxyZ>WZzgT!`*REj<(byKiHZg?&P2;ln zQm|tvv26+CJc;eimIF$eM_))5Qe|$~7Is8055*Q#)3!YaU;Wgi=db#^Hu|0=>mY>P z1p(CK{l`YYq} zZu^t6UbdB`n~oGmgLPgI;o(ED1?z5Wp#|~OS19L3b-ARZ=H&Uq5x=T#GMM6nO-9-u zX7x|mGbLiQq! z3Y;xvP8Cc#UCkn@i$Y}=FJV-uK^Yc|pQ!8`w|t^~_un%=fBX4C9%0OO0(~iizJlB# zcoU%ZDQyF|nG-wJe4WxRSKEsPkv=3cBvS$XJCx?=$?wuvCn=V7FjGH0zG$}gDkhjm zXb_&!|LtzMnhsq{#1=CM$mTH(CmUqPc)CQzpp?h?(rmrpSLKt5_06_pK~tGBht@vr zRpi#6V!mT{tRVOD6)1x`0i=fHE+J5^s2OCYqM9AlCQSluBA!r5^*r8@W^L--Eyfqq zV<*UK6T}-vAg>(2vlJc!5S@vZA)pL=1g0>!hNj9}E~>~o&2Eh;=C=ri3fw!Dk|7xk z;c+JfowgibEgW^n>Hht;M}{hRHsFKWc3L?W-Mw_h)_Xt7f9ZT({4Kna%cd)Ov8hua+Qt#E0*3x*!D2)RK1^s( z5M(_bhg`tXXpB<3D<8-SxuFC%3T`!i=mtuk(jHZh-7(Dd@{gyZ!LOr4MA9gca(0C!P?zniFKWro(kC0H&DdCb6JKK` zyOAnAHi8A^TSzzy~b84tSp{DZV=ck*2q-CB_fyyJG1(U<1=3z z!JmKV&RdQT|HwI;!K+iijeKSr)FGTg!G4-VVMs<18&lXOxx1#)tJ7?sO2udC<$Zlc z(_R8JX3lRgfAaGq1|IwPF6GfbmOb`}@xV!914BDF*grG`(6FFki~j|H#r6-Z!~b$< zaA;sdf1^LUp?`3oAO9gh*AA@R06Ms!D?B)~p#ivE*Wcg2VJ&Ft_OAtu#zX4?>oNFO z*9{JC04&LWcEc1iaY+Na4bt@ zbSYo9s5m5U`-IXl{y_#YTrAsFzuWEZ~kpk?U9-?R@cG|lwe2O&HIY1CI{^YF;7 z15daX0E}g`W7;kp(`@f*>>NQnrxCl@X}d~b^14eJM@S0VyMQ3Mdsgk{flF@f-J|dE z_`d(N2rpB>&9*VH=0HM|HvmEX4Q%OpfXd}xrbrIPc#;@1kz^;-eHFg5R(0fzMJpJK z1~Yu!|E&Ju*e9G#Z>{9+x#HHB;8pz)LvTNsf1btX4?vxQV{l`_Kn|mw63|5u2e@ok z)GLg-qQbaXtaj(~VL*dL0#kUuZ+p>&Ua{13#VsGAzO4tpAA-910N{)No7036CEPn< z2x?*Q?uAheeke=on8jADs+m?_$;Y!MOci%fG=#q|06D%IGpom{&ZC)VaiWN{_Gfsx z24?W)AQVkwIB>d{GX&IVXTsPi7=~+26}+-O=hq9RR*9g-4fEJ_sj!^rW8%>P06V_% zB)HP0&3<9-NE|_ z_Q7{Q-0gnEbo$4Kj=;z{P@0~_6Rtp7Hj^6oUw$71e3WWG6apxS0RG(X( zOvUZmXGkC;#sk&tYd@U)#y9lV{r4@q+jI9gcn^Ug_@a@bw~>H~@}34MUSn1t*jj_o zZSv&QmSmn)W&6!(b0nldyJ}TGUXKjMMN--yW8-y?4_c>w8UE=y{+|}h!7d#ZyJzQ z;VPsP|AhwG_WbsG07p}N< z-3vQT>JB-x)+s4*gA!gLs;knq&|6Qn^Tq%@oL5q`;@;{>wC zgwVql8Y)T|d=V7^xMKU!n-|}5_fxJPxbq(Pbnv&~_^swNfj;;e($tuYe18+4J!MEz#p8H?E zGW1)_K6S!v@^7BW9K!F*c@h}y7R-mI3;2g%cp41EQ@RA8&!DLqGU1viYP9%@cCkfW z=NPT5eyG9d+&k>#qS=Spf2Z|tz5SuR{a@Hd>j9!)cw#8pNoWLI&k`Fvcgb9hE3K9s zWnV@wObe@h0&7XMz41u6HMslfmkC|>Y5?kFNkjuCu7lQ!#rJDZ%~9?MvpcncOFIY=K(3%LhpxT zSHChP0AWC$zi><2al_R&$*k+3ZZX*BNt6zW422fL4H;r#qS@0g%5B+-m>+SZavX)u zW=v=}cGnG;)3O&Q#oqd$*W`Pt^D|x96X>_Jwo4|!)TKx- zZz(bY{t1|qv#8#tDaZ7@ia(n3WEBy6Ue^}_yoC5NfQFUv>xyT7OHd!^7k%>d!`IxW zfDs`A?g{?gIz@XZ*oSQ`Gq^kjdLE6}TvoX$U)Hcp{#3A-4A+yY1ds^FFUT#EEtGG5 z?LFhWZ+~c!gmf!>u^qwh+Ym$#5jzBOw0#1V3f%-@HzV!%iy8D1TRzKnMSKy9rpS^9 zVp%!3A3{JOx#jt7s;zwI-wWp~THNw#jHbfRV;lo$UjEyJ>0;sIBuoWU8(K-4q(CXo zm%X*LGM`HbgSoKBaZUS062J-em=u4!{?$G|^T~N@Hy!`Ds=fLyEMTOxdxh(EhoetBZ$ z&SeAPH(uT~?pkc|9T&gEwuc~la%2Xx%;f*T@97OO{U6-ScZfT@;FMfeq!z$g?^ z@UsVKI_Hvh$lp2UeSUiGA1w$4s_BGFxbeb`#U$5g`GLVNByZn+_vvLHyf!jMZ0CPYq^v>ct8rJTgt3>Y zWH^L1$jri`Tv;J^%UIQToukt0g`7&@M8oOeH+<37XIm#P{cp?*pV@9ceRY@pZgRI| zHPXYaw{&vuA!Dy%xR+nioFia4(`Js}BMZBtaiCwIWb(wB>4Xbp5g_XPM|=C{8+X<` z6Yd^n9scvBweY-Q-FyJGKMr?D@cn5JEd-s6oV>&L(7JC1A%+-_v?mh) z!Cwb=5D#A3NaWVdq_g-bw#XfpvLfm$*bV-AT49tZx;|PxOh58&vlIp`6YN*C!9tJ6o1`uY8@E?VzENR{q!c>4 zTN3c8Yc*R@n*Y8T)eT=x5S*7!p1du6*YkV37Cfy-=?jKoQ#znd?j{ocl_(6s8&E?6 z)X&eyvRt;=nuxG1X*;K?F&hJN_)=r|EP3zsDe zon0etRUBTyoqp-QHSpp^54HlL;(n-`JA&H5olJnHld#805OOctpkKywQ;x5ePu5Fj zepu@fMgn11b#1e-{@QD$=!|0@9DTLA^1==i*#C^RV*_)deFiu#FhJJ&lx7wU6oN?zG~Tf49g`V0j0 zbcDf@NJymN2xoYs-m6Z;w4PwhqB6wxIuHtI?M_d;7!Bk^3x zmu1I9b$v*{(xshMw@2T{Y2e1dB&P9U{^~dORo3r)$l$vA$&xHa1Y$r(Vca3W)Mu%n zP{ri1&(O}HT$w&q$_xA+sVu|IIQxpRq(!y?YLe)DHEiS7H+@$_(QiuAU+w^;tnk+e z&>+9m-pkoHVssaehTBdH*Xj_9Q$Am;FXN4A+##N=#scDx68z-O4-G%F*Bj}K1{hyd ziuwQ6APg><)`EveDPpG>4@6!7n^Ga5YmjrKQlD6?Gr2gSKDN-G_NSDIpm5&^{ObT1 z#n$z6CVgHiKYB$XvT>N`ihU!H)2$8t@Ik1PlW&2~(Xb4W$PnHSqeJ-RRJp8fqhIY8 z+AFF)Q^=v?+U)f$B;3P*Zre!5D9*scr)H9dzO+vb+1@(^cMBOLtaBXH$(u#M7$gd^ zgo3{>?qE!EXS|{_;n!0lGlopel;0FP1w0jKxn26`-dhl(>gKt`cZ?TYx2+yVVsOtw zEozuvZeekFPIP#ea2NI$B_UInImxIqt1n!xz9{(7ty9(gl}a$`-Nsi ze?erl-Tcybx9lB&=p;tF_+<)}K8lu{g55_Z(-^op_qkYNZ6VEysCYVcNEWHa!z|ke zAb9{Y_Thz>ChXmQ{WW_#K3e$p)a@z;3CWHFwN^XYGMxb9x#&nLp^LkpaDn9F7*w9B zyDrw5gBm%<7kAd}M=pJ%e<41!EaCQ z7QRXC;a#LnlW?XIpvMsG3krnf8nm&bf`-F4XZVp+oo6VrecWPIn)0`UZNY8TmK&;9 z+}QiT-2Jbp%CEFf{$@GC;C%_0%IH?Kga0Um9iB)=mQg^BiAFWz2;&a?kwT%Lg(aHS-g{x$20SqCA?gmqU!<;uq zHv7Q2?1O1L=v( z?&uP|1t2}zgt!!rYSczHr^ZueP4&K{>c-0gR4=Z%^x6;PG4BiZ=cb9S2#tD+KtDFE zhd-V`i;l#`6DY{jCw`H-bMfPx?RwpqBveJUG&QWtTqw%c)@PxVJ zU)TPqnfmD?{WRi-)|Y;iqx41e9?m#Ir(iW1d!IsvFHbl5?M|O9mJ74u5i3{DbmCqq zScXVVKwErrhpKbkzf(W@igj=8>Z`YX)dv5BP!=QDe^UVC9g4j^8Eri<5#JT7D;dZ$ z3rT;W97u?I84Wj=~J8Wh}Ie2q4=)$CPBLt2{D;u}>E(d*gA9 z*kvljZXiQP@h6$jaT8ydKBeoco5x>rd^`TJ9R&JU!+J!)mJZ(6!?2&n;$bzuEe%Rk zjzHz~`U-kwiJc8f`aG6kKK=u(In%WLTBUVWYMTDVfe+(XpJlGuLFg8)A4Pwwqm!?o z!K)x_K7J2sZD2@?6pp013W+qM;s_&hi$X3imct8)(D7N9;M)0@v5%&XzIHw3w_V5f zAKW${1;G025v*$lMC};SJ7GSE*k(3}645H#EUKD>O1E6WRTgyOf+H&pA3>Xi#&_he z?>@M~Gw$zUyRLuk3aGx5z!2dFX9I-Y-VIUL%*NC-O6z-V=h39ICUs=Ao{C+StlRTm zPsXXQT*kHCWmsa$kKQ>x^!|*mt}Rh_T`>{4p$#-ICgB%cu#p6i=zVlz>%3v-NCpv0 zuT6?Qsi5B+(UnsQPQ2;`_6ETGS=;wbFps|P?c1+^ywU0t7rlO2Hk?xVEzDF(B5&H`1NHZ$>u34Z zdV!u_Hf5UNm5+AfiEd*^uSYbULW>hIHA?Q{fs>rq)m>~;RIO1v@=S@F&8mpB1~uC3 zB0s(M^N+ql$A(T{{QSlL=(43Lha!XK(yIC*s~bg#RFhdRn%QH z+x2`Mx6aq8m11R1U);w6OW^i=6zLhsgjc7g&Q0>q88-OL>6`EXqD}&+c*%|to!mAm zJQ~3!5g=p)5uJ>i(5$NW&!c9KBwdd5ne`R5Kw?Zwvfgqe0Y*FV%OF`C*>=Ii zgkSq}@3w(k4&8=F!d;yWVaOJ&Q)FsyXn+E`LZ!hj_Sy_;Wgt+uh}t2Og zP!XynfIOY0E;QKc?(5hUdHzaBnqLZ&+lhn9)I}nm%9S{>reM|W{%l!|3 zgxgQ6sGVn^(~hGZVsJZK$*p}Y=g~lkV^hjhbx|%Y40600ja(8jUk*nyKU>=wgISqrb|YoWhS!HBrAYo|gh5NIY0S|!Ll27tMcoDq4=uZ1Q*q=0r#-E6%V5HVO{Tv#T zxlNq3)f+Zea~x(OUh$SQ!DE-XL|2Tw?TgTu>U)VVe>k%9mXmorkoakAFPK8sCmE5`Q2!wPFV;ag_Y zfpXVLl*Q*yA&g*1u7VrhNtN$YrgTh>G-L5`tv*{l#K{GZz)iy9QCk)Fu73$BeEl_Q zegC^e;eAr0*}7p}|0AFsI?zAZKR7fnFf`EUkAl|ghJm%~*8`$r{I>xh9^2nPuy*ah zhM}Rg{f!Rnz~B)0hX>X+v|oP_g#FczzgHMPfO2{_Y+a?Tx>o4GNa;D2;m zMPOE8%zLY@v43j|{JJT&?8=z-1iWMeXzsF|5M?9OF1Q1t4nbph8z3{l@U8=RTCo-a z;U}5Ri})q^w9n^P^|36@e6$vhB`N@Of#0Q1E8qP6+C$-i_@%#?%cl<90R(9o{6896 zuY5dRp2m>?c*I9dJzDN%aaMVz=tw0iCU34>u1eFMc;2ZHNiXZsQWx3pH?#$w`gM29 z12?}!_zAx8FwEdIL{&j~ewu`hKi*XhL0Wh^(x6VuM+z04sA?`pRN{h3&+YSibDS%i zD7j}YvZuab+V=bPTRwStV`Zfa4yK!M~$v5K>8%K_fByOa+^wz~$!xey*a@fC=N@?tZDh_tS@jyX7xrW~854 zzDov=6A04~MGp50K!Fj!pg#j_j8Ki&3`vskN)z>7Fsu+jP^JB*$wc`F}Q^W3TZ06zpfSaS=br2Ihe?E(!sbmD}&Ed z#9$b2#A7c^+-m;h273OAzaDz`jX`+TI|PQf!I|1CCX*oQWC9+W0ZKd-47Hv_&!UlF zFy^gVY@4D^>;_JGJC!V}CelH%q4naNqA!xct zcmf7wwSy3mwi-E)Rzo#AH*Qi?oK~|p?sONGP7zz#^h3jmXNoPK*e8e8iCx!Nf6JXY(XYui203KPfVoCQE#LiW?5`jy}YEcR#eP_(v^(b_BX*&H=f--cLbIC{YN_%KF#os zQ{K~x+)Qb7=VlP5^94=DRl>a1MsnciWqc;TOp|7@3MnJ2YSQ@v@(q_qNs_g%1^wzr z{`=|P4}a(1e^tvGq+9YgN>39zIqw54WpYytO%vxxDt?Ji#*ulnOlMMC3ko<_AmI4s?pk=u)3)m& z?o;PhBJ>oooqLW>{g2imT-1VJbP5eLkRoDJ)~2!LED}yd#uEtThJeX)90tqaw{-Da zF-0*k|GPf&jdjY)?=Kv{{i6s$DaYY%{sOo|D5AheVQdvbUD>Yl3j$q$x@3;QLUL(m4dg*vWaR;ra_vO9&E#n z8kjwR{*u2lapkVJIsf$haq-BGet79?R0eMyN;wSE!^BSEYzlt78>83PQPC^m3nVq) z!*pi69-}8Eua|6QT`*T#4_zYQ_qJ>0zqaydPEGc~G1KIIoADq(uo&s#`H55&3Rr6&|O)i&P!ihylWAt?4jsr(Obp>}BdABa3Ogwn|JQ$jVQ0BtD zT>Ssh_EXw3{6=0+>m-~-nSFAzSYnm&aw)q}Vio18Y=v(dC_@5H#0z)ce&#dy;3gaI zvn!wKCWP0M7(6=()L-zWT8^Tu3EA}!2^rba;F;AK3-O}NuMYFoW{V=J?h6+SK<*u1 z3xBmq`zO3OYSp5px6hHF8&9Xk;fq{Dgu40v5ve!eNgjm^pKHvWplL}_mRA|msjOQh z5vD9cRtO*_FMxM@}_9^$TeEsYu^Xaqxp^g!Vi9wkU(=QS`Lr;O#!~@>&qh9eeTg$UHQS= z!U=Ok9PtD3l=z6VMv&%_k#EetL?3M-Wv`tsHAtz_!Mo!H)ae0qT+v0F*0&9tr7DnEU5%jT$Pj+#=ca{ zt@IQnZu#Y*s@C(ti|^g=25UdiZQ>lQ%TKr-8iDQ zX!G9j-!7U;z;7qEhXA!4qyZ1q+5<>2^jRBAYf|JTrEnb2MXXL&opTs%7ng@$gq~zv zS}uR~+jTdcTPIZ(K+Sk@YmfLs3m!(1K+f5EVdOc~AmZ>c$tYhRlGF-yUBFg$`@O&v zf_@}xTV6aAh93s1c~I;2w)3c8$1Vng0$tUv z=*yX7Oi7>~EF5k|EU`ytXIT2V39he0<}=H&>po-`nbDy>JDs zO@;RG4&wm}1Dc$F| z{ey|dEpwG?A;j24nF9lQ&X((lmy?(-Az;W78gw>S*eU1K#V&!-E!XDa5?kXc;0yim zyw!Oe`EvfqV|$iOcw(FSYq(onXzjs2LnlW}!`72f=3d5*TPt~_g&EZMw3UOVrm!+bJs279>cNFAbiF!m3TMgurEr-pCj zC8F+Z$*79f`6;ei8THE0hAp++*m_VrYVas&`Mk+r`Nv&1Kx*qI^l$<#)C29<5JYX2 z($1qHZo*n*h7Bf1!BUahqD5P($Wk{O{FT^8ubjL^a3!{bc->1K>3@cxZq5&Qe4v3l zg*yqbv>jW~N@NHu5PBMa6pNo5tyjanL95z5AF}R;K5d|@A)~>4w71er9 z@6##V0gsBWSpkS$K;`4+VN+)>f9HyuLwA0W&Q-_0OQ3&`_J|I{o#I_>_%bN+3#nmf zDurw;p6ctTlXd|9CDeOul@xU{Rb1 z#=n4KNwlStOC@0w2vq2|Mo@rioxG$f@9^oZHc>Rp@;gHkR_qy4lN@=x@z|&rzn)H9 zwDi|+tcMn_-T-w=PN3NPqoGbg8wm>zry$OTo+T=Z%PO8qyp9xQj8^A4X9)J}|MR@{@9M^X*IcVd zkscz*lqH);osw06+ZAFEurDc4D`2^hnLUxDjhmKdqlsEt&vGQ|rTWQcdP6*Z=&tU^ zsB0$f3v4$TetBO7(|;U^r6)l&jD(HB$PCdSf&vn+Xk2Nj`C_(ARL7N=;yHVQ8vz7Z z;0!MtkL`WXx(+G-`PGxUx$8HA3EP{H9?1_dE!$w8MmihN1T>{^n^}fhk;e-f5(bXb z8Hpr{mqnTG72JO5jb{#3Xt!>2SkE4PIfGwBW((y97`(@H5&Mc^ScXVx1+C+9UK-U) zyqpNXt|$j2KroEw!qXBwV8&1Jn_I>)zYr|G^{s8&wMVZPxjrC_4;)F(rEIo70LdaBl<0%2@zIW5js$E^Z^Xe%5vlRcp8i8A-t}PbGn& zXiP+pxnVQs8{I=6zxUYURBU?a*hE6NpxDyRxe=n4=u{f1cf#Kz$qeyNfEes7D&T1< zT7B5<&3WSCq&J<)7i_XUcql0bU5k^s-^M+De_-R0x@yY(uQNzX@Z4<=p@(~}y_4^v zVM`DcA+|T{1urM9@QSufxt=S!;yziB!>n^JE4?1mBh3fH9a)_{=5sjNY)?s)VVf0(usG6K20uRi_YQ;w{ErvCzFxk3 z)~~%^M~HM8OgEw({H+)^r;Q5ez5&%zI>VNPatcMUPsz^N9C|BHBPlAIr|01t=9c^4 zdigH?rV;z(xqn_%!VJ-fb_$+cKimq@x@KT+6UeO-N1P*t>KTpG;uCu~`l?u<4w~78 z{Ngd~;$x#P!WGFomcOrGXnXF=U2Ct@Gl$k7$N-ApE4mVHy_$w?nT*GL6+&ao&MXnj zg#J>&ne!R#PL9|jcQfxKw~J5U%UpQ~KK0bow#N)w+F=QMzAE2j66TGQFW3^Ek>ow5cU?+WiLmQ&Dp|93m5k9XvCNUDr!ST4?xp!o#+jEyU;eqkg;0 zqDj>Y+Gwz5O%t1P?xQDNbJW!zA7}2l`lktGuJj~~JVygG#Y(u7k4LucBnoXb6*pQ{ zz0FxJDfl^cxg4uT1Cm_8ep9muN*;EX?c(wy1JAxW_PXphkLWNGGN}`E6cG+YyKib^ z7UKF5jWZLpC*!WZYOG|bWMr~3FX*tODxjf(AK%>c39hyNS1(N^cAd@fj_-swjzjDK zt%DtDgIfNjK`)W9b2JDUqBW?eR0exq6J|1X7O6iV5ZZJZyDTvQYZuQRaS0yr;#1wf zzB%c)&g{CorWBXnF&~ESfw4!SR@$>&czQ=+a4wK=Uv+`xuJMg7r$?Zx#r-8_KBe== zHS?Qi_^R2hPUZQj(;j~P$K#WqSiN%vLXWl27K)QZYy@>AqHb;K)7v!?2j61l>kEmP zfa@>2<4z#V1RS_^{6FU9A02*b;_62q-WI#}k!MKVoR_KCPs1Qut`n}pxWU4MM)TRKVvCRE$*9%UFfSf;=I@SJO8_kMlXgYa%Xd_SxJ-2;c9 zN1z|p!F`4Vy-xx&>PUdv0KJs-dRe_-6F3!#Xh|to1ldAU-!1}v_b$S(4ley*cg-R` z{OW?`1=DSht%Hy^M*<9IVkFeT+24VUClHZqsSPqEpWCg9xu4Xek(l)CbQyBM^|NvJ4TtDsui7Sq z8Jzp!2E26~L|Z-_lff;mBoe;86{Egl3x+Kzt<7qVgn4$iH5w#B8tz5-bpmzg=$?5t z#)6XvzngsL@+U~hB@!5v7q@kaR{<@O7UU~3&>}%y7LLSaPUU<#Z{A$1MR*CmIDWio z%^m;T;5e0tJjT3o=K6#4=B$}PpuaY*muDLd_3~#BM!+Xq8xEmXhl08~*LUNeIO$`?HOjEV8wgtyTtmc~26e>SsvFnjdW@?M%I4m3 z16BA0?g<`j?ZN$7FLxy}68U5}x(dPLa*0>W+6|{RHauba)>DI{_1ry$$&sR1xL#^dVheJe0Ju5-o&PCHyLEU=iU?Z)4r;JaKo_OWyt6q4UGV<*csu$1(iE;mWKsVgKe#79v(BQg9`Zo-2 z*nt1_AYd?FH#oR<9caY@>?{7y^{*Wo*f2OaxPEAGpnvVU!GU%74+b~%<9`kS1Z+RP z(mEhJ+Yf$$?(4w7(E1G<*KZj3b1b~<|LDAm|L@ML@c%%$3WT#qLch~5(-?!!>;KDS zY=B_n|8Bcpn5ImYY|(nXsFw5Xe7&Q{k(H96|Iv08gSPxI{awrF{5)p%u){+?f7Ufr zhL`q3V+DZ56u|Jr{m}4sPNRT%j+|AMswJCQoQxOEGI6Bf45$ie>w4${3c|Cio_lTh z8+S8JzUD}$k*8#t&g zE@%e#8EqnuoU7oMIBvC0l+fkMv3O-&Q`l!{_oAz3EkE+JYs|W%Q=a<%7Qk`)J7@*Z zmhc`0#LbKeA3|88xy-{~8n6y%I3|6AS0!(J5wh}o< z1_i!T=SEC;;mO+U6(9VuDEsS{eejL%Q0P-A^tI3!!6Oj#7#UFLb@3(mw+pe{T5UC0 z5QZyKnc1T%s(d=-BTbK8`D@L@(KAo|1QCz#dC{dEHbjDdfhga=?cy;obpxqWu#>>b zWEUZLGX5WmUWs2DL#|j-%EBpQSnHO#swP`r8c=}|QBa1O{ZyuX^hVB+QKYMlsx4h3 zNO*+yH6B>u28VY&GO9}mazR!!7G)~zTu;Q6D};1r0iJ3&El@?F6W08G;3gG`ORsQ9R0<6qcwls56TCcsV;) z)tAWEvOwVl)S#aJ=))!NwD7i8HqBc3*cE>aZh*S^Hz7T|$%Ib+2NWzsq;yHZB4Tx) z*WVY{ae_>?H=n6$xCMy`G)lo(=Whv5;=!9f|M11YYrpp<=L$o_Zmt^c5&n#_INZI2 z_69nS#L;L=dY3^gaAqq4emGW3Rl*wdQUf&pS$_6(+oj_=_Q}-)`>yVpvkGY&B4HX7 z>J%IYy+3jnAD}s0S_wV;hV@K+#0PG;s$*x zSd=IFPJpMv?a7NozzfTy}PwT2w=IJNhm{N1OTJ6 zWQnxk@_5*OkxyT!vCW}ksKzQuxovnrg75U7w2{}`(E0P-Pw$sM`qF{zugYOUnA*U3 z;`d%WsnL~Ya7PduS+h~0V#&P~YqIKeX;l$f-cpQ-rc;^|;B3y~mRsBJ898#Cd*{;^ z{lCg#_+x8y5{S`S(Ux_ehjyu!d!C8S|Pm!p|(bgu(Pl>B`hRj@*C*v#| z!d6Ejn9Ux)%vS&8&#SDTzC5z_*&DCiX%bEAr;w1xX+TDHjSNmw# z)nps0IudEM!#@$S@!!2~%oj~%kK|;1ieCj;*)S@TuzqtF0Q=xnDJqC=Dcn-y3 zQD|gRLqA5myshCG&AMvB*%xsn{BpjfSk4-R+LQzQ7jQEsUK_MM@ab*+ug?4S2iD+Z z1H5<(mBIfKX#h}8p)L5{9EOPu;pqkeIBHY7<$O-Hfz%`1 zMd;uR!{9-{*h@gB4o6qu>0QZf45gjbU{&LcnsO|y-NOuuFZY#R3wA$bxO#VKobcIq zwTsvOv5SD*)YhVGNN@?;dbxklMlu9^r19y)JXx9hSXn8Yyk)`fP(s> zzR3B%HVVdcead$u4@}#VY5|kI`1ca8A$N-A41*6*!Er=>BQ-*Gb~&R68I1w`6;N9L)yd=-*UC?Q~0BpB+`Io;Thw6xFtlyI!B-k z;TB?}P7(I|%Y~@K8Q}W-c_TAemAF(XfW8Bus@h}EK94!F5#Q4vu6^foe8Ixesm3Sd1r7#}Tj}X{0V536DI&d4Wdh6!1j(y2n+w=~+T&uG-VYcGurj zGfb6V-uTkZ*ZsF~#_k;i2ACFG4`Hu%z|_a6*yAKJa{aIdIyU6d6ys$xH||zAJYH@@ z%-6Ww0b)~&yp;R-<})wfbls=d+_wJA($9TM5C;E>#upQeCjeM0wz~27x6`Kqe>7w zW9WD-(uJ~jj+H|%WS5c|;@?2@(j&Zz*vY?|2p>YBsW2F?Ze0K7a~^b#(RC1A$JaLwz_9Uis)gQ6B*`tRG1Uki72bPE=s z82&W0C>`J(lrWJ7hHGSMwlB-Jg4_aLmNpLn5I+Vwk&T^`{fElC0uiB+4%@p7<2S-Km-Hk@SpzuVG8%R zMU&Tj^2*;ojyUzjAk@u^wP0@(a6hd=VFj4-CbqM;Lg-2S9Etio7DddE3uz11vN){K zYwCU%K$QX(s$cH=kUs3k;w|ml-&sBF`fqR(4nGJ}W)gZt%r-!ogl)zs$VF;{Vb1SR zdW2jbFIX1}E7p>@&T%Hn!}0G1CdcBO(WfJo!o00JX>WY!oH*wcihKtwKDMwE>J*-U z;TuqF9|58rh0l=`EFM#Aeg3QC*-YI&L1mofKdqBJarX2@YKbn=g*cGAFCawgFQbP_ut8Cy|K~bYXr+Kxw_H`y7dHH>o9hg;Wp=m4#8BQ^FL9 zj5P2-_?Q2FqUz879VbR-e{B2g>@OF$V5DxI3ht5IMy9Psu*z_>OSlC)huXsCYBZkb zg_S8$p%&Kq@@k10l#D=4P|w1_2GVlgNK=#x;-y$seJA;1L*(tN39ok!>h5x@Uz{D-I#zWj znU3ecPgAJtpbh~bp@IN*fgzYfMt9-alQAVr203w|DPs4eT>%+8!Y)-7H~DY4mQca7 zRq*En54m=J{LkziiIxU4jA${^!JP=CT8IqMi!F`NgOe(<%6eg#sSCQTB1M5!kq8Pm zlN$uZUtG2Ljm_)MJuphX<){C!+H>6mcoq@Ave+-}P=|;@g?A9J126$OGO7_fWYhv% zlBi1sS+sgpMb_n1a~ zard0p3COd(xZ{|`6AqGSbH~DY0QqZJSipGWs+pAjbSkYB3gz;WJY_1y6U;-+49GoE zk%&izZ(c?{yixeWhVyt@e+W-p55X-<5bUGTqtB7#HfD{hW$A@Xlcg-rmh?e({Hk93 z1cH`jOYiev-LdcVQS%!!W>0^A!oGuWH{e`ZN`?SY6?PC0rZ{exjJraTDPLgPU7=9D z?BKb)9%nLL&0Irl=bY)h2z~R@`N`K*uKe^n*JzvexwYE~$VW)aL7098O8ahnZ*AFB zv`b9G&ZE*SyO7Vvf-<2l%<~J(0lq4hzYP3BZkxIJ)vL*a*M7IzlwIn7T1R7uj{;~h zrlUbvwR?0I{$%G+yCln3qyxDBj8~0*K}8zEqmJcBv&5+XMof=<)aiMSv$+rc?7H-F zgwAd2;eXf$@SGwr%nc#`b)evS*Eo4IQ^E=B^g>Pq!l13I-FhCUj73EuDf;No}J zPTG9a9#VKCx_1mhf@ZYLv zWJubql5e^4@zHwAibIpee|DwynMtKd1Z4Rz@J>n;U#Y97!LThkikszP$e*c3Vv-{M zTv}h$E3&3lR#5l{*x8r9czn;f8(#5!F#f?YKew!u9fIM{k(Ngxx}Qirf@0e!yfh7^SVw^B1%{RqF1y&^X90q+l`Xc=7{-6Fk`1xx0OOGt~|MKCX)%Y5pG`QFW zSGQ2-!q_30(h6Qj7!$Z$PKnkKRY$evWQePGIF*+Lv48AwI?bBdaR0bd-CqrTHe8Ay zmtB-z34H|A@;!=e#v>=mFHnP&IH?mRB&>|jWmNFQW~o0RsIiTJ<{RWocdpxT_Wak5 z9cO<#+Re?`uV$w_ zG67TQv!oR}2$vca;06AVKlIO-mY#fd&yA<2&j6ITB87Hm9}P#TDMB%2u6eQSV^Kx=arY++nLZ*_R5t%i^la$%lxT* zia}_ybIIWz?g>EtOz&kYXoS`sZRgQgKpx7Q#1f}hYvcI!b&e+)RZVEhps(EW=+lSh zT9+|CAAI5S+PKl{Ao`9rjLd>Mz$EDkB5pMyhKPxv2f)=1RJdWg!Bntt^?J6?94i-rw@i%}kYP)my!@M1}{di1u&tD8zAEGfPy6! zi1X1(Rp={btzutE%jJPI2|zY}nt$o!zQb?zJoNI4Igum6g9~8fiILzc_$J|&b2+(T zYykBqz+07a?usWKvD=KfY$)dACAp@Q>T>aR>&7kDPW?o&?}_rL%00pGsOVD0=BxfF#rzw8SZK{pA*<@JZB+qS9uIMtDw&dQe*%` zxoQmase7&8>6sem{!R3_|3BP8KGfcTKrScK@MZ5NVsGK;=-X}Q&`6rY=Nq(jxjd4# z84@yoU8%KzToM3LZcJAXKhL8~J)wAYXOcsik9&kq#zPQcS}3a(bV%@g;t))39Y5P^aYeX?UnjYF$hQty5QC6VrN_DZb6CGP_i+YTU5AwaKo!`}1Vau+bN;Wn5>! zZ{*d1nTKKIrQral|6B)tnsI}X;58Gr`S`;m94=vk&GSZ`%8IX&VtMKsRpszylI`0B z^*fATEtRsPEsGa&_Phl~IEw^Oh{9uj?6=;LG$2$QwfL;QK*$q}tIY*|$f(KIiVKO* zr&BJ%Oa8WmUvcNh-~PgCL(i?xESI8)s4?P$Vo(R?IwEc&8a0C(a0AFzS-o5}S8nw6 z3DQQsLtJHf%s{LIKHSi?4np=!1yXwgAP9heB6JwiIvl^8 z?c8Cr&cPDC%0LEapC)~EXd{Bi@G-mFpmtD;XVq2 zwocAi0!Hsak@s2~C)pM=k@^fq-4F!XdN0CXoL`W7 zr+)6?J0{-I2jBhP)bRxR<9zIi4yc9LflbBj`ukuw@eh=pH+sbqaaK{u)k-P3KqE2- zir=Gs6wr?1uU%%N!*_4%!q*Lq)g<99Lj!1%q@OsL*si7tf0j5~aC1Y7l+F!4xt5TQ<+!-L`U--yfAKh^3^w6rMCz5j_@4zcHf?ob= zgh71*!ycnj2zzIuO85`d&v)93%2c4Far(<)jiZEHXZ;KUai|%fBv%f5QG3;^rOs{N zfBM?HV`uCo&~IY&NNCh)6220K^aLzQglVCc3#im-6c;OfwuBl_Yiq2CSX7mJjx~#E zuzb!dRO_ul4U=`~%p0<6Hjn7$t|EiU;SMpLteGpIFu58QChHgD+-CD z5~xS=w~r!TmWompcb~mw!Ir<-*k`|GMW@fdN1#7A8QY9s3GpTp_8x(Xyum{^LT5Dj6=T#_F2zjF1alQ4ZI0sDgnO%qE_ z;?WSP0qZ>l$l5QGRC=E_Z?b4jN}oV34%c)hjcf*?5$KF~O!M@o@A6eO+B?rr`grF% zCt+l0BxOILN0KH|-Se>-cs|rW`47~WcIcGGV9BP;sd;*lG$eDl1izz=x5DpwB(%5v zo!JWAsso#M6i0l1EJN%TW{5pv3ypeT7xobaMQGDe1$+TbRZaCsU6S@&wf0Kh#CN(3 zO!+=SLzeb|;f2NXBXMNdt{19S+rQL@$qgv&qy0l0K$jMvY1cPMhSv_R?FXF0{S5`$ z!F5CHK*x4n|KPfHpp`qct{>1AuOE1HeLuj_4sKY#{?Wl9{BPjvY}h!6|2DWD;A#QA zaf92qe`w&(E_m_(-+nGf^gsH!hq=Q4DN9THe^InrXqfVfbE=5T zuSwf=wX(ocX|!`M-ybm7So`95 ZAaDN`F-943gem=YuUI&fiaGg-gdZ?Yf1fuqX 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%0A1hG)B961M*+BUbzK*T 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 OkVrwGJzxY7=>Gr~slns` literal 0 HcmV?d00001 diff --git a/core/src/test/resources/indices/bwc/repo-5.4.0.zip b/core/src/test/resources/indices/bwc/repo-5.4.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..53c565b4776273c188114fbd3d261905ff085d0e GIT binary patch literal 189447 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 Date: Thu, 4 May 2017 14:21:28 +0300 Subject: [PATCH 11/44] Tests: Switch to fedora-25 in test plugin Use fedora-25 Vagrant box in VagrantTestPlugin, which was missing from 9a3ab3e8000be059ccf4edeee53b62ddb5913fc6 causing packaging test failures. Additionally update TESTING.asciidoc --- TESTING.asciidoc | 6 +++--- .../elasticsearch/gradle/vagrant/VagrantTestPlugin.groovy | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/TESTING.asciidoc b/TESTING.asciidoc index 216100c07da..f8a54abee89 100644 --- a/TESTING.asciidoc +++ b/TESTING.asciidoc @@ -350,7 +350,7 @@ These are the linux flavors the Vagrantfile currently supports: * debian-8 aka jessie, the current debian stable distribution * centos-6 * centos-7 -* fedora-24 +* fedora-25 * oel-6 aka Oracle Enterprise Linux 6 * oel-7 aka Oracle Enterprise Linux 7 * sles-12 @@ -436,13 +436,13 @@ vagrantUbuntu1604#up. Once up, you can then connect to the VM using SSH from the elasticsearch directory: ------------------------------------------------- -vagrant ssh fedora-24 +vagrant ssh fedora-25 ------------------------------------------------- Or from another directory: ------------------------------------------------- -VAGRANT_CWD=/path/to/elasticsearch vagrant ssh fedora-24 +VAGRANT_CWD=/path/to/elasticsearch vagrant ssh fedora-25 ------------------------------------------------- Note: Starting vagrant VM outside of the elasticsearch folder requires to diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/VagrantTestPlugin.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/VagrantTestPlugin.groovy index 2fb047e9305..d314258766a 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/VagrantTestPlugin.groovy +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/VagrantTestPlugin.groovy @@ -17,7 +17,7 @@ class VagrantTestPlugin implements Plugin { 'centos-6', 'centos-7', 'debian-8', - 'fedora-24', + 'fedora-25', 'oel-6', 'oel-7', 'opensuse-13', From 07f106d39c0acd71d1ad7773d2743896e513199b Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Thu, 4 May 2017 14:14:22 +0200 Subject: [PATCH 12/44] [TEST] Rollback temporarily disabled field_caps test (#24483) --- .../rest-api-spec/test/multi_cluster/30_field_caps.yaml | 4 ++-- .../resources/rest-api-spec/test/field_caps/10_basic.yaml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/qa/multi-cluster-search/src/test/resources/rest-api-spec/test/multi_cluster/30_field_caps.yaml b/qa/multi-cluster-search/src/test/resources/rest-api-spec/test/multi_cluster/30_field_caps.yaml index d3922ca46cb..b5be2f7e124 100644 --- a/qa/multi-cluster-search/src/test/resources/rest-api-spec/test/multi_cluster/30_field_caps.yaml +++ b/qa/multi-cluster-search/src/test/resources/rest-api-spec/test/multi_cluster/30_field_caps.yaml @@ -1,8 +1,8 @@ --- "Get simple field caps from remote cluster": - skip: - version: " - 5.99.99" - reason: this uses a new API that has been added in 6.0.0 + version: " - 5.4.99" + reason: this uses a new API functionality that has been added in 5.5.0 - do: indices.create: diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/field_caps/10_basic.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/field_caps/10_basic.yaml index be2fd820a12..cef72b6e3fe 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/field_caps/10_basic.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/field_caps/10_basic.yaml @@ -76,7 +76,7 @@ setup: --- "Get simple field caps": - skip: - version: " - 5.99.99" # temporarily disabled until bwc code is backported and propagated + version: " - 5.3.99" reason: this uses a new API that has been added in 5.4.0 - do: @@ -117,7 +117,7 @@ setup: --- "Get nested field caps": - skip: - version: " - 5.99.99" # temporarily disabled until bwc code is backported and propagated + version: " - 5.3.99" reason: this uses a new API that has been added in 5.4.0 - do: @@ -148,7 +148,7 @@ setup: --- "Get prefix field caps": - skip: - version: " - 5.99.99" # temporarily disabled until bwc code is backported and propagated + version: " - 5.3.99" reason: this uses a new API that has been added in 5.4.0 - do: From 8356df0846b41f1384ac66912f705eed9ab28801 Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Thu, 4 May 2017 14:29:59 +0200 Subject: [PATCH 13/44] [TEST] Add a test that alias requests are dense for all indices --- .../action/search/TransportSearchAction.java | 10 +++++----- .../elasticsearch/search/internal/AliasFilter.java | 2 ++ .../rest-api-spec/test/multi_cluster/10_basic.yaml | 12 ++++++++++++ 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java b/core/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java index 501504631bc..9c8d1a879b1 100644 --- a/core/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java +++ b/core/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java @@ -212,25 +212,25 @@ public class TransportSearchAction extends HandledTransportAction indicesAndFilters = searchShardsResponse.getIndicesAndFilters(); + final Map indicesAndFilters = searchShardsResponse.getIndicesAndFilters(); for (ClusterSearchShardsGroup clusterSearchShardsGroup : searchShardsResponse.getGroups()) { //add the cluster name to the remote index names for indices disambiguation //this ends up in the hits returned with the search response ShardId shardId = clusterSearchShardsGroup.getShardId(); Index remoteIndex = shardId.getIndex(); - Index index = new Index(clusterAlias + RemoteClusterAware.REMOTE_CLUSTER_INDEX_SEPARATOR + remoteIndex.getName(), + Index index = new Index(RemoteClusterAware.buildRemoteIndexName(clusterAlias, remoteIndex.getName()), remoteIndex.getUUID()); OriginalIndices originalIndices = remoteIndicesByCluster.get(clusterAlias); assert originalIndices != null; SearchShardIterator shardIterator = new SearchShardIterator(clusterAlias, new ShardId(index, shardId.getId()), Arrays.asList(clusterSearchShardsGroup.getShards()), originalIndices); remoteShardIterators.add(shardIterator); - AliasFilter aliasFilter; + final AliasFilter aliasFilter; if (indicesAndFilters == null) { - aliasFilter = new AliasFilter(null, Strings.EMPTY_ARRAY); + aliasFilter = AliasFilter.EMPTY; } else { aliasFilter = indicesAndFilters.get(shardId.getIndexName()); - assert aliasFilter != null; + assert aliasFilter != null : "alias filter must not be null for index: " + shardId.getIndex(); } // here we have to map the filters to the UUID since from now on we use the uuid for the lookup aliasFilterMap.put(remoteIndex.getUUID(), aliasFilter); diff --git a/core/src/main/java/org/elasticsearch/search/internal/AliasFilter.java b/core/src/main/java/org/elasticsearch/search/internal/AliasFilter.java index f053b3d48fe..46fba776277 100644 --- a/core/src/main/java/org/elasticsearch/search/internal/AliasFilter.java +++ b/core/src/main/java/org/elasticsearch/search/internal/AliasFilter.java @@ -44,6 +44,8 @@ public final class AliasFilter implements Writeable { private final QueryBuilder filter; private final boolean reparseAliases; + public static final AliasFilter EMPTY = new AliasFilter(null, Strings.EMPTY_ARRAY); + public AliasFilter(QueryBuilder filter, String... aliases) { this.aliases = aliases == null ? Strings.EMPTY_ARRAY : aliases; this.filter = filter; diff --git a/qa/multi-cluster-search/src/test/resources/rest-api-spec/test/multi_cluster/10_basic.yaml b/qa/multi-cluster-search/src/test/resources/rest-api-spec/test/multi_cluster/10_basic.yaml index bca0703d457..e6b0e9d13c0 100644 --- a/qa/multi-cluster-search/src/test/resources/rest-api-spec/test/multi_cluster/10_basic.yaml +++ b/qa/multi-cluster-search/src/test/resources/rest-api-spec/test/multi_cluster/10_basic.yaml @@ -153,3 +153,15 @@ - match: { hits.total: 2 } - match: { hits.hits.0._source.filter_field: 1 } - match: { hits.hits.0._index: "my_remote_cluster:test_index" } + +--- +"Search an filtered alias and empty index on the remote cluster": + + - do: + search: + index: my_remote_cluster:aliased_test_index,my_remote_cluster:field_caps_index_1 + + - match: { _shards.total: 8 } + - match: { hits.total: 2 } + - match: { hits.hits.0._source.filter_field: 1 } + - match: { hits.hits.0._index: "my_remote_cluster:test_index" } From c4002e5ca44fb799bc51a0d67ee9a68961b0b0de Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Thu, 4 May 2017 14:50:05 +0200 Subject: [PATCH 14/44] Bump the Lucene version for ES V5_4_1 --- core/src/main/java/org/elasticsearch/Version.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/elasticsearch/Version.java b/core/src/main/java/org/elasticsearch/Version.java index 21b0af5f882..ea25a1bad8a 100644 --- a/core/src/main/java/org/elasticsearch/Version.java +++ b/core/src/main/java/org/elasticsearch/Version.java @@ -81,7 +81,7 @@ public class Version implements Comparable { public static final int V_5_4_0_ID_UNRELEASED = 5040099; public static final Version V_5_4_0_UNRELEASED = new Version(V_5_4_0_ID_UNRELEASED, org.apache.lucene.util.Version.LUCENE_6_5_0); public static final int V_5_4_1_ID_UNRELEASED = 5040199; - public static final Version V_5_4_1_UNRELEASED = new Version(V_5_4_1_ID_UNRELEASED, org.apache.lucene.util.Version.LUCENE_6_5_0); + public static final Version V_5_4_1_UNRELEASED = new Version(V_5_4_1_ID_UNRELEASED, org.apache.lucene.util.Version.LUCENE_6_5_1); public static final int V_5_5_0_ID_UNRELEASED = 5050099; public static final Version V_5_5_0_UNRELEASED = new Version(V_5_5_0_ID_UNRELEASED, org.apache.lucene.util.Version.LUCENE_6_5_0); public static final int V_6_0_0_alpha1_ID_UNRELEASED = 6000001; From 1fc777b6e36d30da7bb93f25da45944322febacf Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Thu, 4 May 2017 09:22:29 -0400 Subject: [PATCH 15/44] Change logging level on reroute test We are still chasing a test failure here and increasing the logging level stopped the failures. We have a theory as to what is going on so this commit reduces the logging level to hopefully trigger the failure again and give us the logging that we need to confirm the theory. --- .../org/elasticsearch/indices/recovery/IndexRecoveryIT.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/src/test/java/org/elasticsearch/indices/recovery/IndexRecoveryIT.java b/core/src/test/java/org/elasticsearch/indices/recovery/IndexRecoveryIT.java index 5fb59245935..f0f38ba48c4 100644 --- a/core/src/test/java/org/elasticsearch/indices/recovery/IndexRecoveryIT.java +++ b/core/src/test/java/org/elasticsearch/indices/recovery/IndexRecoveryIT.java @@ -242,13 +242,9 @@ public class IndexRecoveryIT extends ESIntegTestCase { @TestLogging( "_root:DEBUG," - + "org.elasticsearch.action.bulk:TRACE," - + "org.elasticsearch.action.get:TRACE," + "org.elasticsearch.cluster.service:TRACE," - + "org.elasticsearch.discovery:TRACE," + "org.elasticsearch.indices.cluster:TRACE," + "org.elasticsearch.indices.recovery:TRACE," - + "org.elasticsearch.index.seqno:TRACE," + "org.elasticsearch.index.shard:TRACE") public void testRerouteRecovery() throws Exception { logger.info("--> start node A"); From 953add8e70ac7ddd789bade84819ba86605c7bc4 Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Thu, 4 May 2017 15:56:47 +0200 Subject: [PATCH 16/44] Add 5.4.0 to bwc versions --- qa/vagrant/versions | 1 + 1 file changed, 1 insertion(+) diff --git a/qa/vagrant/versions b/qa/vagrant/versions index 996b8f7e8a2..e65c667a240 100644 --- a/qa/vagrant/versions +++ b/qa/vagrant/versions @@ -9,3 +9,4 @@ 5.3.0 5.3.1 5.3.2 +5.4.0 From d928ae210d6bf1a10b50d8057d94641e3ffd0cc5 Mon Sep 17 00:00:00 2001 From: James Baiera Date: Thu, 4 May 2017 10:17:55 -0400 Subject: [PATCH 17/44] Add Vagrant based testing fixture (#24249) --- .../gradle/test/AntFixture.groovy | 291 ++++++++++++++++++ .../gradle/test/ClusterFormationTasks.groovy | 2 +- .../elasticsearch/gradle/test/Fixture.groovy | 265 +--------------- .../gradle/test/RestIntegTestTask.groovy | 4 +- .../gradle/test/VagrantFixture.groovy | 54 ++++ .../gradle/vagrant/BatsOverVagrantTask.groovy | 11 +- .../gradle/vagrant/VagrantCommandTask.groovy | 36 ++- .../gradle/vagrant/VagrantTestPlugin.groovy | 13 +- plugins/jvm-example/build.gradle | 2 +- plugins/repository-hdfs/build.gradle | 2 +- 10 files changed, 401 insertions(+), 279 deletions(-) create mode 100644 buildSrc/src/main/groovy/org/elasticsearch/gradle/test/AntFixture.groovy create mode 100644 buildSrc/src/main/groovy/org/elasticsearch/gradle/test/VagrantFixture.groovy diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/AntFixture.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/AntFixture.groovy new file mode 100644 index 00000000000..34c3046aa2b --- /dev/null +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/AntFixture.groovy @@ -0,0 +1,291 @@ +/* + * 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.gradle.test + +import org.apache.tools.ant.taskdefs.condition.Os +import org.elasticsearch.gradle.AntTask +import org.elasticsearch.gradle.LoggedExec +import org.gradle.api.GradleException +import org.gradle.api.Task +import org.gradle.api.tasks.Exec +import org.gradle.api.tasks.Input + +/** + * A fixture for integration tests which runs in a separate process launched by Ant. + */ +public class AntFixture extends AntTask implements Fixture { + + /** The path to the executable that starts the fixture. */ + @Input + String executable + + private final List arguments = new ArrayList<>() + + @Input + public void args(Object... args) { + arguments.addAll(args) + } + + /** + * Environment variables for the fixture process. The value can be any object, which + * will have toString() called at execution time. + */ + private final Map environment = new HashMap<>() + + @Input + public void env(String key, Object value) { + environment.put(key, value) + } + + /** A flag to indicate whether the command should be executed from a shell. */ + @Input + boolean useShell = false + + /** + * A flag to indicate whether the fixture should be run in the foreground, or spawned. + * It is protected so subclasses can override (eg RunTask). + */ + protected boolean spawn = true + + /** + * A closure to call before the fixture is considered ready. The closure is passed the fixture object, + * as well as a groovy AntBuilder, to enable running ant condition checks. The default wait + * condition is for http on the http port. + */ + @Input + Closure waitCondition = { AntFixture fixture, AntBuilder ant -> + File tmpFile = new File(fixture.cwd, 'wait.success') + ant.get(src: "http://${fixture.addressAndPort}", + dest: tmpFile.toString(), + ignoreerrors: true, // do not fail on error, so logging information can be flushed + retries: 10) + return tmpFile.exists() + } + + private final Task stopTask + + public AntFixture() { + stopTask = createStopTask() + finalizedBy(stopTask) + } + + @Override + public Task getStopTask() { + return stopTask + } + + @Override + protected void runAnt(AntBuilder ant) { + project.delete(baseDir) // reset everything + cwd.mkdirs() + final String realExecutable + final List realArgs = new ArrayList<>() + final Map realEnv = environment + // We need to choose which executable we are using. In shell mode, or when we + // are spawning and thus using the wrapper script, the executable is the shell. + if (useShell || spawn) { + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + realExecutable = 'cmd' + realArgs.add('/C') + realArgs.add('"') // quote the entire command + } else { + realExecutable = 'sh' + } + } else { + realExecutable = executable + realArgs.addAll(arguments) + } + if (spawn) { + writeWrapperScript(executable) + realArgs.add(wrapperScript) + realArgs.addAll(arguments) + } + if (Os.isFamily(Os.FAMILY_WINDOWS) && (useShell || spawn)) { + realArgs.add('"') + } + commandString.eachLine { line -> logger.info(line) } + + ant.exec(executable: realExecutable, spawn: spawn, dir: cwd, taskname: name) { + realEnv.each { key, value -> env(key: key, value: value) } + realArgs.each { arg(value: it) } + } + + String failedProp = "failed${name}" + // first wait for resources, or the failure marker from the wrapper script + ant.waitfor(maxwait: '30', maxwaitunit: 'second', checkevery: '500', checkeveryunit: 'millisecond', timeoutproperty: failedProp) { + or { + resourceexists { + file(file: failureMarker.toString()) + } + and { + resourceexists { + file(file: pidFile.toString()) + } + resourceexists { + file(file: portsFile.toString()) + } + } + } + } + + if (ant.project.getProperty(failedProp) || failureMarker.exists()) { + fail("Failed to start ${name}") + } + + // the process is started (has a pid) and is bound to a network interface + // so now wait undil the waitCondition has been met + // TODO: change this to a loop? + boolean success + try { + success = waitCondition(this, ant) == false + } catch (Exception e) { + String msg = "Wait condition caught exception for ${name}" + logger.error(msg, e) + fail(msg, e) + } + if (success == false) { + fail("Wait condition failed for ${name}") + } + } + + /** Returns a debug string used to log information about how the fixture was run. */ + protected String getCommandString() { + String commandString = "\n${name} configuration:\n" + commandString += "-----------------------------------------\n" + commandString += " cwd: ${cwd}\n" + commandString += " command: ${executable} ${arguments.join(' ')}\n" + commandString += ' environment:\n' + environment.each { k, v -> commandString += " ${k}: ${v}\n" } + if (spawn) { + commandString += "\n [${wrapperScript.name}]\n" + wrapperScript.eachLine('UTF-8', { line -> commandString += " ${line}\n"}) + } + return commandString + } + + /** + * Writes a script to run the real executable, so that stdout/stderr can be captured. + * TODO: this could be removed if we do use our own ProcessBuilder and pump output from the process + */ + private void writeWrapperScript(String executable) { + wrapperScript.parentFile.mkdirs() + String argsPasser = '"$@"' + String exitMarker = "; if [ \$? != 0 ]; then touch run.failed; fi" + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + argsPasser = '%*' + exitMarker = "\r\n if \"%errorlevel%\" neq \"0\" ( type nul >> run.failed )" + } + wrapperScript.setText("\"${executable}\" ${argsPasser} > run.log 2>&1 ${exitMarker}", 'UTF-8') + } + + /** Fail the build with the given message, and logging relevant info*/ + private void fail(String msg, Exception... suppressed) { + if (logger.isInfoEnabled() == false) { + // We already log the command at info level. No need to do it twice. + commandString.eachLine { line -> logger.error(line) } + } + logger.error("${name} output:") + logger.error("-----------------------------------------") + logger.error(" failure marker exists: ${failureMarker.exists()}") + logger.error(" pid file exists: ${pidFile.exists()}") + logger.error(" ports file exists: ${portsFile.exists()}") + // also dump the log file for the startup script (which will include ES logging output to stdout) + if (runLog.exists()) { + logger.error("\n [log]") + runLog.eachLine { line -> logger.error(" ${line}") } + } + logger.error("-----------------------------------------") + GradleException toThrow = new GradleException(msg) + for (Exception e : suppressed) { + toThrow.addSuppressed(e) + } + throw toThrow + } + + /** Adds a task to kill an elasticsearch node with the given pidfile */ + private Task createStopTask() { + final AntFixture fixture = this + final Object pid = "${ -> fixture.pid }" + Exec stop = project.tasks.create(name: "${name}#stop", type: LoggedExec) + stop.onlyIf { fixture.pidFile.exists() } + stop.doFirst { + logger.info("Shutting down ${fixture.name} with pid ${pid}") + } + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + stop.executable = 'Taskkill' + stop.args('/PID', pid, '/F') + } else { + stop.executable = 'kill' + stop.args('-9', pid) + } + stop.doLast { + project.delete(fixture.pidFile) + } + return stop + } + + /** + * A path relative to the build dir that all configuration and runtime files + * will live in for this fixture + */ + protected File getBaseDir() { + return new File(project.buildDir, "fixtures/${name}") + } + + /** Returns the working directory for the process. Defaults to "cwd" inside baseDir. */ + protected File getCwd() { + return new File(baseDir, 'cwd') + } + + /** Returns the file the process writes its pid to. Defaults to "pid" inside baseDir. */ + protected File getPidFile() { + return new File(baseDir, 'pid') + } + + /** Reads the pid file and returns the process' pid */ + public int getPid() { + return Integer.parseInt(pidFile.getText('UTF-8').trim()) + } + + /** Returns the file the process writes its bound ports to. Defaults to "ports" inside baseDir. */ + protected File getPortsFile() { + return new File(baseDir, 'ports') + } + + /** Returns an address and port suitable for a uri to connect to this node over http */ + public String getAddressAndPort() { + return portsFile.readLines("UTF-8").get(0) + } + + /** Returns a file that wraps around the actual command when {@code spawn == true}. */ + protected File getWrapperScript() { + return new File(cwd, Os.isFamily(Os.FAMILY_WINDOWS) ? 'run.bat' : 'run') + } + + /** Returns a file that the wrapper script writes when the command failed. */ + protected File getFailureMarker() { + return new File(cwd, 'run.failed') + } + + /** Returns a file that the wrapper script writes when the command failed. */ + protected File getRunLog() { + return new File(cwd, 'run.log') + } +} diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterFormationTasks.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterFormationTasks.groovy index 8a4dc72d15a..4e9d8a63f0f 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterFormationTasks.groovy +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterFormationTasks.groovy @@ -208,7 +208,7 @@ class ClusterFormationTasks { start.finalizedBy(stop) for (Object dependency : config.dependencies) { if (dependency instanceof Fixture) { - Task depStop = ((Fixture)dependency).stopTask + def depStop = ((Fixture)dependency).stopTask runner.finalizedBy(depStop) start.finalizedBy(depStop) } diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/Fixture.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/Fixture.groovy index 46b81624ba3..498a1627b35 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/Fixture.groovy +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/Fixture.groovy @@ -16,272 +16,15 @@ * specific language governing permissions and limitations * under the License. */ - package org.elasticsearch.gradle.test -import org.apache.tools.ant.taskdefs.condition.Os -import org.elasticsearch.gradle.AntTask -import org.elasticsearch.gradle.LoggedExec -import org.gradle.api.GradleException -import org.gradle.api.Task -import org.gradle.api.tasks.Exec -import org.gradle.api.tasks.Input - /** - * A fixture for integration tests which runs in a separate process. + * Any object that can produce an accompanying stop task, meant to tear down + * a previously instantiated service. */ -public class Fixture extends AntTask { - - /** The path to the executable that starts the fixture. */ - @Input - String executable - - private final List arguments = new ArrayList<>() - - @Input - public void args(Object... args) { - arguments.addAll(args) - } - - /** - * Environment variables for the fixture process. The value can be any object, which - * will have toString() called at execution time. - */ - private final Map environment = new HashMap<>() - - @Input - public void env(String key, Object value) { - environment.put(key, value) - } - - /** A flag to indicate whether the command should be executed from a shell. */ - @Input - boolean useShell = false - - /** - * A flag to indicate whether the fixture should be run in the foreground, or spawned. - * It is protected so subclasses can override (eg RunTask). - */ - protected boolean spawn = true - - /** - * A closure to call before the fixture is considered ready. The closure is passed the fixture object, - * as well as a groovy AntBuilder, to enable running ant condition checks. The default wait - * condition is for http on the http port. - */ - @Input - Closure waitCondition = { Fixture fixture, AntBuilder ant -> - File tmpFile = new File(fixture.cwd, 'wait.success') - ant.get(src: "http://${fixture.addressAndPort}", - dest: tmpFile.toString(), - ignoreerrors: true, // do not fail on error, so logging information can be flushed - retries: 10) - return tmpFile.exists() - } +public interface Fixture { /** A task which will stop this fixture. This should be used as a finalizedBy for any tasks that use the fixture. */ - public final Task stopTask + public Object getStopTask() - public Fixture() { - stopTask = createStopTask() - finalizedBy(stopTask) - } - - @Override - protected void runAnt(AntBuilder ant) { - project.delete(baseDir) // reset everything - cwd.mkdirs() - final String realExecutable - final List realArgs = new ArrayList<>() - final Map realEnv = environment - // We need to choose which executable we are using. In shell mode, or when we - // are spawning and thus using the wrapper script, the executable is the shell. - if (useShell || spawn) { - if (Os.isFamily(Os.FAMILY_WINDOWS)) { - realExecutable = 'cmd' - realArgs.add('/C') - realArgs.add('"') // quote the entire command - } else { - realExecutable = 'sh' - } - } else { - realExecutable = executable - realArgs.addAll(arguments) - } - if (spawn) { - writeWrapperScript(executable) - realArgs.add(wrapperScript) - realArgs.addAll(arguments) - } - if (Os.isFamily(Os.FAMILY_WINDOWS) && (useShell || spawn)) { - realArgs.add('"') - } - commandString.eachLine { line -> logger.info(line) } - - ant.exec(executable: realExecutable, spawn: spawn, dir: cwd, taskname: name) { - realEnv.each { key, value -> env(key: key, value: value) } - realArgs.each { arg(value: it) } - } - - String failedProp = "failed${name}" - // first wait for resources, or the failure marker from the wrapper script - ant.waitfor(maxwait: '30', maxwaitunit: 'second', checkevery: '500', checkeveryunit: 'millisecond', timeoutproperty: failedProp) { - or { - resourceexists { - file(file: failureMarker.toString()) - } - and { - resourceexists { - file(file: pidFile.toString()) - } - resourceexists { - file(file: portsFile.toString()) - } - } - } - } - - if (ant.project.getProperty(failedProp) || failureMarker.exists()) { - fail("Failed to start ${name}") - } - - // the process is started (has a pid) and is bound to a network interface - // so now wait undil the waitCondition has been met - // TODO: change this to a loop? - boolean success - try { - success = waitCondition(this, ant) == false - } catch (Exception e) { - String msg = "Wait condition caught exception for ${name}" - logger.error(msg, e) - fail(msg, e) - } - if (success == false) { - fail("Wait condition failed for ${name}") - } - } - - /** Returns a debug string used to log information about how the fixture was run. */ - protected String getCommandString() { - String commandString = "\n${name} configuration:\n" - commandString += "-----------------------------------------\n" - commandString += " cwd: ${cwd}\n" - commandString += " command: ${executable} ${arguments.join(' ')}\n" - commandString += ' environment:\n' - environment.each { k, v -> commandString += " ${k}: ${v}\n" } - if (spawn) { - commandString += "\n [${wrapperScript.name}]\n" - wrapperScript.eachLine('UTF-8', { line -> commandString += " ${line}\n"}) - } - return commandString - } - - /** - * Writes a script to run the real executable, so that stdout/stderr can be captured. - * TODO: this could be removed if we do use our own ProcessBuilder and pump output from the process - */ - private void writeWrapperScript(String executable) { - wrapperScript.parentFile.mkdirs() - String argsPasser = '"$@"' - String exitMarker = "; if [ \$? != 0 ]; then touch run.failed; fi" - if (Os.isFamily(Os.FAMILY_WINDOWS)) { - argsPasser = '%*' - exitMarker = "\r\n if \"%errorlevel%\" neq \"0\" ( type nul >> run.failed )" - } - wrapperScript.setText("\"${executable}\" ${argsPasser} > run.log 2>&1 ${exitMarker}", 'UTF-8') - } - - /** Fail the build with the given message, and logging relevant info*/ - private void fail(String msg, Exception... suppressed) { - if (logger.isInfoEnabled() == false) { - // We already log the command at info level. No need to do it twice. - commandString.eachLine { line -> logger.error(line) } - } - logger.error("${name} output:") - logger.error("-----------------------------------------") - logger.error(" failure marker exists: ${failureMarker.exists()}") - logger.error(" pid file exists: ${pidFile.exists()}") - logger.error(" ports file exists: ${portsFile.exists()}") - // also dump the log file for the startup script (which will include ES logging output to stdout) - if (runLog.exists()) { - logger.error("\n [log]") - runLog.eachLine { line -> logger.error(" ${line}") } - } - logger.error("-----------------------------------------") - GradleException toThrow = new GradleException(msg) - for (Exception e : suppressed) { - toThrow.addSuppressed(e) - } - throw toThrow - } - - /** Adds a task to kill an elasticsearch node with the given pidfile */ - private Task createStopTask() { - final Fixture fixture = this - final Object pid = "${ -> fixture.pid }" - Exec stop = project.tasks.create(name: "${name}#stop", type: LoggedExec) - stop.onlyIf { fixture.pidFile.exists() } - stop.doFirst { - logger.info("Shutting down ${fixture.name} with pid ${pid}") - } - if (Os.isFamily(Os.FAMILY_WINDOWS)) { - stop.executable = 'Taskkill' - stop.args('/PID', pid, '/F') - } else { - stop.executable = 'kill' - stop.args('-9', pid) - } - stop.doLast { - project.delete(fixture.pidFile) - } - return stop - } - - /** - * A path relative to the build dir that all configuration and runtime files - * will live in for this fixture - */ - protected File getBaseDir() { - return new File(project.buildDir, "fixtures/${name}") - } - - /** Returns the working directory for the process. Defaults to "cwd" inside baseDir. */ - protected File getCwd() { - return new File(baseDir, 'cwd') - } - - /** Returns the file the process writes its pid to. Defaults to "pid" inside baseDir. */ - protected File getPidFile() { - return new File(baseDir, 'pid') - } - - /** Reads the pid file and returns the process' pid */ - public int getPid() { - return Integer.parseInt(pidFile.getText('UTF-8').trim()) - } - - /** Returns the file the process writes its bound ports to. Defaults to "ports" inside baseDir. */ - protected File getPortsFile() { - return new File(baseDir, 'ports') - } - - /** Returns an address and port suitable for a uri to connect to this node over http */ - public String getAddressAndPort() { - return portsFile.readLines("UTF-8").get(0) - } - - /** Returns a file that wraps around the actual command when {@code spawn == true}. */ - protected File getWrapperScript() { - return new File(cwd, Os.isFamily(Os.FAMILY_WINDOWS) ? 'run.bat' : 'run') - } - - /** Returns a file that the wrapper script writes when the command failed. */ - protected File getFailureMarker() { - return new File(cwd, 'run.failed') - } - - /** Returns a file that the wrapper script writes when the command failed. */ - protected File getRunLog() { - return new File(cwd, 'run.log') - } } diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/RestIntegTestTask.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/RestIntegTestTask.groovy index 98ee91e37a8..0b19822a7f1 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/RestIntegTestTask.groovy +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/RestIntegTestTask.groovy @@ -129,7 +129,7 @@ public class RestIntegTestTask extends DefaultTask { runner.dependsOn(dependencies) for (Object dependency : dependencies) { if (dependency instanceof Fixture) { - runner.finalizedBy(((Fixture)dependency).stopTask) + runner.finalizedBy(((Fixture)dependency).getStopTask()) } } return this @@ -140,7 +140,7 @@ public class RestIntegTestTask extends DefaultTask { runner.setDependsOn(dependencies) for (Object dependency : dependencies) { if (dependency instanceof Fixture) { - runner.finalizedBy(((Fixture)dependency).stopTask) + runner.finalizedBy(((Fixture)dependency).getStopTask()) } } } diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/VagrantFixture.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/VagrantFixture.groovy new file mode 100644 index 00000000000..fa08a8f9c66 --- /dev/null +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/VagrantFixture.groovy @@ -0,0 +1,54 @@ +/* + * 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.gradle.test + +import org.elasticsearch.gradle.vagrant.VagrantCommandTask +import org.gradle.api.Task + +/** + * A fixture for integration tests which runs in a virtual machine launched by Vagrant. + */ +class VagrantFixture extends VagrantCommandTask implements Fixture { + + private VagrantCommandTask stopTask + + public VagrantFixture() { + this.stopTask = project.tasks.create(name: "${name}#stop", type: VagrantCommandTask) { + command 'halt' + } + finalizedBy this.stopTask + } + + @Override + void setBoxName(String boxName) { + super.setBoxName(boxName) + this.stopTask.setBoxName(boxName) + } + + @Override + void setEnvironmentVars(Map environmentVars) { + super.setEnvironmentVars(environmentVars) + this.stopTask.setEnvironmentVars(environmentVars) + } + + @Override + public Task getStopTask() { + return this.stopTask + } +} diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/BatsOverVagrantTask.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/BatsOverVagrantTask.groovy index 65b90c4d9a0..110f2fc7e84 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/BatsOverVagrantTask.groovy +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/BatsOverVagrantTask.groovy @@ -27,12 +27,15 @@ import org.gradle.api.tasks.Input public class BatsOverVagrantTask extends VagrantCommandTask { @Input - String command + String remoteCommand BatsOverVagrantTask() { - project.afterEvaluate { - args 'ssh', boxName, '--command', command - } + command = 'ssh' + } + + void setRemoteCommand(String remoteCommand) { + this.remoteCommand = Objects.requireNonNull(remoteCommand) + setArgs(['--command', remoteCommand]) } @Override diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/VagrantCommandTask.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/VagrantCommandTask.groovy index abc6af9e09d..aab120e8d04 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/VagrantCommandTask.groovy +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/VagrantCommandTask.groovy @@ -21,9 +21,15 @@ package org.elasticsearch.gradle.vagrant import org.apache.commons.io.output.TeeOutputStream import org.elasticsearch.gradle.LoggedExec import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Optional +import org.gradle.api.tasks.TaskAction import org.gradle.internal.logging.progress.ProgressLoggerFactory import javax.inject.Inject +import java.util.concurrent.CountDownLatch +import java.util.concurrent.locks.Lock +import java.util.concurrent.locks.ReadWriteLock +import java.util.concurrent.locks.ReentrantLock /** * Runs a vagrant command. Pretty much like Exec task but with a nicer output @@ -31,6 +37,12 @@ import javax.inject.Inject */ public class VagrantCommandTask extends LoggedExec { + @Input + String command + + @Input @Optional + String subcommand + @Input String boxName @@ -40,11 +52,27 @@ public class VagrantCommandTask extends LoggedExec { public VagrantCommandTask() { executable = 'vagrant' + // We're using afterEvaluate here to slot in some logic that captures configurations and + // modifies the command line right before the main execution happens. The reason that we + // call doFirst instead of just doing the work in the afterEvaluate is that the latter + // restricts how subclasses can extend functionality. Calling afterEvaluate is like having + // all the logic of a task happening at construction time, instead of at execution time + // where a subclass can override or extend the logic. project.afterEvaluate { - // It'd be nice if --machine-readable were, well, nice - standardOutput = new TeeOutputStream(standardOutput, createLoggerOutputStream()) - if (environmentVars != null) { - environment environmentVars + doFirst { + if (environmentVars != null) { + environment environmentVars + } + + // Build our command line for vagrant + def vagrantCommand = [executable, command] + if (subcommand != null) { + vagrantCommand = vagrantCommand + subcommand + } + commandLine([*vagrantCommand, boxName, *args]) + + // It'd be nice if --machine-readable were, well, nice + standardOutput = new TeeOutputStream(standardOutput, createLoggerOutputStream()) } } } diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/VagrantTestPlugin.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/VagrantTestPlugin.groovy index d314258766a..9df6d36ef01 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/VagrantTestPlugin.groovy +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/VagrantTestPlugin.groovy @@ -391,21 +391,23 @@ class VagrantTestPlugin implements Plugin { // always add a halt task for all boxes, so clean makes sure they are all shutdown Task halt = project.tasks.create("vagrant${boxTask}#halt", VagrantCommandTask) { + command 'halt' boxName box environmentVars vagrantEnvVars - args 'halt', box } stop.dependsOn(halt) Task update = project.tasks.create("vagrant${boxTask}#update", VagrantCommandTask) { + command 'box' + subcommand 'update' boxName box environmentVars vagrantEnvVars - args 'box', 'update', box dependsOn vagrantCheckVersion, virtualboxCheckVersion } update.mustRunAfter(setupBats) Task up = project.tasks.create("vagrant${boxTask}#up", VagrantCommandTask) { + command 'up' boxName box environmentVars vagrantEnvVars /* Its important that we try to reprovision the box even if it already @@ -418,7 +420,7 @@ class VagrantTestPlugin implements Plugin { vagrant's default but its possible to change that default and folks do. But the boxes that we use are unlikely to work properly with other virtualization providers. Thus the lock. */ - args 'up', box, '--provision', '--provider', 'virtualbox' + args '--provision', '--provider', 'virtualbox' /* It'd be possible to check if the box is already up here and output SKIPPED but that would require running vagrant status which is slow! */ dependsOn update @@ -434,11 +436,11 @@ class VagrantTestPlugin implements Plugin { vagrantSmokeTest.dependsOn(smoke) Task packaging = project.tasks.create("vagrant${boxTask}#packagingTest", BatsOverVagrantTask) { + remoteCommand BATS_TEST_COMMAND boxName box environmentVars vagrantEnvVars dependsOn up, setupBats finalizedBy halt - command BATS_TEST_COMMAND } TaskExecutionAdapter packagingReproListener = new TaskExecutionAdapter() { @@ -461,11 +463,12 @@ class VagrantTestPlugin implements Plugin { } Task platform = project.tasks.create("vagrant${boxTask}#platformTest", VagrantCommandTask) { + command 'ssh' boxName box environmentVars vagrantEnvVars dependsOn up finalizedBy halt - args 'ssh', boxName, '--command', PLATFORM_TEST_COMMAND + " -Dtests.seed=${-> project.extensions.esvagrant.formattedTestSeed}" + args '--command', PLATFORM_TEST_COMMAND + " -Dtests.seed=${-> project.extensions.esvagrant.formattedTestSeed}" } TaskExecutionAdapter platformReproListener = new TaskExecutionAdapter() { @Override diff --git a/plugins/jvm-example/build.gradle b/plugins/jvm-example/build.gradle index e8a37a144a5..fb362e6fa36 100644 --- a/plugins/jvm-example/build.gradle +++ b/plugins/jvm-example/build.gradle @@ -33,7 +33,7 @@ dependencies { exampleFixture project(':test:fixtures:example-fixture') } -task exampleFixture(type: org.elasticsearch.gradle.test.Fixture) { +task exampleFixture(type: org.elasticsearch.gradle.test.AntFixture) { dependsOn project.configurations.exampleFixture executable = new File(project.javaHome, 'bin/java') args '-cp', "${ -> project.configurations.exampleFixture.asPath }", diff --git a/plugins/repository-hdfs/build.gradle b/plugins/repository-hdfs/build.gradle index 82548f3410e..f17819dba40 100644 --- a/plugins/repository-hdfs/build.gradle +++ b/plugins/repository-hdfs/build.gradle @@ -60,7 +60,7 @@ dependencyLicenses { mapping from: /hadoop-.*/, to: 'hadoop' } -task hdfsFixture(type: org.elasticsearch.gradle.test.Fixture) { +task hdfsFixture(type: org.elasticsearch.gradle.test.AntFixture) { dependsOn project.configurations.hdfsFixture executable = new File(project.javaHome, 'bin/java') env 'CLASSPATH', "${ -> project.configurations.hdfsFixture.asPath }" From 977016ba2503648af98be9aa831b4107bf6f1d1c Mon Sep 17 00:00:00 2001 From: Adrien Grand Date: Thu, 4 May 2017 16:29:35 +0200 Subject: [PATCH 18/44] Do not index `_type` when there is at most one type. (#24363) This change makes `_type` behave pretty much like `_index` when `index.mapping.single_type` is true. --- .../common/lucene/search/Queries.java | 35 +----- ...dData.java => ConstantIndexFieldData.java} | 28 +++-- .../index/mapper/DocumentMapper.java | 7 +- .../index/mapper/IndexFieldMapper.java | 4 +- .../index/mapper/TypeFieldMapper.java | 117 ++++++++++-------- .../index/query/HasChildQueryBuilder.java | 4 +- .../index/query/HasParentQueryBuilder.java | 6 +- .../index/query/QueryRewriteContext.java | 4 +- .../index/query/TypeQueryBuilder.java | 2 +- .../search/DefaultSearchContext.java | 11 +- .../children/ChildrenAggregationBuilder.java | 4 +- .../fetch/subphase/InnerHitsContext.java | 2 +- .../mapper/FieldNamesFieldMapperTests.java | 4 +- .../index/mapper/MapperServiceTests.java | 6 +- .../index/mapper/TypeFieldMapperTests.java | 84 +++++++++++-- .../index/mapper/TypeFieldTypeTests.java | 71 +++++++++-- .../ParentToChildrenAggregatorTests.java | 5 +- docs/reference/search/validate.asciidoc | 6 +- 18 files changed, 256 insertions(+), 144 deletions(-) rename core/src/main/java/org/elasticsearch/index/fielddata/plain/{IndexIndexFieldData.java => ConstantIndexFieldData.java} (83%) diff --git a/core/src/main/java/org/elasticsearch/common/lucene/search/Queries.java b/core/src/main/java/org/elasticsearch/common/lucene/search/Queries.java index acf3f9ffdf8..60673777546 100644 --- a/core/src/main/java/org/elasticsearch/common/lucene/search/Queries.java +++ b/core/src/main/java/org/elasticsearch/common/lucene/search/Queries.java @@ -21,7 +21,6 @@ package org.elasticsearch.common.lucene.search; import org.apache.lucene.index.Term; import org.apache.lucene.queries.ExtendedCommonTermsQuery; -import org.apache.lucene.search.AutomatonQuery; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanClause.Occur; import org.apache.lucene.search.BooleanQuery; @@ -31,9 +30,6 @@ import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.PrefixQuery; import org.apache.lucene.search.Query; import org.apache.lucene.util.BytesRef; -import org.apache.lucene.util.automaton.Automata; -import org.apache.lucene.util.automaton.Automaton; -import org.apache.lucene.util.automaton.Operations; import org.elasticsearch.common.Nullable; import org.elasticsearch.index.mapper.TypeFieldMapper; @@ -42,29 +38,6 @@ import java.util.regex.Pattern; public class Queries { - private static final Automaton NON_NESTED_TYPE_AUTOMATON; - static { - Automaton nestedTypeAutomaton = Operations.concatenate( - Automata.makeString("__"), - Automata.makeAnyString()); - NON_NESTED_TYPE_AUTOMATON = Operations.complement(nestedTypeAutomaton, Operations.DEFAULT_MAX_DETERMINIZED_STATES); - } - - // We use a custom class rather than AutomatonQuery directly in order to - // have a better toString - private static class NonNestedQuery extends AutomatonQuery { - - NonNestedQuery() { - super(new Term(TypeFieldMapper.NAME), NON_NESTED_TYPE_AUTOMATON); - } - - @Override - public String toString(String field) { - return "_type:[^_].*"; - } - - } - public static Query newMatchAllQuery() { return new MatchAllDocsQuery(); } @@ -79,9 +52,11 @@ public class Queries { } public static Query newNonNestedFilter() { - // we use this automaton query rather than a negation of newNestedFilter - // since purely negative queries against high-cardinality clauses are costly - return new NonNestedQuery(); + // TODO: this is slow, make it a positive query + return new BooleanQuery.Builder() + .add(new MatchAllDocsQuery(), Occur.FILTER) + .add(newNestedFilter(), Occur.MUST_NOT) + .build(); } public static BooleanQuery filtered(@Nullable Query query, @Nullable Query filter) { diff --git a/core/src/main/java/org/elasticsearch/index/fielddata/plain/IndexIndexFieldData.java b/core/src/main/java/org/elasticsearch/index/fielddata/plain/ConstantIndexFieldData.java similarity index 83% rename from core/src/main/java/org/elasticsearch/index/fielddata/plain/IndexIndexFieldData.java rename to core/src/main/java/org/elasticsearch/index/fielddata/plain/ConstantIndexFieldData.java index 53832c0b5b1..ebf959e92e1 100644 --- a/core/src/main/java/org/elasticsearch/index/fielddata/plain/IndexIndexFieldData.java +++ b/core/src/main/java/org/elasticsearch/index/fielddata/plain/ConstantIndexFieldData.java @@ -44,26 +44,33 @@ import org.elasticsearch.search.MultiValueMode; import java.io.IOException; import java.util.Collection; import java.util.Collections; +import java.util.function.Function; -public class IndexIndexFieldData extends AbstractIndexOrdinalsFieldData { +public class ConstantIndexFieldData extends AbstractIndexOrdinalsFieldData { public static class Builder implements IndexFieldData.Builder { + private final Function valueFunction; + + public Builder(Function valueFunction) { + this.valueFunction = valueFunction; + } + @Override public IndexFieldData build(IndexSettings indexSettings, MappedFieldType fieldType, IndexFieldDataCache cache, CircuitBreakerService breakerService, MapperService mapperService) { - return new IndexIndexFieldData(indexSettings, fieldType.name()); + return new ConstantIndexFieldData(indexSettings, fieldType.name(), valueFunction.apply(mapperService)); } } - private static class IndexAtomicFieldData extends AbstractAtomicOrdinalsFieldData { + private static class ConstantAtomicFieldData extends AbstractAtomicOrdinalsFieldData { - private final String index; + private final String value; - IndexAtomicFieldData(String index) { + ConstantAtomicFieldData(String value) { super(DEFAULT_SCRIPT_FUNCTION); - this.index = index; + this.value = value; } @Override @@ -78,7 +85,7 @@ public class IndexIndexFieldData extends AbstractIndexOrdinalsFieldData { @Override public SortedSetDocValues getOrdinalsValues() { - final BytesRef term = new BytesRef(index); + final BytesRef term = new BytesRef(value); final SortedDocValues sortedValues = new AbstractSortedDocValues() { private int docID = -1; @@ -120,12 +127,12 @@ public class IndexIndexFieldData extends AbstractIndexOrdinalsFieldData { private final AtomicOrdinalsFieldData atomicFieldData; - private IndexIndexFieldData(IndexSettings indexSettings, String name) { + private ConstantIndexFieldData(IndexSettings indexSettings, String name, String value) { super(indexSettings, name, null, null, TextFieldMapper.Defaults.FIELDDATA_MIN_FREQUENCY, TextFieldMapper.Defaults.FIELDDATA_MAX_FREQUENCY, TextFieldMapper.Defaults.FIELDDATA_MIN_SEGMENT_SIZE); - atomicFieldData = new IndexAtomicFieldData(index().getName()); + atomicFieldData = new ConstantAtomicFieldData(value); } @Override @@ -144,7 +151,8 @@ public class IndexIndexFieldData extends AbstractIndexOrdinalsFieldData { } @Override - public SortField sortField(@Nullable Object missingValue, MultiValueMode sortMode, XFieldComparatorSource.Nested nested, boolean reverse) { + public SortField sortField(@Nullable Object missingValue, MultiValueMode sortMode, XFieldComparatorSource.Nested nested, + boolean reverse) { final XFieldComparatorSource source = new BytesRefFieldComparatorSource(this, missingValue, sortMode, nested); return new SortField(getFieldName(), source, reverse); } diff --git a/core/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java index 39280bcee20..a8d172a5112 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java @@ -24,17 +24,16 @@ import org.apache.lucene.search.Query; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.elasticsearch.ElasticsearchGenerationException; -import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.compress.CompressedXContent; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.text.Text; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.analysis.IndexAnalyzers; import org.elasticsearch.index.mapper.MetadataFieldMapper.TypeParser; +import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.search.internal.SearchContext; import java.io.IOException; @@ -241,8 +240,8 @@ public class DocumentMapper implements ToXContent { return metadataMapper(IndexFieldMapper.class); } - public Query typeFilter() { - return typeMapper().fieldType().termQuery(type, null); + public Query typeFilter(QueryShardContext context) { + return typeMapper().fieldType().termQuery(type, context); } public boolean hasNestedObjects() { diff --git a/core/src/main/java/org/elasticsearch/index/mapper/IndexFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/IndexFieldMapper.java index c961b74d77a..c85f5d7d9fa 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/IndexFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/IndexFieldMapper.java @@ -30,7 +30,7 @@ import org.elasticsearch.common.lucene.search.Queries; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.index.fielddata.IndexFieldData; -import org.elasticsearch.index.fielddata.plain.IndexIndexFieldData; +import org.elasticsearch.index.fielddata.plain.ConstantIndexFieldData; import org.elasticsearch.index.query.QueryShardContext; import java.io.IOException; @@ -157,7 +157,7 @@ public class IndexFieldMapper extends MetadataFieldMapper { @Override public IndexFieldData.Builder fielddataBuilder() { - return new IndexIndexFieldData.Builder(); + return new ConstantIndexFieldData.Builder(mapperService -> mapperService.index().getName()); } } diff --git a/core/src/main/java/org/elasticsearch/index/mapper/TypeFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/TypeFieldMapper.java index c24747e62c8..9d4a4a6987b 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/TypeFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/TypeFieldMapper.java @@ -30,26 +30,29 @@ import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.ConstantScoreQuery; import org.apache.lucene.search.MatchAllDocsQuery; +import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TermInSetQuery; import org.apache.lucene.util.BytesRef; -import org.elasticsearch.common.Nullable; +import org.elasticsearch.action.fieldstats.FieldStats; import org.elasticsearch.common.lucene.Lucene; +import org.elasticsearch.common.lucene.search.Queries; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.index.fielddata.IndexFieldData; import org.elasticsearch.index.fielddata.plain.DocValuesIndexFieldData; -import org.elasticsearch.index.fielddata.plain.PagedBytesIndexFieldData; +import org.elasticsearch.index.fielddata.plain.ConstantIndexFieldData; import org.elasticsearch.index.query.QueryShardContext; import java.io.IOException; import java.util.Arrays; +import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; +import java.util.function.Function; public class TypeFieldMapper extends MetadataFieldMapper { @@ -88,29 +91,12 @@ public class TypeFieldMapper extends MetadataFieldMapper { } static final class TypeFieldType extends StringFieldType { - private boolean fielddata; TypeFieldType() { - this.fielddata = false; } protected TypeFieldType(TypeFieldType ref) { super(ref); - this.fielddata = ref.fielddata; - } - - @Override - public boolean equals(Object o) { - if (super.equals(o) == false) { - return false; - } - TypeFieldType that = (TypeFieldType) o; - return fielddata == that.fielddata; - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), fielddata); } @Override @@ -123,49 +109,76 @@ public class TypeFieldMapper extends MetadataFieldMapper { return CONTENT_TYPE; } - public boolean fielddata() { - return fielddata; - } - - public void setFielddata(boolean fielddata) { - checkIfFrozen(); - this.fielddata = fielddata; - } - @Override public IndexFieldData.Builder fielddataBuilder() { if (hasDocValues()) { return new DocValuesIndexFieldData.Builder(); + } else { + // means the index has a single type and the type field is implicit + Function typeFunction = mapperService -> { + Collection types = mapperService.types(); + if (types.size() > 1) { + throw new AssertionError(); + } + // If we reach here, there is necessarily one type since we were able to find a `_type` field + String type = types.iterator().next(); + return type; + }; + return new ConstantIndexFieldData.Builder(typeFunction); } - assert indexOptions() != IndexOptions.NONE; - if (fielddata) { - return new PagedBytesIndexFieldData.Builder(TextFieldMapper.Defaults.FIELDDATA_MIN_FREQUENCY, - TextFieldMapper.Defaults.FIELDDATA_MAX_FREQUENCY, - TextFieldMapper.Defaults.FIELDDATA_MIN_SEGMENT_SIZE); - } - return super.fielddataBuilder(); } @Override - public Query termQuery(Object value, @Nullable QueryShardContext context) { - if (indexOptions() == IndexOptions.NONE) { - throw new AssertionError(); + public FieldStats stats(IndexReader reader) throws IOException { + if (reader.maxDoc() == 0) { + return null; } - return new TypesQuery(indexedValueForSearch(value)); + return new FieldStats.Text(reader.maxDoc(), reader.numDocs(), reader.maxDoc(), reader.maxDoc(), + isSearchable(), isAggregatable()); } @Override - public void checkCompatibility(MappedFieldType other, - List conflicts, boolean strict) { - super.checkCompatibility(other, conflicts, strict); - TypeFieldType otherType = (TypeFieldType) other; - if (strict) { - if (fielddata() != otherType.fielddata()) { - conflicts.add("mapper [" + name() + "] is used by multiple types. Set update_all_types to true to update [fielddata] " - + "across all types."); + public boolean isSearchable() { + return true; + } + + @Override + public Query termQuery(Object value, QueryShardContext context) { + return termsQuery(Arrays.asList(value), context); + } + + @Override + public Query termsQuery(List values, QueryShardContext context) { + if (context.getIndexSettings().getValue(MapperService.INDEX_MAPPING_SINGLE_TYPE_SETTING)) { + Collection indexTypes = context.getMapperService().types(); + if (indexTypes.isEmpty()) { + return new MatchNoDocsQuery("No types"); } + assert indexTypes.size() == 1; + BytesRef indexType = indexedValueForSearch(indexTypes.iterator().next()); + if (values.stream() + .map(this::indexedValueForSearch) + .anyMatch(indexType::equals)) { + if (context.getMapperService().hasNested()) { + // type filters are expected not to match nested docs + return Queries.newNonNestedFilter(); + } else { + return new MatchAllDocsQuery(); + } + } else { + return new MatchNoDocsQuery("Type list does not contain the index type"); + } + } else { + if (indexOptions() == IndexOptions.NONE) { + throw new AssertionError(); + } + final BytesRef[] types = values.stream() + .map(this::indexedValueForSearch) + .toArray(size -> new BytesRef[size]); + return new TypesQuery(types); } } + } /** @@ -261,7 +274,13 @@ public class TypeFieldMapper extends MetadataFieldMapper { private static MappedFieldType defaultFieldType(Settings indexSettings) { MappedFieldType defaultFieldType = Defaults.FIELD_TYPE.clone(); - defaultFieldType.setHasDocValues(true); + if (MapperService.INDEX_MAPPING_SINGLE_TYPE_SETTING.get(indexSettings)) { + defaultFieldType.setIndexOptions(IndexOptions.NONE); + defaultFieldType.setHasDocValues(false); + } else { + defaultFieldType.setIndexOptions(IndexOptions.DOCS); + defaultFieldType.setHasDocValues(true); + } return defaultFieldType; } diff --git a/core/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java index 37d06f79eb2..18ad7f9f310 100644 --- a/core/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java @@ -338,10 +338,10 @@ public class HasChildQueryBuilder extends AbstractQueryBuilder { // no type means no documents return new MatchNoDocsQuery(); } else { - return documentMapper.typeFilter(); + return documentMapper.typeFilter(context); } } diff --git a/core/src/main/java/org/elasticsearch/search/DefaultSearchContext.java b/core/src/main/java/org/elasticsearch/search/DefaultSearchContext.java index 6619c1ab9e5..45b89675454 100644 --- a/core/src/main/java/org/elasticsearch/search/DefaultSearchContext.java +++ b/core/src/main/java/org/elasticsearch/search/DefaultSearchContext.java @@ -76,6 +76,7 @@ import org.elasticsearch.search.suggest.SuggestionSearchContext; import java.io.IOException; import java.io.UncheckedIOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -290,13 +291,13 @@ final class DefaultSearchContext extends SearchContext { } } - private static Query createTypeFilter(String[] types) { + private Query createTypeFilter(String[] types) { if (types != null && types.length >= 1) { - BytesRef[] typesBytes = new BytesRef[types.length]; - for (int i = 0; i < typesBytes.length; i++) { - typesBytes[i] = new BytesRef(types[i]); + MappedFieldType ft = mapperService().fullName(TypeFieldMapper.NAME); + if (ft != null) { + // ft might be null if no documents have been indexed yet + return ft.termsQuery(Arrays.asList(types), queryShardContext); } - return new TypeFieldMapper.TypesQuery(typesBytes); } return null; } diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/children/ChildrenAggregationBuilder.java b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/children/ChildrenAggregationBuilder.java index ddd252a6f53..3a0d2fff982 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/children/ChildrenAggregationBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/children/ChildrenAggregationBuilder.java @@ -98,8 +98,8 @@ public class ChildrenAggregationBuilder extends ValuesSourceAggregationBuilder

createIndex("test", settings, "t", "nested_field", "type=nested")); + () -> createIndex("test", settings, "t", "nested_field", "type=nested", "foo", "type=keyword")); assertThat(invalidNestedException.getMessage(), containsString("cannot have nested fields when index sort is activated")); - IndexService indexService = createIndex("test", settings, "t"); + IndexService indexService = createIndex("test", settings, "t", "foo", "type=keyword"); CompressedXContent nestedFieldMapping = new CompressedXContent(XContentFactory.jsonBuilder().startObject() .startObject("properties") .startObject("nested_field") diff --git a/core/src/test/java/org/elasticsearch/index/mapper/TypeFieldMapperTests.java b/core/src/test/java/org/elasticsearch/index/mapper/TypeFieldMapperTests.java index 6fade26ca02..d3091ac3459 100644 --- a/core/src/test/java/org/elasticsearch/index/mapper/TypeFieldMapperTests.java +++ b/core/src/test/java/org/elasticsearch/index/mapper/TypeFieldMapperTests.java @@ -19,16 +19,31 @@ package org.elasticsearch.index.mapper; +import org.apache.lucene.index.DirectoryReader; +import org.apache.lucene.index.DocValuesType; +import org.apache.lucene.index.IndexOptions; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.index.IndexableField; +import org.apache.lucene.index.SortedSetDocValues; +import org.apache.lucene.store.Directory; +import org.apache.lucene.util.BytesRef; +import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.compress.CompressedXContent; -import org.elasticsearch.common.xcontent.XContentFactory; -import org.elasticsearch.index.fielddata.plain.DocValuesIndexFieldData; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.index.fielddata.AtomicOrdinalsFieldData; +import org.elasticsearch.index.fielddata.IndexFieldDataCache; +import org.elasticsearch.index.fielddata.IndexOrdinalsFieldData; +import org.elasticsearch.index.mapper.MapperService.MergeReason; +import org.elasticsearch.indices.breaker.NoneCircuitBreakerService; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.test.ESSingleNodeTestCase; import org.elasticsearch.test.InternalSettingsPlugin; +import java.io.IOException; +import java.util.Arrays; import java.util.Collection; - -import static org.hamcrest.Matchers.instanceOf; +import java.util.Collections; public class TypeFieldMapperTests extends ESSingleNodeTestCase { @@ -37,13 +52,60 @@ public class TypeFieldMapperTests extends ESSingleNodeTestCase { return pluginList(InternalSettingsPlugin.class); } - public void testDocValues() throws Exception { - String mapping = XContentFactory.jsonBuilder().startObject().startObject("type").endObject().endObject().string(); - - DocumentMapper docMapper = createIndex("test").mapperService().documentMapperParser().parse("type", new CompressedXContent(mapping)); - TypeFieldMapper typeMapper = docMapper.metadataMapper(TypeFieldMapper.class); - assertTrue(typeMapper.fieldType().hasDocValues()); - assertThat(typeMapper.fieldType().fielddataBuilder(), instanceOf(DocValuesIndexFieldData.Builder.class)); + public void testDocValuesMultipleTypes() throws Exception { + testDocValues(false); } + public void testDocValuesSingleType() throws Exception { + testDocValues(true); + } + + public void testDocValues(boolean singleType) throws IOException { + Settings indexSettings = Settings.builder() + .put("index.mapping.single_type", singleType) + .build(); + MapperService mapperService = createIndex("test", indexSettings).mapperService(); + DocumentMapper mapper = mapperService.merge("type", new CompressedXContent("{\"type\":{}}"), MergeReason.MAPPING_UPDATE, false); + ParsedDocument document = mapper.parse(SourceToParse.source("index", "type", "id", new BytesArray("{}"), XContentType.JSON)); + + Directory dir = newDirectory(); + IndexWriter w = new IndexWriter(dir, newIndexWriterConfig()); + w.addDocument(document.rootDoc()); + DirectoryReader r = DirectoryReader.open(w); + w.close(); + + MappedFieldType ft = mapperService.fullName(TypeFieldMapper.NAME); + IndexOrdinalsFieldData fd = (IndexOrdinalsFieldData) ft.fielddataBuilder().build(mapperService.getIndexSettings(), + ft, new IndexFieldDataCache.None(), new NoneCircuitBreakerService(), mapperService); + AtomicOrdinalsFieldData afd = fd.load(r.leaves().get(0)); + SortedSetDocValues values = afd.getOrdinalsValues(); + assertTrue(values.advanceExact(0)); + assertEquals(0, values.nextOrd()); + assertEquals(SortedSetDocValues.NO_MORE_ORDS, values.nextOrd()); + assertEquals(new BytesRef("type"), values.lookupOrd(0)); + r.close(); + dir.close(); + } + + public void testDefaultsMultipleTypes() throws IOException { + Settings indexSettings = Settings.builder() + .put("index.mapping.single_type", false) + .build(); + MapperService mapperService = createIndex("test", indexSettings).mapperService(); + DocumentMapper mapper = mapperService.merge("type", new CompressedXContent("{\"type\":{}}"), MergeReason.MAPPING_UPDATE, false); + ParsedDocument document = mapper.parse(SourceToParse.source("index", "type", "id", new BytesArray("{}"), XContentType.JSON)); + IndexableField[] fields = document.rootDoc().getFields(TypeFieldMapper.NAME); + assertEquals(IndexOptions.DOCS, fields[0].fieldType().indexOptions()); + assertEquals(DocValuesType.SORTED_SET, fields[1].fieldType().docValuesType()); + } + + public void testDefaultsSingleType() throws IOException { + Settings indexSettings = Settings.builder() + .put("index.mapping.single_type", true) + .build(); + MapperService mapperService = createIndex("test", indexSettings).mapperService(); + DocumentMapper mapper = mapperService.merge("type", new CompressedXContent("{\"type\":{}}"), MergeReason.MAPPING_UPDATE, false); + ParsedDocument document = mapper.parse(SourceToParse.source("index", "type", "id", new BytesArray("{}"), XContentType.JSON)); + assertEquals(Collections.emptyList(), Arrays.asList(document.rootDoc().getFields(TypeFieldMapper.NAME))); + } } diff --git a/core/src/test/java/org/elasticsearch/index/mapper/TypeFieldTypeTests.java b/core/src/test/java/org/elasticsearch/index/mapper/TypeFieldTypeTests.java index 3c80f095f83..b8a2805efe9 100644 --- a/core/src/test/java/org/elasticsearch/index/mapper/TypeFieldTypeTests.java +++ b/core/src/test/java/org/elasticsearch/index/mapper/TypeFieldTypeTests.java @@ -30,15 +30,25 @@ import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.ConstantScoreQuery; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MatchAllDocsQuery; +import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.TermQuery; import org.apache.lucene.store.Directory; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.IOUtils; -import org.junit.Before; +import org.elasticsearch.Version; +import org.elasticsearch.cluster.metadata.IndexMetaData; +import org.elasticsearch.common.UUIDs; +import org.elasticsearch.common.lucene.search.Queries; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.index.IndexSettings; +import org.elasticsearch.index.query.QueryShardContext; +import org.mockito.Mockito; import java.io.IOException; +import java.util.Collections; +import java.util.Set; public class TypeFieldTypeTests extends FieldTypeTestCase { @Override @@ -46,25 +56,62 @@ public class TypeFieldTypeTests extends FieldTypeTestCase { return new TypeFieldMapper.TypeFieldType(); } - @Before - public void setupProperties() { - addModifier(new Modifier("fielddata", true) { - @Override - public void modify(MappedFieldType ft) { - TypeFieldMapper.TypeFieldType tft = (TypeFieldMapper.TypeFieldType) ft; - tft.setFielddata(tft.fielddata() == false); - } - }); + public void testTermsQueryWhenTypesAreDisabled() throws Exception { + QueryShardContext context = Mockito.mock(QueryShardContext.class); + Settings indexSettings = Settings.builder() + .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT) + .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0) + .put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1) + .put(IndexMetaData.SETTING_INDEX_UUID, UUIDs.randomBase64UUID()) + .put("index.mapping.single_type", true).build(); + IndexMetaData indexMetaData = IndexMetaData.builder(IndexMetaData.INDEX_UUID_NA_VALUE).settings(indexSettings).build(); + IndexSettings mockSettings = new IndexSettings(indexMetaData, Settings.EMPTY); + Mockito.when(context.getIndexSettings()).thenReturn(mockSettings); + + MapperService mapperService = Mockito.mock(MapperService.class); + Set types = Collections.emptySet(); + Mockito.when(mapperService.types()).thenReturn(types); + Mockito.when(context.getMapperService()).thenReturn(mapperService); + + TypeFieldMapper.TypeFieldType ft = new TypeFieldMapper.TypeFieldType(); + ft.setName(TypeFieldMapper.NAME); + Query query = ft.termQuery("my_type", context); + assertEquals(new MatchNoDocsQuery(), query); + + types = Collections.singleton("my_type"); + Mockito.when(mapperService.types()).thenReturn(types); + query = ft.termQuery("my_type", context); + assertEquals(new MatchAllDocsQuery(), query); + + Mockito.when(mapperService.hasNested()).thenReturn(true); + query = ft.termQuery("my_type", context); + assertEquals(Queries.newNonNestedFilter(), query); + + types = Collections.singleton("other_type"); + Mockito.when(mapperService.types()).thenReturn(types); + query = ft.termQuery("my_type", context); + assertEquals(new MatchNoDocsQuery(), query); } - public void testTermsQuery() throws Exception { + public void testTermsQueryWhenTypesAreEnabled() throws Exception { Directory dir = newDirectory(); IndexWriter w = new IndexWriter(dir, newIndexWriterConfig()); IndexReader reader = openReaderWithNewType("my_type", w); + QueryShardContext context = Mockito.mock(QueryShardContext.class); + Settings indexSettings = Settings.builder() + .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT) + .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0) + .put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1) + .put(IndexMetaData.SETTING_INDEX_UUID, UUIDs.randomBase64UUID()) + .put("index.mapping.single_type", false).build(); + IndexMetaData indexMetaData = IndexMetaData.builder(IndexMetaData.INDEX_UUID_NA_VALUE).settings(indexSettings).build(); + IndexSettings mockSettings = new IndexSettings(indexMetaData, Settings.EMPTY); + Mockito.when(context.getIndexSettings()).thenReturn(mockSettings); + TypeFieldMapper.TypeFieldType ft = new TypeFieldMapper.TypeFieldType(); ft.setName(TypeFieldMapper.NAME); - Query query = ft.termQuery("my_type", null); + Query query = ft.termQuery("my_type", context); assertEquals(new MatchAllDocsQuery(), query.rewrite(reader)); // Make sure that Lucene actually simplifies the query when there is a single type diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/children/ParentToChildrenAggregatorTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/children/ParentToChildrenAggregatorTests.java index 47aa35bf924..17152bc450a 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/children/ParentToChildrenAggregatorTests.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/children/ParentToChildrenAggregatorTests.java @@ -52,6 +52,7 @@ import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.search.aggregations.AggregatorTestCase; import org.elasticsearch.search.aggregations.metrics.min.InternalMin; import org.elasticsearch.search.aggregations.metrics.min.MinAggregationBuilder; +import org.mockito.Mockito; import java.io.IOException; import java.util.Arrays; @@ -165,8 +166,8 @@ public class ParentToChildrenAggregatorTests extends AggregatorTestCase { when(mapperService.documentMapper(CHILD_TYPE)).thenReturn(childDocMapper); when(mapperService.documentMapper(PARENT_TYPE)).thenReturn(parentDocMapper); when(mapperService.docMappers(false)).thenReturn(Arrays.asList(new DocumentMapper[] { childDocMapper, parentDocMapper })); - when(parentDocMapper.typeFilter()).thenReturn(new TypeFieldMapper.TypesQuery(new BytesRef(PARENT_TYPE))); - when(childDocMapper.typeFilter()).thenReturn(new TypeFieldMapper.TypesQuery(new BytesRef(CHILD_TYPE))); + when(parentDocMapper.typeFilter(Mockito.any())).thenReturn(new TypeFieldMapper.TypesQuery(new BytesRef(PARENT_TYPE))); + when(childDocMapper.typeFilter(Mockito.any())).thenReturn(new TypeFieldMapper.TypesQuery(new BytesRef(CHILD_TYPE))); return mapperService; } diff --git a/docs/reference/search/validate.asciidoc b/docs/reference/search/validate.asciidoc index 2b0ce48152e..7218f6e6b23 100644 --- a/docs/reference/search/validate.asciidoc +++ b/docs/reference/search/validate.asciidoc @@ -227,13 +227,13 @@ Response: "index": "twitter", "shard": 0, "valid": true, - "explanation": "+MatchNoDocsQuery(\"empty BooleanQuery\") #ConstantScore(MatchNoDocsQuery(\"empty BooleanQuery\"))" + "explanation": "user:kimchy~2" }, { "index": "twitter", "shard": 1, "valid": true, - "explanation": "+MatchNoDocsQuery(\"empty BooleanQuery\") #ConstantScore(MatchNoDocsQuery(\"empty BooleanQuery\"))" + "explanation": "user:kimchy~2" }, { "index": "twitter", @@ -251,7 +251,7 @@ Response: "index": "twitter", "shard": 4, "valid": true, - "explanation": "+MatchNoDocsQuery(\"empty BooleanQuery\") #ConstantScore(MatchNoDocsQuery(\"empty BooleanQuery\"))" + "explanation": "user:kimchy~2" } ] } From 50b617f73a7543b4d5ec64490a65311dca2d70d2 Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Thu, 4 May 2017 10:29:00 -0400 Subject: [PATCH 19/44] Remove global checkpoint assertion in index shard Due to races, this assertion in index shard can be wrong. This commit removes that assertion and adjusts the explanatory comment. --- .../elasticsearch/index/shard/IndexShard.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/index/shard/IndexShard.java b/core/src/main/java/org/elasticsearch/index/shard/IndexShard.java index f1cef1fb663..5e004a4759c 100644 --- a/core/src/main/java/org/elasticsearch/index/shard/IndexShard.java +++ b/core/src/main/java/org/elasticsearch/index/shard/IndexShard.java @@ -1523,20 +1523,20 @@ public class IndexShard extends AbstractIndexShardComponent implements IndicesCl verifyReplicationTarget(); final SequenceNumbersService seqNoService = getEngine().seqNoService(); final long localCheckpoint = seqNoService.getLocalCheckpoint(); - if (globalCheckpoint <= localCheckpoint) { - seqNoService.updateGlobalCheckpointOnReplica(globalCheckpoint); - } else { + if (globalCheckpoint > localCheckpoint) { /* * This can happen during recovery when the shard has started its engine but recovery is not finalized and is receiving global - * checkpoint updates from in-flight operations. However, since this shard is not yet contributing to calculating the global - * checkpoint, it can be the case that the global checkpoint update from the primary is ahead of the local checkpoint on this - * shard. In this case, we ignore the global checkpoint update. This should only happen if we are in the translog stage of - * recovery. Prior to this, the engine is not opened and this shard will not receive global checkpoint updates, and after this - * the shard will be contributing to calculations of the the global checkpoint. + * checkpoint updates. However, since this shard is not yet contributing to calculating the global checkpoint, it can be the + * case that the global checkpoint update from the primary is ahead of the local checkpoint on this shard. In this case, we + * ignore the global checkpoint update. This can happen if we are in the translog stage of recovery. Prior to this, the engine + * is not opened and this shard will not receive global checkpoint updates, and after this the shard will be contributing to + * calculations of the the global checkpoint. However, we can not assert that we are in the translog stage of recovery here as + * while the global checkpoint update may have emanated from the primary when we were in that state, we could subsequently move + * to recovery finalization, or even finished recovery before the update arrives here. */ - assert recoveryState().getStage() == RecoveryState.Stage.TRANSLOG - : "expected recovery stage [" + RecoveryState.Stage.TRANSLOG + "] but was [" + recoveryState().getStage() + "]"; + return; } + seqNoService.updateGlobalCheckpointOnReplica(globalCheckpoint); } /** From cb46e97a046b61a20bc237b9d49fa30d2aef9edf Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Thu, 4 May 2017 10:41:20 -0400 Subject: [PATCH 20/44] Fix reschedule async fsync test This commit fixes the reschedule async fsync test in index service tests. This test was passing for the wrong reason. Namely, the test was trying to set translog durability to async, fire off an indexing request, and then assert that the translog eventually got fsynced. The problem here is that in the course of issuing the indexing request, a mapping update is trigger. The mapping update triggers the index settings to be refreshed. Since the test did not issue a cluster state update to change the durability from request to async but instead did this directly through index service, the mapping update flops the durability back to async. This means that when the indexing request executes, an fsync is performed after the request and the assertoin that an fsync is not needed passes but for the wrong reason (in short: the test wanted it to pass because an async fsync fired, but instead it passed because a request async fired). This commit fixes this by going through the index settings API so that a proper cluster state update is triggered and so the mapping update does not flop the durability back to request. --- .../index/IndexServiceTests.java | 48 ++++++++++++------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/core/src/test/java/org/elasticsearch/index/IndexServiceTests.java b/core/src/test/java/org/elasticsearch/index/IndexServiceTests.java index 385770426f5..c202db1470e 100644 --- a/core/src/test/java/org/elasticsearch/index/IndexServiceTests.java +++ b/core/src/test/java/org/elasticsearch/index/IndexServiceTests.java @@ -238,31 +238,43 @@ public class IndexServiceTests extends ESSingleNodeTestCase { } public void testRescheduleAsyncFsync() throws Exception { - Settings settings = Settings.builder() - .put(IndexSettings.INDEX_TRANSLOG_SYNC_INTERVAL_SETTING.getKey(), "100ms") // very often :) - .put(IndexSettings.INDEX_TRANSLOG_DURABILITY_SETTING.getKey(), Translog.Durability.REQUEST) + final Settings settings = Settings.builder() + .put(IndexSettings.INDEX_TRANSLOG_SYNC_INTERVAL_SETTING.getKey(), "100ms") + .put(IndexSettings.INDEX_TRANSLOG_DURABILITY_SETTING.getKey(), Translog.Durability.REQUEST) .build(); - IndexService indexService = createIndex("test", settings); + final IndexService indexService = createIndex("test", settings); ensureGreen("test"); assertNull(indexService.getFsyncTask()); - IndexMetaData metaData = IndexMetaData.builder(indexService.getMetaData()).settings(Settings.builder().put(indexService.getMetaData().getSettings()).put(IndexSettings.INDEX_TRANSLOG_DURABILITY_SETTING.getKey(), Translog.Durability.ASYNC)).build(); - indexService.updateMetaData(metaData); - assertNotNull(indexService.getFsyncTask()); - assertTrue(indexService.getRefreshTask().mustReschedule()); - client().prepareIndex("test", "test", "1").setSource("{\"foo\": \"bar\"}", XContentType.JSON).get(); - IndexShard shard = indexService.getShard(0); - assertBusy(() -> { - assertFalse(shard.getTranslog().syncNeeded()); - }); - metaData = IndexMetaData.builder(indexService.getMetaData()).settings(Settings.builder().put(indexService.getMetaData().getSettings()).put(IndexSettings.INDEX_TRANSLOG_DURABILITY_SETTING.getKey(), Translog.Durability.REQUEST)).build(); - indexService.updateMetaData(metaData); + client() + .admin() + .indices() + .prepareUpdateSettings("test") + .setSettings(Settings.builder().put(IndexSettings.INDEX_TRANSLOG_DURABILITY_SETTING.getKey(), Translog.Durability.ASYNC)) + .get(); + + assertNotNull(indexService.getFsyncTask()); + assertTrue(indexService.getFsyncTask().mustReschedule()); + client().prepareIndex("test", "test", "1").setSource("{\"foo\": \"bar\"}", XContentType.JSON).get(); + assertNotNull(indexService.getFsyncTask()); + final IndexShard shard = indexService.getShard(0); + assertBusy(() -> assertFalse(shard.getTranslog().syncNeeded())); + + client() + .admin() + .indices() + .prepareUpdateSettings("test") + .setSettings(Settings.builder().put(IndexSettings.INDEX_TRANSLOG_DURABILITY_SETTING.getKey(), Translog.Durability.REQUEST)) + .get(); assertNull(indexService.getFsyncTask()); - metaData = IndexMetaData.builder(indexService.getMetaData()).settings(Settings.builder().put(indexService.getMetaData().getSettings()).put(IndexSettings.INDEX_TRANSLOG_DURABILITY_SETTING.getKey(), Translog.Durability.ASYNC)).build(); - indexService.updateMetaData(metaData); + client() + .admin() + .indices() + .prepareUpdateSettings("test") + .setSettings(Settings.builder().put(IndexSettings.INDEX_TRANSLOG_DURABILITY_SETTING.getKey(), Translog.Durability.ASYNC)) + .get(); assertNotNull(indexService.getFsyncTask()); - } public void testIllegalFsyncInterval() { From 4b80e1a5cab3ca7a8b9c5eec2debdf5c53de7808 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Thu, 4 May 2017 09:51:25 -0400 Subject: [PATCH 21/44] Docs: fix list of testing images Fedora-24 is gone. Long live Fedora-25. --- TESTING.asciidoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/TESTING.asciidoc b/TESTING.asciidoc index f8a54abee89..35004570224 100644 --- a/TESTING.asciidoc +++ b/TESTING.asciidoc @@ -426,12 +426,12 @@ sudo -E bats $BATS_TESTS/*.bats You can also use Gradle to prepare the test environment and then starts a single VM: ------------------------------------------------- -gradle vagrantFedora24#up +gradle vagrantFedora25#up ------------------------------------------------- -Or any of vagrantCentos6#up, vagrantDebian8#up, vagrantFedora24#up, vagrantOel6#up, -vagrantOel7#up, vagrantOpensuse13#up, vagrantSles12#up, vagrantUbuntu1404#up, -vagrantUbuntu1604#up. +Or any of vagrantCentos6#up, vagrantCentos7#up, vagrantDebian8#up, +vagrantFedora25#up, vagrantOel6#up, vagrantOel7#up, vagrantOpensuse13#up, +vagrantSles12#up, vagrantUbuntu1404#up, vagrantUbuntu1604#up. Once up, you can then connect to the VM using SSH from the elasticsearch directory: From f5edd5049a2cb824eb66c75047f920bf76dd423e Mon Sep 17 00:00:00 2001 From: James Baiera Date: Thu, 4 May 2017 10:51:31 -0400 Subject: [PATCH 22/44] Fixing permission errors for `KERBEROS` security mode for HDFS Repository (#23439) Added missing permissions required for authenticating with Kerberos to HDFS. Also implemented code to support authentication in the form of using a Kerberos keytab file. In order to support HDFS authentication, users must install a Kerberos keytab file on each node and transfer it to the configuration directory. When a user specifies a Kerberos principal in the repository settings the plugin automatically enables security for Hadoop and begins the login process. There will be a separate PR and commit for the testing infrastructure to support these changes. --- docs/plugins/repository-hdfs.asciidoc | 110 +++++++++++++ .../repositories/hdfs/HdfsBlobStore.java | 17 +- .../repositories/hdfs/HdfsPlugin.java | 32 ++++ .../repositories/hdfs/HdfsRepository.java | 139 +++++++++++++---- .../hdfs/HdfsSecurityContext.java | 145 ++++++++++++++++++ .../plugin-metadata/plugin-security.policy | 45 +++++- 6 files changed, 446 insertions(+), 42 deletions(-) create mode 100644 plugins/repository-hdfs/src/main/java/org/elasticsearch/repositories/hdfs/HdfsSecurityContext.java diff --git a/docs/plugins/repository-hdfs.asciidoc b/docs/plugins/repository-hdfs.asciidoc index 64b87801acb..20c62a5861a 100644 --- a/docs/plugins/repository-hdfs.asciidoc +++ b/docs/plugins/repository-hdfs.asciidoc @@ -68,3 +68,113 @@ The following settings are supported: Override the chunk size. (Disabled by default) +`security.principal`:: + + Kerberos principal to use when connecting to a secured HDFS cluster. + If you are using a service principal for your elasticsearch node, you may + use the `_HOST` pattern in the principal name and the plugin will replace + the pattern with the hostname of the node at runtime (see + link:repository-hdfs-security-runtime[Creating the Secure Repository]). + +[[repository-hdfs-security]] +==== Hadoop Security + +The HDFS Repository Plugin integrates seamlessly with Hadoop's authentication model. The following authentication +methods are supported by the plugin: + +[horizontal] +`simple`:: + + Also means "no security" and is enabled by default. Uses information from underlying operating system account + running elasticsearch to inform Hadoop of the name of the current user. Hadoop makes no attempts to verify this + information. + +`kerberos`:: + + Authenticates to Hadoop through the usage of a Kerberos principal and keytab. Interfacing with HDFS clusters + secured with Kerberos requires a few additional steps to enable (See <> and + <> for more info) + +[[repository-hdfs-security-keytabs]] +[float] +===== Principals and Keytabs +Before attempting to connect to a secured HDFS cluster, provision the Kerberos principals and keytabs that the +Elasticsearch nodes will use for authenticating to Kerberos. For maximum security and to avoid tripping up the Kerberos +replay protection, you should create a service principal per node, following the pattern of +`elasticsearch/hostname@REALM`. + +WARNING: In some cases, if the same principal is authenticating from multiple clients at once, services may reject +authentication for those principals under the assumption that they could be replay attacks. If you are running the +plugin in production with multiple nodes you should be using a unique service principal for each node. + +On each Elasticsearch node, place the appropriate keytab file in the node's configuration location under the +`repository-hdfs` directory using the name `krb5.keytab`: + +[source, bash] +---- +$> cd elasticsearch/config +$> ls +elasticsearch.yml jvm.options log4j2.properties repository-hdfs/ scripts/ +$> cd repository-hdfs +$> ls +krb5.keytab +---- +// TEST[skip:this is for demonstration purposes only + +NOTE: Make sure you have the correct keytabs! If you are using a service principal per node (like +`elasticsearch/hostname@REALM`) then each node will need its own unique keytab file for the principal assigned to that +host! + +// Setup at runtime (principal name) +[[repository-hdfs-security-runtime]] +[float] +===== Creating the Secure Repository +Once your keytab files are in place and your cluster is started, creating a secured HDFS repository is simple. Just +add the name of the principal that you will be authenticating as in the repository settings under the +`security.principal` option: + +[source,js] +---- +PUT _snapshot/my_hdfs_repository +{ + "type": "hdfs", + "settings": { + "uri": "hdfs://namenode:8020/", + "path": "/user/elasticsearch/respositories/my_hdfs_repository", + "security.principal": "elasticsearch@REALM" + } +} +---- +// CONSOLE +// TEST[skip:we don't have hdfs set up while testing this] + +If you are using different service principals for each node, you can use the `_HOST` pattern in your principal +name. Elasticsearch will automatically replace the pattern with the hostname of the node at runtime: + +[source,js] +---- +PUT _snapshot/my_hdfs_repository +{ + "type": "hdfs", + "settings": { + "uri": "hdfs://namenode:8020/", + "path": "/user/elasticsearch/respositories/my_hdfs_repository", + "security.principal": "elasticsearch/_HOST@REALM" + } +} +---- +// CONSOLE +// TEST[skip:we don't have hdfs set up while testing this] + +[[repository-hdfs-security-authorization]] +[float] +===== Authorization +Once Elasticsearch is connected and authenticated to HDFS, HDFS will infer a username to use for +authorizing file access for the client. By default, it picks this username from the primary part of +the kerberos principal used to authenticate to the service. For example, in the case of a principal +like `elasticsearch@REALM` or `elasticsearch/hostname@REALM` then the username that HDFS +extracts for file access checks will be `elasticsearch`. + +NOTE: The repository plugin makes no assumptions of what Elasticsearch's principal name is. The main fragment of the +Kerberos principal is not required to be `elasticsearch`. If you have a principal or service name that works better +for you or your organization then feel free to use it instead! \ No newline at end of file diff --git a/plugins/repository-hdfs/src/main/java/org/elasticsearch/repositories/hdfs/HdfsBlobStore.java b/plugins/repository-hdfs/src/main/java/org/elasticsearch/repositories/hdfs/HdfsBlobStore.java index 7ce5e8d3cd8..8d88b7fd074 100644 --- a/plugins/repository-hdfs/src/main/java/org/elasticsearch/repositories/hdfs/HdfsBlobStore.java +++ b/plugins/repository-hdfs/src/main/java/org/elasticsearch/repositories/hdfs/HdfsBlobStore.java @@ -29,23 +29,21 @@ import org.elasticsearch.common.blobstore.BlobPath; import org.elasticsearch.common.blobstore.BlobStore; import java.io.IOException; -import java.lang.reflect.ReflectPermission; -import java.net.SocketPermission; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; -import javax.security.auth.AuthPermission; - final class HdfsBlobStore implements BlobStore { private final Path root; private final FileContext fileContext; + private final HdfsSecurityContext securityContext; private final int bufferSize; private volatile boolean closed; HdfsBlobStore(FileContext fileContext, String path, int bufferSize) throws IOException { this.fileContext = fileContext; + this.securityContext = new HdfsSecurityContext(fileContext.getUgi()); this.bufferSize = bufferSize; this.root = execute(fileContext1 -> fileContext1.makeQualified(new Path(path))); try { @@ -107,9 +105,6 @@ final class HdfsBlobStore implements BlobStore { /** * Executes the provided operation against this store */ - // we can do FS ops with only two elevated permissions: - // 1) hadoop dynamic proxy is messy with access rules - // 2) allow hadoop to add credentials to our Subject V execute(Operation operation) throws IOException { SpecialPermission.check(); if (closed) { @@ -117,8 +112,12 @@ final class HdfsBlobStore implements BlobStore { } try { return AccessController.doPrivileged((PrivilegedExceptionAction) - () -> operation.run(fileContext), null, new ReflectPermission("suppressAccessChecks"), - new AuthPermission("modifyPrivateCredentials"), new SocketPermission("*", "connect")); + () -> { + securityContext.ensureLogin(); + return operation.run(fileContext); + }, + null, + securityContext.getRestrictedExecutionPermissions()); } catch (PrivilegedActionException pae) { throw (IOException) pae.getException(); } diff --git a/plugins/repository-hdfs/src/main/java/org/elasticsearch/repositories/hdfs/HdfsPlugin.java b/plugins/repository-hdfs/src/main/java/org/elasticsearch/repositories/hdfs/HdfsPlugin.java index 9ea53a5acf2..4e51ab23b80 100644 --- a/plugins/repository-hdfs/src/main/java/org/elasticsearch/repositories/hdfs/HdfsPlugin.java +++ b/plugins/repository-hdfs/src/main/java/org/elasticsearch/repositories/hdfs/HdfsPlugin.java @@ -26,6 +26,9 @@ import java.security.PrivilegedAction; import java.util.Collections; import java.util.Map; +import org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolPB; +import org.apache.hadoop.security.KerberosInfo; +import org.apache.hadoop.security.SecurityUtil; import org.elasticsearch.SpecialPermission; import org.elasticsearch.common.SuppressForbidden; import org.elasticsearch.common.xcontent.NamedXContentRegistry; @@ -40,6 +43,7 @@ public final class HdfsPlugin extends Plugin implements RepositoryPlugin { static { SpecialPermission.check(); AccessController.doPrivileged((PrivilegedAction) HdfsPlugin::evilHadoopInit); + AccessController.doPrivileged((PrivilegedAction) HdfsPlugin::eagerInit); } @SuppressForbidden(reason = "Needs a security hack for hadoop on windows, until HADOOP-XXXX is fixed") @@ -79,6 +83,34 @@ public final class HdfsPlugin extends Plugin implements RepositoryPlugin { return null; } + private static Void eagerInit() { + /* + * Hadoop RPC wire serialization uses ProtocolBuffers. All proto classes for Hadoop + * come annotated with configurations that denote information about if they support + * certain security options like Kerberos, and how to send information with the + * message to support that authentication method. SecurityUtil creates a service loader + * in a static field during its clinit. This loader provides the implementations that + * pull the security information for each proto class. The service loader sources its + * services from the current thread's context class loader, which must contain the Hadoop + * jars. Since plugins don't execute with their class loaders installed as the thread's + * context class loader, we need to install the loader briefly, allow the util to be + * initialized, then restore the old loader since we don't actually own this thread. + */ + ClassLoader oldCCL = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(HdfsRepository.class.getClassLoader()); + KerberosInfo info = SecurityUtil.getKerberosInfo(ClientNamenodeProtocolPB.class, null); + // Make sure that the correct class loader was installed. + if (info == null) { + throw new RuntimeException("Could not initialize SecurityUtil: " + + "Unable to find services for [org.apache.hadoop.security.SecurityInfo]"); + } + } finally { + Thread.currentThread().setContextClassLoader(oldCCL); + } + return null; + } + @Override public Map getRepositories(Environment env, NamedXContentRegistry namedXContentRegistry) { return Collections.singletonMap("hdfs", (metadata) -> new HdfsRepository(metadata, env, namedXContentRegistry)); diff --git a/plugins/repository-hdfs/src/main/java/org/elasticsearch/repositories/hdfs/HdfsRepository.java b/plugins/repository-hdfs/src/main/java/org/elasticsearch/repositories/hdfs/HdfsRepository.java index d784e8bf093..16ed9d06a5e 100644 --- a/plugins/repository-hdfs/src/main/java/org/elasticsearch/repositories/hdfs/HdfsRepository.java +++ b/plugins/repository-hdfs/src/main/java/org/elasticsearch/repositories/hdfs/HdfsRepository.java @@ -19,29 +19,31 @@ package org.elasticsearch.repositories.hdfs; import java.io.IOException; -import java.lang.reflect.Constructor; +import java.io.UncheckedIOException; +import java.net.InetAddress; import java.net.URI; +import java.net.UnknownHostException; import java.security.AccessController; -import java.security.Principal; import java.security.PrivilegedAction; -import java.util.Collections; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; -import javax.security.auth.Subject; - import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.AbstractFileSystem; import org.apache.hadoop.fs.FileContext; import org.apache.hadoop.fs.UnsupportedFileSystemException; -import org.elasticsearch.ElasticsearchGenerationException; +import org.apache.hadoop.security.SecurityUtil; +import org.apache.hadoop.security.UserGroupInformation; +import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod; +import org.apache.logging.log4j.Logger; import org.elasticsearch.SpecialPermission; import org.elasticsearch.cluster.metadata.RepositoryMetaData; import org.elasticsearch.common.Strings; import org.elasticsearch.common.SuppressForbidden; import org.elasticsearch.common.blobstore.BlobPath; import org.elasticsearch.common.blobstore.BlobStore; +import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.ByteSizeUnit; import org.elasticsearch.common.unit.ByteSizeValue; @@ -51,9 +53,14 @@ import org.elasticsearch.repositories.blobstore.BlobStoreRepository; public final class HdfsRepository extends BlobStoreRepository { - private final BlobPath basePath = BlobPath.cleanPath(); + private static final Logger LOGGER = Loggers.getLogger(HdfsRepository.class); + + private static final String CONF_SECURITY_PRINCIPAL = "security.principal"; + + private final Environment environment; private final ByteSizeValue chunkSize; private final boolean compress; + private final BlobPath basePath = BlobPath.cleanPath(); private HdfsBlobStore blobStore; @@ -65,6 +72,7 @@ public final class HdfsRepository extends BlobStoreRepository { NamedXContentRegistry namedXContentRegistry) throws IOException { super(metadata, environment.settings(), namedXContentRegistry); + this.environment = environment; this.chunkSize = metadata.settings().getAsBytesSize("chunk_size", null); this.compress = metadata.settings().getAsBoolean("compress", false); } @@ -101,49 +109,116 @@ public final class HdfsRepository extends BlobStoreRepository { blobStore = new HdfsBlobStore(fileContext, pathSetting, bufferSize); logger.debug("Using file-system [{}] for URI [{}], path [{}]", fileContext.getDefaultFileSystem(), fileContext.getDefaultFileSystem().getUri(), pathSetting); } catch (IOException e) { - throw new ElasticsearchGenerationException(String.format(Locale.ROOT, "Cannot create HDFS repository for uri [%s]", uri), e); + throw new UncheckedIOException(String.format(Locale.ROOT, "Cannot create HDFS repository for uri [%s]", uri), e); } super.doStart(); } // create hadoop filecontext - @SuppressForbidden(reason = "lesser of two evils (the other being a bunch of JNI/classloader nightmares)") - private static FileContext createContext(URI uri, Settings repositorySettings) { - Configuration cfg = new Configuration(repositorySettings.getAsBoolean("load_defaults", true)); - cfg.setClassLoader(HdfsRepository.class.getClassLoader()); - cfg.reloadConfiguration(); + private FileContext createContext(URI uri, Settings repositorySettings) { + Configuration hadoopConfiguration = new Configuration(repositorySettings.getAsBoolean("load_defaults", true)); + hadoopConfiguration.setClassLoader(HdfsRepository.class.getClassLoader()); + hadoopConfiguration.reloadConfiguration(); Map map = repositorySettings.getByPrefix("conf.").getAsMap(); for (Entry entry : map.entrySet()) { - cfg.set(entry.getKey(), entry.getValue()); + hadoopConfiguration.set(entry.getKey(), entry.getValue()); } - // create a hadoop user. if we want some auth, it must be done different anyway, and tested. - Subject subject; - try { - Class clazz = Class.forName("org.apache.hadoop.security.User"); - Constructor ctor = clazz.getConstructor(String.class); - ctor.setAccessible(true); - Principal principal = (Principal) ctor.newInstance(System.getProperty("user.name")); - subject = new Subject(false, Collections.singleton(principal), Collections.emptySet(), Collections.emptySet()); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } + // Create a hadoop user + UserGroupInformation ugi = login(hadoopConfiguration, repositorySettings); - // disable FS cache - cfg.setBoolean("fs.hdfs.impl.disable.cache", true); + // Disable FS cache + hadoopConfiguration.setBoolean("fs.hdfs.impl.disable.cache", true); - // create the filecontext with our user - return Subject.doAs(subject, (PrivilegedAction) () -> { + // Create the filecontext with our user information + // This will correctly configure the filecontext to have our UGI as it's internal user. + return ugi.doAs((PrivilegedAction) () -> { try { - AbstractFileSystem fs = AbstractFileSystem.get(uri, cfg); - return FileContext.getFileContext(fs, cfg); + AbstractFileSystem fs = AbstractFileSystem.get(uri, hadoopConfiguration); + return FileContext.getFileContext(fs, hadoopConfiguration); } catch (UnsupportedFileSystemException e) { - throw new RuntimeException(e); + throw new UncheckedIOException(e); } }); } + private UserGroupInformation login(Configuration hadoopConfiguration, Settings repositorySettings) { + // Validate the authentication method: + AuthenticationMethod authMethod = SecurityUtil.getAuthenticationMethod(hadoopConfiguration); + if (authMethod.equals(AuthenticationMethod.SIMPLE) == false + && authMethod.equals(AuthenticationMethod.KERBEROS) == false) { + throw new RuntimeException("Unsupported authorization mode ["+authMethod+"]"); + } + + // Check if the user added a principal to use, and that there is a keytab file provided + String kerberosPrincipal = repositorySettings.get(CONF_SECURITY_PRINCIPAL); + + // Check to see if the authentication method is compatible + if (kerberosPrincipal != null && authMethod.equals(AuthenticationMethod.SIMPLE)) { + LOGGER.warn("Hadoop authentication method is set to [SIMPLE], but a Kerberos principal is " + + "specified. Continuing with [KERBEROS] authentication."); + SecurityUtil.setAuthenticationMethod(AuthenticationMethod.KERBEROS, hadoopConfiguration); + } else if (kerberosPrincipal == null && authMethod.equals(AuthenticationMethod.KERBEROS)) { + throw new RuntimeException("HDFS Repository does not support [KERBEROS] authentication without " + + "a valid Kerberos principal and keytab. Please specify a principal in the repository settings with [" + + CONF_SECURITY_PRINCIPAL + "]."); + } + + // Now we can initialize the UGI with the configuration. + UserGroupInformation.setConfiguration(hadoopConfiguration); + + // Debugging + LOGGER.debug("Hadoop security enabled: [{}]", UserGroupInformation.isSecurityEnabled()); + LOGGER.debug("Using Hadoop authentication method: [{}]", SecurityUtil.getAuthenticationMethod(hadoopConfiguration)); + + // UserGroupInformation (UGI) instance is just a Hadoop specific wrapper around a Java Subject + try { + if (UserGroupInformation.isSecurityEnabled()) { + String principal = preparePrincipal(kerberosPrincipal); + String keytab = HdfsSecurityContext.locateKeytabFile(environment).toString(); + LOGGER.debug("Using kerberos principal [{}] and keytab located at [{}]", principal, keytab); + return UserGroupInformation.loginUserFromKeytabAndReturnUGI(principal, keytab); + } + return UserGroupInformation.getCurrentUser(); + } catch (IOException e) { + throw new UncheckedIOException("Could not retrieve the current user information", e); + } + } + + // Convert principals of the format 'service/_HOST@REALM' by subbing in the local address for '_HOST'. + private static String preparePrincipal(String originalPrincipal) { + String finalPrincipal = originalPrincipal; + // Don't worry about host name resolution if they don't have the _HOST pattern in the name. + if (originalPrincipal.contains("_HOST")) { + try { + finalPrincipal = SecurityUtil.getServerPrincipal(originalPrincipal, getHostName()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + + if (originalPrincipal.equals(finalPrincipal) == false) { + LOGGER.debug("Found service principal. Converted original principal name [{}] to server principal [{}]", + originalPrincipal, finalPrincipal); + } + } + return finalPrincipal; + } + + @SuppressForbidden(reason = "InetAddress.getLocalHost(); Needed for filling in hostname for a kerberos principal name pattern.") + private static String getHostName() { + try { + /* + * This should not block since it should already be resolved via Log4J and Netty. The + * host information is cached by the JVM and the TTL for the cache entry is infinite + * when the SecurityManager is activated. + */ + return InetAddress.getLocalHost().getCanonicalHostName(); + } catch (UnknownHostException e) { + throw new RuntimeException("Could not locate host information", e); + } + } + @Override protected BlobStore blobStore() { return blobStore; diff --git a/plugins/repository-hdfs/src/main/java/org/elasticsearch/repositories/hdfs/HdfsSecurityContext.java b/plugins/repository-hdfs/src/main/java/org/elasticsearch/repositories/hdfs/HdfsSecurityContext.java new file mode 100644 index 00000000000..3cd1a5a40fd --- /dev/null +++ b/plugins/repository-hdfs/src/main/java/org/elasticsearch/repositories/hdfs/HdfsSecurityContext.java @@ -0,0 +1,145 @@ +/* + * 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.repositories.hdfs; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.lang.reflect.ReflectPermission; +import java.net.SocketPermission; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.Permission; +import java.util.Arrays; +import java.util.Locale; +import java.util.function.Supplier; +import javax.security.auth.AuthPermission; +import javax.security.auth.PrivateCredentialPermission; +import javax.security.auth.kerberos.ServicePermission; + +import org.apache.hadoop.security.UserGroupInformation; +import org.apache.logging.log4j.Logger; +import org.elasticsearch.common.logging.Loggers; +import org.elasticsearch.env.Environment; + +/** + * Oversees all the security specific logic for the HDFS Repository plugin. + * + * Keeps track of the current user for a given repository, as well as which + * permissions to grant the blob store restricted execution methods. + */ +class HdfsSecurityContext { + + private static final Logger LOGGER = Loggers.getLogger(HdfsSecurityContext.class); + + private static final Permission[] SIMPLE_AUTH_PERMISSIONS; + private static final Permission[] KERBEROS_AUTH_PERMISSIONS; + static { + // We can do FS ops with only a few elevated permissions: + SIMPLE_AUTH_PERMISSIONS = new Permission[]{ + new SocketPermission("*", "connect"), + // 1) hadoop dynamic proxy is messy with access rules + new ReflectPermission("suppressAccessChecks"), + // 2) allow hadoop to add credentials to our Subject + new AuthPermission("modifyPrivateCredentials") + }; + + // If Security is enabled, we need all the following elevated permissions: + KERBEROS_AUTH_PERMISSIONS = new Permission[] { + new SocketPermission("*", "connect"), + // 1) hadoop dynamic proxy is messy with access rules + new ReflectPermission("suppressAccessChecks"), + // 2) allow hadoop to add credentials to our Subject + new AuthPermission("modifyPrivateCredentials"), + // 3) allow hadoop to act as the logged in Subject + new AuthPermission("doAs"), + // 4) Listen and resolve permissions for kerberos server principals + new SocketPermission("localhost:0", "listen,resolve"), + // We add the following since hadoop requires the client to re-login when the kerberos ticket expires: + // 5) All the permissions needed for UGI to do its weird JAAS hack + new RuntimePermission("getClassLoader"), + new RuntimePermission("setContextClassLoader"), + // 6) Additional permissions for the login modules + new AuthPermission("modifyPrincipals"), + new PrivateCredentialPermission("org.apache.hadoop.security.Credentials * \"*\"", "read"), + new PrivateCredentialPermission("javax.security.auth.kerberos.KerberosTicket * \"*\"", "read"), + new PrivateCredentialPermission("javax.security.auth.kerberos.KeyTab * \"*\"", "read") + // Included later: + // 7) allow code to initiate kerberos connections as the logged in user + // Still far and away fewer permissions than the original full plugin policy + }; + } + + /** + * Locates the keytab file in the environment and verifies that it exists. + * Expects keytab file to exist at {@code $CONFIG_DIR$/repository-hdfs/krb5.keytab} + */ + static Path locateKeytabFile(Environment environment) { + Path keytabPath = environment.configFile().resolve("repository-hdfs").resolve("krb5.keytab"); + try { + if (Files.exists(keytabPath) == false) { + throw new RuntimeException("Could not locate keytab at [" + keytabPath + "]."); + } + } catch (SecurityException se) { + throw new RuntimeException("Could not locate keytab at [" + keytabPath + "]", se); + } + return keytabPath; + } + + private final UserGroupInformation ugi; + private final Permission[] restrictedExecutionPermissions; + + HdfsSecurityContext(UserGroupInformation ugi) { + this.ugi = ugi; + this.restrictedExecutionPermissions = renderPermissions(ugi); + } + + private Permission[] renderPermissions(UserGroupInformation ugi) { + Permission[] permissions; + if (ugi.isFromKeytab()) { + // KERBEROS + // Leave room to append one extra permission based on the logged in user's info. + int permlen = KERBEROS_AUTH_PERMISSIONS.length + 1; + permissions = new Permission[permlen]; + + System.arraycopy(KERBEROS_AUTH_PERMISSIONS, 0, permissions, 0, KERBEROS_AUTH_PERMISSIONS.length); + + // Append a kerberos.ServicePermission to only allow initiating kerberos connections + // as the logged in user. + permissions[permissions.length - 1] = new ServicePermission(ugi.getUserName(), "initiate"); + } else { + // SIMPLE + permissions = Arrays.copyOf(SIMPLE_AUTH_PERMISSIONS, SIMPLE_AUTH_PERMISSIONS.length); + } + return permissions; + } + + Permission[] getRestrictedExecutionPermissions() { + return restrictedExecutionPermissions; + } + + void ensureLogin() { + if (ugi.isFromKeytab()) { + try { + ugi.checkTGTAndReloginFromKeytab(); + } catch (IOException ioe) { + throw new UncheckedIOException("Could not re-authenticate", ioe); + } + } + } +} diff --git a/plugins/repository-hdfs/src/main/plugin-metadata/plugin-security.policy b/plugins/repository-hdfs/src/main/plugin-metadata/plugin-security.policy index b800f3eee46..f6476f290bc 100644 --- a/plugins/repository-hdfs/src/main/plugin-metadata/plugin-security.policy +++ b/plugins/repository-hdfs/src/main/plugin-metadata/plugin-security.policy @@ -25,17 +25,60 @@ grant { permission java.lang.RuntimePermission "accessDeclaredMembers"; permission java.lang.reflect.ReflectPermission "suppressAccessChecks"; + // Needed so that Hadoop can load the correct classes for SPI and JAAS + // org.apache.hadoop.security.SecurityUtil clinit + // org.apache.hadoop.security.UserGroupInformation.newLoginContext() + permission java.lang.RuntimePermission "setContextClassLoader"; + // org.apache.hadoop.util.StringUtils clinit permission java.util.PropertyPermission "*", "read,write"; // org.apache.hadoop.util.ShutdownHookManager clinit permission java.lang.RuntimePermission "shutdownHooks"; - // JAAS is used always, we use a fake subject, hurts nobody + // JAAS is used by Hadoop for authentication purposes + // The Hadoop Login JAAS module modifies a Subject's private credentials and principals + // The Hadoop RPC Layer must be able to read these credentials, and initiate Kerberos connections + + // org.apache.hadoop.security.UserGroupInformation.getCurrentUser() permission javax.security.auth.AuthPermission "getSubject"; + + // org.apache.hadoop.security.UserGroupInformation.doAs() permission javax.security.auth.AuthPermission "doAs"; + + // org.apache.hadoop.security.UserGroupInformation.getCredentialsInternal() + permission javax.security.auth.PrivateCredentialPermission "org.apache.hadoop.security.Credentials * \"*\"", "read"; + + // Hadoop depends on the Kerberos login module for kerberos authentication + // com.sun.security.auth.module.Krb5LoginModule.login() + permission java.lang.RuntimePermission "accessClassInPackage.sun.security.krb5"; + + // com.sun.security.auth.module.Krb5LoginModule.commit() permission javax.security.auth.AuthPermission "modifyPrivateCredentials"; + permission javax.security.auth.AuthPermission "modifyPrincipals"; + permission javax.security.auth.PrivateCredentialPermission "javax.security.auth.kerberos.KeyTab * \"*\"", "read"; + permission javax.security.auth.PrivateCredentialPermission "javax.security.auth.kerberos.KerberosTicket * \"*\"", "read"; + + // Hadoop depends on OS level user information for simple authentication + // Unix: UnixLoginModule: com.sun.security.auth.module.UnixSystem.UnixSystem init + permission java.lang.RuntimePermission "loadLibrary.jaas_unix"; + // Windows: NTLoginModule: com.sun.security.auth.module.NTSystem.loadNative + permission java.lang.RuntimePermission "loadLibrary.jaas_nt"; + permission javax.security.auth.AuthPermission "modifyPublicCredentials"; + + // org.apache.hadoop.security.SaslRpcServer.init() + permission java.security.SecurityPermission "putProviderProperty.SaslPlainServer"; + + // org.apache.hadoop.security.SaslPlainServer.SecurityProvider.SecurityProvider init + permission java.security.SecurityPermission "insertProvider.SaslPlainServer"; + + // org.apache.hadoop.security.SaslRpcClient.getServerPrincipal -> KerberosPrincipal init + permission javax.security.auth.kerberos.ServicePermission "*", "initiate"; // hdfs client opens socket connections for to access repository permission java.net.SocketPermission "*", "connect"; + + // client binds to the address returned from the host name of any principal set up as a service principal + // org.apache.hadoop.ipc.Client.Connection.setupConnection + permission java.net.SocketPermission "localhost:0", "listen,resolve"; }; From de65f51d34cb05dbdf846417a3c5023979dd863c Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Thu, 4 May 2017 11:19:41 -0400 Subject: [PATCH 23/44] Simplify file store Today we go to heroic lengths to workaround bugs in the JDK or around issues like BSD jails to get information about the underlying file store. For example, we went to lengths to work around a JDK bug where the file store returned would incorrectly report whether or not a path is writable in certain situations in Windows operating systems. Another bug prevented getting file store information on Windows on a virtual drive on Windows. We no longer need to work around these bugs, we could simply try to write to disk and let an I/O exception arise if we could not write to the disk or take advantage of the fact that these bugs are fixed in recent releases of the JDK (e.g., the file store bug is fixed since 8u72). Additionally, we collected information about all file stores on the system which meant that if the user had a stale NFS mount, Elasticsearch could hang and fail on startup if that mount point was not available. Finally, we collected information through Lucene about whether or not a disk was a spinning disk versus an SSD, information that we do not need since we assume SSDs by default. This commit takes into consideration that we simply do not need this heroic effort, we do not need information about all file stores, and we do not need information about whether or not a disk spins to greatly simplfy file store handling. Relates #24402 --- .../org/elasticsearch/env/ESFileStore.java | 132 ++---------------- .../org/elasticsearch/env/Environment.java | 39 +----- .../elasticsearch/env/NodeEnvironment.java | 35 +---- .../org/elasticsearch/monitor/fs/FsInfo.java | 24 +--- .../org/elasticsearch/monitor/fs/FsProbe.java | 1 - .../elasticsearch/bootstrap/security.policy | 1 + .../cluster/node/stats/NodeStatsTests.java | 1 - .../migration/migrate_6_0/stats.asciidoc | 10 ++ 8 files changed, 38 insertions(+), 205 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/env/ESFileStore.java b/core/src/main/java/org/elasticsearch/env/ESFileStore.java index 8ac6cf8a02a..bba1e1e6096 100644 --- a/core/src/main/java/org/elasticsearch/env/ESFileStore.java +++ b/core/src/main/java/org/elasticsearch/env/ESFileStore.java @@ -20,7 +20,6 @@ package org.elasticsearch.env; import org.apache.lucene.util.Constants; -import org.apache.lucene.util.IOUtils; import org.elasticsearch.common.SuppressForbidden; import org.elasticsearch.common.io.PathUtils; @@ -43,24 +42,15 @@ import java.util.List; class ESFileStore extends FileStore { /** Underlying filestore */ final FileStore in; - /** Cached result of Lucene's {@code IOUtils.spins} on path. */ - final Boolean spins; - int majorDeviceNumber; - int minorDeviceNumber; + private int majorDeviceNumber; + private int minorDeviceNumber; @SuppressForbidden(reason = "tries to determine if disk is spinning") // TODO: move PathUtils to be package-private here instead of // public+forbidden api! - ESFileStore(FileStore in) { + ESFileStore(final FileStore in) { this.in = in; - Boolean spins; - // Lucene's IOUtils.spins only works on Linux today: if (Constants.LINUX) { - try { - spins = IOUtils.spins(PathUtils.get(getMountPointLinux(in))); - } catch (Exception e) { - spins = null; - } try { final List lines = Files.readAllLines(PathUtils.get("/proc/self/mountinfo")); for (final String line : lines) { @@ -70,20 +60,21 @@ class ESFileStore extends FileStore { final String[] deviceNumbers = fields[2].split(":"); majorDeviceNumber = Integer.parseInt(deviceNumbers[0]); minorDeviceNumber = Integer.parseInt(deviceNumbers[1]); + break; } } - } catch (Exception e) { + } catch (final Exception e) { majorDeviceNumber = -1; minorDeviceNumber = -1; } } else { - spins = null; + majorDeviceNumber = -1; + minorDeviceNumber = -1; } - this.spins = spins; } - + // these are hacks that are not guaranteed - private static String getMountPointLinux(FileStore store) { + private static String getMountPointLinux(final FileStore store) { String desc = store.toString(); int index = desc.lastIndexOf(" ("); if (index != -1) { @@ -92,109 +83,6 @@ class ESFileStore extends FileStore { return desc; } } - - /** - * Files.getFileStore(Path) useless here! Don't complain, just try it yourself. - */ - @SuppressForbidden(reason = "works around the bugs") - static FileStore getMatchingFileStore(Path path, FileStore fileStores[]) throws IOException { - if (Constants.WINDOWS) { - return getFileStoreWindows(path, fileStores); - } - - final FileStore store; - try { - store = Files.getFileStore(path); - } catch (IOException unexpected) { - // give a better error message if a filestore cannot be retrieved from inside a FreeBSD jail. - if (Constants.FREE_BSD) { - throw new IOException("Unable to retrieve mount point data for " + path + - ". If you are running within a jail, set enforce_statfs=1. See jail(8)", unexpected); - } else { - throw unexpected; - } - } - - try { - String mount = getMountPointLinux(store); - FileStore sameMountPoint = null; - for (FileStore fs : fileStores) { - if (mount.equals(getMountPointLinux(fs))) { - if (sameMountPoint == null) { - sameMountPoint = fs; - } else { - // more than one filesystem has the same mount point; something is wrong! - // fall back to crappy one we got from Files.getFileStore - return store; - } - } - } - - if (sameMountPoint != null) { - // ok, we found only one, use it: - return sameMountPoint; - } else { - // fall back to crappy one we got from Files.getFileStore - return store; - } - } catch (Exception e) { - // ignore - } - - // fall back to crappy one we got from Files.getFileStore - return store; - } - - /** - * remove this code and just use getFileStore for windows on java 9 - * works around https://bugs.openjdk.java.net/browse/JDK-8034057 - */ - @SuppressForbidden(reason = "works around https://bugs.openjdk.java.net/browse/JDK-8034057") - static FileStore getFileStoreWindows(Path path, FileStore fileStores[]) throws IOException { - assert Constants.WINDOWS; - - try { - return Files.getFileStore(path); - } catch (FileSystemException possibleBug) { - final char driveLetter; - // look for a drive letter to see if its the SUBST bug, - // it might be some other type of path, like a windows share - // if something goes wrong, we just deliver the original exception - try { - String root = path.toRealPath().getRoot().toString(); - if (root.length() < 2) { - throw new RuntimeException("root isn't a drive letter: " + root); - } - driveLetter = Character.toLowerCase(root.charAt(0)); - if (Character.isAlphabetic(driveLetter) == false || root.charAt(1) != ':') { - throw new RuntimeException("root isn't a drive letter: " + root); - } - } catch (Exception checkFailed) { - // something went wrong, - possibleBug.addSuppressed(checkFailed); - throw possibleBug; - } - - // we have a drive letter: the hack begins!!!!!!!! - try { - // we have no choice but to parse toString of all stores and find the matching drive letter - for (FileStore store : fileStores) { - String toString = store.toString(); - int length = toString.length(); - if (length > 3 && toString.endsWith(":)") && toString.charAt(length - 4) == '(') { - if (Character.toLowerCase(toString.charAt(length - 3)) == driveLetter) { - return store; - } - } - } - throw new RuntimeException("no filestores matched"); - } catch (Exception weTried) { - IOException newException = new IOException("Unable to retrieve filestore for '" + path + "', tried matching against " + Arrays.toString(fileStores), weTried); - newException.addSuppressed(possibleBug); - throw newException; - } - } - } @Override public String name() { @@ -263,8 +151,6 @@ class ESFileStore extends FileStore { @Override public Object getAttribute(String attribute) throws IOException { switch(attribute) { - // for the device - case "lucene:spins": return spins; // for the partition case "lucene:major_device_number": return majorDeviceNumber; case "lucene:minor_device_number": return minorDeviceNumber; diff --git a/core/src/main/java/org/elasticsearch/env/Environment.java b/core/src/main/java/org/elasticsearch/env/Environment.java index f431a7f646e..0d30f7b576c 100644 --- a/core/src/main/java/org/elasticsearch/env/Environment.java +++ b/core/src/main/java/org/elasticsearch/env/Environment.java @@ -27,6 +27,7 @@ import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.common.settings.Settings; import java.io.IOException; +import java.io.UncheckedIOException; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; @@ -35,7 +36,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.function.Function; @@ -97,22 +100,6 @@ public class Environment { /** Path to the temporary file directory used by the JDK */ private final Path tmpFile = PathUtils.get(System.getProperty("java.io.tmpdir")); - /** List of filestores on the system */ - private static final FileStore[] fileStores; - - /** - * We have to do this in clinit instead of init, because ES code is pretty messy, - * and makes these environments, throws them away, makes them again, etc. - */ - static { - // gather information about filesystems - ArrayList allStores = new ArrayList<>(); - for (FileStore store : PathUtils.getDefaultFileSystem().getFileStores()) { - allStores.add(new ESFileStore(store)); - } - fileStores = allStores.toArray(new ESFileStore[allStores.size()]); - } - public Environment(Settings settings) { final Path homeFile; if (PATH_HOME_SETTING.exists(settings)) { @@ -331,24 +318,8 @@ public class Environment { return tmpFile; } - /** - * Looks up the filestore associated with a Path. - *

- * This is an enhanced version of {@link Files#getFileStore(Path)}: - *

    - *
  • On *nix systems, the store returned for the root filesystem will contain - * the actual filesystem type (e.g. {@code ext4}) instead of {@code rootfs}. - *
  • On some systems, the custom attribute {@code lucene:spins} is supported - * via the {@link FileStore#getAttribute(String)} method. - *
  • Only requires the security permissions of {@link Files#getFileStore(Path)}, - * no permissions to the actual mount point are required. - *
  • Exception handling has the same semantics as {@link Files#getFileStore(Path)}. - *
  • Works around https://bugs.openjdk.java.net/browse/JDK-8034057. - *
  • Gives a better exception when filestore cannot be retrieved from inside a FreeBSD jail. - *
- */ - public static FileStore getFileStore(Path path) throws IOException { - return ESFileStore.getMatchingFileStore(path, fileStores); + public static FileStore getFileStore(final Path path) throws IOException { + return new ESFileStore(Files.getFileStore(path)); } /** diff --git a/core/src/main/java/org/elasticsearch/env/NodeEnvironment.java b/core/src/main/java/org/elasticsearch/env/NodeEnvironment.java index dec59f97f42..a24c3591374 100644 --- a/core/src/main/java/org/elasticsearch/env/NodeEnvironment.java +++ b/core/src/main/java/org/elasticsearch/env/NodeEnvironment.java @@ -94,9 +94,6 @@ public final class NodeEnvironment implements Closeable { public final Path indicesPath; /** Cached FileStore from path */ public final FileStore fileStore; - /** Cached result of Lucene's {@code IOUtils.spins} on path. This is a trilean value: null means we could not determine it (we are - * not running on Linux, or we hit an exception trying), True means the device possibly spins and False means it does not. */ - public final Boolean spins; public final int majorDeviceNumber; public final int minorDeviceNumber; @@ -106,11 +103,9 @@ public final class NodeEnvironment implements Closeable { this.indicesPath = path.resolve(INDICES_FOLDER); this.fileStore = Environment.getFileStore(path); if (fileStore.supportsFileAttributeView("lucene")) { - this.spins = (Boolean) fileStore.getAttribute("lucene:spins"); this.majorDeviceNumber = (int) fileStore.getAttribute("lucene:major_device_number"); this.minorDeviceNumber = (int) fileStore.getAttribute("lucene:minor_device_number"); } else { - this.spins = null; this.majorDeviceNumber = -1; this.minorDeviceNumber = -1; } @@ -136,9 +131,13 @@ public final class NodeEnvironment implements Closeable { public String toString() { return "NodePath{" + "path=" + path + - ", spins=" + spins + + ", indicesPath=" + indicesPath + + ", fileStore=" + fileStore + + ", majorDeviceNumber=" + majorDeviceNumber + + ", minorDeviceNumber=" + minorDeviceNumber + '}'; } + } private final NodePath[] nodePaths; @@ -304,15 +303,6 @@ public final class NodeEnvironment implements Closeable { for (NodePath nodePath : nodePaths) { sb.append('\n').append(" -> ").append(nodePath.path.toAbsolutePath()); - String spinsDesc; - if (nodePath.spins == null) { - spinsDesc = "unknown"; - } else if (nodePath.spins) { - spinsDesc = "possibly"; - } else { - spinsDesc = "no"; - } - FsInfo.Path fsPath = FsProbe.getFSInfo(nodePath); sb.append(", free_space [") .append(fsPath.getFree()) @@ -320,8 +310,6 @@ public final class NodeEnvironment implements Closeable { .append(fsPath.getAvailable()) .append("], total_space [") .append(fsPath.getTotal()) - .append("], spins? [") - .append(spinsDesc) .append("], mount [") .append(fsPath.getMount()) .append("], type [") @@ -332,7 +320,6 @@ public final class NodeEnvironment implements Closeable { } else if (logger.isInfoEnabled()) { FsInfo.Path totFSPath = new FsInfo.Path(); Set allTypes = new HashSet<>(); - Set allSpins = new HashSet<>(); Set allMounts = new HashSet<>(); for (NodePath nodePath : nodePaths) { FsInfo.Path fsPath = FsProbe.getFSInfo(nodePath); @@ -343,21 +330,13 @@ public final class NodeEnvironment implements Closeable { if (type != null) { allTypes.add(type); } - Boolean spins = fsPath.getSpins(); - if (spins == null) { - allSpins.add("unknown"); - } else if (spins.booleanValue()) { - allSpins.add("possibly"); - } else { - allSpins.add("no"); - } totFSPath.add(fsPath); } } // Just log a 1-line summary: - logger.info("using [{}] data paths, mounts [{}], net usable_space [{}], net total_space [{}], spins? [{}], types [{}]", - nodePaths.length, allMounts, totFSPath.getAvailable(), totFSPath.getTotal(), toString(allSpins), toString(allTypes)); + logger.info("using [{}] data paths, mounts [{}], net usable_space [{}], net total_space [{}], types [{}]", + nodePaths.length, allMounts, totFSPath.getAvailable(), totFSPath.getTotal(), toString(allTypes)); } } diff --git a/core/src/main/java/org/elasticsearch/monitor/fs/FsInfo.java b/core/src/main/java/org/elasticsearch/monitor/fs/FsInfo.java index e20eb42427f..6f5e9a52b4f 100644 --- a/core/src/main/java/org/elasticsearch/monitor/fs/FsInfo.java +++ b/core/src/main/java/org/elasticsearch/monitor/fs/FsInfo.java @@ -49,10 +49,6 @@ public class FsInfo implements Iterable, Writeable, ToXContent { long free = -1; long available = -1; - /** Uses Lucene's {@code IOUtils.spins} method to try to determine if the device backed by spinning media. - * This is null if we could not determine it, true if it possibly spins, else false. */ - Boolean spins = null; - public Path() { } @@ -74,7 +70,9 @@ public class FsInfo implements Iterable, Writeable, ToXContent { total = in.readLong(); free = in.readLong(); available = in.readLong(); - spins = in.readOptionalBoolean(); + if (in.getVersion().before(Version.V_6_0_0_alpha1_UNRELEASED)) { + in.readOptionalBoolean(); + } } @Override @@ -85,7 +83,9 @@ public class FsInfo implements Iterable, Writeable, ToXContent { out.writeLong(total); out.writeLong(free); out.writeLong(available); - out.writeOptionalBoolean(spins); + if (out.getVersion().before(Version.V_6_0_0_alpha1_UNRELEASED)) { + out.writeOptionalBoolean(null); + } } public String getPath() { @@ -112,10 +112,6 @@ public class FsInfo implements Iterable, Writeable, ToXContent { return new ByteSizeValue(available); } - public Boolean getSpins() { - return spins; - } - private long addLong(long current, long other) { if (other == -1) { return current; @@ -140,10 +136,6 @@ public class FsInfo implements Iterable, Writeable, ToXContent { total = FsProbe.adjustForHugeFilesystems(addLong(total, path.total)); free = FsProbe.adjustForHugeFilesystems(addLong(free, path.free)); available = FsProbe.adjustForHugeFilesystems(addLong(available, path.available)); - if (path.spins != null && path.spins.booleanValue()) { - // Spinning is contagious! - spins = Boolean.TRUE; - } } static final class Fields { @@ -156,7 +148,6 @@ public class FsInfo implements Iterable, Writeable, ToXContent { static final String FREE_IN_BYTES = "free_in_bytes"; static final String AVAILABLE = "available"; static final String AVAILABLE_IN_BYTES = "available_in_bytes"; - static final String SPINS = "spins"; } @Override @@ -181,9 +172,6 @@ public class FsInfo implements Iterable, Writeable, ToXContent { if (available != -1) { builder.byteSizeField(Fields.AVAILABLE_IN_BYTES, Fields.AVAILABLE, available); } - if (spins != null) { - builder.field(Fields.SPINS, spins.toString()); - } builder.endObject(); return builder; diff --git a/core/src/main/java/org/elasticsearch/monitor/fs/FsProbe.java b/core/src/main/java/org/elasticsearch/monitor/fs/FsProbe.java index 1fdae49a6f1..8e3cd53e74f 100644 --- a/core/src/main/java/org/elasticsearch/monitor/fs/FsProbe.java +++ b/core/src/main/java/org/elasticsearch/monitor/fs/FsProbe.java @@ -159,7 +159,6 @@ public class FsProbe extends AbstractComponent { fsPath.available = nodePath.fileStore.getUsableSpace(); fsPath.type = nodePath.fileStore.type(); fsPath.mount = nodePath.fileStore.toString(); - fsPath.spins = nodePath.spins; return fsPath; } diff --git a/core/src/main/resources/org/elasticsearch/bootstrap/security.policy b/core/src/main/resources/org/elasticsearch/bootstrap/security.policy index 6d28944680e..7b1dcd788c2 100644 --- a/core/src/main/resources/org/elasticsearch/bootstrap/security.policy +++ b/core/src/main/resources/org/elasticsearch/bootstrap/security.policy @@ -120,6 +120,7 @@ grant { permission java.io.FilePermission "/proc/sys/vm/max_map_count", "read"; // io stats on Linux + permission java.io.FilePermission "/proc/self/mountinfo", "read"; permission java.io.FilePermission "/proc/diskstats", "read"; // control group stats on Linux diff --git a/core/src/test/java/org/elasticsearch/action/admin/cluster/node/stats/NodeStatsTests.java b/core/src/test/java/org/elasticsearch/action/admin/cluster/node/stats/NodeStatsTests.java index 0b6b14684f9..9591e31b2b6 100644 --- a/core/src/test/java/org/elasticsearch/action/admin/cluster/node/stats/NodeStatsTests.java +++ b/core/src/test/java/org/elasticsearch/action/admin/cluster/node/stats/NodeStatsTests.java @@ -183,7 +183,6 @@ public class NodeStatsTests extends ESTestCase { assertEquals(fs.getTotal().getFree(), deserializedFs.getTotal().getFree()); assertEquals(fs.getTotal().getMount(), deserializedFs.getTotal().getMount()); assertEquals(fs.getTotal().getPath(), deserializedFs.getTotal().getPath()); - assertEquals(fs.getTotal().getSpins(), deserializedFs.getTotal().getSpins()); assertEquals(fs.getTotal().getType(), deserializedFs.getTotal().getType()); FsInfo.IoStats ioStats = fs.getIoStats(); FsInfo.IoStats deserializedIoStats = deserializedFs.getIoStats(); diff --git a/docs/reference/migration/migrate_6_0/stats.asciidoc b/docs/reference/migration/migrate_6_0/stats.asciidoc index 633604f39ae..ed70d1503c4 100644 --- a/docs/reference/migration/migrate_6_0/stats.asciidoc +++ b/docs/reference/migration/migrate_6_0/stats.asciidoc @@ -5,3 +5,13 @@ Given that store throttling has been removed, the `store` stats do not report `throttle_time` anymore. + +==== FS stats no longer reports if the disk spins + +Elasticsearch has defaulted to assuming that it is running on SSDs since +the 2.x series of Elasticsearch. As such, Elasticsearch no longer needs to +collect information from the operating system as to whether or not the +underlying disks of each data path spin or not. While this functionality was no +longer needed starting in the 2.x series of Elasticsearch, it was maintained in +the filesystem section of the nodes stats APIs. This information has now been +removed. From e9547d6a709541f775fbff9aa2b30a93d8836eea Mon Sep 17 00:00:00 2001 From: Clinton Gormley Date: Thu, 4 May 2017 17:41:21 +0200 Subject: [PATCH 24/44] Rewrote the github issue template to be shorter and more likely to be read (#24486) --- .github/ISSUE_TEMPLATE.md | 47 +++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index ea89d18ca8a..1e4d449a9a5 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,32 +1,26 @@ - -If you are in fact posting a bug report or a feature request, please include -one and only one of the below blocks in your new issue. Note that whether -you're filing a bug report or a feature request, ensure that your submission is -for an [OS that we support](https://www.elastic.co/support/matrix#show_os). Bug -reports on an OS that we do not support or feature requests specific to an OS -that we do not support will be closed. Bug reports that do not follow the below -template are at risk of being closed. ---> +**Describe the feature**: - + **Elasticsearch version**: @@ -39,15 +33,14 @@ and provide responses for all of the below items. **Description of the problem including expected versus actual behavior**: **Steps to reproduce**: + +Please include a *minimal* but *complete* recreation of the problem, including +(e.g.) index creation, mappings, settings, query etc. The easier you make for +us to reproduce it, the more likely that somebody will take the time to look at it. + 1. 2. 3. **Provide logs (if relevant)**: - - -**Describe the feature**: From 6002b41b5f8d6ccfc5b5569ee00958ca565bb7d2 Mon Sep 17 00:00:00 2001 From: Igor Motov Date: Thu, 4 May 2017 12:22:54 -0400 Subject: [PATCH 25/44] Add StreamInput.readEnum and StreamOutput.writeEnum (#24475) Implements the common enum serialization/deserialization pattern for enumeration on the StreamInput/StreamOutput. --- .../cluster/node/DiscoveryNode.java | 8 ++--- .../common/geo/ShapeRelation.java | 8 ++--- .../common/geo/SpatialStrategy.java | 8 ++--- .../common/io/stream/StreamInput.java | 12 ++++++++ .../common/io/stream/StreamOutput.java | 7 +++++ .../search/function/CombineFunction.java | 8 ++--- .../function/FieldValueFactorFunction.java | 8 ++--- .../function/FiltersFunctionScoreQuery.java | 8 ++--- .../org/elasticsearch/index/VersionType.java | 6 ++-- .../elasticsearch/index/query/Operator.java | 8 ++--- .../elasticsearch/search/MultiValueMode.java | 8 ++--- .../search/aggregations/Aggregator.java | 8 ++--- .../percentiles/PercentilesMethod.java | 10 ++----- .../subphase/highlight/HighlightBuilder.java | 16 +++------- .../search/rescore/QueryRescoreMode.java | 10 ++----- .../search/sort/ScriptSortBuilder.java | 8 ++--- .../elasticsearch/search/sort/SortMode.java | 10 ++----- .../elasticsearch/search/sort/SortOrder.java | 8 ++--- .../elasticsearch/search/suggest/SortBy.java | 8 ++--- .../suggest/term/TermSuggestionBuilder.java | 16 +++------- .../common/io/stream/BytesStreamsTests.java | 30 +++++++++++++++++++ 21 files changed, 92 insertions(+), 121 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/cluster/node/DiscoveryNode.java b/core/src/main/java/org/elasticsearch/cluster/node/DiscoveryNode.java index 0e8435d0f8e..caafb82c657 100644 --- a/core/src/main/java/org/elasticsearch/cluster/node/DiscoveryNode.java +++ b/core/src/main/java/org/elasticsearch/cluster/node/DiscoveryNode.java @@ -238,11 +238,7 @@ public class DiscoveryNode implements Writeable, ToXContent { int rolesSize = in.readVInt(); this.roles = EnumSet.noneOf(Role.class); for (int i = 0; i < rolesSize; i++) { - int ordinal = in.readVInt(); - if (ordinal < 0 || ordinal >= Role.values().length) { - throw new IOException("Unknown Role ordinal [" + ordinal + "]"); - } - this.roles.add(Role.values()[ordinal]); + this.roles.add(in.readEnum(Role.class)); } this.version = Version.readVersion(in); } @@ -262,7 +258,7 @@ public class DiscoveryNode implements Writeable, ToXContent { } out.writeVInt(roles.size()); for (Role role : roles) { - out.writeVInt(role.ordinal()); + out.writeEnum(role); } Version.writeVersion(version, out); } diff --git a/core/src/main/java/org/elasticsearch/common/geo/ShapeRelation.java b/core/src/main/java/org/elasticsearch/common/geo/ShapeRelation.java index e9966834a01..e83e18ce432 100644 --- a/core/src/main/java/org/elasticsearch/common/geo/ShapeRelation.java +++ b/core/src/main/java/org/elasticsearch/common/geo/ShapeRelation.java @@ -44,16 +44,12 @@ public enum ShapeRelation implements Writeable { } public static ShapeRelation readFromStream(StreamInput in) throws IOException { - int ordinal = in.readVInt(); - if (ordinal < 0 || ordinal >= values().length) { - throw new IOException("Unknown ShapeRelation ordinal [" + ordinal + "]"); - } - return values()[ordinal]; + return in.readEnum(ShapeRelation.class); } @Override public void writeTo(StreamOutput out) throws IOException { - out.writeVInt(ordinal()); + out.writeEnum(this); } public static ShapeRelation getRelationByName(String name) { diff --git a/core/src/main/java/org/elasticsearch/common/geo/SpatialStrategy.java b/core/src/main/java/org/elasticsearch/common/geo/SpatialStrategy.java index acac5fd6690..0b4f640fd28 100644 --- a/core/src/main/java/org/elasticsearch/common/geo/SpatialStrategy.java +++ b/core/src/main/java/org/elasticsearch/common/geo/SpatialStrategy.java @@ -40,16 +40,12 @@ public enum SpatialStrategy implements Writeable { } public static SpatialStrategy readFromStream(StreamInput in) throws IOException { - int ordinal = in.readVInt(); - if (ordinal < 0 || ordinal >= values().length) { - throw new IOException("Unknown SpatialStrategy ordinal [" + ordinal + "]"); - } - return values()[ordinal]; + return in.readEnum(SpatialStrategy.class); } @Override public void writeTo(StreamOutput out) throws IOException { - out.writeVInt(ordinal()); + out.writeEnum(this); } public static SpatialStrategy fromString(String strategyName) { diff --git a/core/src/main/java/org/elasticsearch/common/io/stream/StreamInput.java b/core/src/main/java/org/elasticsearch/common/io/stream/StreamInput.java index 0efb99a1fab..4681af3392e 100644 --- a/core/src/main/java/org/elasticsearch/common/io/stream/StreamInput.java +++ b/core/src/main/java/org/elasticsearch/common/io/stream/StreamInput.java @@ -901,6 +901,18 @@ public abstract class StreamInput extends InputStream { return builder; } + /** + * Reads an enum with type E that was serialized based on the value of it's ordinal + */ + public > E readEnum(Class enumClass) throws IOException { + int ordinal = readVInt(); + E[] values = enumClass.getEnumConstants(); + if (ordinal < 0 || ordinal >= values.length) { + throw new IOException("Unknown " + enumClass.getSimpleName() + " ordinal [" + ordinal + "]"); + } + return values[ordinal]; + } + public static StreamInput wrap(byte[] bytes) { return wrap(bytes, 0, bytes.length); } diff --git a/core/src/main/java/org/elasticsearch/common/io/stream/StreamOutput.java b/core/src/main/java/org/elasticsearch/common/io/stream/StreamOutput.java index 4d57e7c1b88..5816a9fd469 100644 --- a/core/src/main/java/org/elasticsearch/common/io/stream/StreamOutput.java +++ b/core/src/main/java/org/elasticsearch/common/io/stream/StreamOutput.java @@ -936,4 +936,11 @@ public abstract class StreamOutput extends OutputStream { } } + /** + * Writes an enum with type E that by serialized it based on it's ordinal value + */ + public > void writeEnum(E enumValue) throws IOException { + writeVInt(enumValue.ordinal()); + } + } diff --git a/core/src/main/java/org/elasticsearch/common/lucene/search/function/CombineFunction.java b/core/src/main/java/org/elasticsearch/common/lucene/search/function/CombineFunction.java index e8bd2887998..90d110c3804 100644 --- a/core/src/main/java/org/elasticsearch/common/lucene/search/function/CombineFunction.java +++ b/core/src/main/java/org/elasticsearch/common/lucene/search/function/CombineFunction.java @@ -143,15 +143,11 @@ public enum CombineFunction implements Writeable { @Override public void writeTo(StreamOutput out) throws IOException { - out.writeVInt(this.ordinal()); + out.writeEnum(this); } public static CombineFunction readFromStream(StreamInput in) throws IOException { - int ordinal = in.readVInt(); - if (ordinal < 0 || ordinal >= values().length) { - throw new IOException("Unknown CombineFunction ordinal [" + ordinal + "]"); - } - return values()[ordinal]; + return in.readEnum(CombineFunction.class); } public static CombineFunction fromString(String combineFunction) { diff --git a/core/src/main/java/org/elasticsearch/common/lucene/search/function/FieldValueFactorFunction.java b/core/src/main/java/org/elasticsearch/common/lucene/search/function/FieldValueFactorFunction.java index e225df040ab..1978c0acf0d 100644 --- a/core/src/main/java/org/elasticsearch/common/lucene/search/function/FieldValueFactorFunction.java +++ b/core/src/main/java/org/elasticsearch/common/lucene/search/function/FieldValueFactorFunction.java @@ -191,15 +191,11 @@ public class FieldValueFactorFunction extends ScoreFunction { @Override public void writeTo(StreamOutput out) throws IOException { - out.writeVInt(this.ordinal()); + out.writeEnum(this); } public static Modifier readFromStream(StreamInput in) throws IOException { - int ordinal = in.readVInt(); - if (ordinal < 0 || ordinal >= values().length) { - throw new IOException("Unknown Modifier ordinal [" + ordinal + "]"); - } - return values()[ordinal]; + return in.readEnum(Modifier.class); } @Override diff --git a/core/src/main/java/org/elasticsearch/common/lucene/search/function/FiltersFunctionScoreQuery.java b/core/src/main/java/org/elasticsearch/common/lucene/search/function/FiltersFunctionScoreQuery.java index abf145406c5..2f2a70537c0 100644 --- a/core/src/main/java/org/elasticsearch/common/lucene/search/function/FiltersFunctionScoreQuery.java +++ b/core/src/main/java/org/elasticsearch/common/lucene/search/function/FiltersFunctionScoreQuery.java @@ -81,15 +81,11 @@ public class FiltersFunctionScoreQuery extends Query { @Override public void writeTo(StreamOutput out) throws IOException { - out.writeVInt(this.ordinal()); + out.writeEnum(this); } public static ScoreMode readFromStream(StreamInput in) throws IOException { - int ordinal = in.readVInt(); - if (ordinal < 0 || ordinal >= values().length) { - throw new IOException("Unknown ScoreMode ordinal [" + ordinal + "]"); - } - return values()[ordinal]; + return in.readEnum(ScoreMode.class); } public static ScoreMode fromString(String scoreMode) { diff --git a/core/src/main/java/org/elasticsearch/index/VersionType.java b/core/src/main/java/org/elasticsearch/index/VersionType.java index fcbd6690a38..c5094ea185d 100644 --- a/core/src/main/java/org/elasticsearch/index/VersionType.java +++ b/core/src/main/java/org/elasticsearch/index/VersionType.java @@ -364,13 +364,11 @@ public enum VersionType implements Writeable { } public static VersionType readFromStream(StreamInput in) throws IOException { - int ordinal = in.readVInt(); - assert (ordinal == 0 || ordinal == 1 || ordinal == 2 || ordinal == 3); - return VersionType.values()[ordinal]; + return in.readEnum(VersionType.class); } @Override public void writeTo(StreamOutput out) throws IOException { - out.writeVInt(ordinal()); + out.writeEnum(this); } } diff --git a/core/src/main/java/org/elasticsearch/index/query/Operator.java b/core/src/main/java/org/elasticsearch/index/query/Operator.java index 7972dbb49ad..de88abebad3 100644 --- a/core/src/main/java/org/elasticsearch/index/query/Operator.java +++ b/core/src/main/java/org/elasticsearch/index/query/Operator.java @@ -54,16 +54,12 @@ public enum Operator implements Writeable { } public static Operator readFromStream(StreamInput in) throws IOException { - int ordinal = in.readVInt(); - if (ordinal < 0 || ordinal >= values().length) { - throw new IOException("Unknown Operator ordinal [" + ordinal + "]"); - } - return values()[ordinal]; + return in.readEnum(Operator.class); } @Override public void writeTo(StreamOutput out) throws IOException { - out.writeVInt(this.ordinal()); + out.writeEnum(this); } public static Operator fromString(String op) { diff --git a/core/src/main/java/org/elasticsearch/search/MultiValueMode.java b/core/src/main/java/org/elasticsearch/search/MultiValueMode.java index 2d6fd8a2b60..231bc8bf3c0 100644 --- a/core/src/main/java/org/elasticsearch/search/MultiValueMode.java +++ b/core/src/main/java/org/elasticsearch/search/MultiValueMode.java @@ -948,14 +948,10 @@ public enum MultiValueMode implements Writeable { @Override public void writeTo(StreamOutput out) throws IOException { - out.writeVInt(this.ordinal()); + out.writeEnum(this); } public static MultiValueMode readMultiValueModeFrom(StreamInput in) throws IOException { - int ordinal = in.readVInt(); - if (ordinal < 0 || ordinal >= values().length) { - throw new IOException("Unknown MultiValueMode ordinal [" + ordinal + "]"); - } - return values()[ordinal]; + return in.readEnum(MultiValueMode.class); } } diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/Aggregator.java b/core/src/main/java/org/elasticsearch/search/aggregations/Aggregator.java index 44adb33c01b..41a0fa6dd30 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/Aggregator.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/Aggregator.java @@ -139,16 +139,12 @@ public abstract class Aggregator extends BucketCollector implements Releasable { } public static SubAggCollectionMode readFromStream(StreamInput in) throws IOException { - int ordinal = in.readVInt(); - if (ordinal < 0 || ordinal >= values().length) { - throw new IOException("Unknown SubAggCollectionMode ordinal [" + ordinal + "]"); - } - return values()[ordinal]; + return in.readEnum(SubAggCollectionMode.class); } @Override public void writeTo(StreamOutput out) throws IOException { - out.writeVInt(ordinal()); + out.writeEnum(this); } } } diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/PercentilesMethod.java b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/PercentilesMethod.java index b10880a13c0..3b8085793dc 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/PercentilesMethod.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/PercentilesMethod.java @@ -53,20 +53,16 @@ public enum PercentilesMethod implements Writeable { } public static PercentilesMethod readFromStream(StreamInput in) throws IOException { - int ordinal = in.readVInt(); - if (ordinal < 0 || ordinal >= values().length) { - throw new IOException("Unknown PercentilesMethod ordinal [" + ordinal + "]"); - } - return values()[ordinal]; + return in.readEnum(PercentilesMethod.class); } @Override public void writeTo(StreamOutput out) throws IOException { - out.writeVInt(ordinal()); + out.writeEnum(this); } @Override public String toString() { return parseField.getPreferredName(); } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightBuilder.java b/core/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightBuilder.java index c7c9c547b51..5e49aa7395d 100644 --- a/core/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightBuilder.java @@ -504,16 +504,12 @@ public class HighlightBuilder extends AbstractHighlighterBuilder= values().length) { - throw new IOException("Unknown Order ordinal [" + ordinal + "]"); - } - return values()[ordinal]; + return in.readEnum(Order.class); } @Override public void writeTo(StreamOutput out) throws IOException { - out.writeVInt(this.ordinal()); + out.writeEnum(this); } public static Order fromString(String order) { @@ -533,16 +529,12 @@ public class HighlightBuilder extends AbstractHighlighterBuilder= values().length) { - throw new IOException("Unknown BoundaryScannerType ordinal [" + ordinal + "]"); - } - return values()[ordinal]; + return in.readEnum(BoundaryScannerType.class); } @Override public void writeTo(StreamOutput out) throws IOException { - out.writeVInt(this.ordinal()); + out.writeEnum(this); } public static BoundaryScannerType fromString(String boundaryScannerType) { diff --git a/core/src/main/java/org/elasticsearch/search/rescore/QueryRescoreMode.java b/core/src/main/java/org/elasticsearch/search/rescore/QueryRescoreMode.java index 70718b56c0c..51db82652fc 100644 --- a/core/src/main/java/org/elasticsearch/search/rescore/QueryRescoreMode.java +++ b/core/src/main/java/org/elasticsearch/search/rescore/QueryRescoreMode.java @@ -86,16 +86,12 @@ public enum QueryRescoreMode implements Writeable { public abstract float combine(float primary, float secondary); public static QueryRescoreMode readFromStream(StreamInput in) throws IOException { - int ordinal = in.readVInt(); - if (ordinal < 0 || ordinal >= values().length) { - throw new IOException("Unknown ScoreMode ordinal [" + ordinal + "]"); - } - return values()[ordinal]; + return in.readEnum(QueryRescoreMode.class); } @Override public void writeTo(StreamOutput out) throws IOException { - out.writeVInt(this.ordinal()); + out.writeEnum(this); } public static QueryRescoreMode fromString(String scoreMode) { @@ -111,4 +107,4 @@ public enum QueryRescoreMode implements Writeable { public String toString() { return name().toLowerCase(Locale.ROOT); } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/elasticsearch/search/sort/ScriptSortBuilder.java b/core/src/main/java/org/elasticsearch/search/sort/ScriptSortBuilder.java index 2901e05f051..b136dd77989 100644 --- a/core/src/main/java/org/elasticsearch/search/sort/ScriptSortBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/sort/ScriptSortBuilder.java @@ -350,18 +350,14 @@ public class ScriptSortBuilder extends SortBuilder { @Override public void writeTo(final StreamOutput out) throws IOException { - out.writeVInt(ordinal()); + out.writeEnum(this); } /** * Read from a stream. */ static ScriptSortType readFromStream(final StreamInput in) throws IOException { - int ordinal = in.readVInt(); - if (ordinal < 0 || ordinal >= values().length) { - throw new IOException("Unknown ScriptSortType ordinal [" + ordinal + "]"); - } - return values()[ordinal]; + return in.readEnum(ScriptSortType.class); } public static ScriptSortType fromString(final String str) { diff --git a/core/src/main/java/org/elasticsearch/search/sort/SortMode.java b/core/src/main/java/org/elasticsearch/search/sort/SortMode.java index 21495798a89..07b5bfa98c2 100644 --- a/core/src/main/java/org/elasticsearch/search/sort/SortMode.java +++ b/core/src/main/java/org/elasticsearch/search/sort/SortMode.java @@ -52,15 +52,11 @@ public enum SortMode implements Writeable { @Override public void writeTo(final StreamOutput out) throws IOException { - out.writeVInt(ordinal()); + out.writeEnum(this); } public static SortMode readFromStream(StreamInput in) throws IOException { - int ordinal = in.readVInt(); - if (ordinal < 0 || ordinal >= values().length) { - throw new IOException("Unknown SortMode ordinal [" + ordinal + "]"); - } - return values()[ordinal]; + return in.readEnum(SortMode.class); } public static SortMode fromString(final String str) { @@ -85,4 +81,4 @@ public enum SortMode implements Writeable { public String toString() { return name().toLowerCase(Locale.ROOT); } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/elasticsearch/search/sort/SortOrder.java b/core/src/main/java/org/elasticsearch/search/sort/SortOrder.java index cd0a3bb6d46..fbcb7b4288e 100644 --- a/core/src/main/java/org/elasticsearch/search/sort/SortOrder.java +++ b/core/src/main/java/org/elasticsearch/search/sort/SortOrder.java @@ -52,16 +52,12 @@ public enum SortOrder implements Writeable { }; static SortOrder readFromStream(StreamInput in) throws IOException { - int ordinal = in.readVInt(); - if (ordinal < 0 || ordinal >= values().length) { - throw new IOException("Unknown SortOrder ordinal [" + ordinal + "]"); - } - return values()[ordinal]; + return in.readEnum(SortOrder.class); } @Override public void writeTo(StreamOutput out) throws IOException { - out.writeVInt(this.ordinal()); + out.writeEnum(this); } public static SortOrder fromString(String op) { diff --git a/core/src/main/java/org/elasticsearch/search/suggest/SortBy.java b/core/src/main/java/org/elasticsearch/search/suggest/SortBy.java index 3cd19c5c2fb..328fc4e8218 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/SortBy.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/SortBy.java @@ -38,15 +38,11 @@ public enum SortBy implements Writeable { @Override public void writeTo(final StreamOutput out) throws IOException { - out.writeVInt(ordinal()); + out.writeEnum(this); } public static SortBy readFromStream(final StreamInput in) throws IOException { - int ordinal = in.readVInt(); - if (ordinal < 0 || ordinal >= values().length) { - throw new IOException("Unknown SortBy ordinal [" + ordinal + "]"); - } - return values()[ordinal]; + return in.readEnum(SortBy.class); } public static SortBy resolve(final String str) { diff --git a/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestionBuilder.java b/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestionBuilder.java index 72fd41dc5b4..f701ff36426 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestionBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestionBuilder.java @@ -511,15 +511,11 @@ public class TermSuggestionBuilder extends SuggestionBuilder= values().length) { - throw new IOException("Unknown SuggestMode ordinal [" + ordinal + "]"); - } - return values()[ordinal]; + return in.readEnum(SuggestMode.class); } public static SuggestMode resolve(final String str) { @@ -571,15 +567,11 @@ public class TermSuggestionBuilder extends SuggestionBuilder= values().length) { - throw new IOException("Unknown StringDistanceImpl ordinal [" + ordinal + "]"); - } - return values()[ordinal]; + return in.readEnum(StringDistanceImpl.class); } public static StringDistanceImpl resolve(final String str) { diff --git a/core/src/test/java/org/elasticsearch/common/io/stream/BytesStreamsTests.java b/core/src/test/java/org/elasticsearch/common/io/stream/BytesStreamsTests.java index a8b065343c9..b67000e2b23 100644 --- a/core/src/test/java/org/elasticsearch/common/io/stream/BytesStreamsTests.java +++ b/core/src/test/java/org/elasticsearch/common/io/stream/BytesStreamsTests.java @@ -812,4 +812,34 @@ public class BytesStreamsTests extends ESTestCase { StreamInput in = new BytesArray(Base64.getDecoder().decode("////////////AQAAAAAAAA==")).streamInput(); assertEquals(-1, in.readVLong()); } + + public enum TestEnum { + ONE, + TWO, + THREE + } + + public void testEnum() throws IOException { + TestEnum value = randomFrom(TestEnum.values()); + BytesStreamOutput output = new BytesStreamOutput(); + output.writeEnum(value); + StreamInput input = output.bytes().streamInput(); + assertEquals(value, input.readEnum(TestEnum.class)); + assertEquals(0, input.available()); + } + + public void testInvalidEnum() throws IOException { + BytesStreamOutput output = new BytesStreamOutput(); + int randomNumber = randomInt(); + boolean validEnum = randomNumber >= 0 && randomNumber < TestEnum.values().length; + output.writeVInt(randomNumber); + StreamInput input = output.bytes().streamInput(); + if (validEnum) { + assertEquals(TestEnum.values()[randomNumber], input.readEnum(TestEnum.class)); + } else { + IOException ex = expectThrows(IOException.class, () -> input.readEnum(TestEnum.class)); + assertEquals("Unknown TestEnum ordinal [" + randomNumber + "]", ex.getMessage()); + } + assertEquals(0, input.available()); + } } From 9bc7e210a03a128dd8e7283305ff50b594d945ff Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Thu, 4 May 2017 13:11:09 -0400 Subject: [PATCH 26/44] Test: Move flag to painless tests (#24494) The `-XX:-OmitStackTraceInFastThrow` flag is only required by Painless's tests so we'll only set it there. This is much simpler. --- .../org/elasticsearch/gradle/BuildPlugin.groovy | 13 +------------ modules/lang-painless/build.gradle | 6 ++++-- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy index 3acf865f7bc..b3c2f4faef8 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy @@ -468,18 +468,7 @@ class BuildPlugin implements Plugin { File heapdumpDir = new File(project.buildDir, 'heapdump') heapdumpDir.mkdirs() jvmArg '-XX:HeapDumpPath=' + heapdumpDir - /* - * We only want to append -XX:-OmitStackTraceInFastThrow if a flag for OmitStackTraceInFastThrow is not already included in - * tests.jvm.argline. - */ - final String testsJvmArgline = System.getProperty('tests.jvm.argline') - if (testsJvmArgline == null) { - argLine '-XX:-OmitStackTraceInFastThrow' - } else if (testsJvmArgline.indexOf("OmitStackTraceInFastThrow") < 0) { - argLine testsJvmArgline.trim() + ' ' + '-XX:-OmitStackTraceInFastThrow' - } else { - argLine testsJvmArgline.trim() - } + argLine System.getProperty('tests.jvm.argline') // we use './temp' since this is per JVM and tests are forbidden from writing to CWD systemProperty 'java.io.tmpdir', './temp' diff --git a/modules/lang-painless/build.gradle b/modules/lang-painless/build.gradle index 31b41261b3a..85f609d7757 100644 --- a/modules/lang-painless/build.gradle +++ b/modules/lang-painless/build.gradle @@ -33,6 +33,10 @@ dependencyLicenses { mapping from: /asm-.*/, to: 'asm' } +test { + jvmArg '-XX:-OmitStackTraceInFastThrow' +} + integTestCluster { setting 'script.max_compilations_per_minute', '1000' } @@ -146,5 +150,3 @@ task regen { } } } - - From 9f431543fc56b9b824d2c273c0a751b5fcee4a7a Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Thu, 4 May 2017 17:30:54 -0400 Subject: [PATCH 27/44] CONSOLEify inner hits docs Rewrites most of the snippets in the `innert_hits` docs to be complete examples and enables `VIEW IN CONSOLE`, `COPY AS CURL`, and automatic testing of the snippets. --- docs/build.gradle | 1 - .../search/request/inner-hits.asciidoc | 426 ++++++++++++++---- 2 files changed, 334 insertions(+), 93 deletions(-) diff --git a/docs/build.gradle b/docs/build.gradle index 699cda15872..204b9abb1b9 100644 --- a/docs/build.gradle +++ b/docs/build.gradle @@ -59,7 +59,6 @@ buildRestTests.expectedUnconvertedCandidates = [ 'reference/modules/cross-cluster-search.asciidoc', // this is hard to test since we need 2 clusters -- maybe we can trick it into referencing itself... 'reference/search/field-stats.asciidoc', 'reference/search/profile.asciidoc', - 'reference/search/request/inner-hits.asciidoc', ] integTestCluster { diff --git a/docs/reference/search/request/inner-hits.asciidoc b/docs/reference/search/request/inner-hits.asciidoc index 1b118a419ed..900426bee9b 100644 --- a/docs/reference/search/request/inner-hits.asciidoc +++ b/docs/reference/search/request/inner-hits.asciidoc @@ -22,6 +22,7 @@ The structure looks like this: } } -------------------------------------------------- +// NOTCONSOLE If `inner_hits` is defined on a query that supports it then each search hit will contain an `inner_hits` json object with the following structure: @@ -52,6 +53,7 @@ If `inner_hits` is defined on a query that supports it then each search hit will ... ] -------------------------------------------------- +// NOTCONSOLE ==== Options @@ -80,22 +82,50 @@ Inner hits also supports the following per document features: The nested `inner_hits` can be used to include nested inner objects as inner hits to a search hit. -The example below assumes that there is a nested object field defined with the name `comments`: - [source,js] -------------------------------------------------- +PUT test { - "query" : { - "nested" : { - "path" : "comments", - "query" : { - "match" : {"comments.message" : "[actual query]"} - }, - "inner_hits" : {} <1> + "mappings": { + "doc": { + "properties": { + "comments": { + "type": "nested" } + } } + } +} + +PUT test/doc/1?refresh +{ + "title": "Test title", + "comments": [ + { + "author": "kimchy", + "text": "comment text" + }, + { + "author": "nik9000", + "text": "words words words" + } + ] +} + +POST test/_search +{ + "query": { + "nested": { + "path": "comments", + "query": { + "match": {"comments.text" : "words"} + }, + "inner_hits": {} <1> + } + } } -------------------------------------------------- +// CONSOLE <1> The inner hit definition in the nested query. No other options need to be defined. @@ -103,35 +133,46 @@ An example of a response snippet that could be generated from the above search r [source,js] -------------------------------------------------- -... -"hits": { - ... - "hits": [ - { - "_index": "my-index", - "_type": "question", +{ + ..., + "hits": { + "total": 1, + "max_score": 0.9651416, + "hits": [ + { + "_index": "test", + "_type": "doc", "_id": "1", + "_score": 0.9651416, "_source": ..., "inner_hits": { - "comments": { <1> - "hits": { - "total": ..., - "hits": [ - { - "_nested": { - "field": "comments", - "offset": 2 - }, - "_source": ... - }, - ... - ] - } - } + "comments": { <1> + "hits": { + "total": 1, + "max_score": 0.9651416, + "hits": [ + { + "_nested": { + "field": "comments", + "offset": 1 + }, + "_score": 0.9651416, + "_source": { + "author": "nik9000", + "text": "words words words" + } + } + ] + } + } } - }, - ... + } + ] + } +} -------------------------------------------------- +// TESTRESPONSE[s/"_source": \.\.\./"_source": $body.hits.hits.0._source/] +// TESTRESPONSE[s/\.\.\./"timed_out": false, "took": $body.took, "_shards": $body._shards/] <1> The name used in the inner hit definition in the search request. A custom key can be used via the `name` option. @@ -156,46 +197,111 @@ its `_source` field. To include the source of just the nested document, the sour the relevant bit for the nested document is included as source in the inner hit. Doing this for each matching nested document has an impact on the time it takes to execute the entire search request, especially when `size` and the inner hits' `size` are set higher than the default. To avoid the relative expensive source extraction for nested inner hits, one can disable -including the source and solely rely on stored fields. - -Enabled stored field for fields under the nested object field in your mapping: +including the source and solely rely on stored fields. Like this: [source,js] -------------------------------------------------- +PUT test { - "properties": { - "comment": { - "type": "comments", - "properties" : { - "message" : { - "type" : "text", - "store" : true + "mappings": { + "doc": { + "properties": { + "comments": { + "type": "nested", + "properties": { + "text": { + "type": "text", + "store": true } } } + } } + } +} + +PUT test/doc/1?refresh +{ + "title": "Test title", + "comments": [ + { + "author": "kimchy", + "text": "comment text" + }, + { + "author": "nik9000", + "text": "words words words" + } + ] +} + +POST test/_search +{ + "query": { + "nested": { + "path": "comments", + "query": { + "match": {"comments.text" : "words"} + }, + "inner_hits": { + "_source" : false, + "stored_fields" : ["comments.text"] + } + } + } } -------------------------------------------------- +// CONSOLE -Disable including source and include specific stored fields in the inner hits definition: +//// + +Response not included in text but tested for completeness sake. [source,js] -------------------------------------------------- { - "query" : { - "nested" : { - "path" : "comments", - "query" : { - "match" : {"comments.message" : "[actual query]"} - }, - "inner_hits" : { - "_source" : false, - "stored_fields" : ["comments.text"] + ..., + "hits": { + "total": 1, + "max_score": 0.9651416, + "hits": [ + { + "_index": "test", + "_type": "doc", + "_id": "1", + "_score": 0.9651416, + "_source": ..., + "inner_hits": { + "comments": { <1> + "hits": { + "total": 1, + "max_score": 0.9651416, + "hits": [ + { + "_nested": { + "field": "comments", + "offset": 1 + }, + "_score": 0.9651416, + "fields": { + "comments.text": [ + "words words words" + ] + } + } + ] } + } } - } + } + ] + } } -------------------------------------------------- +// TESTRESPONSE[s/"_source": \.\.\./"_source": $body.hits.hits.0._source/] +// TESTRESPONSE[s/\.\.\./"timed_out": false, "took": $body.took, "_shards": $body._shards/] + +//// [[hierarchical-nested-inner-hits]] ==== Hierarchical levels of nested object fields and inner hits. @@ -206,16 +312,113 @@ with the root hits then the following path can be defined: [source,js] -------------------------------------------------- +PUT test { - "query" : { - "nested" : { - "path" : "comments.votes", - "query" : { ... }, - "inner_hits" : {} + "mappings": { + "doc": { + "properties": { + "comments": { + "type": "nested", + "properties": { + "message": { + "type": "text", + "store": true + }, + "votes": { + "type": "nested" + } + } + } } } + } +} + +PUT test/doc/1?refresh +{ + "title": "Test title", + "comments": [ + { + "author": "kimchy", + "text": "comment text", + "votes": [] + }, + { + "author": "nik9000", + "text": "words words words", + "votes": [ + {"value": 1 , "voter": "kimchy"}, + {"value": -1, "voter": "other"} + ] + } + ] +} + +POST test/_search +{ + "query": { + "nested": { + "path": "comments.votes", + "query": { + "match": { + "comments.votes.voter": "kimchy" + } + }, + "inner_hits" : {} + } + } } -------------------------------------------------- +// CONSOLE + +Which would look like: + +[source,js] +-------------------------------------------------- +{ + ..., + "hits": { + "total": 1, + "max_score": 0.6931472, + "hits": [ + { + "_index": "test", + "_type": "doc", + "_id": "1", + "_score": 0.6931472, + "_source": ..., + "inner_hits": { + "comments.votes": { <1> + "hits": { + "total": 1, + "max_score": 0.6931472, + "hits": [ + { + "_nested": { + "field": "comments", + "offset": 1, + "_nested": { + "field": "votes", + "offset": 0 + } + }, + "_score": 0.6931472, + "_source": { + "value": 1, + "voter": "kimchy" + } + } + ] + } + } + } + } + ] + } +} +-------------------------------------------------- +// TESTRESPONSE[s/"_source": \.\.\./"_source": $body.hits.hits.0._source/] +// TESTRESPONSE[s/\.\.\./"timed_out": false, "took": $body.took, "_shards": $body._shards/] This indirect referencing is only supported for nested inner hits. @@ -224,22 +427,49 @@ This indirect referencing is only supported for nested inner hits. The parent/child `inner_hits` can be used to include parent or child -The examples below assumes that there is a `_parent` field mapping in the `comment` type: - [source,js] -------------------------------------------------- +PUT test { - "query" : { - "has_child" : { - "type" : "comment", - "query" : { - "match" : {"message" : "[actual query]"} - }, - "inner_hits" : {} <1> - } + "settings": { + "mapping.single_type": false + }, + "mappings": { + "my_parent": {}, + "my_child": { + "_parent": { + "type": "my_parent" + } } + } +} + +PUT test/my_parent/1?refresh +{ + "test": "test" +} + +PUT test/my_child/1?parent=1&refresh +{ + "test": "test" +} + +POST test/_search +{ + "query": { + "has_child": { + "type": "my_child", + "query": { + "match": { + "test": "test" + } + }, + "inner_hits": {} <1> + } + } } -------------------------------------------------- +// CONSOLE <1> The inner hit definition like in the nested example. @@ -247,30 +477,42 @@ An example of a response snippet that could be generated from the above search r [source,js] -------------------------------------------------- -... -"hits": { - ... - "hits": [ - { - "_index": "my-index", - "_type": "question", +{ + ..., + "hits": { + "total": 1, + "max_score": 1.0, + "hits": [ + { + "_index": "test", + "_type": "my_parent", "_id": "1", + "_score": 1.0, "_source": ..., "inner_hits": { - "comment": { - "hits": { - "total": ..., - "hits": [ - { - "_type": "comment", - "_id": "5", - "_source": ... - }, - ... - ] - } - } + "my_child": { + "hits": { + "total": 1, + "max_score": 0.18232156, + "hits": [ + { + "_type": "my_child", + "_id": "1", + "_score": 0.18232156, + "_routing": "1", + "_parent": "1", + "_source": { + "test": "test" + } + } + ] + } + } } - }, - ... --------------------------------------------------- \ No newline at end of file + } + ] + } +} +-------------------------------------------------- +// TESTRESPONSE[s/"_source": \.\.\./"_source": $body.hits.hits.0._source/] +// TESTRESPONSE[s/\.\.\./"timed_out": false, "took": $body.took, "_shards": $body._shards/] From 559bec23cca3ad70aa251f163834d18b6bbd2686 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Thu, 4 May 2017 17:57:25 -0400 Subject: [PATCH 28/44] Docs: rewrite the docs/README file I originally wrote this file when we first added snippets testing and a lot has changed. We've grown quite fond of the `// TESTRESPONSE[s/foo/bar/]` construct, for example, but the docs discouraged its use. Relates to #18160 --- docs/README.asciidoc | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/docs/README.asciidoc b/docs/README.asciidoc index 9365f877eb5..90602d76ffa 100644 --- a/docs/README.asciidoc +++ b/docs/README.asciidoc @@ -4,24 +4,28 @@ Elasticsearch documentation build process. See: https://github.com/elastic/docs Snippets marked with `// CONSOLE` are automatically annotated with "VIEW IN -CONSOLE" in the documentation and are automatically tested by the command -`gradle :docs:check`. To test just the docs from a single page, use e.g. -`gradle :docs:check -Dtests.method=*rollover*`. +CONSOLE" and "COPY AS CURL" in the documentation and are automatically tested +by the command `gradle :docs:check`. To test just the docs from a single page, +use e.g. `gradle :docs:check -Dtests.method=*rollover*`. -By default `// CONSOLE` snippet runs as its own isolated -test. You can manipulate the test execution in the following ways: +By default each `// CONSOLE` snippet runs as its own isolated test. You can +manipulate the test execution in the following ways: * `// TEST`: Explicitly marks a snippet as a test. Snippets marked this way -are tests even if they don't have `// CONSOLE`. - * `// TEST[s/foo/bar/]`: Replace `foo` with `bar` in the test. This should be - used sparingly because it makes the test "lie". Sometimes, though, you can use - it to make the tests more clear. +are tests even if they don't have `// CONSOLE` but usually `// TEST` is used +for its modifiers: + * `// TEST[s/foo/bar/]`: Replace `foo` with `bar` in the generated test. This + should be used sparingly because it makes the snippet "lie". Sometimes, + though, you can use it to make the snippet more clear more clear. Keep in + mind the that if there are multiple substitutions then they are applied in + the order that they are defined. * `// TEST[catch:foo]`: Used to expect errors in the requests. Replace `foo` with `request` to expect a 400 error, for example. If the snippet contains multiple requests then only the last request will expect the error. * `// TEST[continued]`: Continue the test started in the last snippet. Between - tests the nodes are cleaned: indexes are removed, etc. This will prevent that. - This is really useful when you have text and snippets that work together to + tests the nodes are cleaned: indexes are removed, etc. This prevents that + from happening between snippets because the two snippets are a single test. + This is most useful when you have text and snippets that work together to tell the story of some use case because it merges the snippets (and thus the use case) into one big test. * `// TEST[skip:reason]`: Skip this test. Replace `reason` with the actual @@ -38,8 +42,11 @@ are tests even if they don't have `// CONSOLE`. * `// TESTRESPONSE`: Matches this snippet against the body of the response of the last test. If the response is JSON then order is ignored. If you add `// TEST[continued]` to the snippet after `// TESTRESPONSE` it will continue - in the same test, allowing you to interleve requests with responses to check. - * `// TESTRESPONSE[s/foo/bar/]`: Substitutions. See `// TEST[s/foo/bar]`. + in the same test, allowing you to interleave requests with responses to check. + * `// TESTRESPONSE[s/foo/bar/]`: Substitutions. See `// TEST[s/foo/bar]` for + how it works. These are much more common than `// TEST[s/foo/bar]` because + they are useful for eliding portions of the response that are not pertinent + to the documentation. * `// TESTRESPONSE[_cat]`: Add substitutions for testing `_cat` responses. Use this after all other substitutions so it doesn't make other substitutions difficult. From a01f8462260c3e985660ffab063726c0ff6b69bf Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Thu, 4 May 2017 21:01:14 -0400 Subject: [PATCH 29/44] CONSOLEify a few more docs Adds CONSOLE to cross-cluster-search docs but skips them for testing because we don't have a second cluster set up. This gets us the `VIEW IN CONSOLE` and `COPY AS CURL` links and makes sure that they are valid yaml (not json, technically) but doesn't get testing. Which is better than we had before. Adds CONSOLE to the dynamic templates docs and ingest-node docs. The ingest-node docs contain a *ton* of non-console snippets. We might want to convert them to full examples later, but that can be a separate thing. Relates to #18160 --- docs/build.gradle | 3 - docs/reference/ingest/ingest-node.asciidoc | 110 +++++++++++------- .../mapping/dynamic/templates.asciidoc | 7 +- .../modules/cross-cluster-search.asciidoc | 9 +- 4 files changed, 83 insertions(+), 46 deletions(-) diff --git a/docs/build.gradle b/docs/build.gradle index 204b9abb1b9..ef53bd135ab 100644 --- a/docs/build.gradle +++ b/docs/build.gradle @@ -54,9 +54,6 @@ buildRestTests.expectedUnconvertedCandidates = [ 'reference/indices/recovery.asciidoc', 'reference/indices/segments.asciidoc', 'reference/indices/shard-stores.asciidoc', - 'reference/ingest/ingest-node.asciidoc', - 'reference/mapping/dynamic/templates.asciidoc', - 'reference/modules/cross-cluster-search.asciidoc', // this is hard to test since we need 2 clusters -- maybe we can trick it into referencing itself... 'reference/search/field-stats.asciidoc', 'reference/search/profile.asciidoc', ] diff --git a/docs/reference/ingest/ingest-node.asciidoc b/docs/reference/ingest/ingest-node.asciidoc index f195ee1f2fd..723d7205cfc 100644 --- a/docs/reference/ingest/ingest-node.asciidoc +++ b/docs/reference/ingest/ingest-node.asciidoc @@ -12,6 +12,7 @@ and a list of `processors`: "processors" : [ ... ] } -------------------------------------------------- +// NOTCONSOLE The `description` is a special field to store a helpful description of what the pipeline does. @@ -126,6 +127,7 @@ using `filter_path` to limit the response to just the `version`: -------------------------------------------------- GET /_ingest/pipeline/my-pipeline-id?filter_path=*.version -------------------------------------------------- +// CONSOLE // TEST[continued] This should give a small response that makes it both easy and inexpensive to parse: @@ -209,6 +211,7 @@ POST _ingest/pipeline/_simulate ] } -------------------------------------------------- +// NOTCONSOLE Here is the structure of a simulate request against an existing pipeline: @@ -223,7 +226,7 @@ POST _ingest/pipeline/my-pipeline-id/_simulate ] } -------------------------------------------------- - +// NOTCONSOLE Here is an example of a simulate request with a pipeline defined in the request and its response: @@ -275,42 +278,36 @@ Response: { "doc": { "_id": "id", - "_ttl": null, - "_parent": null, "_index": "index", - "_routing": null, "_type": "type", - "_timestamp": null, "_source": { "field2": "_value", "foo": "bar" }, "_ingest": { - "timestamp": "2016-01-04T23:53:27.186+0000" + "timestamp": "2017-05-04T22:30:03.187Z" } } }, { "doc": { "_id": "id", - "_ttl": null, - "_parent": null, "_index": "index", - "_routing": null, "_type": "type", - "_timestamp": null, "_source": { "field2": "_value", "foo": "rab" }, "_ingest": { - "timestamp": "2016-01-04T23:53:27.186+0000" + "timestamp": "2017-05-04T22:30:03.188Z" } } } ] } -------------------------------------------------- +// TESTRESPONSE[s/"2017-05-04T22:30:03.187Z"/$body.docs.0.doc._ingest.timestamp/] +// TESTRESPONSE[s/"2017-05-04T22:30:03.188Z"/$body.docs.1.doc._ingest.timestamp/] [[ingest-verbose-param]] ==== Viewing Verbose Results @@ -374,41 +371,31 @@ Response: { "processor_results": [ { - "tag": "processor[set]-0", "doc": { "_id": "id", - "_ttl": null, - "_parent": null, "_index": "index", - "_routing": null, "_type": "type", - "_timestamp": null, "_source": { "field2": "_value2", "foo": "bar" }, "_ingest": { - "timestamp": "2016-01-05T00:02:51.383+0000" + "timestamp": "2017-05-04T22:46:09.674Z" } } }, { - "tag": "processor[set]-1", "doc": { "_id": "id", - "_ttl": null, - "_parent": null, "_index": "index", - "_routing": null, "_type": "type", - "_timestamp": null, "_source": { "field3": "_value3", "field2": "_value2", "foo": "bar" }, "_ingest": { - "timestamp": "2016-01-05T00:02:51.383+0000" + "timestamp": "2017-05-04T22:46:09.675Z" } } } @@ -417,41 +404,31 @@ Response: { "processor_results": [ { - "tag": "processor[set]-0", "doc": { "_id": "id", - "_ttl": null, - "_parent": null, "_index": "index", - "_routing": null, "_type": "type", - "_timestamp": null, "_source": { "field2": "_value2", "foo": "rab" }, "_ingest": { - "timestamp": "2016-01-05T00:02:51.384+0000" + "timestamp": "2017-05-04T22:46:09.676Z" } } }, { - "tag": "processor[set]-1", "doc": { "_id": "id", - "_ttl": null, - "_parent": null, "_index": "index", - "_routing": null, "_type": "type", - "_timestamp": null, "_source": { "field3": "_value3", "field2": "_value2", "foo": "rab" }, "_ingest": { - "timestamp": "2016-01-05T00:02:51.384+0000" + "timestamp": "2017-05-04T22:46:09.677Z" } } } @@ -460,6 +437,10 @@ Response: ] } -------------------------------------------------- +// TESTRESPONSE[s/"2017-05-04T22:46:09.674Z"/$body.docs.0.processor_results.0.doc._ingest.timestamp/] +// TESTRESPONSE[s/"2017-05-04T22:46:09.675Z"/$body.docs.0.processor_results.1.doc._ingest.timestamp/] +// TESTRESPONSE[s/"2017-05-04T22:46:09.676Z"/$body.docs.1.processor_results.0.doc._ingest.timestamp/] +// TESTRESPONSE[s/"2017-05-04T22:46:09.677Z"/$body.docs.1.processor_results.1.doc._ingest.timestamp/] [[accessing-data-in-pipelines]] == Accessing Data in Pipelines @@ -482,6 +463,7 @@ their name. For example: } } -------------------------------------------------- +// NOTCONSOLE On top of this, fields from the source are always accessible via the `_source` prefix: @@ -494,6 +476,7 @@ On top of this, fields from the source are always accessible via the `_source` p } } -------------------------------------------------- +// NOTCONSOLE [float] [[accessing-metadata-fields]] @@ -513,6 +496,7 @@ The following example sets the `_id` metadata field of a document to `1`: } } -------------------------------------------------- +// NOTCONSOLE The following metadata fields are accessible by a processor: `_index`, `_type`, `_id`, `_routing`, `_parent`. @@ -538,6 +522,7 @@ The following example adds a field with the name `received`. The value is the in } } -------------------------------------------------- +// NOTCONSOLE Unlike Elasticsearch metadata fields, the ingest metadata field name `_ingest` can be used as a valid field name in the source of a document. Use `_source._ingest` to refer to the field in the source document. Otherwise, `_ingest` @@ -562,6 +547,7 @@ the values of `field_a` and `field_b`. } } -------------------------------------------------- +// NOTCONSOLE The following example uses the value of the `geoip.country_iso_code` field in the source to set the index that the document will be indexed into: @@ -575,6 +561,7 @@ to set the index that the document will be indexed into: } } -------------------------------------------------- +// NOTCONSOLE [[handling-failure-in-pipelines]] == Handling Failures in Pipelines @@ -620,6 +607,7 @@ Elasticsearch. ] } -------------------------------------------------- +// NOTCONSOLE The following example defines an `on_failure` block on a whole pipeline to change the index to which failed documents get sent. @@ -639,6 +627,7 @@ the index to which failed documents get sent. ] } -------------------------------------------------- +// NOTCONSOLE Alternatively instead of defining behaviour in case of processor failure, it is also possible to ignore a failure and continue with the next processor by specifying the `ignore_failure` setting. @@ -661,6 +650,7 @@ continues to execute, which in this case means that the pipeline does nothing. ] } -------------------------------------------------- +// NOTCONSOLE The `ignore_failure` can be set on any processor and defaults to `false`. @@ -699,6 +689,7 @@ metadata field to provide the error message. ] } -------------------------------------------------- +// NOTCONSOLE [[ingest-processors]] == Processors @@ -713,6 +704,7 @@ All processors are defined in the following way within a pipeline definition: } } -------------------------------------------------- +// NOTCONSOLE Each processor defines its own configuration parameters, but all processors have the ability to declare `tag` and `on_failure` fields. These fields are optional. @@ -765,6 +757,7 @@ Accepts a single value or an array of values. } } -------------------------------------------------- +// NOTCONSOLE [[convert-processor]] === Convert Processor @@ -802,6 +795,7 @@ such a case, `target_field` will still be updated with the unconverted field val } } -------------------------------------------------- +// NOTCONSOLE [[date-processor]] === Date Processor @@ -842,6 +836,7 @@ Here is an example that adds the parsed date to the `timestamp` field based on t ] } -------------------------------------------------- +// NOTCONSOLE [[date-index-name-processor]] === Date Index Name Processor @@ -1011,6 +1006,7 @@ to the requester. } } -------------------------------------------------- +// NOTCONSOLE [[foreach-processor]] === Foreach Processor @@ -1059,6 +1055,7 @@ Assume the following document: "values" : ["foo", "bar", "baz"] } -------------------------------------------------- +// NOTCONSOLE When this `foreach` processor operates on this sample document: @@ -1075,6 +1072,7 @@ When this `foreach` processor operates on this sample document: } } -------------------------------------------------- +// NOTCONSOLE Then the document will look like this after preprocessing: @@ -1084,6 +1082,7 @@ Then the document will look like this after preprocessing: "values" : ["FOO", "BAR", "BAZ"] } -------------------------------------------------- +// NOTCONSOLE Let's take a look at another example: @@ -1102,6 +1101,7 @@ Let's take a look at another example: ] } -------------------------------------------------- +// NOTCONSOLE In this case, the `id` field needs to be removed, so the following `foreach` processor is used: @@ -1119,6 +1119,7 @@ so the following `foreach` processor is used: } } -------------------------------------------------- +// NOTCONSOLE After preprocessing the result is: @@ -1135,6 +1136,7 @@ After preprocessing the result is: ] } -------------------------------------------------- +// NOTCONSOLE The wrapped processor can have a `on_failure` definition. For example, the `id` field may not exist on all person objects. @@ -1162,6 +1164,7 @@ block to send the document to the 'failure_index' index for later inspection: } } -------------------------------------------------- +// NOTCONSOLE In this example, if the `remove` processor does fail, then the array elements that have been processed thus far will @@ -1210,7 +1213,7 @@ The `TYPE` is the type you wish to cast your named field. `int` and `float` are For example, you might want to match the following text: -[source,js] +[source,txt] -------------------------------------------------- 3.44 55.3.244.1 -------------------------------------------------- @@ -1218,7 +1221,7 @@ For example, you might want to match the following text: You may know that the message in the example is a number followed by an IP address. You can match this text by using the following Grok expression. -[source,js] +[source,txt] -------------------------------------------------- %{NUMBER:duration} %{IP:client} -------------------------------------------------- @@ -1247,10 +1250,11 @@ a document. "message": "55.3.244.1 GET /index.html 15824 0.043" } -------------------------------------------------- +// NOTCONSOLE The pattern for this could be: -[source,js] +[source,txt] -------------------------------------------------- %{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration} -------------------------------------------------- @@ -1271,6 +1275,7 @@ Here is an example pipeline for processing the above document by using Grok: ] } -------------------------------------------------- +// NOTCONSOLE This pipeline will insert these named captures as new fields within the document, like so: @@ -1285,6 +1290,7 @@ This pipeline will insert these named captures as new fields within the document "duration": "0.043" } -------------------------------------------------- +// NOTCONSOLE [[custom-patterns]] ==== Custom Patterns and Pattern Files @@ -1313,6 +1319,7 @@ Here is an example of a pipeline specifying custom pattern definitions: ] } -------------------------------------------------- +// NOTCONSOLE [[trace-match]] ==== Providing Multiple Match Patterns @@ -1472,6 +1479,7 @@ If the field is not a string, the processor will throw an exception. } } -------------------------------------------------- +// NOTCONSOLE [[join-processor]] === Join Processor @@ -1496,6 +1504,7 @@ Throws an error when the field is not an array. } } -------------------------------------------------- +// NOTCONSOLE [[json-processor]] === JSON Processor @@ -1522,6 +1531,7 @@ Suppose you provide this configuration of the `json` processor: } } -------------------------------------------------- +// NOTCONSOLE If the following document is processed: @@ -1531,6 +1541,7 @@ If the following document is processed: "string_source": "{\"foo\": 2000}" } -------------------------------------------------- +// NOTCONSOLE after the `json` processor operates on it, it will look like: @@ -1543,6 +1554,7 @@ after the `json` processor operates on it, it will look like: } } -------------------------------------------------- +// NOTCONSOLE If the following configuration is provided, omitting the optional `target_field` setting: [source,js] @@ -1553,6 +1565,7 @@ If the following configuration is provided, omitting the optional `target_field` } } -------------------------------------------------- +// NOTCONSOLE then after the `json` processor operates on this document: @@ -1562,6 +1575,7 @@ then after the `json` processor operates on this document: "source_and_target": "{\"foo\": 2000}" } -------------------------------------------------- +// NOTCONSOLE it will look like: @@ -1573,8 +1587,9 @@ it will look like: } } -------------------------------------------------- +// NOTCONSOLE -This illustrates that, unless it is explicitly named in the processor configuration, the `target_field` +This illustrates that, unless it is explicitly named in the processor configuration, the `target_field` is the same field provided in the required `field` configuration. [[kv-processor]] @@ -1594,6 +1609,7 @@ For example, if you have a log message which contains `ip=1.2.3.4 error=REFUSED` } } -------------------------------------------------- +// NOTCONSOLE [[kv-options]] .Kv Options @@ -1630,6 +1646,7 @@ Converts a string to its lowercase equivalent. } } -------------------------------------------------- +// NOTCONSOLE [[remove-processor]] === Remove Processor @@ -1651,6 +1668,7 @@ Removes an existing field. If the field doesn't exist, an exception will be thro } } -------------------------------------------------- +// NOTCONSOLE [[rename-processor]] === Rename Processor @@ -1675,6 +1693,7 @@ Renames an existing field. If the field doesn't exist or the new name is already } } -------------------------------------------------- +// NOTCONSOLE [[script-processor]] === Script Processor @@ -1718,6 +1737,7 @@ numeric fields `field_a` and `field_b` multiplied by the parameter param_c: } } -------------------------------------------------- +// NOTCONSOLE [[set-processor]] @@ -1744,6 +1764,7 @@ its value will be replaced with the provided one. } } -------------------------------------------------- +// NOTCONSOLE [[split-processor]] === Split Processor @@ -1768,6 +1789,7 @@ Splits a field into an array using a separator character. Only works on string f } } -------------------------------------------------- +// NOTCONSOLE <1> Treat all consecutive whitespace characters as a single separator [[sort-processor]] @@ -1794,6 +1816,7 @@ Throws an error when the field is not an array. } } -------------------------------------------------- +// NOTCONSOLE [[trim-processor]] === Trim Processor @@ -1818,6 +1841,7 @@ NOTE: This only works on leading and trailing whitespace. } } -------------------------------------------------- +// NOTCONSOLE [[uppercase-processor]] === Uppercase Processor @@ -1840,6 +1864,7 @@ Converts a string to its uppercase equivalent. } } -------------------------------------------------- +// NOTCONSOLE [[dot-expand-processor]] === Dot Expander Processor @@ -1865,6 +1890,7 @@ Otherwise these <> can't be accessed by any } } -------------------------------------------------- +// NOTCONSOLE For example the dot expand processor would turn this document: @@ -1874,6 +1900,7 @@ For example the dot expand processor would turn this document: "foo.bar" : "value" } -------------------------------------------------- +// NOTCONSOLE into: @@ -1885,6 +1912,7 @@ into: } } -------------------------------------------------- +// NOTCONSOLE If there is already a `bar` field nested under `foo` then this processor merges the the `foo.bar` field into it. If the field is @@ -1901,6 +1929,7 @@ For example, the following document: } } -------------------------------------------------- +// NOTCONSOLE is transformed by the `dot_expander` processor into: @@ -1912,6 +1941,7 @@ is transformed by the `dot_expander` processor into: } } -------------------------------------------------- +// NOTCONSOLE If any field outside of the leaf field conflicts with a pre-existing field of the same name, then that field needs to be renamed first. @@ -1925,6 +1955,7 @@ Consider the following document: "foo.bar": "value2" } -------------------------------------------------- +// NOTCONSOLE Then the the `foo` needs to be renamed first before the `dot_expander` processor is applied. So in order for the `foo.bar` field to properly @@ -1949,6 +1980,7 @@ pipeline should be used: ] } -------------------------------------------------- +// NOTCONSOLE The reason for this is that Ingest doesn't know how to automatically cast a scalar field to an object field. diff --git a/docs/reference/mapping/dynamic/templates.asciidoc b/docs/reference/mapping/dynamic/templates.asciidoc index eb9eb1a60d9..90fc5de5c45 100644 --- a/docs/reference/mapping/dynamic/templates.asciidoc +++ b/docs/reference/mapping/dynamic/templates.asciidoc @@ -32,6 +32,7 @@ Dynamic templates are specified as an array of named objects: ... ] -------------------------------------------------- +// NOTCONSOLE <1> The template name can be any string value. <2> The match conditions can include any of : `match_mapping_type`, `match`, `match_pattern`, `unmatch`, `path_match`, `path_unmatch`. <3> The mapping that the matched field should use. @@ -94,7 +95,6 @@ PUT my_index/my_type/1 "my_integer": 5, <1> "my_string": "Some string" <2> } - -------------------------------------------------- // CONSOLE <1> The `my_integer` field is mapped as an `integer`. @@ -156,6 +156,7 @@ instead of simple wildcards, for instance: "match_pattern": "regex", "match": "^profit_\d+$" -------------------------------------------------- +// NOTCONSOLE [[path-match-unmatch]] ==== `path_match` and `path_unmatch` @@ -282,6 +283,7 @@ PUT my_index } } -------------------------------------------------- +// CONSOLE ===== `text`-only mappings for strings @@ -311,6 +313,7 @@ PUT my_index } } -------------------------------------------------- +// CONSOLE ===== Disabled norms @@ -345,6 +348,7 @@ PUT my_index } } -------------------------------------------------- +// CONSOLE The sub `keyword` field appears in this template to be consistent with the default rules of dynamic mappings. Of course if you do not need them because @@ -388,6 +392,7 @@ PUT my_index } } -------------------------------------------------- +// CONSOLE <1> Like the default dynamic mapping rules, doubles are mapped as floats, which are usually accurate enough, yet require half the disk space. diff --git a/docs/reference/modules/cross-cluster-search.asciidoc b/docs/reference/modules/cross-cluster-search.asciidoc index a91a56dd270..c4e7d4d3b48 100644 --- a/docs/reference/modules/cross-cluster-search.asciidoc +++ b/docs/reference/modules/cross-cluster-search.asciidoc @@ -105,6 +105,8 @@ POST /cluster_one:twitter/tweet/_search "match_all": {} } -------------------------------------------------- +// CONSOLE +// TEST[skip:we don't have two clusters set up during docs testing] In contrast to the `tribe` feature cross cluster search can also search indices with the same name on different clusters: @@ -116,6 +118,8 @@ POST /cluster_one:twitter,twitter/tweet/_search "match_all": {} } -------------------------------------------------- +// CONSOLE +// TEST[skip:we don't have two clusters set up during docs testing] Search results are disambiguated the same way as the indices are disambiguated in the request. Even if index names are identical these indices will be treated as different indices when results are merged. All results retrieved from a @@ -124,7 +128,7 @@ will be prefixed with their remote cluster name: [source,js] -------------------------------------------------- - { +{ "took" : 89, "timed_out" : false, "_shards" : { @@ -162,6 +166,7 @@ will be prefixed with their remote cluster name: } } -------------------------------------------------- +// TESTRESPONSE [float] === Cross cluster search settings @@ -188,5 +193,3 @@ will be prefixed with their remote cluster name: to `false` (defaults to `true`) to prevent certain nodes from connecting to remote clusters. Cross-cluster search requests must be sent to a node that is allowed to act as a cross-cluster client. - - From 61d5eddbd680f5b8e3f8a1e54805d6cbd2660575 Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Thu, 4 May 2017 21:03:52 -0400 Subject: [PATCH 30/44] Fix typo in comment in IndexShardTestCase This commit fixes a silly typo in IndexShardTestCase.java. --- .../java/org/elasticsearch/index/shard/IndexShardTestCase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/framework/src/main/java/org/elasticsearch/index/shard/IndexShardTestCase.java b/test/framework/src/main/java/org/elasticsearch/index/shard/IndexShardTestCase.java index 95013ee9649..80a0e9486f1 100644 --- a/test/framework/src/main/java/org/elasticsearch/index/shard/IndexShardTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/index/shard/IndexShardTestCase.java @@ -239,7 +239,7 @@ public abstract class IndexShardTestCase extends ESTestCase { @Nullable EngineFactory engineFactory, IndexingOperationListener... listeners) throws IOException { - // add node id as name to settings for popper logging + // add node id as name to settings for proper logging final ShardId shardId = routing.shardId(); final NodeEnvironment.NodePath nodePath = new NodeEnvironment.NodePath(createTempDir()); ShardPath shardPath = new ShardPath(false, nodePath.resolve(shardId), nodePath.resolve(shardId), shardId); From 035494fa175187fe57a11cca9f6b6e5b4fbc54ad Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Fri, 5 May 2017 00:49:18 -0400 Subject: [PATCH 31/44] Remove obsolete JVM options from build We start the test JVMs with various options. There are two that we should remove, they do not make sense. - we require Java 8 yet there was a conditional build option for Java 7 - we do not set MaxDirectMemorySize in our default JVM options, we should not in the test JVMs either Relates #24501 --- .../main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy | 5 ----- 1 file changed, 5 deletions(-) diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy index b3c2f4faef8..64ebba7578c 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy @@ -459,11 +459,6 @@ class BuildPlugin implements Plugin { // TODO: why are we not passing maxmemory to junit4? jvmArg '-Xmx' + System.getProperty('tests.heap.size', '512m') jvmArg '-Xms' + System.getProperty('tests.heap.size', '512m') - if (JavaVersion.current().isJava7()) { - // some tests need a large permgen, but that only exists on java 7 - jvmArg '-XX:MaxPermSize=128m' - } - jvmArg '-XX:MaxDirectMemorySize=512m' jvmArg '-XX:+HeapDumpOnOutOfMemoryError' File heapdumpDir = new File(project.buildDir, 'heapdump') heapdumpDir.mkdirs() From c8712e9531f55e84899be0f65fe435ae09f6a6a5 Mon Sep 17 00:00:00 2001 From: Yannick Welsch Date: Fri, 5 May 2017 08:39:18 +0200 Subject: [PATCH 32/44] Limit AllocationService dependency injection hack (#24479) Changes the scope of the AllocationService dependency injection hack so that it is at least contained to the AllocationService and does not leak into the Discovery world. --- .../routing/allocation/Allocators.java | 4 +-- .../elasticsearch/cluster/ClusterModule.java | 25 +++++++++++-------- .../routing/allocation/AllocationService.java | 18 +++++++++---- .../elasticsearch/discovery/Discovery.java | 7 ------ .../discovery/DiscoveryModule.java | 8 +++--- .../discovery/single/SingleNodeDiscovery.java | 6 ----- .../discovery/zen/ZenDiscovery.java | 18 +++++-------- .../gateway/GatewayAllocator.java | 18 ++++++++----- .../java/org/elasticsearch/node/Node.java | 14 +++++------ .../plugins/DiscoveryPlugin.java | 4 ++- .../cluster/ClusterModuleTests.java | 11 ++++---- .../allocation/BalanceConfigurationTests.java | 2 +- .../discovery/DiscoveryModuleTests.java | 6 +++-- .../discovery/zen/ZenDiscoveryUnitTests.java | 2 +- .../org/elasticsearch/test/NoopDiscovery.java | 5 ---- .../azure/classic/AzureDiscoveryPlugin.java | 6 +++-- .../discovery/ec2/Ec2DiscoveryPlugin.java | 6 +++-- .../discovery/gce/GceDiscoveryPlugin.java | 6 +++-- .../cluster/ESAllocationTestCase.java | 2 +- .../test/discovery/TestZenDiscovery.java | 11 +++++--- .../test/gateway/NoopGatewayAllocator.java | 2 +- .../test/gateway/TestGatewayAllocator.java | 2 +- 22 files changed, 95 insertions(+), 88 deletions(-) diff --git a/benchmarks/src/main/java/org/elasticsearch/benchmark/routing/allocation/Allocators.java b/benchmarks/src/main/java/org/elasticsearch/benchmark/routing/allocation/Allocators.java index 4d8f7cfeaac..591fa400d18 100644 --- a/benchmarks/src/main/java/org/elasticsearch/benchmark/routing/allocation/Allocators.java +++ b/benchmarks/src/main/java/org/elasticsearch/benchmark/routing/allocation/Allocators.java @@ -36,8 +36,6 @@ import org.elasticsearch.common.util.set.Sets; import org.elasticsearch.gateway.GatewayAllocator; import java.lang.reflect.InvocationTargetException; -import java.net.InetAddress; -import java.net.UnknownHostException; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -49,7 +47,7 @@ public final class Allocators { public static final NoopGatewayAllocator INSTANCE = new NoopGatewayAllocator(); protected NoopGatewayAllocator() { - super(Settings.EMPTY, null, null); + super(Settings.EMPTY); } @Override diff --git a/core/src/main/java/org/elasticsearch/cluster/ClusterModule.java b/core/src/main/java/org/elasticsearch/cluster/ClusterModule.java index 716472c76f0..60395210165 100644 --- a/core/src/main/java/org/elasticsearch/cluster/ClusterModule.java +++ b/core/src/main/java/org/elasticsearch/cluster/ClusterModule.java @@ -58,9 +58,7 @@ import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.inject.AbstractModule; import org.elasticsearch.common.io.stream.NamedWriteable; -import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.NamedWriteableRegistry.Entry; -import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.io.stream.Writeable.Reader; import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.Setting; @@ -92,19 +90,22 @@ public class ClusterModule extends AbstractModule { public static final Setting SHARDS_ALLOCATOR_TYPE_SETTING = new Setting<>("cluster.routing.allocation.type", BALANCED_ALLOCATOR, Function.identity(), Property.NodeScope); - private final Settings settings; private final ClusterService clusterService; private final IndexNameExpressionResolver indexNameExpressionResolver; + private final AllocationDeciders allocationDeciders; + private final AllocationService allocationService; // pkg private for tests - final Collection allocationDeciders; + final Collection deciderList; final ShardsAllocator shardsAllocator; - public ClusterModule(Settings settings, ClusterService clusterService, List clusterPlugins) { - this.settings = settings; - this.allocationDeciders = createAllocationDeciders(settings, clusterService.getClusterSettings(), clusterPlugins); + public ClusterModule(Settings settings, ClusterService clusterService, List clusterPlugins, + ClusterInfoService clusterInfoService) { + this.deciderList = createAllocationDeciders(settings, clusterService.getClusterSettings(), clusterPlugins); + this.allocationDeciders = new AllocationDeciders(settings, deciderList); this.shardsAllocator = createShardsAllocator(settings, clusterService.getClusterSettings(), clusterPlugins); this.clusterService = clusterService; - indexNameExpressionResolver = new IndexNameExpressionResolver(settings); + this.indexNameExpressionResolver = new IndexNameExpressionResolver(settings); + this.allocationService = new AllocationService(settings, allocationDeciders, shardsAllocator, clusterInfoService); } @@ -213,10 +214,14 @@ public class ClusterModule extends AbstractModule { "ShardsAllocator factory for [" + allocatorName + "] returned null"); } + public AllocationService getAllocationService() { + return allocationService; + } + @Override protected void configure() { bind(GatewayAllocator.class).asEagerSingleton(); - bind(AllocationService.class).asEagerSingleton(); + bind(AllocationService.class).toInstance(allocationService); bind(ClusterService.class).toInstance(clusterService); bind(NodeConnectionsService.class).asEagerSingleton(); bind(MetaDataCreateIndexService.class).asEagerSingleton(); @@ -233,7 +238,7 @@ public class ClusterModule extends AbstractModule { bind(NodeMappingRefreshAction.class).asEagerSingleton(); bind(MappingUpdatedAction.class).asEagerSingleton(); bind(TaskResultsService.class).asEagerSingleton(); - bind(AllocationDeciders.class).toInstance(new AllocationDeciders(settings, allocationDeciders)); + bind(AllocationDeciders.class).toInstance(allocationDeciders); bind(ShardsAllocator.class).toInstance(shardsAllocator); } } diff --git a/core/src/main/java/org/elasticsearch/cluster/routing/allocation/AllocationService.java b/core/src/main/java/org/elasticsearch/cluster/routing/allocation/AllocationService.java index 8974c8a4a9a..6b0f8bfba2a 100644 --- a/core/src/main/java/org/elasticsearch/cluster/routing/allocation/AllocationService.java +++ b/core/src/main/java/org/elasticsearch/cluster/routing/allocation/AllocationService.java @@ -37,7 +37,6 @@ import org.elasticsearch.cluster.routing.allocation.command.AllocationCommands; import org.elasticsearch.cluster.routing.allocation.decider.AllocationDeciders; import org.elasticsearch.common.collect.ImmutableOpenMap; import org.elasticsearch.common.component.AbstractComponent; -import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.gateway.GatewayAllocator; @@ -61,20 +60,29 @@ import static org.elasticsearch.cluster.routing.UnassignedInfo.INDEX_DELAYED_NOD public class AllocationService extends AbstractComponent { private final AllocationDeciders allocationDeciders; - private final GatewayAllocator gatewayAllocator; + private GatewayAllocator gatewayAllocator; private final ShardsAllocator shardsAllocator; private final ClusterInfoService clusterInfoService; - @Inject - public AllocationService(Settings settings, AllocationDeciders allocationDeciders, GatewayAllocator gatewayAllocator, + public AllocationService(Settings settings, AllocationDeciders allocationDeciders, + GatewayAllocator gatewayAllocator, + ShardsAllocator shardsAllocator, ClusterInfoService clusterInfoService) { + this(settings, allocationDeciders, shardsAllocator, clusterInfoService); + setGatewayAllocator(gatewayAllocator); + } + + public AllocationService(Settings settings, AllocationDeciders allocationDeciders, ShardsAllocator shardsAllocator, ClusterInfoService clusterInfoService) { super(settings); this.allocationDeciders = allocationDeciders; - this.gatewayAllocator = gatewayAllocator; this.shardsAllocator = shardsAllocator; this.clusterInfoService = clusterInfoService; } + public void setGatewayAllocator(GatewayAllocator gatewayAllocator) { + this.gatewayAllocator = gatewayAllocator; + } + /** * Applies the started shards. Note, only initializing ShardRouting instances that exist in the routing table should be * provided as parameter and no duplicates should be contained. diff --git a/core/src/main/java/org/elasticsearch/discovery/Discovery.java b/core/src/main/java/org/elasticsearch/discovery/Discovery.java index 4c28b51bc4f..7f68f417fcb 100644 --- a/core/src/main/java/org/elasticsearch/discovery/Discovery.java +++ b/core/src/main/java/org/elasticsearch/discovery/Discovery.java @@ -23,7 +23,6 @@ import org.elasticsearch.ElasticsearchException; import org.elasticsearch.cluster.ClusterChangedEvent; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.node.DiscoveryNode; -import org.elasticsearch.cluster.routing.allocation.AllocationService; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.component.LifecycleComponent; import org.elasticsearch.common.io.stream.StreamInput; @@ -37,12 +36,6 @@ import java.io.IOException; */ public interface Discovery extends LifecycleComponent { - /** - * Another hack to solve dep injection problem..., note, this will be called before - * any start is called. - */ - void setAllocationService(AllocationService allocationService); - /** * Publish all the changes to the cluster from the master (can be called just by the master). The publish * process should apply this state to the master as well! diff --git a/core/src/main/java/org/elasticsearch/discovery/DiscoveryModule.java b/core/src/main/java/org/elasticsearch/discovery/DiscoveryModule.java index 43fccab1a28..b2367c6e953 100644 --- a/core/src/main/java/org/elasticsearch/discovery/DiscoveryModule.java +++ b/core/src/main/java/org/elasticsearch/discovery/DiscoveryModule.java @@ -19,6 +19,7 @@ package org.elasticsearch.discovery; +import org.elasticsearch.cluster.routing.allocation.AllocationService; import org.elasticsearch.cluster.service.ClusterApplier; import org.elasticsearch.cluster.service.MasterService; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; @@ -58,7 +59,8 @@ public class DiscoveryModule { public DiscoveryModule(Settings settings, ThreadPool threadPool, TransportService transportService, NamedWriteableRegistry namedWriteableRegistry, NetworkService networkService, MasterService masterService, - ClusterApplier clusterApplier, ClusterSettings clusterSettings, List plugins) { + ClusterApplier clusterApplier, ClusterSettings clusterSettings, List plugins, + AllocationService allocationService) { final UnicastHostsProvider hostsProvider; Map> hostProviders = new HashMap<>(); @@ -83,12 +85,12 @@ public class DiscoveryModule { Map> discoveryTypes = new HashMap<>(); discoveryTypes.put("zen", () -> new ZenDiscovery(settings, threadPool, transportService, namedWriteableRegistry, masterService, clusterApplier, - clusterSettings, hostsProvider)); + clusterSettings, hostsProvider, allocationService)); discoveryTypes.put("tribe", () -> new TribeDiscovery(settings, transportService, clusterApplier)); discoveryTypes.put("single-node", () -> new SingleNodeDiscovery(settings, transportService, clusterApplier)); for (DiscoveryPlugin plugin : plugins) { plugin.getDiscoveryTypes(threadPool, transportService, namedWriteableRegistry, - masterService, clusterApplier, clusterSettings, hostsProvider).entrySet().forEach(entry -> { + masterService, clusterApplier, clusterSettings, hostsProvider, allocationService).entrySet().forEach(entry -> { if (discoveryTypes.put(entry.getKey(), entry.getValue()) != null) { throw new IllegalArgumentException("Cannot register discovery type [" + entry.getKey() + "] twice"); } diff --git a/core/src/main/java/org/elasticsearch/discovery/single/SingleNodeDiscovery.java b/core/src/main/java/org/elasticsearch/discovery/single/SingleNodeDiscovery.java index d7275e7be91..11526961797 100644 --- a/core/src/main/java/org/elasticsearch/discovery/single/SingleNodeDiscovery.java +++ b/core/src/main/java/org/elasticsearch/discovery/single/SingleNodeDiscovery.java @@ -27,7 +27,6 @@ import org.elasticsearch.cluster.ClusterStateTaskListener; import org.elasticsearch.cluster.block.ClusterBlocks; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.node.DiscoveryNodes; -import org.elasticsearch.cluster.routing.allocation.AllocationService; import org.elasticsearch.cluster.service.ClusterApplier; import org.elasticsearch.common.component.AbstractLifecycleComponent; import org.elasticsearch.common.settings.Settings; @@ -59,11 +58,6 @@ public class SingleNodeDiscovery extends AbstractLifecycleComponent implements D this.clusterApplier = clusterApplier; } - @Override - public void setAllocationService(final AllocationService allocationService) { - - } - @Override public synchronized void publish(final ClusterChangedEvent event, final AckListener ackListener) { diff --git a/core/src/main/java/org/elasticsearch/discovery/zen/ZenDiscovery.java b/core/src/main/java/org/elasticsearch/discovery/zen/ZenDiscovery.java index fe94cea597d..d08b148554b 100644 --- a/core/src/main/java/org/elasticsearch/discovery/zen/ZenDiscovery.java +++ b/core/src/main/java/org/elasticsearch/discovery/zen/ZenDiscovery.java @@ -109,7 +109,6 @@ public class ZenDiscovery extends AbstractLifecycleComponent implements Discover private final TransportService transportService; private final MasterService masterService; - private AllocationService allocationService; private final ClusterName clusterName; private final DiscoverySettings discoverySettings; protected final ZenPing zenPing; // protected to allow tests access @@ -140,9 +139,8 @@ public class ZenDiscovery extends AbstractLifecycleComponent implements Discover private final JoinThreadControl joinThreadControl; - // must initialized in doStart(), when we have the allocationService set - private volatile NodeJoinController nodeJoinController; - private volatile NodeRemovalClusterStateTaskExecutor nodeRemovalExecutor; + private final NodeJoinController nodeJoinController; + private final NodeRemovalClusterStateTaskExecutor nodeRemovalExecutor; private final ClusterApplier clusterApplier; private final AtomicReference state; // last committed cluster state @@ -151,7 +149,7 @@ public class ZenDiscovery extends AbstractLifecycleComponent implements Discover public ZenDiscovery(Settings settings, ThreadPool threadPool, TransportService transportService, NamedWriteableRegistry namedWriteableRegistry, MasterService masterService, ClusterApplier clusterApplier, - ClusterSettings clusterSettings, UnicastHostsProvider hostsProvider) { + ClusterSettings clusterSettings, UnicastHostsProvider hostsProvider, AllocationService allocationService) { super(settings); this.masterService = masterService; this.clusterApplier = clusterApplier; @@ -213,6 +211,9 @@ public class ZenDiscovery extends AbstractLifecycleComponent implements Discover this.membership = new MembershipAction(settings, transportService, new MembershipListener()); this.joinThreadControl = new JoinThreadControl(); + this.nodeJoinController = new NodeJoinController(masterService, allocationService, electMaster, settings); + this.nodeRemovalExecutor = new NodeRemovalClusterStateTaskExecutor(allocationService, electMaster, this::submitRejoin, logger); + transportService.registerRequestHandler( DISCOVERY_REJOIN_ACTION_NAME, RejoinClusterRequest::new, ThreadPool.Names.SAME, new RejoinClusterRequestHandler()); } @@ -223,11 +224,6 @@ public class ZenDiscovery extends AbstractLifecycleComponent implements Discover return new UnicastZenPing(settings, threadPool, transportService, hostsProvider); } - @Override - public void setAllocationService(AllocationService allocationService) { - this.allocationService = allocationService; - } - @Override protected void doStart() { DiscoveryNode localNode = transportService.getLocalNode(); @@ -239,8 +235,6 @@ public class ZenDiscovery extends AbstractLifecycleComponent implements Discover joinThreadControl.start(); } zenPing.start(this); - this.nodeJoinController = new NodeJoinController(masterService, allocationService, electMaster, settings); - this.nodeRemovalExecutor = new NodeRemovalClusterStateTaskExecutor(allocationService, electMaster, this::submitRejoin, logger); } @Override diff --git a/core/src/main/java/org/elasticsearch/gateway/GatewayAllocator.java b/core/src/main/java/org/elasticsearch/gateway/GatewayAllocator.java index 69f7af6eef5..c616716b86a 100644 --- a/core/src/main/java/org/elasticsearch/gateway/GatewayAllocator.java +++ b/core/src/main/java/org/elasticsearch/gateway/GatewayAllocator.java @@ -43,7 +43,7 @@ import java.util.concurrent.ConcurrentMap; public class GatewayAllocator extends AbstractComponent { - private RoutingService routingService; + private final RoutingService routingService; private final PrimaryShardAllocator primaryShardAllocator; private final ReplicaShardAllocator replicaShardAllocator; @@ -52,14 +52,12 @@ public class GatewayAllocator extends AbstractComponent { private final ConcurrentMap> asyncFetchStore = ConcurrentCollections.newConcurrentMap(); @Inject - public GatewayAllocator(Settings settings, final TransportNodesListGatewayStartedShards startedAction, final TransportNodesListShardStoreMetaData storeAction) { + public GatewayAllocator(Settings settings, ClusterService clusterService, RoutingService routingService, + TransportNodesListGatewayStartedShards startedAction, TransportNodesListShardStoreMetaData storeAction) { super(settings); + this.routingService = routingService; this.primaryShardAllocator = new InternalPrimaryShardAllocator(settings, startedAction); this.replicaShardAllocator = new InternalReplicaShardAllocator(settings, storeAction); - } - - public void setReallocation(final ClusterService clusterService, final RoutingService routingService) { - this.routingService = routingService; clusterService.addStateApplier(event -> { boolean cleanCache = false; DiscoveryNode localNode = event.state().nodes().getLocalNode(); @@ -79,6 +77,14 @@ public class GatewayAllocator extends AbstractComponent { }); } + // for tests + protected GatewayAllocator(Settings settings) { + super(settings); + this.routingService = null; + this.primaryShardAllocator = null; + this.replicaShardAllocator = null; + } + public int getNumberOfInFlightFetch() { int count = 0; for (AsyncShardFetch fetch : asyncFetchStarted.values()) { diff --git a/core/src/main/java/org/elasticsearch/node/Node.java b/core/src/main/java/org/elasticsearch/node/Node.java index 9c933b1da70..28d2f42f592 100644 --- a/core/src/main/java/org/elasticsearch/node/Node.java +++ b/core/src/main/java/org/elasticsearch/node/Node.java @@ -49,7 +49,6 @@ import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.metadata.MetaDataIndexUpgradeService; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.routing.RoutingService; -import org.elasticsearch.cluster.routing.allocation.AllocationService; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.StopWatch; import org.elasticsearch.common.SuppressForbidden; @@ -352,7 +351,7 @@ public class Node implements Closeable { final MonitorService monitorService = new MonitorService(settings, nodeEnvironment, threadPool, clusterInfoService); modules.add(new NodeModule(this, monitorService)); ClusterModule clusterModule = new ClusterModule(settings, clusterService, - pluginsService.filterPlugins(ClusterPlugin.class)); + pluginsService.filterPlugins(ClusterPlugin.class), clusterInfoService); modules.add(clusterModule); IndicesModule indicesModule = new IndicesModule(pluginsService.filterPlugins(MapperPlugin.class)); modules.add(indicesModule); @@ -437,7 +436,8 @@ public class Node implements Closeable { final DiscoveryModule discoveryModule = new DiscoveryModule(this.settings, threadPool, transportService, namedWriteableRegistry, networkService, clusterService.getMasterService(), clusterService.getClusterApplierService(), - clusterService.getClusterSettings(), pluginsService.filterPlugins(DiscoveryPlugin.class)); + clusterService.getClusterSettings(), pluginsService.filterPlugins(DiscoveryPlugin.class), + clusterModule.getAllocationService()); NodeService nodeService = new NodeService(settings, threadPool, monitorService, discoveryModule.getDiscovery(), transportService, indicesService, pluginsService, circuitBreakerService, scriptModule.getScriptService(), httpServerTransport, ingestService, clusterService, settingsModule.getSettingsFilter()); @@ -488,6 +488,9 @@ public class Node implements Closeable { ); injector = modules.createInjector(); + // TODO hack around circular dependencies problems in AllocationService + clusterModule.getAllocationService().setGatewayAllocator(injector.getInstance(GatewayAllocator.class)); + List pluginLifecycleComponents = pluginComponents.stream() .filter(p -> p instanceof LifecycleComponent) .map(p -> (LifecycleComponent) p).collect(Collectors.toList()); @@ -644,8 +647,6 @@ public class Node implements Closeable { Logger logger = Loggers.getLogger(Node.class, NODE_NAME_SETTING.get(settings)); logger.info("starting ..."); - // hack around dependency injection problem (for now...) - injector.getInstance(Discovery.class).setAllocationService(injector.getInstance(AllocationService.class)); pluginLifecycleComponents.forEach(LifecycleComponent::start); injector.getInstance(MappingUpdatedAction.class).setClient(client); @@ -663,9 +664,6 @@ public class Node implements Closeable { nodeConnectionsService.start(); clusterService.setNodeConnectionsService(nodeConnectionsService); - // TODO hack around circular dependencies problems - injector.getInstance(GatewayAllocator.class).setReallocation(clusterService, injector.getInstance(RoutingService.class)); - injector.getInstance(ResourceWatcherService.class).start(); injector.getInstance(GatewayService.class).start(); Discovery discovery = injector.getInstance(Discovery.class); diff --git a/core/src/main/java/org/elasticsearch/plugins/DiscoveryPlugin.java b/core/src/main/java/org/elasticsearch/plugins/DiscoveryPlugin.java index 0569547b822..c3af5593cd7 100644 --- a/core/src/main/java/org/elasticsearch/plugins/DiscoveryPlugin.java +++ b/core/src/main/java/org/elasticsearch/plugins/DiscoveryPlugin.java @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.Map; import java.util.function.Supplier; +import org.elasticsearch.cluster.routing.allocation.AllocationService; import org.elasticsearch.cluster.service.ClusterApplier; import org.elasticsearch.cluster.service.MasterService; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; @@ -68,7 +69,8 @@ public interface DiscoveryPlugin { MasterService masterService, ClusterApplier clusterApplier, ClusterSettings clusterSettings, - UnicastHostsProvider hostsProvider) { + UnicastHostsProvider hostsProvider, + AllocationService allocationService) { return Collections.emptyMap(); } diff --git a/core/src/test/java/org/elasticsearch/cluster/ClusterModuleTests.java b/core/src/test/java/org/elasticsearch/cluster/ClusterModuleTests.java index 9e45b0d3828..67d04c3c235 100644 --- a/core/src/test/java/org/elasticsearch/cluster/ClusterModuleTests.java +++ b/core/src/test/java/org/elasticsearch/cluster/ClusterModuleTests.java @@ -57,6 +57,7 @@ import java.util.Map; import java.util.function.Supplier; public class ClusterModuleTests extends ModuleTestCase { + private ClusterInfoService clusterInfoService = EmptyClusterInfoService.INSTANCE; private ClusterService clusterService = new ClusterService(Settings.EMPTY, new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS), null); static class FakeAllocationDecider extends AllocationDecider { @@ -114,7 +115,7 @@ public class ClusterModuleTests extends ModuleTestCase { public Collection createAllocationDeciders(Settings settings, ClusterSettings clusterSettings) { return Collections.singletonList(new EnableAllocationDecider(settings, clusterSettings)); } - }))); + }), clusterInfoService)); assertEquals(e.getMessage(), "Cannot specify allocation decider [" + EnableAllocationDecider.class.getName() + "] twice"); } @@ -126,8 +127,8 @@ public class ClusterModuleTests extends ModuleTestCase { public Collection createAllocationDeciders(Settings settings, ClusterSettings clusterSettings) { return Collections.singletonList(new FakeAllocationDecider(settings)); } - })); - assertTrue(module.allocationDeciders.stream().anyMatch(d -> d.getClass().equals(FakeAllocationDecider.class))); + }), clusterInfoService); + assertTrue(module.deciderList.stream().anyMatch(d -> d.getClass().equals(FakeAllocationDecider.class))); } private ClusterModule newClusterModuleWithShardsAllocator(Settings settings, String name, Supplier supplier) { @@ -138,7 +139,7 @@ public class ClusterModuleTests extends ModuleTestCase { return Collections.singletonMap(name, supplier); } } - )); + ), clusterInfoService); } public void testRegisterShardsAllocator() { @@ -156,7 +157,7 @@ public class ClusterModuleTests extends ModuleTestCase { public void testUnknownShardsAllocator() { Settings settings = Settings.builder().put(ClusterModule.SHARDS_ALLOCATOR_TYPE_SETTING.getKey(), "dne").build(); IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> - new ClusterModule(settings, clusterService, Collections.emptyList())); + new ClusterModule(settings, clusterService, Collections.emptyList(), clusterInfoService)); assertEquals("Unknown ShardsAllocator [dne]", e.getMessage()); } diff --git a/core/src/test/java/org/elasticsearch/cluster/routing/allocation/BalanceConfigurationTests.java b/core/src/test/java/org/elasticsearch/cluster/routing/allocation/BalanceConfigurationTests.java index cfca80b78ca..5e400d95e4b 100644 --- a/core/src/test/java/org/elasticsearch/cluster/routing/allocation/BalanceConfigurationTests.java +++ b/core/src/test/java/org/elasticsearch/cluster/routing/allocation/BalanceConfigurationTests.java @@ -391,7 +391,7 @@ public class BalanceConfigurationTests extends ESAllocationTestCase { private class NoopGatewayAllocator extends GatewayAllocator { NoopGatewayAllocator() { - super(Settings.EMPTY, null, null); + super(Settings.EMPTY); } @Override diff --git a/core/src/test/java/org/elasticsearch/discovery/DiscoveryModuleTests.java b/core/src/test/java/org/elasticsearch/discovery/DiscoveryModuleTests.java index 9460261e547..39a9dbff959 100644 --- a/core/src/test/java/org/elasticsearch/discovery/DiscoveryModuleTests.java +++ b/core/src/test/java/org/elasticsearch/discovery/DiscoveryModuleTests.java @@ -20,6 +20,7 @@ package org.elasticsearch.discovery; import org.apache.lucene.util.IOUtils; import org.elasticsearch.Version; +import org.elasticsearch.cluster.routing.allocation.AllocationService; import org.elasticsearch.cluster.service.ClusterApplier; import org.elasticsearch.cluster.service.MasterService; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; @@ -71,7 +72,8 @@ public class DiscoveryModuleTests extends ESTestCase { default Map> getDiscoveryTypes(ThreadPool threadPool, TransportService transportService, NamedWriteableRegistry namedWriteableRegistry, MasterService masterService, ClusterApplier clusterApplier, - ClusterSettings clusterSettings, UnicastHostsProvider hostsProvider) { + ClusterSettings clusterSettings, UnicastHostsProvider hostsProvider, + AllocationService allocationService) { return impl(); } } @@ -93,7 +95,7 @@ public class DiscoveryModuleTests extends ESTestCase { private DiscoveryModule newModule(Settings settings, List plugins) { return new DiscoveryModule(settings, threadPool, transportService, namedWriteableRegistry, null, masterService, - clusterApplier, clusterSettings, plugins); + clusterApplier, clusterSettings, plugins, null); } public void testDefaults() { diff --git a/core/src/test/java/org/elasticsearch/discovery/zen/ZenDiscoveryUnitTests.java b/core/src/test/java/org/elasticsearch/discovery/zen/ZenDiscoveryUnitTests.java index 0d0d391663d..d0c138954ab 100644 --- a/core/src/test/java/org/elasticsearch/discovery/zen/ZenDiscoveryUnitTests.java +++ b/core/src/test/java/org/elasticsearch/discovery/zen/ZenDiscoveryUnitTests.java @@ -299,7 +299,7 @@ public class ZenDiscoveryUnitTests extends ESTestCase { ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); ZenDiscovery zenDiscovery = new ZenDiscovery(settings, threadPool, service, new NamedWriteableRegistry(ClusterModule.getNamedWriteables()), masterService, (source, clusterStateSupplier, listener) -> listener.clusterStateProcessed(source, clusterStateSupplier.get(), clusterStateSupplier.get()), - clusterSettings, Collections::emptyList); + clusterSettings, Collections::emptyList, null); zenDiscovery.start(); return zenDiscovery; } diff --git a/core/src/test/java/org/elasticsearch/test/NoopDiscovery.java b/core/src/test/java/org/elasticsearch/test/NoopDiscovery.java index 1a661b509a2..5b33fb1c8de 100644 --- a/core/src/test/java/org/elasticsearch/test/NoopDiscovery.java +++ b/core/src/test/java/org/elasticsearch/test/NoopDiscovery.java @@ -28,11 +28,6 @@ import org.elasticsearch.discovery.DiscoveryStats; public class NoopDiscovery implements Discovery { - @Override - public void setAllocationService(AllocationService allocationService) { - - } - @Override public void publish(ClusterChangedEvent clusterChangedEvent, AckListener ackListener) { diff --git a/plugins/discovery-azure-classic/src/main/java/org/elasticsearch/plugin/discovery/azure/classic/AzureDiscoveryPlugin.java b/plugins/discovery-azure-classic/src/main/java/org/elasticsearch/plugin/discovery/azure/classic/AzureDiscoveryPlugin.java index 6bff34a667c..0240781c1aa 100644 --- a/plugins/discovery-azure-classic/src/main/java/org/elasticsearch/plugin/discovery/azure/classic/AzureDiscoveryPlugin.java +++ b/plugins/discovery-azure-classic/src/main/java/org/elasticsearch/plugin/discovery/azure/classic/AzureDiscoveryPlugin.java @@ -22,6 +22,7 @@ package org.elasticsearch.plugin.discovery.azure.classic; import org.apache.logging.log4j.Logger; import org.elasticsearch.cloud.azure.classic.management.AzureComputeService; import org.elasticsearch.cloud.azure.classic.management.AzureComputeServiceImpl; +import org.elasticsearch.cluster.routing.allocation.AllocationService; import org.elasticsearch.cluster.service.ClusterApplier; import org.elasticsearch.cluster.service.MasterService; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; @@ -76,11 +77,12 @@ public class AzureDiscoveryPlugin extends Plugin implements DiscoveryPlugin { public Map> getDiscoveryTypes(ThreadPool threadPool, TransportService transportService, NamedWriteableRegistry namedWriteableRegistry, MasterService masterService, ClusterApplier clusterApplier, - ClusterSettings clusterSettings, UnicastHostsProvider hostsProvider) { + ClusterSettings clusterSettings, UnicastHostsProvider hostsProvider, + AllocationService allocationService) { // this is for backcompat with pre 5.1, where users would set discovery.type to use ec2 hosts provider return Collections.singletonMap(AZURE, () -> new ZenDiscovery(settings, threadPool, transportService, namedWriteableRegistry, masterService, clusterApplier, - clusterSettings, hostsProvider)); + clusterSettings, hostsProvider, allocationService)); } @Override diff --git a/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/Ec2DiscoveryPlugin.java b/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/Ec2DiscoveryPlugin.java index 3c80d0eda06..3280368631b 100644 --- a/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/Ec2DiscoveryPlugin.java +++ b/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/Ec2DiscoveryPlugin.java @@ -24,6 +24,7 @@ import org.apache.logging.log4j.Logger; import org.apache.lucene.util.IOUtils; import org.apache.lucene.util.SetOnce; import org.elasticsearch.SpecialPermission; +import org.elasticsearch.cluster.routing.allocation.AllocationService; import org.elasticsearch.cluster.service.ClusterApplier; import org.elasticsearch.common.SuppressForbidden; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; @@ -98,11 +99,12 @@ public class Ec2DiscoveryPlugin extends Plugin implements DiscoveryPlugin, Close public Map> getDiscoveryTypes(ThreadPool threadPool, TransportService transportService, NamedWriteableRegistry namedWriteableRegistry, MasterService masterService, ClusterApplier clusterApplier, - ClusterSettings clusterSettings, UnicastHostsProvider hostsProvider) { + ClusterSettings clusterSettings, UnicastHostsProvider hostsProvider, + AllocationService allocationService) { // this is for backcompat with pre 5.1, where users would set discovery.type to use ec2 hosts provider return Collections.singletonMap(EC2, () -> new ZenDiscovery(settings, threadPool, transportService, namedWriteableRegistry, masterService, clusterApplier, - clusterSettings, hostsProvider)); + clusterSettings, hostsProvider, allocationService)); } @Override diff --git a/plugins/discovery-gce/src/main/java/org/elasticsearch/plugin/discovery/gce/GceDiscoveryPlugin.java b/plugins/discovery-gce/src/main/java/org/elasticsearch/plugin/discovery/gce/GceDiscoveryPlugin.java index 44fb5c8d15e..d20b5eaef05 100644 --- a/plugins/discovery-gce/src/main/java/org/elasticsearch/plugin/discovery/gce/GceDiscoveryPlugin.java +++ b/plugins/discovery-gce/src/main/java/org/elasticsearch/plugin/discovery/gce/GceDiscoveryPlugin.java @@ -29,6 +29,7 @@ import org.elasticsearch.cloud.gce.GceInstancesServiceImpl; import org.elasticsearch.cloud.gce.GceMetadataService; import org.elasticsearch.cloud.gce.network.GceNameResolver; import org.elasticsearch.cloud.gce.util.Access; +import org.elasticsearch.cluster.routing.allocation.AllocationService; import org.elasticsearch.cluster.service.ClusterApplier; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.logging.DeprecationLogger; @@ -86,11 +87,12 @@ public class GceDiscoveryPlugin extends Plugin implements DiscoveryPlugin, Close public Map> getDiscoveryTypes(ThreadPool threadPool, TransportService transportService, NamedWriteableRegistry namedWriteableRegistry, MasterService masterService, ClusterApplier clusterApplier, - ClusterSettings clusterSettings, UnicastHostsProvider hostsProvider) { + ClusterSettings clusterSettings, UnicastHostsProvider hostsProvider, + AllocationService allocationService) { // this is for backcompat with pre 5.1, where users would set discovery.type to use ec2 hosts provider return Collections.singletonMap(GCE, () -> new ZenDiscovery(settings, threadPool, transportService, namedWriteableRegistry, masterService, clusterApplier, - clusterSettings, hostsProvider)); + clusterSettings, hostsProvider, allocationService)); } @Override diff --git a/test/framework/src/main/java/org/elasticsearch/cluster/ESAllocationTestCase.java b/test/framework/src/main/java/org/elasticsearch/cluster/ESAllocationTestCase.java index 02f8896be4d..e1205ba846b 100644 --- a/test/framework/src/main/java/org/elasticsearch/cluster/ESAllocationTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/cluster/ESAllocationTestCase.java @@ -205,7 +205,7 @@ public abstract class ESAllocationTestCase extends ESTestCase { protected static class DelayedShardsMockGatewayAllocator extends GatewayAllocator { public DelayedShardsMockGatewayAllocator() { - super(Settings.EMPTY, null, null); + super(Settings.EMPTY); } @Override diff --git a/test/framework/src/main/java/org/elasticsearch/test/discovery/TestZenDiscovery.java b/test/framework/src/main/java/org/elasticsearch/test/discovery/TestZenDiscovery.java index cb4b8e098ae..af1bbc94d27 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/discovery/TestZenDiscovery.java +++ b/test/framework/src/main/java/org/elasticsearch/test/discovery/TestZenDiscovery.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; import java.util.function.Supplier; +import org.elasticsearch.cluster.routing.allocation.AllocationService; import org.elasticsearch.cluster.service.ClusterApplier; import org.elasticsearch.cluster.service.MasterService; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; @@ -59,10 +60,11 @@ public class TestZenDiscovery extends ZenDiscovery { public Map> getDiscoveryTypes(ThreadPool threadPool, TransportService transportService, NamedWriteableRegistry namedWriteableRegistry, MasterService masterService, ClusterApplier clusterApplier, - ClusterSettings clusterSettings, UnicastHostsProvider hostsProvider) { + ClusterSettings clusterSettings, UnicastHostsProvider hostsProvider, + AllocationService allocationService) { return Collections.singletonMap("test-zen", () -> new TestZenDiscovery(settings, threadPool, transportService, namedWriteableRegistry, masterService, - clusterApplier, clusterSettings, hostsProvider)); + clusterApplier, clusterSettings, hostsProvider, allocationService)); } @Override @@ -78,9 +80,10 @@ public class TestZenDiscovery extends ZenDiscovery { private TestZenDiscovery(Settings settings, ThreadPool threadPool, TransportService transportService, NamedWriteableRegistry namedWriteableRegistry, MasterService masterService, - ClusterApplier clusterApplier, ClusterSettings clusterSettings, UnicastHostsProvider hostsProvider) { + ClusterApplier clusterApplier, ClusterSettings clusterSettings, UnicastHostsProvider hostsProvider, + AllocationService allocationService) { super(settings, threadPool, transportService, namedWriteableRegistry, masterService, clusterApplier, clusterSettings, - hostsProvider); + hostsProvider, allocationService); } @Override diff --git a/test/framework/src/main/java/org/elasticsearch/test/gateway/NoopGatewayAllocator.java b/test/framework/src/main/java/org/elasticsearch/test/gateway/NoopGatewayAllocator.java index b2b41b31461..d3e05d36f6e 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/gateway/NoopGatewayAllocator.java +++ b/test/framework/src/main/java/org/elasticsearch/test/gateway/NoopGatewayAllocator.java @@ -35,7 +35,7 @@ public class NoopGatewayAllocator extends GatewayAllocator { public static final NoopGatewayAllocator INSTANCE = new NoopGatewayAllocator(); protected NoopGatewayAllocator() { - super(Settings.EMPTY, null, null); + super(Settings.EMPTY); } @Override diff --git a/test/framework/src/main/java/org/elasticsearch/test/gateway/TestGatewayAllocator.java b/test/framework/src/main/java/org/elasticsearch/test/gateway/TestGatewayAllocator.java index f8c8c4694e5..2bbf2ce4c2c 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/gateway/TestGatewayAllocator.java +++ b/test/framework/src/main/java/org/elasticsearch/test/gateway/TestGatewayAllocator.java @@ -96,7 +96,7 @@ public class TestGatewayAllocator extends GatewayAllocator { }; public TestGatewayAllocator() { - super(Settings.EMPTY, null, null); + super(Settings.EMPTY); } @Override From 6b67e0bf2fb3e27279dff90ba76fa7c93bb4c828 Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Fri, 5 May 2017 09:34:12 +0200 Subject: [PATCH 33/44] Include all aliases including non-filtering in `_search_shards` response (#24489) `_search_shards`API today only returns aliases names if there is an alias filter associated with one of them. Now it can be useful to see which aliases have been expanded for an index given the index expressions. This change also includes non-filtering aliases even without a filtering alias being present. --- .../shards/ClusterSearchShardsResponse.java | 13 ++-- .../TransportClusterSearchShardsAction.java | 6 +- .../metadata/IndexNameExpressionResolver.java | 60 +++++++++++-------- .../IndexNameExpressionResolverTests.java | 14 +++++ docs/reference/search/search-shards.asciidoc | 4 +- .../test/search_shards/10_basic.yaml | 31 +++++++++- 6 files changed, 92 insertions(+), 36 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/shards/ClusterSearchShardsResponse.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/shards/ClusterSearchShardsResponse.java index 3ee5f56ebdc..c2fb90434e5 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/cluster/shards/ClusterSearchShardsResponse.java +++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/shards/ClusterSearchShardsResponse.java @@ -29,6 +29,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.search.internal.AliasFilter; import java.io.IOException; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -117,10 +118,14 @@ public class ClusterSearchShardsResponse extends ActionResponse implements ToXCo String index = entry.getKey(); builder.startObject(index); AliasFilter aliasFilter = entry.getValue(); - if (aliasFilter.getAliases().length > 0) { - builder.array("aliases", aliasFilter.getAliases()); - builder.field("filter"); - aliasFilter.getQueryBuilder().toXContent(builder, params); + String[] aliases = aliasFilter.getAliases(); + if (aliases.length > 0) { + Arrays.sort(aliases); // we want consistent ordering here and these values might be generated from a set / map + builder.array("aliases", aliases); + if (aliasFilter.getQueryBuilder() != null) { // might be null if we include non-filtering aliases + builder.field("filter"); + aliasFilter.getQueryBuilder().toXContent(builder, params); + } } builder.endObject(); } diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/shards/TransportClusterSearchShardsAction.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/shards/TransportClusterSearchShardsAction.java index 8825a426768..20ed69ae5a9 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/cluster/shards/TransportClusterSearchShardsAction.java +++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/shards/TransportClusterSearchShardsAction.java @@ -83,8 +83,10 @@ public class TransportClusterSearchShardsAction extends Map> routingMap = indexNameExpressionResolver.resolveSearchRouting(state, request.routing(), request.indices()); Map indicesAndFilters = new HashMap<>(); for (String index : concreteIndices) { - AliasFilter aliasFilter = indicesService.buildAliasFilter(clusterState, index, request.indices()); - indicesAndFilters.put(index, aliasFilter); + final AliasFilter aliasFilter = indicesService.buildAliasFilter(clusterState, index, request.indices()); + final String[] aliases = indexNameExpressionResolver.indexAliases(clusterState, index, aliasMetadata -> true, true, + request.indices()); + indicesAndFilters.put(index, new AliasFilter(aliasFilter.getQueryBuilder(), aliases)); } Set nodeIds = new HashSet<>(); diff --git a/core/src/main/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolver.java b/core/src/main/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolver.java index 168fe2ad7f2..d4c6ec587db 100644 --- a/core/src/main/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolver.java +++ b/core/src/main/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolver.java @@ -48,6 +48,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.function.Predicate; import java.util.stream.Collectors; public class IndexNameExpressionResolver extends AbstractComponent { @@ -268,8 +269,19 @@ public class IndexNameExpressionResolver extends AbstractComponent { * the index itself - null is returned. Returns null if no filtering is required. */ public String[] filteringAliases(ClusterState state, String index, String... expressions) { + return indexAliases(state, index, AliasMetaData::filteringRequired, false, expressions); + } + + /** + * Iterates through the list of indices and selects the effective list of required aliases for the + * given index. + *

Only aliases where the given predicate tests successfully are returned. If the indices list contains a non-required reference to + * the index itself - null is returned. Returns null if no filtering is required. + */ + public String[] indexAliases(ClusterState state, String index, Predicate requiredAlias, boolean skipIdentity, + String... expressions) { // expand the aliases wildcard - List resolvedExpressions = expressions != null ? Arrays.asList(expressions) : Collections.emptyList(); + List resolvedExpressions = expressions != null ? Arrays.asList(expressions) : Collections.emptyList(); Context context = new Context(state, IndicesOptions.lenientExpandOpen(), true); for (ExpressionResolver expressionResolver : expressionResolvers) { resolvedExpressions = expressionResolver.resolve(context, resolvedExpressions); @@ -278,54 +290,50 @@ public class IndexNameExpressionResolver extends AbstractComponent { if (isAllIndices(resolvedExpressions)) { return null; } + final IndexMetaData indexMetaData = state.metaData().getIndices().get(index); + if (indexMetaData == null) { + // Shouldn't happen + throw new IndexNotFoundException(index); + } // optimize for the most common single index/alias scenario if (resolvedExpressions.size() == 1) { String alias = resolvedExpressions.get(0); - IndexMetaData indexMetaData = state.metaData().getIndices().get(index); - if (indexMetaData == null) { - // Shouldn't happen - throw new IndexNotFoundException(index); - } + AliasMetaData aliasMetaData = indexMetaData.getAliases().get(alias); - boolean filteringRequired = aliasMetaData != null && aliasMetaData.filteringRequired(); - if (!filteringRequired) { + if (aliasMetaData == null || requiredAlias.test(aliasMetaData) == false) { return null; } return new String[]{alias}; } - List filteringAliases = null; + List aliases = null; for (String alias : resolvedExpressions) { if (alias.equals(index)) { - return null; + if (skipIdentity) { + continue; + } else { + return null; + } } - - IndexMetaData indexMetaData = state.metaData().getIndices().get(index); - if (indexMetaData == null) { - // Shouldn't happen - throw new IndexNotFoundException(index); - } - AliasMetaData aliasMetaData = indexMetaData.getAliases().get(alias); // Check that this is an alias for the current index // Otherwise - skip it if (aliasMetaData != null) { - boolean filteringRequired = aliasMetaData.filteringRequired(); - if (filteringRequired) { - // If filtering required - add it to the list of filters - if (filteringAliases == null) { - filteringAliases = new ArrayList<>(); + if (requiredAlias.test(aliasMetaData)) { + // If required - add it to the list of aliases + if (aliases == null) { + aliases = new ArrayList<>(); } - filteringAliases.add(alias); + aliases.add(alias); } else { - // If not, we have a non filtering alias for this index - no filtering needed + // If not, we have a non required alias for this index - no futher checking needed return null; } } } - if (filteringAliases == null) { + if (aliases == null) { return null; } - return filteringAliases.toArray(new String[filteringAliases.size()]); + return aliases.toArray(new String[aliases.size()]); } /** diff --git a/core/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverTests.java b/core/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverTests.java index b68f3735c0a..7d3ca04e5a8 100644 --- a/core/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverTests.java +++ b/core/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverTests.java @@ -33,6 +33,7 @@ import org.elasticsearch.test.ESTestCase; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.function.Predicate; import static org.elasticsearch.common.util.set.Sets.newHashSet; import static org.hamcrest.Matchers.arrayContaining; @@ -956,4 +957,17 @@ public class IndexNameExpressionResolverTests extends ESTestCase { strings = indexNameExpressionResolver.filteringAliases(state, "test-0", "test-*,alias-*"); assertNull(strings); } + + public void testIndexAliases() { + MetaData.Builder mdBuilder = MetaData.builder() + .put(indexBuilder("test-0").state(State.OPEN) + .putAlias(AliasMetaData.builder("test-alias-0").filter("{ \"term\": \"foo\"}")) + .putAlias(AliasMetaData.builder("test-alias-1").filter("{ \"term\": \"foo\"}")) + .putAlias(AliasMetaData.builder("test-alias-non-filtering")) + ); + ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build(); + String[] strings = indexNameExpressionResolver.indexAliases(state, "test-0", x -> true, true, "test-*"); + Arrays.sort(strings); + assertArrayEquals(new String[] {"test-alias-0", "test-alias-1", "test-alias-non-filtering"}, strings); + } } diff --git a/docs/reference/search/search-shards.asciidoc b/docs/reference/search/search-shards.asciidoc index 1515a182d42..b20117bb75d 100644 --- a/docs/reference/search/search-shards.asciidoc +++ b/docs/reference/search/search-shards.asciidoc @@ -4,7 +4,7 @@ The search shards api returns the indices and shards that a search request would be executed against. This can give useful feedback for working out issues or planning optimizations with routing and shard preferences. When filtered aliases -are used, the filter is returned as part of the `indices` section. +are used, the filter is returned as part of the `indices` section [5.1.0] Added in 5.1.0. The `index` may be a single value, or comma-separated. @@ -165,4 +165,4 @@ routing values have been specified. `local`:: A boolean value whether to read the cluster state locally in order to determine where shards are allocated instead of using the Master node's - cluster state. + cluster state. \ No newline at end of file diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/search_shards/10_basic.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/search_shards/10_basic.yaml index 42189883b1b..d2a53a4416a 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/search_shards/10_basic.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/search_shards/10_basic.yaml @@ -14,7 +14,7 @@ --- "Search shards aliases with and without filters": - skip: - version: " - 5.0.99" + version: " - 5.99.99" # temporarily disabled reason: indices section was added in 5.1.0 - do: @@ -49,7 +49,7 @@ - match: { shards.0.0.index: test_index } - is_true: indices.test_index - is_false: indices.test_index.filter - - is_false: indices.test_index.aliases + - match: { indices.test_index.aliases: [test_alias_no_filter]} - do: search_shards: @@ -78,3 +78,30 @@ - match: { indices.test_index.filter.bool.adjust_pure_negative: true} - lte: { indices.test_index.filter.bool.boost: 1.0 } - gte: { indices.test_index.filter.bool.boost: 1.0 } + + - do: + search_shards: + index: "test*" + + - length: { shards: 1 } + - match: { shards.0.0.index: test_index } + - match: { indices.test_index.aliases: [test_alias_filter_1, test_alias_filter_2, test_alias_no_filter]} + - is_false: indices.test_index.filter + + - do: + search_shards: + index: ["test_alias_filter_1","test_alias_no_filter"] + + - length: { shards: 1 } + - match: { shards.0.0.index: test_index } + - match: { indices.test_index.aliases: [test_alias_filter_1, test_alias_no_filter]} + - is_false: indices.test_index.filter + + - do: + search_shards: + index: ["test_alias_no_filter"] + + - length: { shards: 1 } + - match: { shards.0.0.index: test_index } + - match: { indices.test_index.aliases: [test_alias_no_filter]} + - is_false: indices.test_index.filter From 6e970db5337d488e67ab73b25fb68d39835ca850 Mon Sep 17 00:00:00 2001 From: Clinton Gormley Date: Fri, 5 May 2017 11:08:55 +0200 Subject: [PATCH 34/44] Fixed chunking of breaking changes docs --- docs/reference/migration/migrate_6_0/docs.asciidoc | 4 ++-- docs/reference/migration/migrate_6_0/indices.asciidoc | 8 ++++---- docs/reference/migration/migrate_6_0/mappings.asciidoc | 4 ++-- docs/reference/migration/migrate_6_0/rest.asciidoc | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/reference/migration/migrate_6_0/docs.asciidoc b/docs/reference/migration/migrate_6_0/docs.asciidoc index b7a08ea8930..9b4ad82a32d 100644 --- a/docs/reference/migration/migrate_6_0/docs.asciidoc +++ b/docs/reference/migration/migrate_6_0/docs.asciidoc @@ -1,11 +1,11 @@ [[breaking_60_docs_changes]] === Document API changes -==== version type 'force' removed +==== version type `force` removed Document modification operations may no longer specify the `version_type` of `force` to override any previous version checks. -==== <> no longer support versions +==== <> no longer support versions Adding a `version` to an upsert request is no longer supported. diff --git a/docs/reference/migration/migrate_6_0/indices.asciidoc b/docs/reference/migration/migrate_6_0/indices.asciidoc index a1d1ffd578d..0a05fd55139 100644 --- a/docs/reference/migration/migrate_6_0/indices.asciidoc +++ b/docs/reference/migration/migrate_6_0/indices.asciidoc @@ -1,7 +1,7 @@ [[breaking_60_indices_changes]] -=== Templates changes +=== Indices changes -==== `template` is now `index_patterns` +==== Index templates use `index_patterns` instead of `template` Previously templates expressed the indices that they should match using a glob style pattern in the `template` field. They should now use the `index_patterns` @@ -29,7 +29,7 @@ PUT _template/template_2 // CONSOLE -=== Shadow Replicas have been removed +==== Shadow Replicas have been removed Shadow replicas don't see enough usage, and have been removed. This includes the following settings: @@ -38,7 +38,7 @@ following settings: - `index.shadow_replicas` - `node.add_lock_id_to_custom_path` -=== Open/Close index API allows wildcard expressions that match no indices by default +==== Open/Close index API allows wildcard expressions that match no indices by default The default value of the `allow_no_indices` option for the Open/Close index API has been changed from `false` to `true` so it is aligned with the behaviour of the diff --git a/docs/reference/migration/migrate_6_0/mappings.asciidoc b/docs/reference/migration/migrate_6_0/mappings.asciidoc index 754f4fe7266..e85b31d97ff 100644 --- a/docs/reference/migration/migrate_6_0/mappings.asciidoc +++ b/docs/reference/migration/migrate_6_0/mappings.asciidoc @@ -4,7 +4,7 @@ ==== Coercion of boolean fields Previously, Elasticsearch recognized the strings `true`, `false`, `on`, `off`, `yes`, `no`, `0`, `1` as booleans. Elasticsearch 6.0 -recognizes only `true` and `false` as boolean and will throw an error otherwise. For backwards compatibility purposes, during the 6.x +recognizes only the strings `true` and `false` as booleans and will throw an error otherwise. For backwards compatibility purposes, during the 6.x series the previous coercion rules will continue to work on pre-6.0 indices. This means that you do not need to change affected existing mappings immediately. However, it is not possible to create new indices from existing index templates that violate the strict `boolean` coercion rules. @@ -20,7 +20,7 @@ created with Elasticsearch version 6.0 or later. ==== The `include_in_all` mapping parameter is now disallowed -Since the `_all` field is now disabled by default and cannot be configured for +Since the ++_all++ field is now disabled by default and cannot be configured for indices created with Elasticsearch 6.0 or later, the `include_in_all` setting is now disallowed for these indices' mappings. diff --git a/docs/reference/migration/migrate_6_0/rest.asciidoc b/docs/reference/migration/migrate_6_0/rest.asciidoc index 5ef09a15bff..cfd8a9511a2 100644 --- a/docs/reference/migration/migrate_6_0/rest.asciidoc +++ b/docs/reference/migration/migrate_6_0/rest.asciidoc @@ -48,7 +48,7 @@ Refresh requests that are broadcast to multiple shards that can have one or more shards fail during the request now return a 500 response instead of a 200 response in the event there is at least one failure. -=== Delete by Query API requires an explicit query +==== Delete by Query API requires an explicit query In previous versions of Elasticsearch, delete by query requests without an explicit query were accepted, match_all was used as the default query and all documents were deleted From 03267e03da5facdef138a082e9762fb8a04c00e1 Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Fri, 5 May 2017 11:56:03 +0200 Subject: [PATCH 35/44] Fix NPE if field caps request has a field that exists not in all indices (#24504) If a field caps request contains a field name that doesn't exist in all indices the response will be partial and we hide an NPE. The NPE is now fixed but we still have the problem that we don't pass on errors on the shard level to the user. This will be fixed in a followup. --- ...TransportFieldCapabilitiesIndexAction.java | 6 ++- .../test/field_caps/10_basic.yaml | 42 +++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesIndexAction.java b/core/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesIndexAction.java index e7db685b4a8..b9e6f56b6d7 100644 --- a/core/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesIndexAction.java +++ b/core/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesIndexAction.java @@ -80,8 +80,10 @@ public class TransportFieldCapabilitiesIndexAction extends TransportSingleShardA Map responseMap = new HashMap<>(); for (String field : fieldNames) { MappedFieldType ft = mapperService.fullName(field); - FieldCapabilities fieldCap = new FieldCapabilities(field, ft.typeName(), ft.isSearchable(), ft.isAggregatable()); - responseMap.put(field, fieldCap); + if (ft != null) { + FieldCapabilities fieldCap = new FieldCapabilities(field, ft.typeName(), ft.isSearchable(), ft.isAggregatable()); + responseMap.put(field, fieldCap); + } } return new FieldCapabilitiesIndexResponse(shardId.getIndexName(), responseMap); } diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/field_caps/10_basic.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/field_caps/10_basic.yaml index cef72b6e3fe..e6dd5a2c71f 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/field_caps/10_basic.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/field_caps/10_basic.yaml @@ -165,3 +165,45 @@ setup: - match: {fields.number.long.indices: ["test3"]} - is_false: fields.number.long.non_searchable_indices - is_false: fields.number.long.non_aggregatable_indices + +--- +"Mix in non-existing field field caps": + - skip: + version: " - 5.4.0" + reason: this bug has been fixed in 5.4.0 + + - do: + field_caps: + index: 'test1,test2,test3' + fields: [text, keyword, no_such_field, number, geo] + + - match: {fields.text.text.searchable: true} + - match: {fields.text.text.aggregatable: false} + - is_false: fields.text.text.indices + - is_false: fields.text.text.non_searchable_indices + - is_false: fields.text.text.non_aggregatable_indices + - match: {fields.keyword.keyword.searchable: true} + - match: {fields.keyword.keyword.aggregatable: true} + - is_false: fields.text.keyword.indices + - is_false: fields.text.keyword.non_searchable_indices + - is_false: fields.text.keyword.non_aggregatable_indices + - match: {fields.number.double.searchable: true} + - match: {fields.number.double.aggregatable: true} + - match: {fields.number.double.indices: ["test1", "test2"]} + - is_false: fields.number.double.non_searchable_indices + - is_false: fields.number.double.non_aggregatable_indices + - match: {fields.number.long.searchable: true} + - match: {fields.number.long.aggregatable: true} + - match: {fields.number.long.indices: ["test3"]} + - is_false: fields.number.long.non_searchable_indices + - is_false: fields.number.long.non_aggregatable_indices + - match: {fields.geo.geo_point.searchable: true} + - match: {fields.geo.geo_point.aggregatable: true} + - match: {fields.geo.geo_point.indices: ["test1", "test2"]} + - is_false: fields.geo.geo_point.non_searchable_indices + - is_false: fields.geo.geo_point.non_aggregatable_indices + - match: {fields.geo.keyword.searchable: true} + - match: {fields.geo.keyword.aggregatable: true} + - match: {fields.geo.keyword.indices: ["test3"]} + - is_false: fields.geo.keyword.non_searchable_indices + - is_false: fields.geo.keyword.on_aggregatable_indices From 8055b14f2eb16e0b8b697655006355f3bf243e87 Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Fri, 5 May 2017 12:08:00 +0200 Subject: [PATCH 36/44] Temporarily disable tests --- .../main/resources/rest-api-spec/test/field_caps/10_basic.yaml | 2 +- .../resources/rest-api-spec/test/search_shards/10_basic.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/field_caps/10_basic.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/field_caps/10_basic.yaml index e6dd5a2c71f..2568f401a5e 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/field_caps/10_basic.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/field_caps/10_basic.yaml @@ -169,7 +169,7 @@ setup: --- "Mix in non-existing field field caps": - skip: - version: " - 5.4.0" + version: " - 6.0.0" # temporarily disabled reason: this bug has been fixed in 5.4.0 - do: diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/search_shards/10_basic.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/search_shards/10_basic.yaml index d2a53a4416a..ef01f3b7b44 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/search_shards/10_basic.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/search_shards/10_basic.yaml @@ -14,7 +14,7 @@ --- "Search shards aliases with and without filters": - skip: - version: " - 5.99.99" # temporarily disabled + version: " - 6.0.0" # temporarily disabled reason: indices section was added in 5.1.0 - do: From c9aecbb8a5a911861fbbcc1083a8f39453b34386 Mon Sep 17 00:00:00 2001 From: Clinton Gormley Date: Fri, 5 May 2017 11:52:57 +0200 Subject: [PATCH 37/44] Added removal of JavaScript and Python to breaking changes --- docs/reference/migration/migrate_6_0/scripting.asciidoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/reference/migration/migrate_6_0/scripting.asciidoc b/docs/reference/migration/migrate_6_0/scripting.asciidoc index 67402009223..075678b3ab3 100644 --- a/docs/reference/migration/migrate_6_0/scripting.asciidoc +++ b/docs/reference/migration/migrate_6_0/scripting.asciidoc @@ -1,10 +1,10 @@ [[breaking_60_scripting_changes]] === Scripting changes -==== Groovy language removed +==== Groovy, JavaScript, and Python languages removed -The groovy scripting language was deprecated in elasticsearch 5.0 and is now removed. -Use painless instead. +The Groovy, JavaScript, and Python scripting languages were deprecated in +elasticsearch 5.0 and have now been removed. Use painless instead. ==== Date fields now return dates From 017411929664bba1d01ee5420d4316939b7c5509 Mon Sep 17 00:00:00 2001 From: Clinton Gormley Date: Fri, 5 May 2017 12:39:41 +0200 Subject: [PATCH 38/44] Added release notes for 6.0.0-alpha1 --- docs/Versions.asciidoc | 6 +- docs/reference/index.asciidoc | 4 +- docs/reference/release-notes.asciidoc | 8 +- .../release-notes/6.0.0-alpha1-5x.asciidoc | 1096 +++++++++++++++++ .../release-notes/6.0.0-alpha1.asciidoc | 309 +++++ 5 files changed, 1416 insertions(+), 7 deletions(-) create mode 100644 docs/reference/release-notes/6.0.0-alpha1-5x.asciidoc create mode 100644 docs/reference/release-notes/6.0.0-alpha1.asciidoc diff --git a/docs/Versions.asciidoc b/docs/Versions.asciidoc index 12e606ba78a..bbd5f3bce07 100644 --- a/docs/Versions.asciidoc +++ b/docs/Versions.asciidoc @@ -1,9 +1,9 @@ :version: 6.0.0-alpha1 :major-version: 6.x -:lucene_version: 6.4.0 -:lucene_version_path: 6_4_0 +:lucene_version: 7.0.0-SNAPSHOT +:lucene_version_path: 7_0_0 :branch: master -:jdk: 1.8.0_73 +:jdk: 1.8.0_131 ////////// release-state can be: released | prerelease | unreleased diff --git a/docs/reference/index.asciidoc b/docs/reference/index.asciidoc index 2a4d7852a2f..cb97bcf6d9f 100644 --- a/docs/reference/index.asciidoc +++ b/docs/reference/index.asciidoc @@ -42,9 +42,7 @@ include::testing.asciidoc[] include::glossary.asciidoc[] -////// - include::release-notes.asciidoc[] -////// +include::release-notes.asciidoc[] include::painless-api-reference.asciidoc[] diff --git a/docs/reference/release-notes.asciidoc b/docs/reference/release-notes.asciidoc index 267525b1b3c..909d2cb6d1c 100644 --- a/docs/reference/release-notes.asciidoc +++ b/docs/reference/release-notes.asciidoc @@ -3,5 +3,11 @@ [partintro] -- -This section will summarize the changes in released versions. +This section summarizes the changes in each release. + +* <> +* <> + -- +include::release-notes/6.0.0-alpha1.asciidoc[] +include::release-notes/6.0.0-alpha1-5x.asciidoc[] diff --git a/docs/reference/release-notes/6.0.0-alpha1-5x.asciidoc b/docs/reference/release-notes/6.0.0-alpha1-5x.asciidoc new file mode 100644 index 00000000000..699260fd0c8 --- /dev/null +++ b/docs/reference/release-notes/6.0.0-alpha1-5x.asciidoc @@ -0,0 +1,1096 @@ +[[release-notes-6.0.0-alpha1-5x]] +== 6.0.0-alpha1 Release Notes (Changes previously released in 5.x) + +The changes listed below were first released in the 5.x series. Changes +released for the first time in Elasticsearch 6.0.0-alpha1 are listed in +<>. + +[[breaking-6.0.0-alpha1-5x]] +[float] +=== Breaking changes + +Aliases:: +* Validate alias names the same as index names {pull}20771[#20771] (issue: {issue}20748[#20748]) + +CRUD:: +* Fixed naming inconsistency for fields/stored_fields in the APIs {pull}20166[#20166] (issues: {issue}18943[#18943], {issue}20155[#20155]) + +Core:: +* Add system call filter bootstrap check {pull}21940[#21940] +* Remove ignore system bootstrap checks {pull}20511[#20511] + +Internal:: +* `_flush` should block by default {pull}20597[#20597] (issue: {issue}20569[#20569]) + +Packaging:: +* Rename service.bat to elasticsearch-service.bat {pull}20496[#20496] (issue: {issue}17528[#17528]) + +Plugin Lang Painless:: +* Remove all date 'now' methods from Painless {pull}20766[#20766] (issue: {issue}20762[#20762]) + +Query DSL:: +* Fix name of `enabled_position_increments` {pull}22895[#22895] + +REST:: +* Change separator for shards preference {pull}20786[#20786] (issues: {issue}20722[#20722], {issue}20769[#20769]) + +Search:: +* Remove DFS_QUERY_AND_FETCH as a search type {pull}22787[#22787] + +Settings:: +* Remove support for default settings {pull}24093[#24093] (issues: {issue}23981[#23981], {issue}24052[#24052], {issue}24074[#24074]) + + + +[[breaking-java-6.0.0-alpha1-5x]] +[float] +=== Breaking Java changes + +Aggregations:: +* Move getProperty method out of MultiBucketsAggregation.Bucket interface {pull}23988[#23988] +* Remove getProperty method from Aggregations interface and impl {pull}23972[#23972] +* Move getProperty method out of Aggregation interface {pull}23949[#23949] + +Allocation:: +* Cluster Explain API uses the allocation process to explain shard allocation decisions {pull}22182[#22182] (issues: {issue}20347[#20347], {issue}20634[#20634], {issue}21103[#21103], {issue}21662[#21662], {issue}21691[#21691]) + +Cluster:: +* Remove PROTO-based custom cluster state components {pull}22336[#22336] (issue: {issue}21868[#21868]) + +Core:: +* Remove ability to plug-in TransportService {pull}20505[#20505] + +Discovery:: +* Remove pluggability of ElectMasterService {pull}21031[#21031] + +Exceptions:: +* Remove `IndexTemplateAlreadyExistsException` and `IndexShardAlreadyExistsException` {pull}21539[#21539] (issue: {issue}21494[#21494]) +* Replace IndexAlreadyExistsException with ResourceAlreadyExistsException {pull}21494[#21494] + +Ingest:: +* Change type of ingest doc meta-data field 'TIMESTAMP' to `Date` {pull}22234[#22234] (issue: {issue}22074[#22074]) + +Internal:: +* Replace SearchExtRegistry with namedObject {pull}22492[#22492] +* Replace Suggesters with namedObject {pull}22491[#22491] +* Consolidate the last easy parser construction {pull}22095[#22095] +* Introduce XContentParser#namedObject {pull}22003[#22003] +* Pass executor name to request interceptor to support async intercept calls {pull}21089[#21089] +* Remove TransportService#registerRequestHandler leniency {pull}20469[#20469] (issue: {issue}20468[#20468]) + +Java API:: +* Fold InternalSearchHits and friends into their interfaces {pull}23042[#23042] + +Network:: +* Remove HttpServer and HttpServerAdapter in favor of a simple dispatch method {pull}22636[#22636] (issue: {issue}18482[#18482]) +* Unguice Transport and friends {pull}20526[#20526] + +Plugins:: +* Deguice rest handlers {pull}22575[#22575] +* Plugins: Replace Rest filters with RestHandler wrapper {pull}21905[#21905] +* Plugins: Remove support for onModule {pull}21416[#21416] +* Cleanup sub fetch phase extension point {pull}20382[#20382] + +Query DSL:: +* Resolve index names in indices_boost {pull}21393[#21393] (issue: {issue}4756[#4756]) + +Scripting:: +* Refactor ScriptType to be a Top-Level Class {pull}21136[#21136] + +Search:: +* Remove QUERY_AND_FETCH search type {pull}22996[#22996] +* Cluster search shards improvements: expose ShardId, adjust visibility of some members {pull}21752[#21752] + + + +[[deprecation-6.0.0-alpha1-5x]] +[float] +=== Deprecations + +Java API:: +* Add BulkProcessor methods with XContentType parameter {pull}23078[#23078] (issue: {issue}22691[#22691]) +* Deprecate and remove "minimumNumberShouldMatch" in BoolQueryBuilder {pull}22403[#22403] + +Plugin Repository S3:: +* S3 Repository: Deprecate remaining `repositories.s3.*` settings {pull}24144[#24144] (issue: {issue}24143[#24143]) +* Deprecate specifying credentials through env vars, sys props, and remove profile files {pull}22567[#22567] (issues: {issue}21041[#21041], {issue}22479[#22479]) + +Query DSL:: +* Add deprecation logging message for 'fuzzy' query {pull}20993[#20993] (issue: {issue}15760[#15760]) + +REST:: +* Optionally require a valid content type for all rest requests with content {pull}22691[#22691] (issue: {issue}19388[#19388]) + +Scripting:: +* Change Namespace for Stored Script to Only Use Id {pull}22206[#22206] + +Shadow Replicas:: +* Add a deprecation notice to shadow replicas {pull}22647[#22647] (issue: {issue}22024[#22024]) + +Stats:: +* Deprecate _field_stats endpoint {pull}23914[#23914] + + + +[[feature-6.0.0-alpha1-5x]] +[float] +=== New features + +Aggregations:: +* Initial version of an adjacency matrix using the Filters aggregation {pull}22239[#22239] (issue: {issue}22169[#22169]) + +Analysis:: +* Adds pattern keyword marker filter support {pull}23600[#23600] (issue: {issue}4877[#4877]) +* Expose WordDelimiterGraphTokenFilter {pull}23327[#23327] (issue: {issue}23104[#23104]) +* Synonym Graph Support (LUCENE-6664) {pull}21517[#21517] +* Expose Lucenes Ukrainian analyzer {pull}21176[#21176] (issue: {issue}19433[#19433]) + +CAT API:: +* Provides a cat api endpoint for templates. {pull}20545[#20545] (issue: {issue}20467[#20467]) + +CRUD:: +* Allow an index to be partitioned with custom routing {pull}22274[#22274] (issue: {issue}21585[#21585]) + +Highlighting:: +* Integrate UnifiedHighlighter {pull}21621[#21621] (issue: {issue}21376[#21376]) + +Index APIs:: +* Add FieldCapabilities (_field_caps) API {pull}23007[#23007] (issue: {issue}22438[#22438]) + +Ingest:: +* introduce KV Processor in Ingest Node {pull}22272[#22272] (issue: {issue}22222[#22222]) + +Mapping:: +* Add the ability to set a normalizer on keyword fields. {pull}21919[#21919] (issue: {issue}18064[#18064]) +* Add RangeFieldMapper for numeric and date range types {pull}21002[#21002] (issue: {issue}20999[#20999]) + +Plugin Discovery File:: +* File-based discovery plugin {pull}20394[#20394] (issue: {issue}20323[#20323]) + +Query DSL:: +* Add "all fields" execution mode to simple_query_string query {pull}21341[#21341] (issues: {issue}19784[#19784], {issue}20925[#20925]) +* Add support for `quote_field_suffix` to `simple_query_string`. {pull}21060[#21060] (issue: {issue}18641[#18641]) +* Add "all field" execution mode to query_string query {pull}20925[#20925] (issue: {issue}19784[#19784]) + +Reindex API:: +* Add automatic parallelization support to reindex and friends {pull}20767[#20767] (issue: {issue}20624[#20624]) + +Search:: +* Introduce incremental reduction of TopDocs {pull}23946[#23946] +* Add federated cross cluster search capabilities {pull}22502[#22502] (issue: {issue}21473[#21473]) +* Add field collapsing for search request {pull}22337[#22337] (issue: {issue}21833[#21833]) + +Settings:: +* Add infrastructure for elasticsearch keystore {pull}22335[#22335] + +Similarities:: +* Adds boolean similarity to Elasticsearch {pull}23637[#23637] (issue: {issue}6731[#6731]) + + + +[[enhancement-6.0.0-alpha1-5x]] +[float] +=== Enhancements + +Aggregations:: +* Add `count` to rest output of `geo_centroid` {pull}24387[#24387] (issue: {issue}24366[#24366]) +* Allow scripted metric agg to access `_score` {pull}24295[#24295] +* Add BucketMetricValue interface {pull}24188[#24188] +* Move aggs CommonFields and TYPED_KEYS_DELIMITER from InternalAggregation to Aggregation {pull}23987[#23987] +* Use ParseField for aggs CommonFields rather than String {pull}23717[#23717] +* Share XContent rendering code in terms aggs {pull}23680[#23680] +* Add unit tests for ParentToChildAggregator {pull}23305[#23305] (issue: {issue}22278[#22278]) +* First step towards incremental reduction of query responses {pull}23253[#23253] +* `value_type` is useful regardless of scripting. {pull}22160[#22160] (issue: {issue}20163[#20163]) +* Support for partitioning set of terms {pull}21626[#21626] (issue: {issue}21487[#21487]) +* Rescorer should be applied in the TopHits aggregation {pull}20978[#20978] (issue: {issue}19317[#19317]) + +Aliases:: +* Handle multiple aliases in _cat/aliases api {pull}23698[#23698] (issue: {issue}23661[#23661]) + +Allocation:: +* Trigger replica recovery restarts by master when primary relocation completes {pull}23926[#23926] (issue: {issue}23904[#23904]) +* Makes the same_shard host dynamically updatable {pull}23397[#23397] (issue: {issue}22992[#22992]) +* Include stale replica shard info when explaining an unassigned primary {pull}22826[#22826] +* Adds setting level to allocation decider explanations {pull}22268[#22268] (issue: {issue}21771[#21771]) +* Improves allocation decider decision explanation messages {pull}21771[#21771] +* Prepares allocator decision objects for use with the allocation explain API {pull}21691[#21691] +* Balance step in BalancedShardsAllocator for a single shard {pull}21103[#21103] +* Process more expensive allocation deciders last {pull}20724[#20724] (issue: {issue}12815[#12815]) +* Separates decision making from decision application in BalancedShardsAllocator {pull}20634[#20634] + +Analysis:: +* Support Keyword type in Analyze API {pull}23161[#23161] +* Expose FlattenGraphTokenFilter {pull}22643[#22643] +* Analyze API Position Length Support {pull}22574[#22574] +* Remove AnalysisService and reduce it to a simple name to analyzer mapping {pull}20627[#20627] (issues: {issue}19827[#19827], {issue}19828[#19828]) + +CAT API:: +* Adding built-in sorting capability to _cat apis. {pull}20658[#20658] (issue: {issue}16975[#16975]) +* Add health status parameter to cat indices API {pull}20393[#20393] + +CRUD:: +* Use correct block levels for TRA subclasses {pull}22224[#22224] +* Make index and delete operation execute as a single bulk item {pull}21964[#21964] + +Cache:: +* Do not cache term queries. {pull}21566[#21566] (issues: {issue}16031[#16031], {issue}20116[#20116]) +* Parse alias filters on the coordinating node {pull}20916[#20916] + +Circuit Breakers:: +* Closing a ReleasableBytesStreamOutput closes the underlying BigArray {pull}23941[#23941] +* Add used memory amount to CircuitBreakingException message (#22521) {pull}22693[#22693] (issue: {issue}22521[#22521]) +* Cluster Settings Updates should not trigger circuit breakers. {pull}20827[#20827] + +Cluster:: +* Extract a common base class to allow services to listen to remote cluster config updates {pull}24367[#24367] +* Prevent nodes from joining if newer indices exist in the cluster {pull}23843[#23843] +* Connect to new nodes concurrently {pull}22984[#22984] (issue: {issue}22828[#22828]) +* Keep NodeConnectionsService in sync with current nodes in the cluster state {pull}22509[#22509] +* Add a generic way of checking version before serializing custom cluster object {pull}22376[#22376] (issue: {issue}22313[#22313]) +* Add validation for supported index version on node join, restore, upgrade & open index {pull}21830[#21830] (issue: {issue}21670[#21670]) +* Let ClusterStateObserver only hold onto state that's needed for change detection {pull}21631[#21631] (issue: {issue}21568[#21568]) +* Cache successful shard deletion checks {pull}21438[#21438] +* Remove mutable status field from cluster state {pull}21379[#21379] +* Skip shard management code when updating cluster state on client/tribe nodes {pull}20731[#20731] +* Add clusterUUID to RestMainAction output {pull}20503[#20503] + +Core:: +* Regex upgrades {pull}24316[#24316] (issue: {issue}24226[#24226]) +* Detect remnants of path.data/default.path.data bug {pull}24099[#24099] (issues: {issue}23981[#23981], {issue}24052[#24052], {issue}24074[#24074], {issue}24093[#24093]) +* Await termination after shutting down executors {pull}23889[#23889] +* Add early-access check {pull}23743[#23743] (issue: {issue}23668[#23668]) +* Adapter action future should restore interrupts {pull}23618[#23618] (issue: {issue}23617[#23617]) +* Disable bootstrap checks for single-node discovery {pull}23598[#23598] (issues: {issue}23585[#23585], {issue}23595[#23595]) +* Enable explicitly enforcing bootstrap checks {pull}23585[#23585] (issue: {issue}21864[#21864]) +* Add equals/hashcode method to ReplicationResponse {pull}23215[#23215] +* Simplify ElasticsearchException rendering as a XContent {pull}22611[#22611] +* Remove setLocalNode from ClusterService and TransportService {pull}22608[#22608] +* Rename bootstrap.seccomp to bootstrap.system_call_filter {pull}22226[#22226] (issue: {issue}21940[#21940]) +* Cleanup random stats serialization code {pull}22223[#22223] +* Avoid corruption when deserializing booleans {pull}22152[#22152] +* Reduce memory pressure when sending large terms queries. {pull}21776[#21776] +* Install a security manager on startup {pull}21716[#21716] +* Log node ID on startup {pull}21673[#21673] +* Ensure source filtering automatons are only compiled once {pull}20857[#20857] (issue: {issue}20839[#20839]) +* Improve scheduling fairness when batching cluster state changes with equal priority {pull}20775[#20775] (issue: {issue}20768[#20768]) +* Add production warning for pre-release builds {pull}20674[#20674] +* Add serial collector bootstrap check {pull}20558[#20558] +* Do not log full bootstrap checks exception {pull}19989[#19989] + +Dates:: +* Improve error handling for epoch format parser with time zone (#22621) {pull}23689[#23689] + +Discovery:: +* Introduce single-node discovery {pull}23595[#23595] +* UnicastZenPing shouldn't ping the address of the local node {pull}23567[#23567] +* MasterFaultDetection can start after the initial cluster state has been processed {pull}23037[#23037] (issue: {issue}22828[#22828]) +* Simplify Unicast Zen Ping {pull}22277[#22277] (issues: {issue}19370[#19370], {issue}21739[#21739], {issue}22120[#22120], {issue}22194[#22194]) +* Prefer joining node with conflicting transport address when becoming master {pull}22134[#22134] (issues: {issue}22049[#22049], {issue}22120[#22120]) + +Engine:: +* Engine: store maxUnsafeAutoIdTimestamp in commit {pull}24149[#24149] +* Replace EngineClosedException with AlreadyClosedExcpetion {pull}22631[#22631] + +Exceptions:: +* Add BWC layer for Exceptions {pull}21694[#21694] (issue: {issue}21656[#21656]) + +Geo:: +* Optimize geo-distance sorting. {pull}20596[#20596] (issue: {issue}20450[#20450]) + +Highlighting:: +* Add support for fragment_length in the unified highlighter {pull}23431[#23431] +* Add BreakIteratorBoundaryScanner support {pull}23248[#23248] + +Index APIs:: +* Open and close index to honour allow_no_indices option {pull}24222[#24222] (issue: {issue}24031[#24031]) +* Wildcard cluster names for cross cluster search {pull}23985[#23985] (issue: {issue}23893[#23893]) +* Indexing: Add shard id to indexing operation listener {pull}22606[#22606] +* Better error when can't auto create index {pull}22488[#22488] (issues: {issue}21448[#21448], {issue}22435[#22435]) +* Add date-math support to `_rollover` {pull}20709[#20709] + +Ingest:: +* Lazy load the geoip databases {pull}23337[#23337] +* add `ignore_missing` flag to ingest plugins {pull}22273[#22273] +* Added ability to remove pipelines via wildcards (#22149) {pull}22191[#22191] (issue: {issue}22149[#22149]) +* Enables the ability to inject serialized json fields into root of document {pull}22179[#22179] (issue: {issue}21898[#21898]) +* compile ScriptProcessor inline scripts when creating ingest pipelines {pull}21858[#21858] (issue: {issue}21842[#21842]) +* add `ignore_missing` option to SplitProcessor {pull}20982[#20982] (issues: {issue}19995[#19995], {issue}20840[#20840]) +* add ignore_missing option to convert,trim,lowercase,uppercase,grok,rename {pull}20194[#20194] (issue: {issue}19995[#19995]) +* introduce the JSON Processor {pull}20128[#20128] (issue: {issue}20052[#20052]) + +Internal:: +* Log JVM arguments on startup {pull}24451[#24451] +* Move RemoteClusterService into TransportService {pull}24424[#24424] +* Enum related performance additions. {pull}24274[#24274] (issue: {issue}24226[#24226]) +* Add a dedicated TransportRemoteInfoAction for consistency {pull}24040[#24040] (issue: {issue}23969[#23969]) +* Simplify sorted top docs merging in SearchPhaseController {pull}23881[#23881] +* Synchronized CollapseTopFieldDocs with lucenes relatives {pull}23854[#23854] +* Cleanup SearchPhaseController interface {pull}23844[#23844] +* Do not create String instances in 'Strings' methods accepting StringBuilder {pull}22907[#22907] +* Improve connection closing in `RemoteClusterConnection` {pull}22804[#22804] (issue: {issue}22803[#22803]) +* Remove some more usages of ParseFieldMatcher {pull}22437[#22437] (issues: {issue}19552[#19552], {issue}22130[#22130]) +* Remove some more usages of ParseFieldMatcher {pull}22398[#22398] (issues: {issue}19552[#19552], {issue}22130[#22130]) +* Remove some more usages of ParseFieldMatcher {pull}22395[#22395] (issues: {issue}19552[#19552], {issue}22130[#22130]) +* Remove some ParseFieldMatcher usages {pull}22389[#22389] (issues: {issue}19552[#19552], {issue}22130[#22130]) +* Introduce ToXContentObject interface {pull}22387[#22387] (issue: {issue}16347[#16347]) +* Add infrastructure to manage network connections outside of Transport/TransportService {pull}22194[#22194] +* Replace strict parsing mode with response headers assertions {pull}22130[#22130] (issues: {issue}11859[#11859], {issue}19552[#19552], {issue}20993[#20993]) +* Start using `ObjectParser` for aggs. {pull}22048[#22048] (issue: {issue}22009[#22009]) +* Don't output null source node in RecoveryFailedException {pull}21963[#21963] +* ClusterService should expose "applied" cluster states (i.e., remove ClusterStateStatus) {pull}21817[#21817] +* Rename ClusterState#lookupPrototypeSafe to `lookupPrototype` and remove "unsafe" unused variant {pull}21686[#21686] +* ShardActiveResponseHandler shouldn't hold to an entire cluster state {pull}21470[#21470] (issue: {issue}21394[#21394]) +* Remove unused ClusterService dependency from SearchPhaseController {pull}21421[#21421] +* Remove special case in case no action filters are registered {pull}21251[#21251] +* Use TimveValue instead of long for CacheBuilder methods {pull}20887[#20887] +* Remove SearchContext#current and all it's threadlocals {pull}20778[#20778] (issue: {issue}19341[#19341]) +* Remove poor-mans compression in InternalSearchHit and friends {pull}20472[#20472] + +Java API:: +* Added types options to DeleteByQueryRequest {pull}23265[#23265] (issue: {issue}21984[#21984]) +* prevent NPE when trying to uncompress a null BytesReference {pull}22386[#22386] + +Java High Level REST Client:: +* Add utility method to parse named XContent objects with typed prefix {pull}24240[#24240] (issue: {issue}22965[#22965]) +* Convert suggestion response parsing to use NamedXContentRegistry {pull}23355[#23355] +* UpdateRequest implements ToXContent {pull}23289[#23289] +* Add javadoc for DocWriteResponse.Builders {pull}23267[#23267] +* Expose WriteRequest.RefreshPolicy string representation {pull}23106[#23106] +* Use `typed_keys` parameter to prefix suggester names by type in search responses {pull}23080[#23080] (issue: {issue}22965[#22965]) +* Add parsing from xContent to MainResponse {pull}22934[#22934] +* Parse elasticsearch exception's root causes {pull}22924[#22924] +* Add parsing method to BytesRestResponse's error {pull}22873[#22873] +* Add parsing methods to BulkItemResponse {pull}22859[#22859] +* Add parsing method for ElasticsearchException.generateFailureXContent() {pull}22815[#22815] +* Add parsing method for ElasticsearchException.generateThrowableXContent() {pull}22783[#22783] +* Add parsing methods for UpdateResponse {pull}22586[#22586] +* Add parsing from xContent to InternalSearchHit and InternalSearchHits {pull}22429[#22429] +* Add fromxcontent methods to index response {pull}22229[#22229] +* Add fromXContent() methods for ReplicationResponse {pull}22196[#22196] (issue: {issue}22082[#22082]) +* Add parsing method for ElasticsearchException {pull}22143[#22143] +* Add fromXContent method to GetResponse {pull}22082[#22082] + +Java REST Client:: +* move ignore parameter support from yaml test client to low level rest client {pull}22637[#22637] +* Warn log deprecation warnings received from server {pull}21895[#21895] +* Support Preemptive Authentication with RestClient {pull}21336[#21336] +* Provide error message when rest request path is null {pull}21233[#21233] (issue: {issue}21232[#21232]) + +Logging:: +* Log deleting indices at info level {pull}22627[#22627] (issue: {issue}22605[#22605]) +* Expose logs base path {pull}22625[#22625] +* Log failure to connect to node at info instead of debug {pull}21809[#21809] (issue: {issue}6468[#6468]) +* Truncate log messages from the end {pull}21609[#21609] (issue: {issue}21602[#21602]) +* Ensure logging is initialized in CLI tools {pull}20575[#20575] +* Give useful error message if log config is missing {pull}20493[#20493] +* Complete Elasticsearch logger names {pull}20457[#20457] (issue: {issue}20326[#20326]) +* Logging shutdown hack {pull}20389[#20389] (issue: {issue}20304[#20304]) +* Disable console logging {pull}20387[#20387] +* Warn on not enough masters during election {pull}20063[#20063] (issue: {issue}8362[#8362]) + +Mapping:: +* Only allow one type on 6.0 indices {pull}24317[#24317] (issue: {issue}15613[#15613]) +* token_count type : add an option to count tokens (fix #23227) {pull}24175[#24175] (issue: {issue}23227[#23227]) +* Atomic mapping updates across types {pull}22220[#22220] +* Only update DocumentMapper if field type changes {pull}22165[#22165] +* Better error message when _parent isn't an object {pull}21987[#21987] +* Create the QueryShardContext lazily in DocumentMapperParser. {pull}21287[#21287] + +Nested Docs:: +* Avoid adding unnecessary nested filters when ranges are used. {pull}23427[#23427] + +Network:: +* Set available processors for Netty {pull}24420[#24420] (issue: {issue}6224[#6224]) +* Adjust default Netty receive predictor size to 64k {pull}23542[#23542] (issue: {issue}23185[#23185]) +* Keep the pipeline handler queue small initially {pull}23335[#23335] +* Set network receive predictor size to 32kb {pull}23284[#23284] (issue: {issue}23185[#23185]) +* TransportService.connectToNode should validate remote node ID {pull}22828[#22828] (issue: {issue}22194[#22194]) +* Disable the Netty recycler {pull}22452[#22452] (issues: {issue}22189[#22189], {issue}22360[#22360], {issue}22406[#22406], {issue}5904[#5904]) +* Tell Netty not to be unsafe in transport client {pull}22284[#22284] +* Introduce a low level protocol handshake {pull}22094[#22094] +* Detach handshake from connect to node {pull}22037[#22037] +* Reduce number of connections per node depending on the nodes role {pull}21849[#21849] +* Add a connect timeout to the ConnectionProfile to allow per node connect timeouts {pull}21847[#21847] (issue: {issue}19719[#19719]) +* Grant Netty permission to read system somaxconn {pull}21840[#21840] +* Remove connectToNodeLight and replace it with a connection profile {pull}21799[#21799] +* Lazy resolve unicast hosts {pull}21630[#21630] (issues: {issue}14441[#14441], {issue}16412[#16412]) +* Fix handler name on message not fully read {pull}21478[#21478] +* Handle rejected pings on shutdown gracefully {pull}20842[#20842] +* Network: Allow to listen on virtual interfaces. {pull}19568[#19568] (issues: {issue}17473[#17473], {issue}19537[#19537]) + +Packaging:: +* Introduce Java version check {pull}23194[#23194] (issue: {issue}21102[#21102]) +* Improve the out-of-the-box experience {pull}21920[#21920] (issues: {issue}18317[#18317], {issue}21783[#21783]) +* Add empty plugins dir for archive distributions {pull}21204[#21204] (issue: {issue}20342[#20342]) +* Make explicit missing settings for Windows service {pull}21200[#21200] (issue: {issue}18317[#18317]) +* Change permissions on config files {pull}20966[#20966] +* Add quiet option to disable console logging {pull}20422[#20422] (issues: {issue}15315[#15315], {issue}16159[#16159], {issue}17220[#17220]) + +Percolator:: +* Allowing range queries with now ranges inside percolator queries {pull}23921[#23921] (issue: {issue}23859[#23859]) +* Add term extraction support for MultiPhraseQuery {pull}23176[#23176] + +Plugin Discovery EC2:: +* Settings: Migrate ec2 discovery sensitive settings to elasticsearch keystore {pull}23961[#23961] (issue: {issue}22475[#22475]) +* Add support for ca-central-1 region to EC2 and S3 plugins {pull}22458[#22458] (issue: {issue}22454[#22454]) +* Support for eu-west-2 (London) cloud-aws plugin {pull}22308[#22308] (issue: {issue}22306[#22306]) +* Add us-east-2 AWS region {pull}21961[#21961] (issue: {issue}21881[#21881]) +* Add setting to set read timeout for EC2 discovery and S3 repository plugins {pull}21956[#21956] (issue: {issue}19078[#19078]) + +Plugin Ingest GeoIp:: +* Cache results of geoip lookups {pull}22231[#22231] (issue: {issue}22074[#22074]) + +Plugin Lang Painless:: +* Allow painless to load stored fields {pull}24290[#24290] +* Start on custom whitelists for Painless {pull}23563[#23563] +* Fix Painless's implementation of interfaces returning primitives {pull}23298[#23298] (issue: {issue}22983[#22983]) +* Allow painless to implement more interfaces {pull}22983[#22983] +* Generate reference links for painless API {pull}22775[#22775] +* Painless: Add augmentation to String for base 64 {pull}22665[#22665] (issue: {issue}22648[#22648]) +* Improve painless's ScriptException generation {pull}21762[#21762] (issue: {issue}21733[#21733]) +* Add Debug.explain to painless {pull}21723[#21723] (issue: {issue}20263[#20263]) +* Implement the ?: operator in painless {pull}21506[#21506] +* In painless suggest a long constant if int won't do {pull}21415[#21415] (issue: {issue}21313[#21313]) +* Support decimal constants with trailing [dD] in painless {pull}21412[#21412] (issue: {issue}21116[#21116]) +* Implement reading from null safe dereferences {pull}21239[#21239] +* Painless negative offsets {pull}21080[#21080] (issue: {issue}20870[#20870]) +* Remove more equivalents of the now method from the Painless whitelist. {pull}21047[#21047] +* Disable regexes by default in painless {pull}20427[#20427] (issue: {issue}20397[#20397]) + +Plugin Repository Azure:: +* Add Backoff policy to azure repository {pull}23387[#23387] (issue: {issue}22728[#22728]) + +Plugin Repository S3:: +* Removes the retry mechanism from the S3 blob store {pull}23952[#23952] (issue: {issue}22845[#22845]) +* S3 Repository: Eagerly load static settings {pull}23910[#23910] +* S3 repository: Add named configurations {pull}22762[#22762] (issues: {issue}22479[#22479], {issue}22520[#22520]) +* Make the default S3 buffer size depend on the available memory. {pull}21299[#21299] + +Plugins:: +* Plugins: Add support for platform specific plugins {pull}24265[#24265] +* Plugins: Remove leniency for missing plugins dir {pull}24173[#24173] +* Modify permissions dialog for plugins {pull}23742[#23742] +* Plugins: Add plugin cli specific exit codes {pull}23599[#23599] (issue: {issue}15295[#15295]) +* Plugins: Output better error message when existing plugin is incompatible {pull}23562[#23562] (issue: {issue}20691[#20691]) +* Add the ability to define search response listeners in search plugin {pull}22682[#22682] +* Pass ThreadContext to transport interceptors to allow header modification {pull}22618[#22618] (issue: {issue}22585[#22585]) +* Provide helpful error message if a plugin exists {pull}22305[#22305] (issue: {issue}22084[#22084]) +* Add shutdown hook for closing CLI commands {pull}22126[#22126] (issue: {issue}22111[#22111]) +* Allow plugins to install bootstrap checks {pull}22110[#22110] +* Clarify that plugins can be closed {pull}21669[#21669] +* Plugins: Convert custom discovery to pull based plugin {pull}21398[#21398] +* Removing plugin that isn't installed shouldn't trigger usage information {pull}21272[#21272] (issue: {issue}21250[#21250]) +* Remove pluggability of ZenPing {pull}21049[#21049] +* Make UnicastHostsProvider extension pull based {pull}21036[#21036] +* Revert "Display plugins versions" {pull}20807[#20807] (issues: {issue}18683[#18683], {issue}20668[#20668]) +* Provide error message when plugin id is missing {pull}20660[#20660] + +Query DSL:: +* Make it possible to validate a query on all shards instead of a single random shard {pull}23697[#23697] (issue: {issue}18254[#18254]) +* QueryString and SimpleQueryString Graph Support {pull}22541[#22541] +* Additional Graph Support in Match Query {pull}22503[#22503] (issue: {issue}22490[#22490]) +* RangeQuery WITHIN case now normalises query {pull}22431[#22431] (issue: {issue}22412[#22412]) +* Un-deprecate fuzzy query {pull}22088[#22088] (issue: {issue}15760[#15760]) +* support numeric bounds with decimal parts for long/integer/short/byte datatypes {pull}21972[#21972] (issue: {issue}21600[#21600]) +* Using ObjectParser in MatchAllQueryBuilder and IdsQueryBuilder {pull}21273[#21273] +* Expose splitOnWhitespace in `Query String Query` {pull}20965[#20965] (issue: {issue}20841[#20841]) +* Throw error if query element doesn't end with END_OBJECT {pull}20528[#20528] (issue: {issue}20515[#20515]) +* Remove `lowercase_expanded_terms` and `locale` from query-parser options. {pull}20208[#20208] (issue: {issue}9978[#9978]) + +REST:: +* Allow passing single scrollID in clear scroll API body {pull}24242[#24242] (issue: {issue}24233[#24233]) +* Validate top-level keys when parsing mget requests {pull}23746[#23746] (issue: {issue}23720[#23720]) +* Cluster stats should not render empty http/transport types {pull}23735[#23735] +* Add parameter to prefix aggs name with type in search responses {pull}22965[#22965] +* Add a REST spec for the create API {pull}20924[#20924] +* Add response params to REST params did you mean {pull}20753[#20753] (issues: {issue}20722[#20722], {issue}20747[#20747]) +* Add did you mean to strict REST params {pull}20747[#20747] (issue: {issue}20722[#20722]) + +Reindex API:: +* Increase visibility of doExecute so it can be used directly {pull}22614[#22614] +* Improve error message when reindex-from-remote gets bad json {pull}22536[#22536] (issue: {issue}22330[#22330]) +* Reindex: Better error message for pipeline in wrong place {pull}21985[#21985] +* Timeout improvements for rest client and reindex {pull}21741[#21741] (issue: {issue}21707[#21707]) +* Add "simple match" support for reindex-from-remote whitelist {pull}21004[#21004] +* Make reindex-from-remote ignore unknown fields {pull}20591[#20591] (issue: {issue}20504[#20504]) + +Scripting:: +* Expose multi-valued dates to scripts and document painless's date functions {pull}22875[#22875] (issue: {issue}22162[#22162]) +* Wrap VerifyError in ScriptException {pull}21769[#21769] +* Log ScriptException's xcontent if file script compilation fails {pull}21767[#21767] (issue: {issue}21733[#21733]) +* Support binary field type in script values {pull}21484[#21484] (issue: {issue}14469[#14469]) +* Mustache: Add {{#url}}{{/url}} function to URL encode strings {pull}20838[#20838] +* Expose `ctx._now` in update scripts {pull}20835[#20835] (issue: {issue}17895[#17895]) + +Search:: +* Remove leniency when merging fetched hits in a search response phase {pull}24158[#24158] +* Set shard count limit to unlimited {pull}24012[#24012] +* Streamline shard index availability in all SearchPhaseResults {pull}23788[#23788] +* Search took time should use a relative clock {pull}23662[#23662] +* Prevent negative `from` parameter in SearchSourceBuilder {pull}23358[#23358] (issue: {issue}23324[#23324]) +* Remove unnecessary result sorting in SearchPhaseController {pull}23321[#23321] +* Expose `batched_reduce_size` via `_search` {pull}23288[#23288] (issue: {issue}23253[#23253]) +* Adding fromXContent to Suggest and Suggestion class {pull}23226[#23226] (issue: {issue}23202[#23202]) +* Adding fromXContent to Suggestion.Entry and subclasses {pull}23202[#23202] +* Add CollapseSearchPhase as a successor for the FetchSearchPhase {pull}23165[#23165] +* Integrate IndexOrDocValuesQuery. {pull}23119[#23119] +* Detach SearchPhases from AbstractSearchAsyncAction {pull}23118[#23118] +* Fix GraphQuery expectation after Lucene upgrade to 6.5 {pull}23117[#23117] (issue: {issue}23102[#23102]) +* Nested queries should avoid adding unnecessary filters when possible. {pull}23079[#23079] (issue: {issue}20797[#20797]) +* Add xcontent parsing to completion suggestion option {pull}23071[#23071] +* Add xcontent parsing to suggestion options {pull}23018[#23018] +* Separate reduce (aggs, suggest and profile) from merging fetched hits {pull}23017[#23017] +* Add a setting to disable remote cluster connections on a node {pull}23005[#23005] +* First step towards separating individual search phases {pull}22802[#22802] +* Add parsing from xContent to SearchProfileShardResults and nested classes {pull}22649[#22649] +* Move SearchTransportService and SearchPhaseController creation outside of TransportSearchAction constructor {pull}21754[#21754] +* Don't carry ShardRouting around when not needed in AbstractSearchAsyncAction {pull}21753[#21753] +* ShardSearchRequest to take ShardId constructor argument rather than the whole ShardRouting {pull}21750[#21750] +* Use index uuid as key in the alias filter map rather than the index name {pull}21749[#21749] +* Add indices and filter information to search shards api output {pull}21738[#21738] (issue: {issue}20916[#20916]) +* remove pointless catch exception in TransportSearchAction {pull}21689[#21689] +* Optimize query with types filter in the URL (t/t/_search) {pull}20979[#20979] +* Makes search action cancelable by task management API {pull}20405[#20405] + +Search Templates:: +* Add profile and explain parameters to template API {pull}20451[#20451] + +Settings:: +* Add secure file setting to keystore {pull}24001[#24001] +* Add a setting which specifies a list of setting {pull}23883[#23883] +* Add a property to mark setting as final {pull}23872[#23872] +* Remove obsolete index setting `index.version.minimum_compatible`. {pull}23593[#23593] +* Provide a method to retrieve a closeable char[] from a SecureString {pull}23389[#23389] +* Update indices settings api to support CBOR and SMILE format {pull}23309[#23309] (issues: {issue}23242[#23242], {issue}23245[#23245]) +* Improve setting deprecation message {pull}23156[#23156] (issue: {issue}22849[#22849]) +* Add secure settings validation on startup {pull}22894[#22894] +* Allow comma delimited array settings to have a space after each entry {pull}22591[#22591] (issue: {issue}22297[#22297]) +* Allow affix settings to be dynamic / updatable {pull}22526[#22526] +* Allow affix settings to delegate to actual settings {pull}22523[#22523] +* Make s3 repository sensitive settings use secure settings {pull}22479[#22479] +* Speed up filter and prefix settings operations {pull}22249[#22249] +* Add precise logging on unknown or invalid settings {pull}20951[#20951] (issue: {issue}20946[#20946]) + +Snapshot/Restore:: +* Ensure every repository has an incompatible-snapshots blob {pull}24403[#24403] (issue: {issue}22267[#22267]) +* Change snapshot status error to use generic SnapshotException {pull}24355[#24355] (issue: {issue}24225[#24225]) +* Duplicate snapshot name throws InvalidSnapshotNameException {pull}22921[#22921] (issue: {issue}18228[#18228]) +* Fixes retrieval of the latest snapshot index blob {pull}22700[#22700] +* Use general cluster state batching mechanism for snapshot state updates {pull}22528[#22528] (issue: {issue}14899[#14899]) +* Synchronize snapshot deletions on the cluster state {pull}22313[#22313] (issue: {issue}19957[#19957]) +* Abort snapshots on a node that leaves the cluster {pull}21084[#21084] (issue: {issue}20876[#20876]) + +Stats:: +* Show JVM arguments {pull}24450[#24450] +* Add cross-cluster search remote cluster info API {pull}23969[#23969] (issue: {issue}23925[#23925]) +* Add geo_point to FieldStats {pull}21947[#21947] (issue: {issue}20707[#20707]) +* Include unindexed field in FieldStats response {pull}21821[#21821] (issue: {issue}21952[#21952]) +* Remove load average leniency {pull}21380[#21380] +* Strengthen handling of unavailable cgroup stats {pull}21094[#21094] (issue: {issue}21029[#21029]) +* Add basic cgroup CPU metrics {pull}21029[#21029] + +Suggesters:: +* Provide informative error message in case of unknown suggestion context. {pull}24241[#24241] +* Allow different data types for category in Context suggester {pull}23491[#23491] (issue: {issue}22358[#22358]) + +Task Manager:: +* Allow task to be unregistered by ClusterStateApplier {pull}23931[#23931] +* Limit IndexRequest toString() length {pull}22832[#22832] +* Improve the error message if task and node isn't found {pull}22062[#22062] (issue: {issue}22027[#22027]) +* Add descriptions to create snapshot and restore snapshot tasks. {pull}21901[#21901] (issue: {issue}21768[#21768]) +* Add proper descriptions to reindex, update-by-query and delete-by-query tasks. {pull}21841[#21841] (issue: {issue}21768[#21768]) +* Add search task descriptions {pull}21740[#21740] + +Tribe Node:: +* Add support for merging custom meta data in tribe node {pull}21552[#21552] (issues: {issue}20544[#20544], {issue}20791[#20791], {issue}9372[#9372]) + + + +[[bug-6.0.0-alpha1-5x]] +[float] +=== Bug fixes + +Aggregations:: +* InternalPercentilesBucket should not rely on ordered percents array {pull}24336[#24336] (issue: {issue}24331[#24331]) +* Align behavior HDR percentiles iterator with percentile() method {pull}24206[#24206] +* The `filter` and `significant_terms` aggregations should parse the `filter` as a filter, not a query. {pull}23797[#23797] +* Completion suggestion should also consider text if prefix/regex is missing {pull}23451[#23451] (issue: {issue}23340[#23340]) +* Fixes the per term error in the terms aggregation {pull}23399[#23399] +* Fixes terms error count for multiple reduce phases {pull}23291[#23291] (issue: {issue}23286[#23286]) +* Fix scaled_float numeric type in aggregations {pull}22351[#22351] (issue: {issue}22350[#22350]) +* Allow terms aggregations on pure boolean scripts. {pull}22201[#22201] (issue: {issue}20941[#20941]) +* Fix numeric terms aggregations with includes/excludes and minDocCount=0 {pull}22141[#22141] (issue: {issue}22140[#22140]) +* Fix `missing` on aggs on `boolean` fields. {pull}22135[#22135] (issue: {issue}22009[#22009]) +* IP range masks exclude the maximum address of the range. {pull}22018[#22018] (issue: {issue}22005[#22005]) +* Fix `other_bucket` on the `filters` agg to be enabled if a key is set. {pull}21994[#21994] (issue: {issue}21951[#21951]) +* Rewrite Queries/Filter in FilterAggregationBuilder and ensure client usage marks query as non-cachable {pull}21303[#21303] (issue: {issue}21301[#21301]) +* Percentiles bucket fails for 100th percentile {pull}21218[#21218] +* Thread safety for scripted significance heuristics {pull}21113[#21113] (issue: {issue}18120[#18120]) +* `ip_range` aggregation should accept null bounds. {pull}21043[#21043] (issue: {issue}21006[#21006]) +* Fixes bug preventing script sort working on top_hits aggregation {pull}21023[#21023] (issue: {issue}21022[#21022]) +* Fixed writeable name from range to geo_distance {pull}20860[#20860] +* Fix date_range aggregation to not cache if now is used {pull}20740[#20740] +* The `top_hits` aggregation should compile scripts only once. {pull}20738[#20738] + +Allocation:: +* Cannot force allocate primary to a node where the shard already exists {pull}22031[#22031] (issue: {issue}22021[#22021]) +* Promote shadow replica to primary when initializing primary fails {pull}22021[#22021] +* Trim in-sync allocations set only when it grows {pull}21976[#21976] (issue: {issue}21719[#21719]) +* Allow master to assign primary shard to node that has shard store locked during shard state fetching {pull}21656[#21656] (issue: {issue}19416[#19416]) +* Keep a shadow replicas' allocation id when it is promoted to primary {pull}20863[#20863] (issue: {issue}20650[#20650]) +* IndicesClusterStateService should clean local started when re-assigns an initializing shard with the same aid {pull}20687[#20687] +* IndexRoutingTable.initializeEmpty shouldn't override supplied primary RecoverySource {pull}20638[#20638] (issue: {issue}20637[#20637]) +* Update incoming recoveries stats when shadow replica is reinitialized {pull}20612[#20612] +* `index.routing.allocation.initial_recovery` limits replica allocation {pull}20589[#20589] + +Analysis:: +* AsciiFoldingFilter's multi-term component should never preserve the original token. {pull}21982[#21982] +* Pre-built analysis factories do not implement MultiTermAware correctly. {pull}21981[#21981] +* Can load non-PreBuiltTokenFilter in Analyze API {pull}20396[#20396] +* Named analyzer should close the analyzer that it wraps {pull}20197[#20197] + +Bulk:: +* Reject empty IDs {pull}24118[#24118] (issue: {issue}24116[#24116]) + +CAT API:: +* Consume `full_id` request parameter early {pull}21270[#21270] (issue: {issue}21266[#21266]) + +CRUD:: +* Reject external versioning and explicit version numbers on create {pull}21998[#21998] +* MultiGet should not fail entirely if alias resolves to many indices {pull}20858[#20858] (issue: {issue}20845[#20845]) +* Fixed date math expression support in multi get requests. {pull}20659[#20659] (issue: {issue}17957[#17957]) + +Cache:: +* Invalidate cached query results if query timed out {pull}22807[#22807] (issue: {issue}22789[#22789]) +* Fix the request cache keys to not hold references to the SearchContext. {pull}21284[#21284] +* Prevent requests that use scripts or now() from being cached {pull}20750[#20750] (issue: {issue}20645[#20645]) + +Circuit Breakers:: +* ClusterState publishing shouldn't trigger circuit breakers {pull}20986[#20986] (issues: {issue}20827[#20827], {issue}20960[#20960]) + +Cluster:: +* Don't set local node on cluster state used for node join validation {pull}23311[#23311] (issues: {issue}21830[#21830], {issue}3[#3], {issue}4[#4], {issue}6[#6], {issue}9[#9]) +* Allow a cluster state applier to create an observer and wait for a better state {pull}23132[#23132] (issue: {issue}21817[#21817]) +* Cluster allocation explain to never return empty response body {pull}23054[#23054] +* IndicesService handles all exceptions during index deletion {pull}22433[#22433] +* Remove cluster update task when task times out {pull}21578[#21578] (issue: {issue}21568[#21568]) + +Core:: +* Check for default.path.data included in path.data {pull}24285[#24285] (issue: {issue}24283[#24283]) +* Improve performance of extracting warning value {pull}24114[#24114] (issue: {issue}24018[#24018]) +* Reject duplicate settings on the command line {pull}24053[#24053] +* Restrict build info loading to ES jar, not any jar {pull}24049[#24049] (issue: {issue}21955[#21955]) +* Streamline foreign stored context restore and allow to perserve response headers {pull}22677[#22677] (issue: {issue}22647[#22647]) +* Support negative numbers in readVLong {pull}22314[#22314] +* Add a StreamInput#readArraySize method that ensures sane array sizes {pull}21697[#21697] +* Use a buffer to do character to byte conversion in StreamOutput#writeString {pull}21680[#21680] (issue: {issue}21660[#21660]) +* Fix ShardInfo#toString {pull}21319[#21319] +* Protect BytesStreamOutput against overflows of the current number of written bytes. {pull}21174[#21174] (issue: {issue}21159[#21159]) +* Return target index name even if _rollover conditions are not met {pull}21138[#21138] +* .es_temp_file remains after system crash, causing it not to start again {pull}21007[#21007] (issue: {issue}20992[#20992]) +* StoreStatsCache should also ignore AccessDeniedException when checking file size {pull}20790[#20790] (issue: {issue}17580[#17580]) + +Dates:: +* Fix time zone rounding edge case for DST overlaps {pull}21550[#21550] (issue: {issue}20833[#20833]) + +Discovery:: +* ZenDiscovery - only validate min_master_nodes values if local node is master {pull}23915[#23915] (issue: {issue}23695[#23695]) +* Close InputStream when receiving cluster state in PublishClusterStateAction {pull}22711[#22711] +* Do not reply to pings from another cluster {pull}21894[#21894] (issue: {issue}21874[#21874]) +* Add current cluster state version to zen pings and use them in master election {pull}20384[#20384] (issue: {issue}20348[#20348]) + +Engine:: +* Close and flush refresh listeners on shard close {pull}22342[#22342] +* Die with dignity on the Lucene layer {pull}21721[#21721] (issue: {issue}19272[#19272]) +* Fix `InternalEngine#isThrottled` to not always return `false`. {pull}21592[#21592] +* Retrying replication requests on replica doesn't call `onRetry` {pull}21189[#21189] (issue: {issue}20211[#20211]) +* Take refresh IOExceptions into account when catching ACE in InternalEngine {pull}20546[#20546] (issue: {issue}19975[#19975]) + +Exceptions:: +* Stop returning "es." internal exception headers as http response headers {pull}22703[#22703] (issue: {issue}17593[#17593]) +* Fixing shard recovery error message to report the number of docs correctly for each node {pull}22515[#22515] (issue: {issue}21893[#21893]) + +Highlighting:: +* Fix FiltersFunctionScoreQuery highlighting {pull}21827[#21827] +* Fix highlighting on a stored keyword field {pull}21645[#21645] (issue: {issue}21636[#21636]) +* Fix highlighting of MultiTermQuery within a FunctionScoreQuery {pull}20400[#20400] (issue: {issue}20392[#20392]) + +Index APIs:: +* Fixes restore of a shrunken index when initial recovery node is gone {pull}24322[#24322] (issue: {issue}24257[#24257]) +* Honor update request timeout {pull}23825[#23825] +* Ensure shrunk indices carry over version information from its source {pull}22469[#22469] (issue: {issue}22373[#22373]) +* Validate the `_rollover` target index name early to also fail if dry_run=true {pull}21330[#21330] (issue: {issue}21149[#21149]) +* Only negate index expression on all indices with preceding wildcard {pull}20898[#20898] (issues: {issue}19800[#19800], {issue}20033[#20033]) +* Fix IndexNotFoundException in multi index search request. {pull}20188[#20188] (issue: {issue}3839[#3839]) + +Index Templates:: +* Fix integer overflows when dealing with templates. {pull}21628[#21628] (issue: {issue}21622[#21622]) + +Ingest:: +* Improve missing ingest processor error {pull}23379[#23379] (issue: {issue}23392[#23392]) +* update _ingest.timestamp to use new ZonedDateTime {pull}23174[#23174] (issue: {issue}23168[#23168]) +* fix date-processor to a new default year for every new pipeline execution {pull}22601[#22601] (issue: {issue}22547[#22547]) +* fix index out of bounds error in KV Processor {pull}22288[#22288] (issue: {issue}22272[#22272]) +* Fixes GrokProcessor's ignorance of named-captures with same name. {pull}22131[#22131] (issue: {issue}22117[#22117]) +* fix trace_match behavior for when there is only one grok pattern {pull}21413[#21413] (issue: {issue}21371[#21371]) +* Stored scripts and ingest node configurations should be included into a snapshot {pull}21227[#21227] (issue: {issue}21184[#21184]) +* make painless the default scripting language for ScriptProcessor {pull}20981[#20981] (issue: {issue}20943[#20943]) +* no null values in ingest configuration error messages {pull}20616[#20616] +* JSON Processor was not properly added {pull}20613[#20613] + +Inner Hits:: +* Replace NestedChildrenQuery with ParentChildrenBlockJoinQuery {pull}24016[#24016] (issue: {issue}24009[#24009]) +* Changed DisMaxQueryBuilder to extract inner hits from leaf queries {pull}23512[#23512] (issue: {issue}23482[#23482]) +* Inner hits and ignore unmapped {pull}21693[#21693] (issue: {issue}21620[#21620]) +* Skip adding a parent field to nested documents. {pull}21522[#21522] (issue: {issue}21503[#21503]) + +Internal:: +* Add infrastructure to mark contexts as system contexts {pull}23830[#23830] +* Always restore the ThreadContext for operations delayed due to a block {pull}23349[#23349] +* Index creation and setting update may not return deprecation logging {pull}22702[#22702] +* Rethrow ExecutionException from the loader to concurrent callers of Cache#computeIfAbsent {pull}21549[#21549] +* Restore thread's original context before returning to the ThreadPool {pull}21411[#21411] +* Fix NPE in SearchContext.toString() {pull}21069[#21069] +* Prevent AbstractArrays from release bytes more than once {pull}20819[#20819] +* Source filtering should treat dots in field names as sub objects. {pull}20736[#20736] (issue: {issue}20719[#20719]) +* IndicesAliasesRequest should not implement CompositeIndicesRequest {pull}20726[#20726] +* Ensure elasticsearch doesn't start with unuspported indices {pull}20514[#20514] (issue: {issue}20512[#20512]) + +Java API:: +* Don't output empty ext object in SearchSourceBuilder#toXContent {pull}22093[#22093] (issue: {issue}20969[#20969]) +* Transport client: Fix remove address to actually work {pull}21743[#21743] +* Add a HostFailureListener to notify client code if a node got disconnected {pull}21709[#21709] (issue: {issue}21424[#21424]) +* Fix InternalSearchHit#hasSource to return the proper boolean value {pull}21441[#21441] (issue: {issue}21419[#21419]) +* Null checked for source when calling sourceRef {pull}21431[#21431] (issue: {issue}19279[#19279]) +* ClusterAdminClient.prepareDeletePipeline method should accept pipeline id to delete {pull}21228[#21228] +* fix IndexResponse#toString to print out shards info {pull}20562[#20562] + +Java High Level REST Client:: +* Correctly parse BulkItemResponse.Failure's status {pull}23432[#23432] + +Java REST Client:: +* Make buffer limit configurable in HeapBufferedConsumerFactory {pull}23970[#23970] (issue: {issue}23958[#23958]) +* RestClient asynchronous execution should not throw exceptions {pull}23307[#23307] +* Don't use null charset in RequestLogger {pull}22197[#22197] (issue: {issue}22190[#22190]) +* Rest client: don't reuse the same HttpAsyncResponseConsumer across multiple retries {pull}21378[#21378] + +Logging:: +* Do not prematurely shutdown Log4j {pull}21519[#21519] (issue: {issue}21514[#21514]) +* Assert status logger does not warn on Log4j usage {pull}21339[#21339] +* Fix logger names for Netty {pull}21223[#21223] (issue: {issue}20457[#20457]) +* Fix logger when you can not create an azure storage client {pull}20670[#20670] (issues: {issue}20633[#20633], {issue}20669[#20669]) +* Avoid unnecessary creation of prefix loggers {pull}20571[#20571] (issue: {issue}20570[#20570]) +* Fix logging hierarchy configs {pull}20463[#20463] +* Fix prefix logging {pull}20429[#20429] + +Mapping:: +* Preserve response headers when creating an index {pull}23950[#23950] (issue: {issue}23947[#23947]) +* Improves disabled fielddata error message {pull}23841[#23841] (issue: {issue}22768[#22768]) +* Fix MapperService StackOverflowError {pull}23605[#23605] (issue: {issue}23604[#23604]) +* Fix NPE with scaled floats stats when field is not indexed {pull}23528[#23528] (issue: {issue}23487[#23487]) +* Range types causing `GetFieldMappingsIndexRequest` to fail due to `NullPointerException` in `RangeFieldMapper.doXContentBody` when `include_defaults=true` is on the query string {pull}22925[#22925] +* Disallow introducing illegal object mappings (double '..') {pull}22891[#22891] (issue: {issue}22794[#22794]) +* The `_all` default mapper is not completely configured. {pull}22236[#22236] +* Fix MapperService.allEnabled(). {pull}22227[#22227] +* Dynamic `date` fields should use the `format` that was used to detect it is a date. {pull}22174[#22174] (issue: {issue}9410[#9410]) +* Sub-fields should not accept `include_in_all` parameter {pull}21971[#21971] (issue: {issue}21710[#21710]) +* Mappings: Fix get mapping when no indexes exist to not fail in response generation {pull}21924[#21924] (issue: {issue}21916[#21916]) +* Fail to index fields with dots in field names when one of the intermediate objects is nested. {pull}21787[#21787] (issue: {issue}21726[#21726]) +* Uncommitted mapping updates should not efect existing indices {pull}21306[#21306] (issue: {issue}21189[#21189]) + +Nested Docs:: +* Fix bug in query builder rewrite that ignores the ignore_unmapped option {pull}22456[#22456] + +Network:: +* Respect promises on pipelined responses {pull}23317[#23317] (issues: {issue}23310[#23310], {issue}23322[#23322]) +* Ensure that releasing listener is called {pull}23310[#23310] +* Pass `forceExecution` flag to transport interceptor {pull}22739[#22739] +* Ensure new connections won't be opened if transport is closed or closing {pull}22589[#22589] (issue: {issue}22554[#22554]) +* Prevent open channel leaks if handshake times out or is interrupted {pull}22554[#22554] +* Execute low level handshake in #openConnection {pull}22440[#22440] +* Handle connection close / reset events gracefully during handshake {pull}22178[#22178] +* Do not lose host information when pinging {pull}21939[#21939] (issue: {issue}21828[#21828]) +* DiscoveryNode and TransportAddress should preserve host information {pull}21828[#21828] +* Die with dignity on the network layer {pull}21720[#21720] (issue: {issue}19272[#19272]) +* Fix connection close header handling {pull}20956[#20956] (issue: {issue}20938[#20938]) +* Ensure port range is readable in the exception message {pull}20893[#20893] +* Prevent double release in TcpTransport if send listener throws an exception {pull}20880[#20880] + +Packaging:: +* Fall back to non-atomic move when removing plugins {pull}23548[#23548] (issue: {issue}35[#35]) +* Another fix for handling of paths on Windows {pull}22132[#22132] (issue: {issue}21921[#21921]) +* Fix handling of spaces in Windows paths {pull}21921[#21921] (issues: {issue}20809[#20809], {issue}21525[#21525]) +* Add option to skip kernel parameters on install {pull}21899[#21899] (issue: {issue}21877[#21877]) +* Set vm.max_map_count on systemd package install {pull}21507[#21507] +* Export ES_JVM_OPTIONS for SysV init {pull}21445[#21445] (issue: {issue}21255[#21255]) +* Debian: configure start-stop-daemon to not go into background {pull}21343[#21343] (issues: {issue}12716[#12716], {issue}21300[#21300]) +* Generate POM files with non-wildcard excludes {pull}21234[#21234] (issue: {issue}21170[#21170]) +* [Packaging] Do not remove scripts directory on upgrade {pull}20452[#20452] +* [Package] Remove bin/lib/modules directories on RPM uninstall/upgrade {pull}20448[#20448] + +Parent/Child:: +* Add null check in case of orphan child document {pull}22772[#22772] (issue: {issue}22770[#22770]) + +Percolator:: +* Fix memory leak when percolator uses bitset or field data cache {pull}24115[#24115] (issue: {issue}24108[#24108]) +* Fix NPE in percolator's 'now' range check for percolator queries with range queries {pull}22356[#22356] (issue: {issue}22355[#22355]) + +Plugin Analysis Stempel:: +* Fix thread safety of Stempel's token filter factory {pull}22610[#22610] (issue: {issue}21911[#21911]) + +Plugin Discovery EC2:: +* Fix ec2 discovery when used with IAM profiles. {pull}21048[#21048] (issue: {issue}21039[#21039]) + +Plugin Ingest GeoIp:: +* [ingest-geoip] update geoip to not include null-valued results from {pull}20455[#20455] + +Plugin Lang Painless:: +* painless: Fix method references to ctor with the new LambdaBootstrap and cleanup code {pull}24406[#24406] +* Fix Painless Lambdas for Java 9 {pull}24070[#24070] (issue: {issue}23473[#23473]) +* Fix painless's regex lexer and error messages {pull}23634[#23634] +* Replace Painless's Cast with casting strategies {pull}23369[#23369] +* Fix Bad Casts In Painless {pull}23282[#23282] (issue: {issue}23238[#23238]) +* Don't allow casting from void to def in painless {pull}22969[#22969] (issue: {issue}22908[#22908]) +* Fix def invoked qualified method refs {pull}22918[#22918] +* Whitelist some ScriptDocValues in painless {pull}22600[#22600] (issue: {issue}22584[#22584]) +* Update Painless Loop Counter to be Higher {pull}22560[#22560] (issue: {issue}22508[#22508]) +* Fix some issues with painless's strings {pull}22393[#22393] (issue: {issue}22372[#22372]) +* Test fix for def equals in Painless {pull}21945[#21945] (issue: {issue}21801[#21801]) +* Fix a VerifyError bug in Painless {pull}21765[#21765] +* Fix Lambdas in Painless to be Able to Use Top-Level Variables Such as params and doc {pull}21635[#21635] (issues: {issue}20869[#20869], {issue}21479[#21479]) +* Fix String Concatenation Bug In Painless {pull}20623[#20623] + +Plugin Repository Azure:: +* Azure blob store's readBlob() method first checks if the blob exists {pull}23483[#23483] (issue: {issue}23480[#23480]) +* Fixes default chunk size for Azure repositories {pull}22577[#22577] (issue: {issue}22513[#22513]) +* readonly on azure repository must be taken into account {pull}22055[#22055] (issues: {issue}22007[#22007], {issue}22053[#22053]) + +Plugin Repository S3:: +* Handle BlobPath's trailing separator case. Add test cases to BlobPathTests.java {pull}23091[#23091] +* Fixes leading forward slash in S3 repository base_path {pull}20861[#20861] + +Plugins:: +* Fix delete of plugin directory on remove plugin {pull}24266[#24266] (issue: {issue}24252[#24252]) +* Use a marker file when removing a plugin {pull}24252[#24252] (issue: {issue}24231[#24231]) +* Remove hidden file leniency from plugin service {pull}23982[#23982] (issue: {issue}12465[#12465]) +* Add check for null pluginName in remove command {pull}22930[#22930] (issue: {issue}22922[#22922]) +* Use sysprop like with es.path.home to pass conf dir {pull}18870[#18870] (issue: {issue}18689[#18689]) + +Query DSL:: +* FuzzyQueryBuilder should error when parsing array of values {pull}23762[#23762] (issue: {issue}23759[#23759]) +* Fix parsing for `max_determinized_states` {pull}22749[#22749] (issue: {issue}22722[#22722]) +* Fix script score function that combines _score and weight {pull}22713[#22713] (issue: {issue}21483[#21483]) +* Fixes date range query using epoch with timezone {pull}21542[#21542] (issue: {issue}21501[#21501]) +* Allow overriding all-field leniency when `lenient` option is specified {pull}21504[#21504] (issues: {issue}20925[#20925], {issue}21341[#21341]) +* Max score should be updated when a rescorer is used {pull}20977[#20977] (issue: {issue}20651[#20651]) +* Fixes MultiMatchQuery so that it doesn't provide a null context {pull}20882[#20882] +* Fix silently accepting malformed queries {pull}20515[#20515] (issue: {issue}20500[#20500]) +* Fix match_phrase_prefix query with single term on _all field {pull}20471[#20471] (issue: {issue}20470[#20470]) + +REST:: +* [API] change wait_for_completion default according to docs {pull}23672[#23672] +* Deprecate request_cache for clear-cache {pull}23638[#23638] (issue: {issue}22748[#22748]) +* HTTP transport stashes the ThreadContext instead of the RestController {pull}23456[#23456] +* Fix date format in warning headers {pull}23418[#23418] (issue: {issue}23275[#23275]) +* Align REST specs for HEAD requests {pull}23313[#23313] (issue: {issue}21125[#21125]) +* Correct warning header to be compliant {pull}23275[#23275] (issue: {issue}22986[#22986]) +* Fix get HEAD requests {pull}23186[#23186] (issue: {issue}21125[#21125]) +* Handle bad HTTP requests {pull}23153[#23153] (issue: {issue}23034[#23034]) +* Fix get source HEAD requests {pull}23151[#23151] (issue: {issue}21125[#21125]) +* Properly encode location header {pull}23133[#23133] (issues: {issue}21057[#21057], {issue}23115[#23115]) +* Fix template HEAD requests {pull}23130[#23130] (issue: {issue}21125[#21125]) +* Fix index HEAD requests {pull}23112[#23112] (issue: {issue}21125[#21125]) +* Fix alias HEAD requests {pull}23094[#23094] (issue: {issue}21125[#21125]) +* Strict level parsing for indices stats {pull}21577[#21577] (issue: {issue}21024[#21024]) +* The routing query string param is supported by mget but was missing from the rest spec {pull}21357[#21357] +* fix thread_pool_patterns path variable definition {pull}21332[#21332] +* Read indices options in indices upgrade API {pull}21281[#21281] (issue: {issue}21099[#21099]) +* ensure the XContentBuilder is always closed in RestBuilderListener {pull}21124[#21124] +* Add correct Content-Length on HEAD requests {pull}21123[#21123] (issue: {issue}21077[#21077]) +* Make sure HEAD / has 0 Content-Length {pull}21077[#21077] (issue: {issue}21075[#21075]) +* Adds percent-encoding for Location headers {pull}21057[#21057] (issue: {issue}21016[#21016]) +* Whitelist node stats indices level parameter {pull}21024[#21024] (issue: {issue}20722[#20722]) +* Remove lenient URL parameter parsing {pull}20722[#20722] (issue: {issue}14719[#14719]) +* XContentBuilder: Avoid building self-referencing objects {pull}20550[#20550] (issues: {issue}19475[#19475], {issue}20540[#20540]) + +Recovery:: +* Provide target allocation id as part of start recovery request {pull}24333[#24333] (issue: {issue}24167[#24167]) +* Fix primary relocation for shadow replicas {pull}22474[#22474] (issue: {issue}20300[#20300]) +* Don't close store under CancellableThreads {pull}22434[#22434] (issue: {issue}22325[#22325]) +* Use a fresh recovery id when retrying recoveries {pull}22325[#22325] (issue: {issue}22043[#22043]) +* Allow flush/force_merge/upgrade on shard marked as relocated {pull}22078[#22078] (issue: {issue}22043[#22043]) +* Fix concurrency issues between cancelling a relocation and marking shard as relocated {pull}20443[#20443] + +Reindex API:: +* Fix throttled reindex_from_remote {pull}23953[#23953] (issues: {issue}23828[#23828], {issue}23945[#23945]) +* Fix reindex with a remote source on a version before 2.0.0 {pull}23805[#23805] +* Make reindex wait for cleanup before responding {pull}23677[#23677] (issue: {issue}23653[#23653]) +* Reindex: do not log when can't clear old scroll {pull}22942[#22942] (issue: {issue}22937[#22937]) +* Fix reindex-from-remote from <2.0 {pull}22931[#22931] (issue: {issue}22893[#22893]) +* Fix reindex from remote clearing scroll {pull}22525[#22525] (issue: {issue}22514[#22514]) +* Fix source filtering in reindex-from-remote {pull}22514[#22514] (issue: {issue}22507[#22507]) +* Remove content type detection from reindex-from-remote {pull}22504[#22504] (issue: {issue}22329[#22329]) +* Don't close rest client from its callback {pull}22061[#22061] (issue: {issue}22027[#22027]) +* Keep context during reindex's retries {pull}21941[#21941] +* Ignore IllegalArgumentException with assertVersionSerializable {pull}21409[#21409] (issues: {issue}20767[#20767], {issue}21350[#21350]) +* Bump reindex-from-remote's buffer to 200mb {pull}21222[#21222] (issue: {issue}21185[#21185]) +* Fix reindex-from-remote for parent/child from <2.0 {pull}21070[#21070] (issue: {issue}21044[#21044]) + +Scripting:: +* Convert script/template objects to json format internally {pull}23308[#23308] (issue: {issue}23245[#23245]) +* Script: Fix value of `ctx._now` to be current epoch time in milliseconds {pull}23175[#23175] (issue: {issue}23169[#23169]) +* Expose `ip` fields as strings in scripts. {pull}21997[#21997] (issue: {issue}21977[#21977]) +* Add support for booleans in scripts {pull}20950[#20950] (issue: {issue}20949[#20949]) +* Native scripts should be created once per index, not per segment. {pull}20609[#20609] + +Search:: +* Cross Cluster Search: propagate original indices per cluster {pull}24328[#24328] +* Query string default field {pull}24214[#24214] +* Speed up parsing of large `terms` queries. {pull}24210[#24210] +* IndicesQueryCache should delegate the scorerSupplier method. {pull}24209[#24209] +* Disable graph analysis at query time for shingle and cjk filters producing tokens of different size {pull}23920[#23920] (issue: {issue}23918[#23918]) +* Fix cross-cluster remote node gateway attributes {pull}23863[#23863] +* Use a fixed seed for computing term hashCode in TermsSliceQuery {pull}23795[#23795] +* Honor max concurrent searches in multi-search {pull}23538[#23538] (issue: {issue}23527[#23527]) +* Avoid stack overflow in multi-search {pull}23527[#23527] (issue: {issue}23523[#23523]) +* Fix query_string_query to transform "foo:*" in an exists query on the field name {pull}23433[#23433] (issue: {issue}23356[#23356]) +* Factor out filling of TopDocs in SearchPhaseController {pull}23380[#23380] (issues: {issue}19356[#19356], {issue}23357[#23357]) +* Replace blocking calls in ExpandCollapseSearchResponseListener by asynchronous requests {pull}23053[#23053] (issue: {issue}23048[#23048]) +* Ensure fixed serialization order of InnerHitBuilder {pull}22820[#22820] (issue: {issue}22808[#22808]) +* Improve concurrency of ShardCoreKeyMap. {pull}22316[#22316] +* Make `-0` compare less than `+0` consistently. {pull}22173[#22173] (issue: {issue}22167[#22167]) +* Fix boost_mode propagation when the function score query builder is rewritten {pull}22172[#22172] (issue: {issue}22138[#22138]) +* FiltersAggregationBuilder: rewriting filter queries, the same way as in FilterAggregationBuilder {pull}22076[#22076] +* Fix cross_fields type on multi_match query with synonyms {pull}21638[#21638] (issue: {issue}21633[#21633]) +* Fix match_phrase_prefix on boosted fields {pull}21623[#21623] (issue: {issue}21613[#21613]) +* Respect default search timeout {pull}21599[#21599] (issues: {issue}12211[#12211], {issue}21595[#21595]) +* Remove LateParsingQuery to prevent timestamp access after context is frozen {pull}21328[#21328] (issue: {issue}21295[#21295]) +* Make range queries round up upper bounds again. {pull}20582[#20582] (issues: {issue}20579[#20579], {issue}8889[#8889]) +* Throw error when trying to fetch fields from source and source is disabled {pull}20424[#20424] (issues: {issue}20093[#20093], {issue}20408[#20408]) + +Search Templates:: +* No longer add illegal content type option to stored search templates {pull}24251[#24251] (issue: {issue}24227[#24227]) +* SearchTemplateRequest to implement CompositeIndicesRequest {pull}21865[#21865] (issue: {issue}21747[#21747]) + +Settings:: +* Do not set path.data in environment if not set {pull}24132[#24132] (issue: {issue}24099[#24099]) +* Correct handling of default and array settings {pull}24074[#24074] (issues: {issue}23981[#23981], {issue}24052[#24052]) +* Fix merge scheduler config settings {pull}23391[#23391] +* Settings: Fix keystore cli prompting for yes/no to handle console returning null {pull}23320[#23320] +* Expose `search.highlight.term_vector_multi_value` as a node level setting {pull}22999[#22999] +* NPE when no setting name passed to elasticsearch-keystore {pull}22609[#22609] +* Handle spaces in `action.auto_create_index` gracefully {pull}21790[#21790] (issue: {issue}21449[#21449]) +* Fix settings diff generation for affix and group settings {pull}21788[#21788] +* Don't reset non-dynamic settings unless explicitly requested {pull}21646[#21646] (issue: {issue}21593[#21593]) +* Fix Setting.timeValue() method {pull}20696[#20696] (issue: {issue}20662[#20662]) +* Add a hard limit for `index.number_of_shard` {pull}20682[#20682] +* Include complex settings in settings requests {pull}20622[#20622] + +Snapshot/Restore:: +* Fixes maintaining the shards a snapshot is waiting on {pull}24289[#24289] +* Fixes snapshot status on failed snapshots {pull}23833[#23833] (issue: {issue}23716[#23716]) +* Fixes snapshot deletion handling on in-progress snapshot failure {pull}23703[#23703] (issue: {issue}23663[#23663]) +* Prioritize listing index-N blobs over index.latest in reading snapshots {pull}23333[#23333] +* Gracefully handles pre 2.x compressed snapshots {pull}22267[#22267] +* URLRepository should throw NoSuchFileException to correctly adhere to readBlob contract {pull}22069[#22069] (issue: {issue}22004[#22004]) +* Fixes shard level snapshot metadata loading when index-N file is missing {pull}21813[#21813] +* Ensures cleanup of temporary index-* generational blobs during snapshotting {pull}21469[#21469] (issue: {issue}21462[#21462]) +* Fixes get snapshot duplicates when asking for _all {pull}21340[#21340] (issue: {issue}21335[#21335]) + +Stats:: +* Avoid overflow when computing total FS stats {pull}23641[#23641] +* Handle existence of cgroup version 2 hierarchy {pull}23493[#23493] (issue: {issue}23486[#23486]) +* Handle long overflow when adding paths' totals {pull}23293[#23293] (issue: {issue}23093[#23093]) +* Fix control group pattern {pull}23219[#23219] (issue: {issue}23218[#23218]) +* Fix total disk bytes returning negative value {pull}23093[#23093] +* Implement stats for geo_point and geo_shape field {pull}22391[#22391] (issue: {issue}22384[#22384]) +* Use reader for doc stats {pull}22317[#22317] (issue: {issue}22285[#22285]) +* Avoid NPE in NodeService#stats if HTTP is disabled {pull}22060[#22060] (issue: {issue}22058[#22058]) +* Add support for "include_segment_file_sizes" in indices stats REST handler {pull}21879[#21879] (issue: {issue}21878[#21878]) +* Remove output_uuid parameter from cluster stats {pull}21020[#21020] (issue: {issue}20722[#20722]) +* Fix FieldStats deserialization of `ip` field {pull}20522[#20522] (issue: {issue}20516[#20516]) + +Task Manager:: +* Task Management: Make TaskInfo parsing forwards compatible {pull}24073[#24073] (issue: {issue}23250[#23250]) +* Fix hanging cancelling task with no children {pull}22796[#22796] +* Fix broken TaskInfo.toString() {pull}22698[#22698] (issue: {issue}22387[#22387]) +* Task cancellation command should wait for all child nodes to receive cancellation request before returning {pull}21397[#21397] (issue: {issue}21126[#21126]) + +Term Vectors:: +* Fix _termvectors with preference to not hit NPE {pull}21959[#21959] +* Return correct term statistics when a field is not found in a shard {pull}21922[#21922] (issue: {issue}21906[#21906]) + +Tribe Node:: +* Add socket permissions for tribe nodes {pull}21546[#21546] (issues: {issue}16392[#16392], {issue}21122[#21122]) + + + +[[regression-6.0.0-alpha1-5x]] +[float] +=== Regressions + +Bulk:: +* Fix _bulk response when it can't create an index {pull}24048[#24048] (issues: {issue}22488[#22488], {issue}24028[#24028]) + +Core:: +* Source filtering: only accept array items if the previous include pattern matches {pull}22593[#22593] (issue: {issue}22557[#22557]) + +Highlighting:: +* Handle SynonymQuery extraction for the FastVectorHighlighter {pull}20829[#20829] (issue: {issue}20781[#20781]) + +Logging:: +* Restores the original default format of search slow log {pull}21770[#21770] (issue: {issue}21711[#21711]) + +Plugin Discovery EC2:: +* Fix ec2 discovery when used with IAM profiles. {pull}21042[#21042] (issue: {issue}21039[#21039]) + +Plugin Repository S3:: +* Fix s3 repository when used with IAM profiles {pull}21058[#21058] (issue: {issue}21048[#21048]) + +Plugins:: +* Plugins: Add back user agent when downloading plugins {pull}20872[#20872] + +Search:: +* Handle specialized term queries in MappedFieldType.extractTerm(Query) {pull}21889[#21889] (issue: {issue}21882[#21882]) + + + +[[upgrade-6.0.0-alpha1-5x]] +[float] +=== Upgrades + +Aggregations:: +* Upgrade HDRHistogram to 2.1.9 {pull}23254[#23254] (issue: {issue}23239[#23239]) + +Core:: +* Upgrade to Lucene 6.5.0 {pull}23750[#23750] +* Upgrade from JNA 4.2.2 to JNA 4.4.0 {pull}23636[#23636] +* Upgrade to lucene-6.5.0-snapshot-d00c5ca {pull}23385[#23385] +* Upgrade to lucene-6.5.0-snapshot-f919485. {pull}23087[#23087] +* Upgrade to Lucene 6.4.0 {pull}22724[#22724] +* Update Jackson to 2.8.6 {pull}22596[#22596] (issue: {issue}22266[#22266]) +* Upgrade to lucene-6.4.0-snapshot-084f7a0. {pull}22413[#22413] +* Upgrade to lucene-6.4.0-snapshot-ec38570 {pull}21853[#21853] +* Upgrade to lucene-6.3.0. {pull}21464[#21464] + +Dates:: +* Update Joda Time to version 2.9.5 {pull}21468[#21468] (issues: {issue}20911[#20911], {issue}332[#332], {issue}373[#373], {issue}378[#378], {issue}379[#379], {issue}386[#386], {issue}394[#394], {issue}396[#396], {issue}397[#397], {issue}404[#404], {issue}69[#69]) + +Internal:: +* Upgrade to Lucene 6.4.1. {pull}22978[#22978] + +Logging:: +* Upgrade to Log4j 2.8.2 {pull}23995[#23995] +* Upgrade Log4j 2 to version 2.7 {pull}20805[#20805] (issue: {issue}20304[#20304]) + +Network:: +* Upgrade Netty to 4.1.10.Final {pull}24414[#24414] +* Upgrade to Netty 4.1.9 {pull}23540[#23540] (issues: {issue}23172[#23172], {issue}6308[#6308], {issue}6374[#6374]) +* Upgrade to Netty 4.1.8 {pull}23055[#23055] +* Upgrade to Netty 4.1.7 {pull}22587[#22587] +* Upgrade to Netty 4.1.6 {pull}21051[#21051] + +Plugin Repository Azure:: +* Update to Azure Storage 5.0.0 {pull}23517[#23517] (issue: {issue}23448[#23448]) + diff --git a/docs/reference/release-notes/6.0.0-alpha1.asciidoc b/docs/reference/release-notes/6.0.0-alpha1.asciidoc new file mode 100644 index 00000000000..d66d3ba0ed1 --- /dev/null +++ b/docs/reference/release-notes/6.0.0-alpha1.asciidoc @@ -0,0 +1,309 @@ +[[release-notes-6.0.0-alpha1]] +== 6.0.0-alpha1 Release Notes + +The changes listed below have been released for the first time in Elasticsearch 6.0.0-alpha1. Changes in this release which were first released in the 5.x series are listed in <>. + + +Also see <>. + +[[breaking-6.0.0-alpha1]] +[float] +=== Breaking changes + +Allocation:: +* Remove `cluster.routing.allocation.snapshot.relocation_enabled` setting {pull}20994[#20994] + +Analysis:: +* Removing query-string parameters in `_analyze` API {pull}20704[#20704] (issue: {issue}20246[#20246]) + +CAT API:: +* Write -1 on unbounded queue in cat thread pool {pull}21342[#21342] (issue: {issue}21187[#21187]) + +CRUD:: +* Disallow `VersionType.FORCE` for GetRequest {pull}21079[#21079] (issue: {issue}20995[#20995]) +* Disallow `VersionType.FORCE` versioning for 6.x indices {pull}20995[#20995] (issue: {issue}20377[#20377]) + +Cluster:: +* No longer allow cluster name in data path {pull}20433[#20433] (issue: {issue}20391[#20391]) + +Core:: +* Make boolean conversion strict {pull}22200[#22200] +* Remove the `default` store type. {pull}21616[#21616] +* Remove store throttling. {pull}21573[#21573] + +Geo:: +* Remove deprecated geo search features {pull}22876[#22876] +* Reduce GeoDistance Insanity {pull}19846[#19846] + +Index APIs:: +* Remove support for controversial `ignore_unavailable` and `allow_no_indices` from indices exists api {pull}20712[#20712] + +Index Templates:: +* Allows multiple patterns to be specified for index templates {pull}21009[#21009] (issue: {issue}20690[#20690]) + +Java API:: +* Enforce Content-Type requirement on the rest layer and remove deprecated methods {pull}23146[#23146] (issue: {issue}19388[#19388]) + +Mapping:: +* Disallow `include_in_all` for 6.0+ indices {pull}22970[#22970] (issue: {issue}22923[#22923]) +* Disable _all by default, disallow configuring _all on 6.0+ indices {pull}22144[#22144] (issues: {issue}19784[#19784], {issue}20925[#20925], {issue}21341[#21341]) +* Throw an exception on unrecognized "match_mapping_type" {pull}22090[#22090] (issue: {issue}17285[#17285]) + +NOT CLASSIFIED:: +* Add note to docs on duplicate keys in config {pull}24022[#24022] (issue: {issue}24006[#24006]) + +Network:: +* Remove blocking TCP clients and servers {pull}22639[#22639] +* Remove `modules/transport_netty_3` in favor of `netty_4` {pull}21590[#21590] +* Remove LocalTransport in favor of MockTcpTransport {pull}20695[#20695] + +Packaging:: +* Remove customization of ES_USER and ES_GROUP {pull}23989[#23989] (issue: {issue}23848[#23848]) + +Percolator:: +* Remove deprecated percolate and mpercolate apis {pull}22331[#22331] + +Plugin Delete By Query:: +* Require explicit query in _delete_by_query API {pull}23632[#23632] (issue: {issue}23629[#23629]) + +Plugin Discovery EC2:: +* Ec2 Discovery: Cleanup deprecated settings {pull}24150[#24150] +* Discovery EC2: Remove region setting {pull}23991[#23991] (issue: {issue}22758[#22758]) +* AWS Plugins: Remove signer type setting {pull}23984[#23984] (issue: {issue}22599[#22599]) + +Plugin Lang JS:: +* Remove lang-python and lang-javascript {pull}20734[#20734] (issue: {issue}20698[#20698]) + +Plugin Mapper Attachment:: +* Remove mapper attachments plugin {pull}20416[#20416] (issue: {issue}18837[#18837]) + +Plugin Repository Azure:: +* Remove global `repositories.azure` settings {pull}23262[#23262] (issues: {issue}22800[#22800], {issue}22856[#22856]) +* Remove auto creation of container for azure repository {pull}22858[#22858] (issue: {issue}22857[#22857]) + +Plugin Repository S3:: +* S3 Repository: Cleanup deprecated settings {pull}24097[#24097] +* S3 Repository: Remove region setting {pull}22853[#22853] (issue: {issue}22758[#22758]) +* S3 Repository: Remove bucket auto create {pull}22846[#22846] (issue: {issue}22761[#22761]) +* S3 Repository: Remove env var and sysprop credentials support {pull}22842[#22842] + +Query DSL:: +* Remove deprecated `minimum_number_should_match` in BoolQueryBuilder {pull}22416[#22416] +* Remove support for empty queries {pull}22092[#22092] (issue: {issue}17624[#17624]) +* Remove deprecated query names: in, geo_bbox, mlt, fuzzy_match and match_fuzzy {pull}21852[#21852] +* The `terms` query should always map to a Lucene `TermsQuery`. {pull}21786[#21786] +* Be strict when parsing values searching for booleans {pull}21555[#21555] (issue: {issue}21545[#21545]) +* Remove collect payloads parameter {pull}20385[#20385] + +REST:: +* Remove ldjson support and document ndjson for bulk/msearch {pull}23049[#23049] (issue: {issue}23025[#23025]) +* Enable strict duplicate checks for all XContent types {pull}22225[#22225] (issues: {issue}19614[#19614], {issue}22073[#22073]) +* Enable strict duplicate checks for JSON content {pull}22073[#22073] (issue: {issue}19614[#19614]) +* Remove lenient stats parsing {pull}21417[#21417] (issues: {issue}20722[#20722], {issue}21410[#21410]) +* Remove allow unquoted JSON {pull}20388[#20388] (issues: {issue}17674[#17674], {issue}17801[#17801]) +* Remove FORCE version_type {pull}20377[#20377] (issue: {issue}19769[#19769]) + +Scripting:: +* Make dates be ReadableDateTimes in scripts {pull}22948[#22948] (issue: {issue}22875[#22875]) +* Remove groovy scripting language {pull}21607[#21607] + +Search:: +* ProfileResult and CollectorResult should print machine readable timing information {pull}22561[#22561] +* Remove indices query {pull}21837[#21837] (issue: {issue}17710[#17710]) +* Remove ignored type parameter in search_shards api {pull}21688[#21688] + +Sequence IDs:: +* Change certain replica failures not to fail the replica shard {pull}22874[#22874] (issue: {issue}10708[#10708]) + +Shadow Replicas:: +* Remove shadow replicas {pull}23906[#23906] (issue: {issue}22024[#22024]) + + + +[[breaking-java-6.0.0-alpha1]] +[float] +=== Breaking Java changes + +Network:: +* Simplify TransportAddress {pull}20798[#20798] + + + +[[deprecation-6.0.0-alpha1]] +[float] +=== Deprecations + +Index Templates:: +* Restore deprecation warning for invalid match_mapping_type values {pull}22304[#22304] + +Internal:: +* Deprecate XContentType auto detection methods in XContentFactory {pull}22181[#22181] (issue: {issue}19388[#19388]) + + + +[[feature-6.0.0-alpha1]] +[float] +=== New features + +Core:: +* Enable index-time sorting {pull}24055[#24055] (issue: {issue}6720[#6720]) + + + +[[enhancement-6.0.0-alpha1]] +[float] +=== Enhancements + +Aggregations:: +* Agg builder accessibility fixes {pull}24323[#24323] +* Remove support for the include/pattern syntax. {pull}23141[#23141] (issue: {issue}22933[#22933]) +* Promote longs to doubles when a terms agg mixes decimal and non-decimal numbers {pull}22449[#22449] (issue: {issue}22232[#22232]) + +Analysis:: +* Match- and MultiMatchQueryBuilder should only allow setting analyzer on string values {pull}23684[#23684] (issue: {issue}21665[#21665]) + +Bulk:: +* Simplify bulk request execution {pull}20109[#20109] + +CRUD:: +* Added validation for upsert request {pull}24282[#24282] (issue: {issue}16671[#16671]) + +Cluster:: +* Separate publishing from applying cluster states {pull}24236[#24236] +* Adds cluster state size to /_cluster/state response {pull}23440[#23440] (issue: {issue}3415[#3415]) + +Core:: +* Remove connect SocketPermissions from core {pull}22797[#22797] +* Add repository-url module and move URLRepository {pull}22752[#22752] (issue: {issue}22116[#22116]) +* Remove accept SocketPermissions from core {pull}22622[#22622] (issue: {issue}22116[#22116]) +* Move IfConfig.logIfNecessary call into bootstrap {pull}22455[#22455] (issue: {issue}22116[#22116]) +* Remove artificial default processors limit {pull}20874[#20874] (issue: {issue}20828[#20828]) +* Simplify write failure handling {pull}19105[#19105] (issue: {issue}20109[#20109]) + +Engine:: +* Fill missing sequence IDs up to max sequence ID when recovering from store {pull}24238[#24238] (issue: {issue}10708[#10708]) +* Use sequence numbers to identify out of order delivery in replicas & recovery {pull}24060[#24060] (issue: {issue}10708[#10708]) +* Add replica ops with version conflict to translog {pull}22626[#22626] +* Clarify global checkpoint recovery {pull}21934[#21934] (issue: {issue}21254[#21254]) + +Internal:: +* Try to convince the JVM not to lose stacktraces {pull}24426[#24426] (issue: {issue}24376[#24376]) +* Make document write requests immutable {pull}23038[#23038] + +Java High Level REST Client:: +* Add info method to High Level Rest client {pull}23350[#23350] +* Add support for named xcontent parsers to high level REST client {pull}23328[#23328] +* Add BulkRequest support to High Level Rest client {pull}23312[#23312] +* Add UpdateRequest support to High Level Rest client {pull}23266[#23266] +* Add delete API to the High Level Rest Client {pull}23187[#23187] +* Add Index API to High Level Rest Client {pull}23040[#23040] +* Add get/exists method to RestHighLevelClient {pull}22706[#22706] +* Add fromxcontent methods to delete response {pull}22680[#22680] (issue: {issue}22229[#22229]) +* Add parsing from xContent to SearchResponse {pull}22533[#22533] +* Add REST high level client gradle submodule and first simple method {pull}22371[#22371] + +Java REST Client:: +* Wrap rest httpclient with doPrivileged blocks {pull}22603[#22603] (issue: {issue}22116[#22116]) + +Mapping:: +* Date detection should not rely on a hardcoded set of characters. {pull}22171[#22171] (issue: {issue}1694[#1694]) + +Network:: +* Isolate SocketPermissions to Netty {pull}23057[#23057] +* Wrap netty accept/connect ops with doPrivileged {pull}22572[#22572] (issue: {issue}22116[#22116]) +* Replace Socket, ServerSocket, and HttpServer usages in tests with mocksocket versions {pull}22287[#22287] (issue: {issue}22116[#22116]) + +Plugin Discovery EC2:: +* Read ec2 discovery address from aws instance tags {pull}22743[#22743] (issue: {issue}22566[#22566]) + +Plugin Repository HDFS:: +* Add doPrivilege blocks for socket connect ops in repository-hdfs {pull}22793[#22793] (issue: {issue}22116[#22116]) + +Plugins:: +* Add doPrivilege blocks for socket connect operations in plugins {pull}22534[#22534] (issue: {issue}22116[#22116]) + +Recovery:: +* Peer Recovery: remove maxUnsafeAutoIdTimestamp hand off {pull}24243[#24243] (issue: {issue}24149[#24149]) +* Introduce sequence-number-based recovery {pull}22484[#22484] (issue: {issue}10708[#10708]) + +Search:: +* Add parsing from xContent to Suggest {pull}22903[#22903] +* Add parsing from xContent to ShardSearchFailure {pull}22699[#22699] + +Sequence IDs:: +* Add primary term to doc write response {pull}24171[#24171] (issue: {issue}10708[#10708]) +* Preserve multiple translog generations {pull}24015[#24015] (issue: {issue}10708[#10708]) +* Introduce translog generation rolling {pull}23606[#23606] (issue: {issue}10708[#10708]) +* Replicate write failures {pull}23314[#23314] +* Introduce sequence-number-aware translog {pull}22822[#22822] (issue: {issue}10708[#10708]) +* Introduce translog no-op {pull}22291[#22291] (issue: {issue}10708[#10708]) +* Tighten sequence numbers recovery {pull}22212[#22212] (issue: {issue}10708[#10708]) +* Add BWC layer to seq no infra and enable BWC tests {pull}22185[#22185] (issue: {issue}21670[#21670]) +* Add internal _primary_term doc values field, fix _seq_no indexing {pull}21637[#21637] (issues: {issue}10708[#10708], {issue}21480[#21480]) +* Add global checkpoint to translog checkpoints {pull}21254[#21254] +* Sequence numbers commit data for Lucene uses Iterable interface {pull}20793[#20793] (issue: {issue}10708[#10708]) +* Simplify GlobalCheckpointService and properly hook it for cluster state updates {pull}20720[#20720] + +Stats:: +* Expose disk usage estimates in nodes stats {pull}22081[#22081] (issue: {issue}8686[#8686]) + +Store:: +* Remote support for lucene versions without checksums {pull}24021[#24021] + +Suggesters:: +* Remove deprecated _suggest endpoint {pull}22203[#22203] (issue: {issue}20305[#20305]) + +Task Manager:: +* Add descriptions to bulk tasks {pull}22059[#22059] (issue: {issue}21768[#21768]) + + + +[[bug-6.0.0-alpha1]] +[float] +=== Bug fixes + +Ingest:: +* Remove support for Visio and potm files {pull}22079[#22079] (issue: {issue}22077[#22077]) + +Inner Hits:: +* If size / offset are out of bounds just do a plain count {pull}20556[#20556] (issue: {issue}20501[#20501]) + +Internal:: +* Fix handling of document failure exception in InternalEngine {pull}22718[#22718] + +Plugin Ingest Attachment:: +* Add missing mime4j library {pull}22764[#22764] (issue: {issue}22077[#22077]) + +Plugin Repository S3:: +* Wrap getCredentials() in a doPrivileged() block {pull}23297[#23297] (issues: {issue}22534[#22534], {issue}23271[#23271]) + +Sequence IDs:: +* Avoid losing ops in file-based recovery {pull}22945[#22945] (issue: {issue}22484[#22484]) + +Snapshot/Restore:: +* Keep snapshot restore state and routing table in sync {pull}20836[#20836] (issue: {issue}19774[#19774]) + +Translog:: +* Fix Translog.Delete serialization for sequence numbers {pull}22543[#22543] + + + +[[regression-6.0.0-alpha1]] +[float] +=== Regressions + +Bulk:: +* Only re-parse operation if a mapping update was needed {pull}23832[#23832] (issue: {issue}23665[#23665]) + + + +[[upgrade-6.0.0-alpha1]] +[float] +=== Upgrades + +Core:: +* Upgrade to a Lucene 7 snapshot {pull}24089[#24089] (issues: {issue}23966[#23966], {issue}24086[#24086], {issue}24087[#24087], {issue}24088[#24088]) + +Plugin Ingest Attachment:: +* Update to Tika 1.14 {pull}21591[#21591] (issue: {issue}20390[#20390]) + From 5bfb98ade4d1692093ac47fe882ecef633529f8c Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Fri, 5 May 2017 16:02:26 +0200 Subject: [PATCH 39/44] [TEST] Reenable disabled tests for _field_caps and _search_shards (#24505) --- .../resources/rest-api-spec/test/field_caps/10_basic.yaml | 4 ++-- .../resources/rest-api-spec/test/search_shards/10_basic.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/field_caps/10_basic.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/field_caps/10_basic.yaml index 2568f401a5e..f22afb91169 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/field_caps/10_basic.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/field_caps/10_basic.yaml @@ -169,8 +169,8 @@ setup: --- "Mix in non-existing field field caps": - skip: - version: " - 6.0.0" # temporarily disabled - reason: this bug has been fixed in 5.4.0 + version: " - 5.4.0" + reason: "#24504 fixed a bug in this API in 5.4.1" - do: field_caps: diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/search_shards/10_basic.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/search_shards/10_basic.yaml index ef01f3b7b44..c2d341e3439 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/search_shards/10_basic.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/search_shards/10_basic.yaml @@ -14,8 +14,8 @@ --- "Search shards aliases with and without filters": - skip: - version: " - 6.0.0" # temporarily disabled - reason: indices section was added in 5.1.0 + version: " - 5.4.0" + reason: "#24489 fixed a bug that not all aliases where added in 5.4.1 - indices section was added in 5.1.0" - do: indices.create: From 9f08a553d960cd3253d85ee8b98a9ef22804d192 Mon Sep 17 00:00:00 2001 From: Clinton Gormley Date: Fri, 5 May 2017 16:06:48 +0200 Subject: [PATCH 40/44] Fixed docs syntax for for-in loop in painless --- docs/reference/modules/scripting/painless-syntax.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/modules/scripting/painless-syntax.asciidoc b/docs/reference/modules/scripting/painless-syntax.asciidoc index e3a6ed24bc0..15656d72f2c 100644 --- a/docs/reference/modules/scripting/painless-syntax.asciidoc +++ b/docs/reference/modules/scripting/painless-syntax.asciidoc @@ -207,7 +207,7 @@ In addition to Java's `enhanced for` loop, the `for in` syntax from groovy can a [source,painless] --------------------------------------------------------- -for (item : list) { +for (def item : list) { ... } --------------------------------------------------------- From e3766d28288ed2e0f3cd098e7a6b8c22de3a0fa6 Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Fri, 5 May 2017 16:40:04 +0200 Subject: [PATCH 41/44] Expand cross cluster search indices for search requests to the concrete index or to it's aliases (#24502) This change will expand the shard level request to the actual concrete index or to the aliases that expanded to the concrete index to ensure shard level requests won't see wildcard expressions as their original indices --- .../action/search/TransportSearchAction.java | 13 ++++++++----- .../org/elasticsearch/common/util/ArrayUtils.java | 1 - .../action/search/TransportSearchActionTests.java | 15 +++++++++------ 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java b/core/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java index 9c8d1a879b1..f65597a966b 100644 --- a/core/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java +++ b/core/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java @@ -220,11 +220,6 @@ public class TransportSearchAction extends HandledTransportAction { diff --git a/core/src/main/java/org/elasticsearch/common/util/ArrayUtils.java b/core/src/main/java/org/elasticsearch/common/util/ArrayUtils.java index de23663b3e9..20c12d564da 100644 --- a/core/src/main/java/org/elasticsearch/common/util/ArrayUtils.java +++ b/core/src/main/java/org/elasticsearch/common/util/ArrayUtils.java @@ -84,5 +84,4 @@ public class ArrayUtils { System.arraycopy(other, 0, target, one.length, other.length); return target; } - } diff --git a/core/src/test/java/org/elasticsearch/action/search/TransportSearchActionTests.java b/core/src/test/java/org/elasticsearch/action/search/TransportSearchActionTests.java index f34f4313fd6..7491eda8fd7 100644 --- a/core/src/test/java/org/elasticsearch/action/search/TransportSearchActionTests.java +++ b/core/src/test/java/org/elasticsearch/action/search/TransportSearchActionTests.java @@ -64,7 +64,6 @@ public class TransportSearchActionTests extends ESTestCase { ThreadPool.terminate(threadPool, 10, TimeUnit.SECONDS); } - public void testMergeShardsIterators() throws IOException { List localShardIterators = new ArrayList<>(); { @@ -159,7 +158,8 @@ public class TransportSearchActionTests extends ESTestCase { new DiscoveryNode("node2", buildNewFakeTransportAddress(), Version.CURRENT) }; Map indicesAndAliases = new HashMap<>(); - indicesAndAliases.put("foo", new AliasFilter(new TermsQueryBuilder("foo", "bar"), Strings.EMPTY_ARRAY)); + indicesAndAliases.put("foo", new AliasFilter(new TermsQueryBuilder("foo", "bar"), "some_alias_for_foo", + "some_other_foo_alias")); indicesAndAliases.put("bar", new AliasFilter(new MatchAllQueryBuilder(), Strings.EMPTY_ARRAY)); ClusterSearchShardsGroup[] groups = new ClusterSearchShardsGroup[] { new ClusterSearchShardsGroup(new ShardId("foo", "foo_id", 0), @@ -180,7 +180,9 @@ public class TransportSearchActionTests extends ESTestCase { new ClusterSearchShardsGroup(new ShardId("xyz", "xyz_id", 0), new ShardRouting[] {TestShardRouting.newShardRouting("xyz", 0, "node3", true, ShardRoutingState.STARTED)}) }; - searchShardsResponseMap.put("test_cluster_2", new ClusterSearchShardsResponse(groups2, nodes2, null)); + Map filter = new HashMap<>(); + filter.put("xyz", new AliasFilter(null, "some_alias_for_xyz")); + searchShardsResponseMap.put("test_cluster_2", new ClusterSearchShardsResponse(groups2, nodes2, filter)); Map remoteIndicesByCluster = new HashMap<>(); remoteIndicesByCluster.put("test_cluster_1", @@ -193,7 +195,8 @@ public class TransportSearchActionTests extends ESTestCase { assertEquals(4, iteratorList.size()); for (SearchShardIterator iterator : iteratorList) { if (iterator.shardId().getIndexName().endsWith("foo")) { - assertArrayEquals(new String[]{"fo*", "ba*"}, iterator.getOriginalIndices().indices()); + assertArrayEquals(new String[]{"some_alias_for_foo", "some_other_foo_alias"}, + iterator.getOriginalIndices().indices()); assertTrue(iterator.shardId().getId() == 0 || iterator.shardId().getId() == 1); assertEquals("test_cluster_1:foo", iterator.shardId().getIndexName()); ShardRouting shardRouting = iterator.nextOrNull(); @@ -204,7 +207,7 @@ public class TransportSearchActionTests extends ESTestCase { assertEquals(shardRouting.getIndexName(), "foo"); assertNull(iterator.nextOrNull()); } else if (iterator.shardId().getIndexName().endsWith("bar")) { - assertArrayEquals(new String[]{"fo*", "ba*"}, iterator.getOriginalIndices().indices()); + assertArrayEquals(new String[]{"bar"}, iterator.getOriginalIndices().indices()); assertEquals(0, iterator.shardId().getId()); assertEquals("test_cluster_1:bar", iterator.shardId().getIndexName()); ShardRouting shardRouting = iterator.nextOrNull(); @@ -215,7 +218,7 @@ public class TransportSearchActionTests extends ESTestCase { assertEquals(shardRouting.getIndexName(), "bar"); assertNull(iterator.nextOrNull()); } else if (iterator.shardId().getIndexName().endsWith("xyz")) { - assertArrayEquals(new String[]{"x*"}, iterator.getOriginalIndices().indices()); + assertArrayEquals(new String[]{"some_alias_for_xyz"}, iterator.getOriginalIndices().indices()); assertEquals(0, iterator.shardId().getId()); assertEquals("test_cluster_2:xyz", iterator.shardId().getIndexName()); ShardRouting shardRouting = iterator.nextOrNull(); From 0c4eb0a02940139ca26ccc45523c03ba26c7d75b Mon Sep 17 00:00:00 2001 From: Nicholas Knize Date: Tue, 2 May 2017 09:56:52 -0500 Subject: [PATCH 42/44] Add new ip_range field type This commit adds support for indexing and searching a new ip_range field type. Both IPv4 and IPv6 formats are supported. Tests are updated and docs are added. --- .../index/mapper/RangeFieldMapper.java | 236 ++++++++++-------- .../index/mapper/RangeFieldMapperTests.java | 44 +++- .../index/mapper/RangeFieldTypeTests.java | 28 ++- docs/reference/mapping/types/range.asciidoc | 2 + .../release-notes/6.0.0-alpha1.asciidoc | 1 + 5 files changed, 201 insertions(+), 110 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java index 9a271916ac1..257792b8b09 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java @@ -22,6 +22,8 @@ import org.apache.lucene.document.Field; import org.apache.lucene.document.DoubleRange; import org.apache.lucene.document.FloatRange; import org.apache.lucene.document.IntRange; +import org.apache.lucene.document.InetAddressPoint; +import org.apache.lucene.document.InetAddressRange; import org.apache.lucene.document.LongRange; import org.apache.lucene.document.StoredField; import org.apache.lucene.index.IndexOptions; @@ -29,12 +31,12 @@ import org.apache.lucene.index.IndexableField; import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.Query; import org.apache.lucene.util.BytesRef; -import org.apache.lucene.util.NumericUtils; import org.elasticsearch.common.Explicit; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.geo.ShapeRelation; import org.elasticsearch.common.joda.DateMathParser; import org.elasticsearch.common.joda.FormatDateTimeFormatter; +import org.elasticsearch.common.network.InetAddresses; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.LocaleUtils; @@ -45,6 +47,7 @@ import org.elasticsearch.index.query.QueryShardContext; import org.joda.time.DateTimeZone; import java.io.IOException; +import java.net.InetAddress; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -341,8 +344,8 @@ public class RangeFieldMapper extends FieldMapper { RangeFieldType fieldType = fieldType(); RangeType rangeType = fieldType.rangeType; String fieldName = null; - Number from = rangeType.minValue(); - Number to = rangeType.maxValue(); + Object from = rangeType.minValue(); + Object to = rangeType.maxValue(); boolean includeFrom = DEFAULT_INCLUDE_LOWER; boolean includeTo = DEFAULT_INCLUDE_UPPER; XContentParser.Token token; @@ -427,10 +430,72 @@ public class RangeFieldMapper extends FieldMapper { /** Enum defining the type of range */ public enum RangeType { + IP("ip_range") { + @Override + public Field getRangeField(String name, Range r) { + return new InetAddressRange(name, (InetAddress)r.from, (InetAddress)r.to); + } + @Override + public InetAddress parseFrom(RangeFieldType fieldType, XContentParser parser, boolean coerce, boolean included) + throws IOException { + InetAddress address = InetAddresses.forString(parser.text()); + return included ? address : nextUp(address); + } + @Override + public InetAddress parseTo(RangeFieldType fieldType, XContentParser parser, boolean coerce, boolean included) + throws IOException { + InetAddress address = InetAddresses.forString(parser.text()); + return included ? address : nextDown(address); + } + @Override + public InetAddress parse(Object value, boolean coerce) { + return value instanceof InetAddress ? (InetAddress) value : InetAddresses.forString((String) value); + } + @Override + public InetAddress minValue() { + return InetAddressPoint.MIN_VALUE; + } + @Override + public InetAddress maxValue() { + return InetAddressPoint.MAX_VALUE; + } + @Override + public InetAddress nextUp(Object value) { + return InetAddressPoint.nextUp((InetAddress)value); + } + @Override + public InetAddress nextDown(Object value) { + return InetAddressPoint.nextDown((InetAddress)value); + } + @Override + public Query withinQuery(String field, Object from, Object to, boolean includeLower, boolean includeUpper) { + InetAddress lower = (InetAddress)from; + InetAddress upper = (InetAddress)to; + return InetAddressRange.newWithinQuery(field, + includeLower ? lower : nextUp(lower), includeUpper ? upper : nextDown(upper)); + } + @Override + public Query containsQuery(String field, Object from, Object to, boolean includeLower, boolean includeUpper) { + InetAddress lower = (InetAddress)from; + InetAddress upper = (InetAddress)to; + return InetAddressRange.newContainsQuery(field, + includeLower ? lower : nextUp(lower), includeUpper ? upper : nextDown(upper)); + } + @Override + public Query intersectsQuery(String field, Object from, Object to, boolean includeLower, boolean includeUpper) { + InetAddress lower = (InetAddress)from; + InetAddress upper = (InetAddress)to; + return InetAddressRange.newIntersectsQuery(field, + includeLower ? lower : nextUp(lower), includeUpper ? upper : nextDown(upper)); + } + public String toString(InetAddress address) { + return InetAddresses.toAddrString(address); + } + }, DATE("date_range", NumberType.LONG) { @Override public Field getRangeField(String name, Range r) { - return new LongRange(name, new long[] {r.from.longValue()}, new long[] {r.to.longValue()}); + return new LongRange(name, new long[] {((Number)r.from).longValue()}, new long[] {((Number)r.to).longValue()}); } private Number parse(DateMathParser dateMathParser, String dateStr) { return dateMathParser.parse(dateStr, () -> {throw new IllegalArgumentException("now is not used at indexing time");}); @@ -456,16 +521,12 @@ public class RangeFieldMapper extends FieldMapper { return Long.MAX_VALUE; } @Override - public Number nextUp(Number value) { - return LONG.nextUp(value); + public Long nextUp(Object value) { + return (long) LONG.nextUp(value); } @Override - public Number nextDown(Number value) { - return LONG.nextDown(value); - } - @Override - public byte[] getBytes(Range r) { - return LONG.getBytes(r); + public Long nextDown(Object value) { + return (long) LONG.nextDown(value); } @Override public Query rangeQuery(String field, Object lowerTerm, Object upperTerm, boolean includeLower, boolean includeUpper, @@ -484,15 +545,15 @@ public class RangeFieldMapper extends FieldMapper { return super.rangeQuery(field, low, high, includeLower, includeUpper, relation, zone, dateMathParser, context); } @Override - public Query withinQuery(String field, Number from, Number to, boolean includeLower, boolean includeUpper) { + public Query withinQuery(String field, Object from, Object to, boolean includeLower, boolean includeUpper) { return LONG.withinQuery(field, from, to, includeLower, includeUpper); } @Override - public Query containsQuery(String field, Number from, Number to, boolean includeLower, boolean includeUpper) { + public Query containsQuery(String field, Object from, Object to, boolean includeLower, boolean includeUpper) { return LONG.containsQuery(field, from, to, includeLower, includeUpper); } @Override - public Query intersectsQuery(String field, Number from, Number to, boolean includeLower, boolean includeUpper) { + public Query intersectsQuery(String field, Object from, Object to, boolean includeLower, boolean includeUpper) { return LONG.intersectsQuery(field, from, to, includeLower, includeUpper); } }, @@ -507,38 +568,31 @@ public class RangeFieldMapper extends FieldMapper { return Float.POSITIVE_INFINITY; } @Override - public Float nextUp(Number value) { - return Math.nextUp(value.floatValue()); + public Float nextUp(Object value) { + return Math.nextUp(((Number)value).floatValue()); } @Override - public Float nextDown(Number value) { - return Math.nextDown(value.floatValue()); + public Float nextDown(Object value) { + return Math.nextDown(((Number)value).floatValue()); } @Override public Field getRangeField(String name, Range r) { - return new FloatRange(name, new float[] {r.from.floatValue()}, new float[] {r.to.floatValue()}); + return new FloatRange(name, new float[] {((Number)r.from).floatValue()}, new float[] {((Number)r.to).floatValue()}); } @Override - public byte[] getBytes(Range r) { - byte[] b = new byte[Float.BYTES*2]; - NumericUtils.intToSortableBytes(NumericUtils.floatToSortableInt(r.from.floatValue()), b, 0); - NumericUtils.intToSortableBytes(NumericUtils.floatToSortableInt(r.to.floatValue()), b, Float.BYTES); - return b; - } - @Override - public Query withinQuery(String field, Number from, Number to, boolean includeFrom, boolean includeTo) { + public Query withinQuery(String field, Object from, Object to, boolean includeFrom, boolean includeTo) { return FloatRange.newWithinQuery(field, new float[] {includeFrom ? (Float)from : Math.nextUp((Float)from)}, new float[] {includeTo ? (Float)to : Math.nextDown((Float)to)}); } @Override - public Query containsQuery(String field, Number from, Number to, boolean includeFrom, boolean includeTo) { + public Query containsQuery(String field, Object from, Object to, boolean includeFrom, boolean includeTo) { return FloatRange.newContainsQuery(field, new float[] {includeFrom ? (Float)from : Math.nextUp((Float)from)}, new float[] {includeTo ? (Float)to : Math.nextDown((Float)to)}); } @Override - public Query intersectsQuery(String field, Number from, Number to, boolean includeFrom, boolean includeTo) { + public Query intersectsQuery(String field, Object from, Object to, boolean includeFrom, boolean includeTo) { return FloatRange.newIntersectsQuery(field, new float[] {includeFrom ? (Float)from : Math.nextUp((Float)from)}, new float[] {includeTo ? (Float)to : Math.nextDown((Float)to)}); @@ -554,38 +608,31 @@ public class RangeFieldMapper extends FieldMapper { return Double.POSITIVE_INFINITY; } @Override - public Double nextUp(Number value) { - return Math.nextUp(value.doubleValue()); + public Double nextUp(Object value) { + return Math.nextUp(((Number)value).doubleValue()); } @Override - public Double nextDown(Number value) { - return Math.nextDown(value.doubleValue()); + public Double nextDown(Object value) { + return Math.nextDown(((Number)value).doubleValue()); } @Override public Field getRangeField(String name, Range r) { - return new DoubleRange(name, new double[] {r.from.doubleValue()}, new double[] {r.to.doubleValue()}); + return new DoubleRange(name, new double[] {((Number)r.from).doubleValue()}, new double[] {((Number)r.to).doubleValue()}); } @Override - public byte[] getBytes(Range r) { - byte[] b = new byte[Double.BYTES*2]; - NumericUtils.longToSortableBytes(NumericUtils.doubleToSortableLong(r.from.doubleValue()), b, 0); - NumericUtils.longToSortableBytes(NumericUtils.doubleToSortableLong(r.to.doubleValue()), b, Double.BYTES); - return b; - } - @Override - public Query withinQuery(String field, Number from, Number to, boolean includeFrom, boolean includeTo) { + public Query withinQuery(String field, Object from, Object to, boolean includeFrom, boolean includeTo) { return DoubleRange.newWithinQuery(field, new double[] {includeFrom ? (Double)from : Math.nextUp((Double)from)}, new double[] {includeTo ? (Double)to : Math.nextDown((Double)to)}); } @Override - public Query containsQuery(String field, Number from, Number to, boolean includeFrom, boolean includeTo) { + public Query containsQuery(String field, Object from, Object to, boolean includeFrom, boolean includeTo) { return DoubleRange.newContainsQuery(field, new double[] {includeFrom ? (Double)from : Math.nextUp((Double)from)}, new double[] {includeTo ? (Double)to : Math.nextDown((Double)to)}); } @Override - public Query intersectsQuery(String field, Number from, Number to, boolean includeFrom, boolean includeTo) { + public Query intersectsQuery(String field, Object from, Object to, boolean includeFrom, boolean includeTo) { return DoubleRange.newIntersectsQuery(field, new double[] {includeFrom ? (Double)from : Math.nextUp((Double)from)}, new double[] {includeTo ? (Double)to : Math.nextDown((Double)to)}); @@ -603,36 +650,29 @@ public class RangeFieldMapper extends FieldMapper { return Integer.MAX_VALUE; } @Override - public Integer nextUp(Number value) { - return value.intValue() + 1; + public Integer nextUp(Object value) { + return ((Number)value).intValue() + 1; } @Override - public Integer nextDown(Number value) { - return value.intValue() - 1; + public Integer nextDown(Object value) { + return ((Number)value).intValue() - 1; } @Override public Field getRangeField(String name, Range r) { - return new IntRange(name, new int[] {r.from.intValue()}, new int[] {r.to.intValue()}); + return new IntRange(name, new int[] {((Number)r.from).intValue()}, new int[] {((Number)r.to).intValue()}); } @Override - public byte[] getBytes(Range r) { - byte[] b = new byte[Integer.BYTES*2]; - NumericUtils.intToSortableBytes(r.from.intValue(), b, 0); - NumericUtils.intToSortableBytes(r.to.intValue(), b, Integer.BYTES); - return b; - } - @Override - public Query withinQuery(String field, Number from, Number to, boolean includeFrom, boolean includeTo) { + public Query withinQuery(String field, Object from, Object to, boolean includeFrom, boolean includeTo) { return IntRange.newWithinQuery(field, new int[] {(Integer)from + (includeFrom ? 0 : 1)}, new int[] {(Integer)to - (includeTo ? 0 : 1)}); } @Override - public Query containsQuery(String field, Number from, Number to, boolean includeFrom, boolean includeTo) { + public Query containsQuery(String field, Object from, Object to, boolean includeFrom, boolean includeTo) { return IntRange.newContainsQuery(field, new int[] {(Integer)from + (includeFrom ? 0 : 1)}, new int[] {(Integer)to - (includeTo ? 0 : 1)}); } @Override - public Query intersectsQuery(String field, Number from, Number to, boolean includeFrom, boolean includeTo) { + public Query intersectsQuery(String field, Object from, Object to, boolean includeFrom, boolean includeTo) { return IntRange.newIntersectsQuery(field, new int[] {(Integer)from + (includeFrom ? 0 : 1)}, new int[] {(Integer)to - (includeTo ? 0 : 1)}); } @@ -647,43 +687,40 @@ public class RangeFieldMapper extends FieldMapper { return Long.MAX_VALUE; } @Override - public Long nextUp(Number value) { - return value.longValue() + 1; + public Long nextUp(Object value) { + return ((Number)value).longValue() + 1; } @Override - public Long nextDown(Number value) { - return value.longValue() - 1; + public Long nextDown(Object value) { + return ((Number)value).longValue() - 1; } @Override public Field getRangeField(String name, Range r) { - return new LongRange(name, new long[] {r.from.longValue()}, new long[] {r.to.longValue()}); + return new LongRange(name, new long[] {((Number)r.from).longValue()}, + new long[] {((Number)r.to).longValue()}); } @Override - public byte[] getBytes(Range r) { - byte[] b = new byte[Long.BYTES*2]; - long from = r.from == null ? Long.MIN_VALUE : r.from.longValue(); - long to = r.to == null ? Long.MAX_VALUE : r.to.longValue(); - NumericUtils.longToSortableBytes(from, b, 0); - NumericUtils.longToSortableBytes(to, b, Long.BYTES); - return b; - } - @Override - public Query withinQuery(String field, Number from, Number to, boolean includeFrom, boolean includeTo) { + public Query withinQuery(String field, Object from, Object to, boolean includeFrom, boolean includeTo) { return LongRange.newWithinQuery(field, new long[] {(Long)from + (includeFrom ? 0 : 1)}, new long[] {(Long)to - (includeTo ? 0 : 1)}); } @Override - public Query containsQuery(String field, Number from, Number to, boolean includeFrom, boolean includeTo) { + public Query containsQuery(String field, Object from, Object to, boolean includeFrom, boolean includeTo) { return LongRange.newContainsQuery(field, new long[] {(Long)from + (includeFrom ? 0 : 1)}, new long[] {(Long)to - (includeTo ? 0 : 1)}); } @Override - public Query intersectsQuery(String field, Number from, Number to, boolean includeFrom, boolean includeTo) { + public Query intersectsQuery(String field, Object from, Object to, boolean includeFrom, boolean includeTo) { return LongRange.newIntersectsQuery(field, new long[] {(Long)from + (includeFrom ? 0 : 1)}, new long[] {(Long)to - (includeTo ? 0 : 1)}); } }; + RangeType(String name) { + this.name = name; + this.numberType = null; + } + RangeType(String name, NumberType type) { this.name = name; this.numberType = type; @@ -694,7 +731,6 @@ public class RangeFieldMapper extends FieldMapper { return name; } - protected abstract byte[] getBytes(Range range); public abstract Field getRangeField(String name, Range range); public List createFields(String name, Range range, boolean indexed, boolean docValued, boolean stored) { assert range != null : "range cannot be null when creating fields"; @@ -709,29 +745,31 @@ public class RangeFieldMapper extends FieldMapper { return fields; } /** parses from value. rounds according to included flag */ - public Number parseFrom(RangeFieldType fieldType, XContentParser parser, boolean coerce, boolean included) throws IOException { + public Object parseFrom(RangeFieldType fieldType, XContentParser parser, boolean coerce, boolean included) throws IOException { Number value = numberType.parse(parser, coerce); - return included ? value : nextUp(value); + return included ? value : (Number)nextUp(value); } /** parses to value. rounds according to included flag */ - public Number parseTo(RangeFieldType fieldType, XContentParser parser, boolean coerce, boolean included) throws IOException { + public Object parseTo(RangeFieldType fieldType, XContentParser parser, boolean coerce, boolean included) throws IOException { Number value = numberType.parse(parser, coerce); - return included ? value : nextDown(value); + return included ? value : (Number)nextDown(value); } - public abstract Number minValue(); - public abstract Number maxValue(); - public abstract Number nextUp(Number value); - public abstract Number nextDown(Number value); - public abstract Query withinQuery(String field, Number from, Number to, boolean includeFrom, boolean includeTo); - public abstract Query containsQuery(String field, Number from, Number to, boolean includeFrom, boolean includeTo); - public abstract Query intersectsQuery(String field, Number from, Number to, boolean includeFrom, boolean includeTo); - + public abstract Object minValue(); + public abstract Object maxValue(); + public abstract Object nextUp(Object value); + public abstract Object nextDown(Object value); + public abstract Query withinQuery(String field, Object from, Object to, boolean includeFrom, boolean includeTo); + public abstract Query containsQuery(String field, Object from, Object to, boolean includeFrom, boolean includeTo); + public abstract Query intersectsQuery(String field, Object from, Object to, boolean includeFrom, boolean includeTo); + public Object parse(Object value, boolean coerce) { + return numberType.parse(value, coerce); + } public Query rangeQuery(String field, Object from, Object to, boolean includeFrom, boolean includeTo, ShapeRelation relation, @Nullable DateTimeZone timeZone, @Nullable DateMathParser dateMathParser, QueryShardContext context) { - Number lower = from == null ? minValue() : numberType.parse(from, false); - Number upper = to == null ? maxValue() : numberType.parse(to, false); + Object lower = from == null ? minValue() : parse(from, false); + Object upper = to == null ? maxValue() : parse(to, false); if (relation == ShapeRelation.WITHIN) { return withinQuery(field, lower, upper, includeFrom, includeTo); } else if (relation == ShapeRelation.CONTAINS) { @@ -747,12 +785,12 @@ public class RangeFieldMapper extends FieldMapper { /** Class defining a range */ public static class Range { RangeType type; - private Number from; - private Number to; + private Object from; + private Object to; private boolean includeFrom; private boolean includeTo; - public Range(RangeType type, Number from, Number to, boolean includeFrom, boolean includeTo) { + public Range(RangeType type, Object from, Object to, boolean includeFrom, boolean includeTo) { this.type = type; this.from = from; this.to = to; @@ -764,9 +802,11 @@ public class RangeFieldMapper extends FieldMapper { public String toString() { StringBuilder sb = new StringBuilder(); sb.append(includeFrom ? '[' : '('); - sb.append(includeFrom || from.equals(type.minValue()) ? from : type.nextDown(from)); - sb.append(':'); - sb.append(includeTo || to.equals(type.maxValue()) ? to : type.nextUp(to)); + Object f = includeFrom || from.equals(type.minValue()) ? from : type.nextDown(from); + Object t = includeTo || to.equals(type.maxValue()) ? to : type.nextUp(to); + sb.append(type == RangeType.IP ? InetAddresses.toAddrString((InetAddress)f) : f.toString()); + sb.append(" : "); + sb.append(type == RangeType.IP ? InetAddresses.toAddrString((InetAddress)t) : t.toString()); sb.append(includeTo ? ']' : ')'); return sb.toString(); } diff --git a/core/src/test/java/org/elasticsearch/index/mapper/RangeFieldMapperTests.java b/core/src/test/java/org/elasticsearch/index/mapper/RangeFieldMapperTests.java index 18a771bb467..a6fbfc44a56 100644 --- a/core/src/test/java/org/elasticsearch/index/mapper/RangeFieldMapperTests.java +++ b/core/src/test/java/org/elasticsearch/index/mapper/RangeFieldMapperTests.java @@ -18,14 +18,17 @@ */ package org.elasticsearch.index.mapper; +import org.apache.lucene.document.InetAddressPoint; import org.apache.lucene.index.IndexableField; import org.elasticsearch.common.compress.CompressedXContent; +import org.elasticsearch.common.network.InetAddresses; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentType; import java.io.IOException; +import java.net.InetAddress; import java.util.Arrays; import java.util.HashSet; import java.util.Locale; @@ -40,6 +43,8 @@ import static org.hamcrest.Matchers.containsString; public class RangeFieldMapperTests extends AbstractNumericFieldMapperTestCase { private static String FROM_DATE = "2016-10-31"; private static String TO_DATE = "2016-11-01 20:00:00"; + private static String FROM_IP = "::ffff:c0a8:107"; + private static String TO_IP = "2001:db8::"; private static int FROM = 5; private static String FROM_STR = FROM + ""; private static int TO = 10; @@ -48,12 +53,14 @@ public class RangeFieldMapperTests extends AbstractNumericFieldMapperTestCase { @Override protected void setTypeList() { - TYPES = new HashSet<>(Arrays.asList("date_range", "float_range", "double_range", "integer_range", "long_range")); + TYPES = new HashSet<>(Arrays.asList("date_range", "ip_range", "float_range", "double_range", "integer_range", "long_range")); } private Object getFrom(String type) { if (type.equals("date_range")) { return FROM_DATE; + } else if (type.equals("ip_range")) { + return FROM_IP; } return random().nextBoolean() ? FROM : FROM_STR; } @@ -69,13 +76,17 @@ public class RangeFieldMapperTests extends AbstractNumericFieldMapperTestCase { private Object getTo(String type) { if (type.equals("date_range")) { return TO_DATE; + } else if (type.equals("ip_range")) { + return TO_IP; } return random().nextBoolean() ? TO : TO_STR; } - private Number getMax(String type) { + private Object getMax(String type) { if (type.equals("date_range") || type.equals("long_range")) { return Long.MAX_VALUE; + } else if (type.equals("ip_range")) { + return InetAddressPoint.MAX_VALUE; } else if (type.equals("integer_range")) { return Integer.MAX_VALUE; } else if (type.equals("float_range")) { @@ -189,7 +200,14 @@ public class RangeFieldMapperTests extends AbstractNumericFieldMapperTestCase { assertEquals(2, pointField.fieldType().pointDimensionCount()); IndexableField storedField = fields[1]; assertTrue(storedField.fieldType().stored()); - assertThat(storedField.stringValue(), containsString(type.equals("date_range") ? "1477872000000" : "5")); + String strVal = "5"; + if (type.equals("date_range")) { + strVal = "1477872000000"; + } else if (type.equals("ip_range")) { + strVal = InetAddresses.toAddrString(InetAddresses.forString("192.168.1.7")) + " : " + + InetAddresses.toAddrString(InetAddresses.forString("2001:db8:0:0:0:0:0:0")); + } + assertThat(storedField.stringValue(), containsString(strVal)); } @Override @@ -234,7 +252,8 @@ public class RangeFieldMapperTests extends AbstractNumericFieldMapperTestCase { .endObject().bytes(), XContentType.JSON)); MapperParsingException e = expectThrows(MapperParsingException.class, runnable); - assertThat(e.getCause().getMessage(), anyOf(containsString("passed as String"), containsString("failed to parse date"))); + assertThat(e.getCause().getMessage(), anyOf(containsString("passed as String"), + containsString("failed to parse date"), containsString("is not an IP string literal"))); } @Override @@ -261,7 +280,8 @@ public class RangeFieldMapperTests extends AbstractNumericFieldMapperTestCase { assertEquals(2, doc.rootDoc().getFields("field").length); IndexableField[] fields = doc.rootDoc().getFields("field"); IndexableField storedField = fields[1]; - assertThat(storedField.stringValue(), containsString(type.equals("date_range") ? Long.MAX_VALUE+"" : getMax(type)+"")); + String expected = type.equals("ip_range") ? InetAddresses.toAddrString((InetAddress)getMax(type)) : getMax(type) +""; + assertThat(storedField.stringValue(), containsString(expected)); // test null max value doc = mapper.parse(SourceToParse.source("test", "type", "1", XContentFactory.jsonBuilder() @@ -280,8 +300,14 @@ public class RangeFieldMapperTests extends AbstractNumericFieldMapperTestCase { assertFalse(pointField.fieldType().stored()); storedField = fields[1]; assertTrue(storedField.fieldType().stored()); - assertThat(storedField.stringValue(), containsString(type.equals("date_range") ? "1477872000000" : "5")); - assertThat(storedField.stringValue(), containsString(getMax(type) + "")); + String strVal = "5"; + if (type.equals("date_range")) { + strVal = "1477872000000"; + } else if (type.equals("ip_range")) { + strVal = InetAddresses.toAddrString(InetAddresses.forString("192.168.1.7")) + " : " + + InetAddresses.toAddrString(InetAddresses.forString("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")); + } + assertThat(storedField.stringValue(), containsString(strVal)); } public void testNoBounds() throws Exception { @@ -316,8 +342,8 @@ public class RangeFieldMapperTests extends AbstractNumericFieldMapperTestCase { assertFalse(pointField.fieldType().stored()); IndexableField storedField = fields[1]; assertTrue(storedField.fieldType().stored()); - assertThat(storedField.stringValue(), containsString(type.equals("date_range") ? Long.MAX_VALUE+"" : getMax(type)+"")); - assertThat(storedField.stringValue(), containsString(getMax(type) + "")); + String expected = type.equals("ip_range") ? InetAddresses.toAddrString((InetAddress)getMax(type)) : getMax(type) +""; + assertThat(storedField.stringValue(), containsString(expected)); } public void testIllegalArguments() throws Exception { diff --git a/core/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java b/core/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java index b3d7db23c38..015509d4a73 100644 --- a/core/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java +++ b/core/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java @@ -21,6 +21,8 @@ package org.elasticsearch.index.mapper; import com.carrotsearch.randomizedtesting.generators.RandomPicks; import org.apache.lucene.document.DoubleRange; import org.apache.lucene.document.FloatRange; +import org.apache.lucene.document.InetAddressPoint; +import org.apache.lucene.document.InetAddressRange; import org.apache.lucene.document.IntRange; import org.apache.lucene.document.LongRange; import org.apache.lucene.index.IndexOptions; @@ -37,6 +39,7 @@ import org.elasticsearch.test.IndexSettingsModule; import org.joda.time.DateTime; import org.junit.Before; +import java.net.InetAddress; import java.util.Locale; public class RangeFieldTypeTests extends FieldTypeTestCase { @@ -100,6 +103,8 @@ public class RangeFieldTypeTests extends FieldTypeTestCase { return getLongRangeQuery(relation, (long)from, (long)to, includeLower, includeUpper); case DOUBLE: return getDoubleRangeQuery(relation, (double)from, (double)to, includeLower, includeUpper); + case IP: + return getInetAddressRangeQuery(relation, (InetAddress)from, (InetAddress)to, includeLower, includeUpper); default: return getFloatRangeQuery(relation, (float)from, (float)to, includeLower, includeUpper); } @@ -142,7 +147,8 @@ public class RangeFieldTypeTests extends FieldTypeTestCase { return FloatRange.newIntersectsQuery(FIELDNAME, lower, upper); } - private Query getDoubleRangeQuery(ShapeRelation relation, double from, double to, boolean includeLower, boolean includeUpper) { + private Query getDoubleRangeQuery(ShapeRelation relation, double from, double to, boolean includeLower, + boolean includeUpper) { double[] lower = new double[] {includeLower ? from : Math.nextUp(from)}; double[] upper = new double[] {includeUpper ? to : Math.nextDown(to)}; if (relation == ShapeRelation.WITHIN) { @@ -153,7 +159,19 @@ public class RangeFieldTypeTests extends FieldTypeTestCase { return DoubleRange.newIntersectsQuery(FIELDNAME, lower, upper); } - private Object nextFrom() { + private Query getInetAddressRangeQuery(ShapeRelation relation, InetAddress from, InetAddress to, boolean includeLower, + boolean includeUpper) { + InetAddress lower = includeLower ? from : InetAddressPoint.nextUp(from); + InetAddress upper = includeUpper ? to : InetAddressPoint.nextDown(to); + if (relation == ShapeRelation.WITHIN) { + return InetAddressRange.newWithinQuery(FIELDNAME, lower, upper); + } else if (relation == ShapeRelation.CONTAINS) { + return InetAddressRange.newContainsQuery(FIELDNAME, lower, upper); + } + return InetAddressRange.newIntersectsQuery(FIELDNAME, lower, upper); + } + + private Object nextFrom() throws Exception { switch (type) { case INTEGER: return (int)(random().nextInt() * 0.5 - DISTANCE); @@ -163,12 +181,14 @@ public class RangeFieldTypeTests extends FieldTypeTestCase { return (long)(random().nextLong() * 0.5 - DISTANCE); case FLOAT: return (float)(random().nextFloat() * 0.5 - DISTANCE); + case IP: + return InetAddress.getByName("::ffff:c0a8:107"); default: return random().nextDouble() * 0.5 - DISTANCE; } } - private Object nextTo(Object from) { + private Object nextTo(Object from) throws Exception { switch (type) { case INTEGER: return (Integer)from + DISTANCE; @@ -178,6 +198,8 @@ public class RangeFieldTypeTests extends FieldTypeTestCase { return (Long)from + DISTANCE; case DOUBLE: return (Double)from + DISTANCE; + case IP: + return InetAddress.getByName("2001:db8::"); default: return (Float)from + DISTANCE; } diff --git a/docs/reference/mapping/types/range.asciidoc b/docs/reference/mapping/types/range.asciidoc index d4bf76b0cef..4ac7ec03f61 100644 --- a/docs/reference/mapping/types/range.asciidoc +++ b/docs/reference/mapping/types/range.asciidoc @@ -9,6 +9,8 @@ The following range types are supported: `long_range`:: A range of signed 64-bit integers with a minimum value of +-2^63^+ and maximum of +2^63^-1+. `double_range`:: A range of double-precision 64-bit IEEE 754 floating point values. `date_range`:: A range of date values represented as unsigned 64-bit integer milliseconds elapsed since system epoch. +`ip_range` :: A range of ip values supporting either https://en.wikipedia.org/wiki/IPv4[IPv4] or + https://en.wikipedia.org/wiki/IPv6[IPv6] (or mixed) addresses. Below is an example of configuring a mapping with various range fields followed by an example that indexes several range types. diff --git a/docs/reference/release-notes/6.0.0-alpha1.asciidoc b/docs/reference/release-notes/6.0.0-alpha1.asciidoc index d66d3ba0ed1..3af5dc49df8 100644 --- a/docs/reference/release-notes/6.0.0-alpha1.asciidoc +++ b/docs/reference/release-notes/6.0.0-alpha1.asciidoc @@ -147,6 +147,7 @@ Internal:: Core:: * Enable index-time sorting {pull}24055[#24055] (issue: {issue}6720[#6720]) +* Add new ip_range field type {pull}24433[#24433] From 0b36fb052c10eea5b248bfab71e5caffaf51ef92 Mon Sep 17 00:00:00 2001 From: Anupam Date: Fri, 5 May 2017 21:03:32 +0530 Subject: [PATCH 43/44] Update completion-suggest.asciidoc (#24506) --- docs/reference/search/suggesters/completion-suggest.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/search/suggesters/completion-suggest.asciidoc b/docs/reference/search/suggesters/completion-suggest.asciidoc index 6bf17a4ac39..3f21a18de72 100644 --- a/docs/reference/search/suggesters/completion-suggest.asciidoc +++ b/docs/reference/search/suggesters/completion-suggest.asciidoc @@ -130,7 +130,7 @@ PUT music/song/1?refresh // TEST[continued] You can use the following shorthand form. Note that you can not specify -a weight with suggestion(s). +a weight with suggestion(s) in the shorthand form. [source,js] -------------------------------------------------- From 7bd2abe48af5a651b54bcd5bcb41c88e29390be0 Mon Sep 17 00:00:00 2001 From: Tanguy Leroux Date: Fri, 5 May 2017 20:00:39 +0200 Subject: [PATCH 44/44] Change Terms.Bucket to an interface (#24492) This commit changes the Terms.Bucket abstract class to an interface, so that it's easier for the Java High Level Rest Client to provide its own implementation. In its current state, the Terms.Bucket abstract class inherits from InternalMultiBucketAggregation.InternalBucket which forces subclasses to implement Writeable and exposes a public getProperty() method that relies on InternalAggregation. This two points make it difficult for the Java High Level Rest Client to implement the Terms and Terms.Bucket correctly. This is also different from other MultiBucketsAggregation like Range which are pure interfaces. Changing Terms.Bucket to an interface causes a method clashes for the `getBuckets()` method in InternalTerms. This is because: - InternalTerms implements Terms which declared a `List getBuckets()` method - InternalTerms extends InternalMultiBucketAggregation which declares a `List getBuckets()` method - both overrides the MultiBucketsAggregation `List getBuckets()` method There was no clashes before this change because Terms.Bucket extends InternalBucket and conformed to both declaration. With Terms.Bucket now an interface, the getBuckets() method in the Terms interface is changed to avoid method clash. This is a breaking change in the Java API but it's a straightforward change and the Terms multi bucket aggregation interface is also more coherent with the other Range, Histogram, Filters, AdjacencyMatrix etc that all return a `List`. --- .../bucket/terms/DoubleTerms.java | 2 +- .../GlobalOrdinalsStringTermsAggregator.java | 2 +- .../bucket/terms/InternalMappedTerms.java | 3 +- .../bucket/terms/InternalTerms.java | 16 +++----- .../aggregations/bucket/terms/LongTerms.java | 4 +- .../bucket/terms/StringTerms.java | 2 +- .../aggregations/bucket/terms/Terms.java | 38 +++---------------- .../bucket/terms/UnmappedTerms.java | 2 +- .../search/aggregations/CombiIT.java | 4 +- .../search/aggregations/EquivalenceIT.java | 6 +-- .../bucket/DiversifiedSamplerIT.java | 11 +++--- .../aggregations/bucket/DoubleTermsIT.java | 4 +- .../aggregations/bucket/LongTermsIT.java | 4 +- .../aggregations/bucket/MinDocCountIT.java | 4 +- .../search/aggregations/bucket/SamplerIT.java | 5 ++- .../aggregations/bucket/ShardSizeTermsIT.java | 32 ++++++++-------- .../SignificantTermsSignificanceScoreIT.java | 2 +- .../aggregations/bucket/StringTermsIT.java | 8 ++-- .../bucket/TermsDocCountErrorIT.java | 10 ++--- .../bucket/terms/TermsAggregatorTests.java | 2 +- .../search/aggregations/metrics/AvgIT.java | 2 +- .../aggregations/metrics/ExtendedStatsIT.java | 2 +- .../aggregations/metrics/GeoBoundsIT.java | 2 +- .../metrics/HDRPercentileRanksIT.java | 2 +- .../metrics/HDRPercentilesIT.java | 2 +- .../search/aggregations/metrics/MaxIT.java | 2 +- .../search/aggregations/metrics/MinIT.java | 2 +- .../search/aggregations/metrics/StatsIT.java | 2 +- .../search/aggregations/metrics/SumIT.java | 2 +- .../metrics/TDigestPercentileRanksIT.java | 2 +- .../metrics/TDigestPercentilesIT.java | 2 +- .../aggregations/metrics/TopHitsIT.java | 8 ++-- .../aggregations/pipeline/AvgBucketIT.java | 12 +++--- .../pipeline/ExtendedStatsBucketIT.java | 12 +++--- .../aggregations/pipeline/MaxBucketIT.java | 12 +++--- .../aggregations/pipeline/MinBucketIT.java | 12 +++--- .../pipeline/PercentilesBucketIT.java | 18 ++++----- .../aggregations/pipeline/StatsBucketIT.java | 12 +++--- .../aggregations/pipeline/SumBucketIT.java | 12 +++--- 39 files changed, 125 insertions(+), 156 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/DoubleTerms.java b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/DoubleTerms.java index ae18cb59d95..e4c7906f215 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/DoubleTerms.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/DoubleTerms.java @@ -76,7 +76,7 @@ public class DoubleTerms extends InternalMappedTerms, B exten } @Override - public List getBucketsInternal() { + public List getBuckets() { return buckets; } diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/InternalTerms.java b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/InternalTerms.java index 0fb4ceea33a..3834f9a65be 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/InternalTerms.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/InternalTerms.java @@ -40,15 +40,13 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import static java.util.Collections.unmodifiableList; - public abstract class InternalTerms, B extends InternalTerms.Bucket> extends InternalMultiBucketAggregation implements Terms, ToXContent { protected static final ParseField DOC_COUNT_ERROR_UPPER_BOUND_FIELD_NAME = new ParseField("doc_count_error_upper_bound"); protected static final ParseField SUM_OF_OTHER_DOC_COUNTS = new ParseField("sum_other_doc_count"); - public abstract static class Bucket> extends Terms.Bucket { + public abstract static class Bucket> extends InternalMultiBucketAggregation.InternalBucket implements Terms.Bucket { /** * Reads a bucket. Should be a constructor reference. @@ -212,11 +210,7 @@ public abstract class InternalTerms, B extends Int protected abstract void writeTermTypeInfoTo(StreamOutput out) throws IOException; @Override - public final List getBuckets() { - return unmodifiableList(getBucketsInternal()); - } - - protected abstract List getBucketsInternal(); + public abstract List getBuckets(); @Override public abstract B getBucketByKey(String term); @@ -244,7 +238,7 @@ public abstract class InternalTerms, B extends Int } otherDocCount += terms.getSumOfOtherDocCounts(); final long thisAggDocCountError; - if (terms.getBucketsInternal().size() < getShardSize() || InternalOrder.isTermOrder(order)) { + if (terms.getBuckets().size() < getShardSize() || InternalOrder.isTermOrder(order)) { thisAggDocCountError = 0; } else if (InternalOrder.isCountDesc(this.order)) { if (terms.getDocCountError() > 0) { @@ -254,7 +248,7 @@ public abstract class InternalTerms, B extends Int } else { // otherwise use the doc count of the last term in the // aggregation - thisAggDocCountError = terms.getBucketsInternal().get(terms.getBucketsInternal().size() - 1).docCount; + thisAggDocCountError = terms.getBuckets().get(terms.getBuckets().size() - 1).docCount; } } else { thisAggDocCountError = -1; @@ -267,7 +261,7 @@ public abstract class InternalTerms, B extends Int } } setDocCountError(thisAggDocCountError); - for (B bucket : terms.getBucketsInternal()) { + for (B bucket : terms.getBuckets()) { // If there is already a doc count error for this bucket // subtract this aggs doc count error from it to make the // new value for the bucket. This then means that when the diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/LongTerms.java b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/LongTerms.java index 98aa4825ee7..0de13a4d98f 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/LongTerms.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/LongTerms.java @@ -76,7 +76,7 @@ public class LongTerms extends InternalMappedTerms } @Override - int compareTerm(Terms.Bucket other) { + public int compareTerm(Terms.Bucket other) { return Long.compare(term, ((Number) other.getKey()).longValue()); } @@ -161,7 +161,7 @@ public class LongTerms extends InternalMappedTerms * Converts a {@link LongTerms} into a {@link DoubleTerms}, returning the value of the specified long terms as doubles. */ static DoubleTerms convertLongTermsToDouble(LongTerms longTerms, DocValueFormat decimalFormat) { - List buckets = longTerms.getBuckets(); + List buckets = longTerms.getBuckets(); List newBuckets = new ArrayList<>(); for (Terms.Bucket bucket : buckets) { newBuckets.add(new DoubleTerms.Bucket(bucket.getKeyAsNumber().doubleValue(), diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/StringTerms.java b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/StringTerms.java index b48c443fac9..049d996c08c 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/StringTerms.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/StringTerms.java @@ -75,7 +75,7 @@ public class StringTerms extends InternalMappedTerms getBuckets(); + List getBuckets(); /** * Get the bucket for the given term, or null if there is no such bucket. diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/UnmappedTerms.java b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/UnmappedTerms.java index bdc95b2e87e..40cbacd37e6 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/UnmappedTerms.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/UnmappedTerms.java @@ -127,7 +127,7 @@ public class UnmappedTerms extends InternalTerms getBucketsInternal() { + public List getBuckets() { return emptyList(); } diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/CombiIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/CombiIT.java index 7517e98ff27..c38552ae254 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/CombiIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/CombiIT.java @@ -30,7 +30,7 @@ import org.elasticsearch.search.aggregations.bucket.terms.Terms; import org.elasticsearch.test.ESIntegTestCase; import org.hamcrest.Matchers; -import java.util.Collection; +import java.util.List; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.search.aggregations.AggregationBuilders.histogram; @@ -95,7 +95,7 @@ public class CombiIT extends ESIntegTestCase { Terms terms = aggs.get("values"); assertNotNull(terms); - Collection buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(values.size())); for (Terms.Bucket bucket : buckets) { values.remove(((Number) bucket.getKey()).intValue()); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/EquivalenceIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/EquivalenceIT.java index 00f82dfbe44..6c08c169724 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/EquivalenceIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/EquivalenceIT.java @@ -485,10 +485,10 @@ public class EquivalenceIT extends ESIntegTestCase { } private void assertEquals(Terms t1, Terms t2) { - List t1Buckets = t1.getBuckets(); - List t2Buckets = t1.getBuckets(); + List t1Buckets = t1.getBuckets(); + List t2Buckets = t1.getBuckets(); assertEquals(t1Buckets.size(), t2Buckets.size()); - for (Iterator it1 = t1Buckets.iterator(), it2 = t2Buckets.iterator(); it1.hasNext(); ) { + for (Iterator it1 = t1Buckets.iterator(), it2 = t2Buckets.iterator(); it1.hasNext(); ) { final Terms.Bucket b1 = it1.next(); final Terms.Bucket b2 = it2.next(); assertEquals(b1.getDocCount(), b2.getDocCount()); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/DiversifiedSamplerIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/DiversifiedSamplerIT.java index 9af28806fef..c8803b7e790 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/DiversifiedSamplerIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/DiversifiedSamplerIT.java @@ -32,6 +32,7 @@ import org.elasticsearch.search.aggregations.metrics.max.Max; import org.elasticsearch.test.ESIntegTestCase; import java.util.Collection; +import java.util.List; import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS; import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_SHARDS; @@ -108,7 +109,7 @@ public class DiversifiedSamplerIT extends ESIntegTestCase { ).execute().actionGet(); assertSearchResponse(response); Terms genres = response.getAggregations().get("genres"); - Collection genreBuckets = genres.getBuckets(); + Collection genreBuckets = genres.getBuckets(); // For this test to be useful we need >1 genre bucket to compare assertThat(genreBuckets.size(), greaterThan(1)); double lastMaxPrice = asc ? Double.MIN_VALUE : Double.MAX_VALUE; @@ -141,7 +142,7 @@ public class DiversifiedSamplerIT extends ESIntegTestCase { assertSearchResponse(response); Sampler sample = response.getAggregations().get("sample"); Terms authors = sample.getAggregations().get("authors"); - Collection testBuckets = authors.getBuckets(); + List testBuckets = authors.getBuckets(); for (Terms.Bucket testBucket : testBuckets) { assertThat(testBucket.getDocCount(), lessThanOrEqualTo((long) NUM_SHARDS * MAX_DOCS_PER_AUTHOR)); @@ -162,11 +163,11 @@ public class DiversifiedSamplerIT extends ESIntegTestCase { .addAggregation(rootTerms).execute().actionGet(); assertSearchResponse(response); Terms genres = response.getAggregations().get("genres"); - Collection genreBuckets = genres.getBuckets(); + List genreBuckets = genres.getBuckets(); for (Terms.Bucket genreBucket : genreBuckets) { Sampler sample = genreBucket.getAggregations().get("sample"); Terms authors = sample.getAggregations().get("authors"); - Collection testBuckets = authors.getBuckets(); + List testBuckets = authors.getBuckets(); for (Terms.Bucket testBucket : testBuckets) { assertThat(testBucket.getDocCount(), lessThanOrEqualTo((long) NUM_SHARDS * MAX_DOCS_PER_AUTHOR)); @@ -195,7 +196,7 @@ public class DiversifiedSamplerIT extends ESIntegTestCase { Sampler sample = genreSample.getAggregations().get("sample"); Terms genres = sample.getAggregations().get("genres"); - Collection testBuckets = genres.getBuckets(); + List testBuckets = genres.getBuckets(); for (Terms.Bucket testBucket : testBuckets) { assertThat(testBucket.getDocCount(), lessThanOrEqualTo((long) NUM_SHARDS * MAX_DOCS_PER_GENRE)); } diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/DoubleTermsIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/DoubleTermsIT.java index cf28541121c..ca106721fcc 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/DoubleTermsIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/DoubleTermsIT.java @@ -842,7 +842,7 @@ public class DoubleTermsIT extends AbstractTermsTestCase { assertThat(tags.getName(), equalTo("num_tags")); assertThat(tags.getBuckets().size(), equalTo(2)); - Iterator iters = tags.getBuckets().iterator(); + Iterator iters = tags.getBuckets().iterator(); Terms.Bucket tag = iters.next(); assertThat(tag, notNullValue()); @@ -883,7 +883,7 @@ public class DoubleTermsIT extends AbstractTermsTestCase { assertThat(tags.getName(), equalTo("tags")); assertThat(tags.getBuckets().size(), equalTo(2)); - Iterator iters = tags.getBuckets().iterator(); + Iterator iters = tags.getBuckets().iterator(); // the max for "1" is 2 // the max for "0" is 4 diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/LongTermsIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/LongTermsIT.java index 6793768a91f..a54dc3e2f5e 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/LongTermsIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/LongTermsIT.java @@ -854,7 +854,7 @@ public class LongTermsIT extends AbstractTermsTestCase { assertThat(tags.getName(), equalTo("num_tags")); assertThat(tags.getBuckets().size(), equalTo(2)); - Iterator iters = tags.getBuckets().iterator(); + Iterator iters = tags.getBuckets().iterator(); Terms.Bucket tag = iters.next(); assertThat(tag, notNullValue()); @@ -893,7 +893,7 @@ public class LongTermsIT extends AbstractTermsTestCase { assertThat(tags.getName(), equalTo("tags")); assertThat(tags.getBuckets().size(), equalTo(2)); - Iterator iters = tags.getBuckets().iterator(); + Iterator iters = tags.getBuckets().iterator(); // the max for "1" is 2 // the max for "0" is 4 diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/MinDocCountIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/MinDocCountIT.java index 7307b756e3f..e1e8f1ba660 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/MinDocCountIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/MinDocCountIT.java @@ -161,8 +161,8 @@ public class MinDocCountIT extends AbstractTermsTestCase { // check that terms2 is a subset of terms1 private void assertSubset(Terms terms1, Terms terms2, long minDocCount, int size, String include) { final Matcher matcher = include == null ? null : Pattern.compile(include).matcher("");; - final Iterator it1 = terms1.getBuckets().iterator(); - final Iterator it2 = terms2.getBuckets().iterator(); + final Iterator it1 = terms1.getBuckets().iterator(); + final Iterator it2 = terms2.getBuckets().iterator(); int size2 = 0; while (it1.hasNext()) { final Terms.Bucket bucket1 = it1.next(); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/SamplerIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/SamplerIT.java index f87b98bc878..ebd078de674 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/SamplerIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/SamplerIT.java @@ -31,6 +31,7 @@ import org.elasticsearch.search.aggregations.metrics.max.Max; import org.elasticsearch.test.ESIntegTestCase; import java.util.Collection; +import java.util.List; import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS; import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_SHARDS; @@ -104,7 +105,7 @@ public class SamplerIT extends ESIntegTestCase { ).execute().actionGet(); assertSearchResponse(response); Terms genres = response.getAggregations().get("genres"); - Collection genreBuckets = genres.getBuckets(); + List genreBuckets = genres.getBuckets(); // For this test to be useful we need >1 genre bucket to compare assertThat(genreBuckets.size(), greaterThan(1)); double lastMaxPrice = asc ? Double.MIN_VALUE : Double.MAX_VALUE; @@ -130,7 +131,7 @@ public class SamplerIT extends ESIntegTestCase { assertSearchResponse(response); Sampler sample = response.getAggregations().get("sample"); Terms authors = sample.getAggregations().get("authors"); - Collection testBuckets = authors.getBuckets(); + List testBuckets = authors.getBuckets(); long maxBooksPerAuthor = 0; for (Terms.Bucket testBucket : testBuckets) { diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/ShardSizeTermsIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/ShardSizeTermsIT.java index ecc16b85f13..748c5f886f6 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/ShardSizeTermsIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/ShardSizeTermsIT.java @@ -22,8 +22,8 @@ import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.search.aggregations.Aggregator.SubAggCollectionMode; import org.elasticsearch.search.aggregations.bucket.terms.Terms; -import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; @@ -43,7 +43,7 @@ public class ShardSizeTermsIT extends ShardSizeTestCase { .execute().actionGet(); Terms terms = response.getAggregations().get("keys"); - Collection buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(3)); Map expected = new HashMap<>(); expected.put("1", 8L); @@ -66,7 +66,7 @@ public class ShardSizeTermsIT extends ShardSizeTestCase { .execute().actionGet(); Terms terms = response.getAggregations().get("keys"); - Collection buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(3)); Map expected = new HashMap<>(); expected.put("1", 8L); @@ -90,7 +90,7 @@ public class ShardSizeTermsIT extends ShardSizeTestCase { .execute().actionGet(); Terms terms = response.getAggregations().get("keys"); - Collection buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(3)); // we still only return 3 entries (based on the 'size' param) Map expected = new HashMap<>(); expected.put("1", 8L); @@ -114,7 +114,7 @@ public class ShardSizeTermsIT extends ShardSizeTestCase { .execute().actionGet(); Terms terms = response.getAggregations().get("keys"); - Collection buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(3)); // we still only return 3 entries (based on the 'size' param) Map expected = new HashMap<>(); expected.put("1", 5L); @@ -137,7 +137,7 @@ public class ShardSizeTermsIT extends ShardSizeTestCase { .execute().actionGet(); Terms terms = response.getAggregations().get("keys"); - Collection buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(3)); Map expected = new HashMap<>(); expected.put("1", 8L); @@ -160,7 +160,7 @@ public class ShardSizeTermsIT extends ShardSizeTestCase { .execute().actionGet(); Terms terms = response.getAggregations().get("keys"); - Collection buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(3)); Map expected = new HashMap<>(); expected.put(1, 8L); @@ -183,7 +183,7 @@ public class ShardSizeTermsIT extends ShardSizeTestCase { .execute().actionGet(); Terms terms = response.getAggregations().get("keys"); - Collection buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(3)); Map expected = new HashMap<>(); expected.put(1, 8L); @@ -206,7 +206,7 @@ public class ShardSizeTermsIT extends ShardSizeTestCase { .execute().actionGet(); Terms terms = response.getAggregations().get("keys"); - Collection buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(3)); // we still only return 3 entries (based on the 'size' param) Map expected = new HashMap<>(); expected.put(1, 8L); @@ -230,7 +230,7 @@ public class ShardSizeTermsIT extends ShardSizeTestCase { .execute().actionGet(); Terms terms = response.getAggregations().get("keys"); - Collection buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(3)); // we still only return 3 entries (based on the 'size' param) Map expected = new HashMap<>(); expected.put(1, 5L); @@ -253,7 +253,7 @@ public class ShardSizeTermsIT extends ShardSizeTestCase { .execute().actionGet(); Terms terms = response.getAggregations().get("keys"); - Collection buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(3)); Map expected = new HashMap<>(); expected.put(1, 8L); @@ -276,7 +276,7 @@ public class ShardSizeTermsIT extends ShardSizeTestCase { .execute().actionGet(); Terms terms = response.getAggregations().get("keys"); - Collection buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(3)); Map expected = new HashMap<>(); expected.put(1, 8L); @@ -299,7 +299,7 @@ public class ShardSizeTermsIT extends ShardSizeTestCase { .execute().actionGet(); Terms terms = response.getAggregations().get("keys"); - Collection buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(3)); Map expected = new HashMap<>(); expected.put(1, 8L); @@ -322,7 +322,7 @@ public class ShardSizeTermsIT extends ShardSizeTestCase { .execute().actionGet(); Terms terms = response.getAggregations().get("keys"); - Collection buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(3)); Map expected = new HashMap<>(); expected.put(1, 8L); @@ -345,7 +345,7 @@ public class ShardSizeTermsIT extends ShardSizeTestCase { .execute().actionGet(); Terms terms = response.getAggregations().get("keys"); - Collection buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(3)); Map expected = new HashMap<>(); expected.put(1, 5L); @@ -368,7 +368,7 @@ public class ShardSizeTermsIT extends ShardSizeTestCase { .execute().actionGet(); Terms terms = response.getAggregations().get("keys"); - Collection buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(3)); Map expected = new HashMap<>(); expected.put(1, 8L); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/SignificantTermsSignificanceScoreIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/SignificantTermsSignificanceScoreIT.java index 7fc20908e81..09cec9a458f 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/SignificantTermsSignificanceScoreIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/SignificantTermsSignificanceScoreIT.java @@ -438,7 +438,7 @@ public class SignificantTermsSignificanceScoreIT extends ESIntegTestCase { assertSearchResponse(response); StringTerms classes = response.getAggregations().get("class"); assertThat(classes.getBuckets().size(), equalTo(2)); - Iterator classBuckets = classes.getBuckets().iterator(); + Iterator classBuckets = classes.getBuckets().iterator(); Aggregations aggregations = classBuckets.next().getAggregations(); SignificantTerms sigTerms = aggregations.get("mySignificantTerms"); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/StringTermsIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/StringTermsIT.java index b5dbcd9085a..df69cfcfa93 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/StringTermsIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/StringTermsIT.java @@ -1012,7 +1012,7 @@ public class StringTermsIT extends AbstractTermsTestCase { assertThat(tags.getName(), equalTo("tags")); assertThat(tags.getBuckets().size(), equalTo(2)); - Iterator iters = tags.getBuckets().iterator(); + Iterator iters = tags.getBuckets().iterator(); Terms.Bucket tag = iters.next(); assertThat(tag, notNullValue()); @@ -1054,7 +1054,7 @@ public class StringTermsIT extends AbstractTermsTestCase { assertThat(tags.getName(), equalTo("tags")); assertThat(tags.getBuckets().size(), equalTo(2)); - Iterator iters = tags.getBuckets().iterator(); + Iterator iters = tags.getBuckets().iterator(); // the max for "more" is 2 // the max for "less" is 4 @@ -1117,7 +1117,7 @@ public class StringTermsIT extends AbstractTermsTestCase { assertThat(tags.getName(), equalTo("tags")); assertThat(tags.getBuckets().size(), equalTo(2)); - Iterator iters = tags.getBuckets().iterator(); + Iterator iters = tags.getBuckets().iterator(); // the max for "more" is 2 // the max for "less" is 4 @@ -1180,7 +1180,7 @@ public class StringTermsIT extends AbstractTermsTestCase { assertThat(tags.getName(), equalTo("tags")); assertThat(tags.getBuckets().size(), equalTo(2)); - Iterator iters = tags.getBuckets().iterator(); + Iterator iters = tags.getBuckets().iterator(); // the max for "more" is 2 // the max for "less" is 4 diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/TermsDocCountErrorIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/TermsDocCountErrorIT.java index 9d5ca3afc54..9ed32ca2e7b 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/TermsDocCountErrorIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/TermsDocCountErrorIT.java @@ -177,7 +177,7 @@ public class TermsDocCountErrorIT extends ESIntegTestCase { assertThat(testTerms, notNullValue()); assertThat(testTerms.getName(), equalTo("terms")); assertThat(testTerms.getDocCountError(), greaterThanOrEqualTo(0L)); - Collection testBuckets = testTerms.getBuckets(); + List testBuckets = testTerms.getBuckets(); assertThat(testBuckets.size(), lessThanOrEqualTo(size)); assertThat(accurateTerms.getBuckets().size(), greaterThanOrEqualTo(testBuckets.size())); @@ -211,7 +211,7 @@ public class TermsDocCountErrorIT extends ESIntegTestCase { assertThat(testTerms, notNullValue()); assertThat(testTerms.getName(), equalTo("terms")); assertThat(testTerms.getDocCountError(), equalTo(0L)); - Collection testBuckets = testTerms.getBuckets(); + List testBuckets = testTerms.getBuckets(); assertThat(testBuckets.size(), lessThanOrEqualTo(size)); assertThat(accurateTerms.getBuckets().size(), greaterThanOrEqualTo(testBuckets.size())); @@ -229,7 +229,7 @@ public class TermsDocCountErrorIT extends ESIntegTestCase { assertThat(testTerms, notNullValue()); assertThat(testTerms.getName(), equalTo("terms")); assertThat(testTerms.getDocCountError(), equalTo(0L)); - Collection testBuckets = testTerms.getBuckets(); + List testBuckets = testTerms.getBuckets(); assertThat(testBuckets.size(), lessThanOrEqualTo(size)); for (Terms.Bucket testBucket : testBuckets) { @@ -248,7 +248,7 @@ public class TermsDocCountErrorIT extends ESIntegTestCase { assertThat(testTerms, notNullValue()); assertThat(testTerms.getName(), equalTo("terms")); assertThat(testTerms.getDocCountError(),anyOf(equalTo(-1L), equalTo(0L))); - Collection testBuckets = testTerms.getBuckets(); + List testBuckets = testTerms.getBuckets(); assertThat(testBuckets.size(), lessThanOrEqualTo(size)); assertThat(accurateTerms.getBuckets().size(), greaterThanOrEqualTo(testBuckets.size())); @@ -988,7 +988,7 @@ public class TermsDocCountErrorIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getDocCountError(), equalTo(46L)); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets, notNullValue()); assertThat(buckets.size(), equalTo(5)); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/terms/TermsAggregatorTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/terms/TermsAggregatorTests.java index f2977fd7692..1648d8ede9f 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/terms/TermsAggregatorTests.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/terms/TermsAggregatorTests.java @@ -136,7 +136,7 @@ public class TermsAggregatorTests extends AggregatorTestCase { InternalAggregation mergedAggs = internalAgg.doReduce(aggs, ctx); assertTrue(mergedAggs instanceof DoubleTerms); long expected = numLongs + numDoubles; - List buckets = ((DoubleTerms) mergedAggs).getBuckets(); + List buckets = ((DoubleTerms) mergedAggs).getBuckets(); assertEquals(4, buckets.size()); assertEquals("1.0", buckets.get(0).getKeyAsString()); assertEquals(expected, buckets.get(0).getDocCount()); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/AvgIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/AvgIT.java index 2e2aa9657d8..b7739d6c816 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/AvgIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/AvgIT.java @@ -334,7 +334,7 @@ public class AvgIT extends AbstractNumericTestCase { Terms terms = searchResponse.getAggregations().get("terms"); assertThat(terms, notNullValue()); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets, notNullValue()); assertThat(buckets.size(), equalTo(10)); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/ExtendedStatsIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/ExtendedStatsIT.java index 7de7bb0f315..3903dd8b0bc 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/ExtendedStatsIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/ExtendedStatsIT.java @@ -604,7 +604,7 @@ public class ExtendedStatsIT extends AbstractNumericTestCase { Terms terms = searchResponse.getAggregations().get("terms"); assertThat(terms, notNullValue()); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets, notNullValue()); assertThat(buckets.size(), equalTo(10)); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/GeoBoundsIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/GeoBoundsIT.java index e4444571a31..1a97cb49164 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/GeoBoundsIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/GeoBoundsIT.java @@ -233,7 +233,7 @@ public class GeoBoundsIT extends AbstractGeoTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(10)); for (int i = 0; i < 10; i++) { Bucket bucket = buckets.get(i); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/HDRPercentileRanksIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/HDRPercentileRanksIT.java index 0aef20bca6d..5b56e6b7efb 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/HDRPercentileRanksIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/HDRPercentileRanksIT.java @@ -515,7 +515,7 @@ public class HDRPercentileRanksIT extends AbstractNumericTestCase { Terms terms = searchResponse.getAggregations().get("terms"); assertThat(terms, notNullValue()); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets, notNullValue()); assertThat(buckets.size(), equalTo(10)); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/HDRPercentilesIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/HDRPercentilesIT.java index d3531da9250..56fb14402ad 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/HDRPercentilesIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/HDRPercentilesIT.java @@ -506,7 +506,7 @@ public class HDRPercentilesIT extends AbstractNumericTestCase { Terms terms = searchResponse.getAggregations().get("terms"); assertThat(terms, notNullValue()); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets, notNullValue()); assertThat(buckets.size(), equalTo(10)); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/MaxIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/MaxIT.java index 5c9e14c3453..03eb9a09237 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/MaxIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/MaxIT.java @@ -336,7 +336,7 @@ public class MaxIT extends AbstractNumericTestCase { Terms terms = searchResponse.getAggregations().get("terms"); assertThat(terms, notNullValue()); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets, notNullValue()); assertThat(buckets.size(), equalTo(10)); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/MinIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/MinIT.java index 2b517b64fa1..cba2ba9eb97 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/MinIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/MinIT.java @@ -348,7 +348,7 @@ public class MinIT extends AbstractNumericTestCase { Terms terms = searchResponse.getAggregations().get("terms"); assertThat(terms, notNullValue()); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets, notNullValue()); assertThat(buckets.size(), equalTo(10)); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/StatsIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/StatsIT.java index 85db6166307..9231f093963 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/StatsIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/StatsIT.java @@ -455,7 +455,7 @@ public class StatsIT extends AbstractNumericTestCase { Terms terms = searchResponse.getAggregations().get("terms"); assertThat(terms, notNullValue()); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets, notNullValue()); assertThat(buckets.size(), equalTo(10)); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/SumIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/SumIT.java index 1591e6df931..16d345c7b84 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/SumIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/SumIT.java @@ -333,7 +333,7 @@ public class SumIT extends AbstractNumericTestCase { Terms terms = searchResponse.getAggregations().get("terms"); assertThat(terms, notNullValue()); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets, notNullValue()); assertThat(buckets.size(), equalTo(10)); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/TDigestPercentileRanksIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/TDigestPercentileRanksIT.java index 057731e275a..f1943747ceb 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/TDigestPercentileRanksIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/TDigestPercentileRanksIT.java @@ -466,7 +466,7 @@ public class TDigestPercentileRanksIT extends AbstractNumericTestCase { Terms terms = searchResponse.getAggregations().get("terms"); assertThat(terms, notNullValue()); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets, notNullValue()); assertThat(buckets.size(), equalTo(10)); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/TDigestPercentilesIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/TDigestPercentilesIT.java index d81ca004b97..2589e9977a6 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/TDigestPercentilesIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/TDigestPercentilesIT.java @@ -451,7 +451,7 @@ public class TDigestPercentilesIT extends AbstractNumericTestCase { Terms terms = searchResponse.getAggregations().get("terms"); assertThat(terms, notNullValue()); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets, notNullValue()); assertThat(buckets.size(), equalTo(10)); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/TopHitsIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/TopHitsIT.java index aeef44d6272..e9b9ae20407 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/TopHitsIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/TopHitsIT.java @@ -519,9 +519,9 @@ public class TopHitsIT extends ESIntegTestCase { SearchHits hits = topHits.getHits(); assertThat(hits.getTotalHits(), equalTo(10L)); assertThat(hits.getHits().length, equalTo(3)); - assertThat((Long) hits.getAt(0).getSortValues()[0], equalTo(higestSortValue)); - assertThat((Long) hits.getAt(1).getSortValues()[0], equalTo(higestSortValue - 1)); - assertThat((Long) hits.getAt(2).getSortValues()[0], equalTo(higestSortValue - 2)); + assertThat(hits.getAt(0).getSortValues()[0], equalTo(higestSortValue)); + assertThat(hits.getAt(1).getSortValues()[0], equalTo(higestSortValue - 1)); + assertThat(hits.getAt(2).getSortValues()[0], equalTo(higestSortValue - 2)); Max max = bucket.getAggregations().get("max_sort"); assertThat(max.getValue(), equalTo(((Long) higestSortValue).doubleValue())); higestSortValue -= 10; @@ -544,7 +544,7 @@ public class TopHitsIT extends ESIntegTestCase { assertThat(terms.getName(), equalTo("terms")); assertThat(terms.getBuckets().size(), equalTo(3)); - Iterator bucketIterator = terms.getBuckets().iterator(); + Iterator bucketIterator = terms.getBuckets().iterator(); Terms.Bucket bucket = bucketIterator.next(); assertThat(key(bucket), equalTo("b")); TopHits topHits = bucket.getAggregations().get("hits"); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/AvgBucketIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/AvgBucketIT.java index d62e93fa5e9..4f6ff0e32ed 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/AvgBucketIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/AvgBucketIT.java @@ -140,7 +140,7 @@ public class AvgBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -182,7 +182,7 @@ public class AvgBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(interval)); double bucketSum = 0; @@ -223,7 +223,7 @@ public class AvgBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -277,7 +277,7 @@ public class AvgBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -322,7 +322,7 @@ public class AvgBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(0)); InternalSimpleValue avgBucketValue = response.getAggregations().get("avg_bucket"); @@ -349,7 +349,7 @@ public class AvgBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); double aggTermsSum = 0; diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/ExtendedStatsBucketIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/ExtendedStatsBucketIT.java index d4310e581c0..607124ecb15 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/ExtendedStatsBucketIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/ExtendedStatsBucketIT.java @@ -211,7 +211,7 @@ public class ExtendedStatsBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -262,7 +262,7 @@ public class ExtendedStatsBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(interval)); double bucketSum = 0; @@ -312,7 +312,7 @@ public class ExtendedStatsBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -375,7 +375,7 @@ public class ExtendedStatsBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -429,7 +429,7 @@ public class ExtendedStatsBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(0)); ExtendedStatsBucket extendedStatsBucketValue = response.getAggregations().get("extended_stats_bucket"); @@ -487,7 +487,7 @@ public class ExtendedStatsBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); double aggTermsSum = 0; diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/MaxBucketIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/MaxBucketIT.java index aba941ebb4b..632f11f7ec7 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/MaxBucketIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/MaxBucketIT.java @@ -149,7 +149,7 @@ public class MaxBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -196,7 +196,7 @@ public class MaxBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(interval)); List maxKeys = new ArrayList<>(); @@ -242,7 +242,7 @@ public class MaxBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -348,7 +348,7 @@ public class MaxBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -397,7 +397,7 @@ public class MaxBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(0)); InternalBucketMetricValue maxBucketValue = response.getAggregations().get("max_bucket"); @@ -425,7 +425,7 @@ public class MaxBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); List maxTermsKeys = new ArrayList<>(); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/MinBucketIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/MinBucketIT.java index cbd6824b3a4..04fdd0c3133 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/MinBucketIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/MinBucketIT.java @@ -146,7 +146,7 @@ public class MinBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -193,7 +193,7 @@ public class MinBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(interval)); List minKeys = new ArrayList<>(); @@ -239,7 +239,7 @@ public class MinBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -298,7 +298,7 @@ public class MinBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -347,7 +347,7 @@ public class MinBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(0)); InternalBucketMetricValue minBucketValue = response.getAggregations().get("min_bucket"); @@ -375,7 +375,7 @@ public class MinBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); List minTermsKeys = new ArrayList<>(); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/PercentilesBucketIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/PercentilesBucketIT.java index c582c76bd8c..e23e5441431 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/PercentilesBucketIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/PercentilesBucketIT.java @@ -145,7 +145,7 @@ public class PercentilesBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -187,7 +187,7 @@ public class PercentilesBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(interval)); double[] values = new double[interval]; @@ -220,7 +220,7 @@ public class PercentilesBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(interval)); double[] values = new double[interval]; @@ -261,7 +261,7 @@ public class PercentilesBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -316,7 +316,7 @@ public class PercentilesBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -361,7 +361,7 @@ public class PercentilesBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(0)); PercentilesBucket percentilesBucketValue = response.getAggregations().get("percentiles_bucket"); @@ -384,7 +384,7 @@ public class PercentilesBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(0)); PercentilesBucket percentilesBucketValue = response.getAggregations().get("percentiles_bucket"); @@ -479,7 +479,7 @@ public class PercentilesBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); double[] values = new double[termsBuckets.size()]; @@ -539,7 +539,7 @@ public class PercentilesBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); double[] values = new double[termsBuckets.size()]; diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/StatsBucketIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/StatsBucketIT.java index c38dc99bdf9..231005f1b5b 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/StatsBucketIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/StatsBucketIT.java @@ -147,7 +147,7 @@ public class StatsBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -195,7 +195,7 @@ public class StatsBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(interval)); double bucketSum = 0; @@ -242,7 +242,7 @@ public class StatsBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -302,7 +302,7 @@ public class StatsBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -353,7 +353,7 @@ public class StatsBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(0)); StatsBucket statsBucketValue = response.getAggregations().get("stats_bucket"); @@ -380,7 +380,7 @@ public class StatsBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); double aggTermsSum = 0; diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/SumBucketIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/SumBucketIT.java index 09582430046..048dfac8648 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/SumBucketIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/SumBucketIT.java @@ -137,7 +137,7 @@ public class SumBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -176,7 +176,7 @@ public class SumBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(interval)); double bucketSum = 0; @@ -214,7 +214,7 @@ public class SumBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -265,7 +265,7 @@ public class SumBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); for (int i = 0; i < interval; ++i) { @@ -307,7 +307,7 @@ public class SumBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List buckets = terms.getBuckets(); + List buckets = terms.getBuckets(); assertThat(buckets.size(), equalTo(0)); InternalSimpleValue sumBucketValue = response.getAggregations().get("sum_bucket"); @@ -334,7 +334,7 @@ public class SumBucketIT extends ESIntegTestCase { Terms terms = response.getAggregations().get("terms"); assertThat(terms, notNullValue()); assertThat(terms.getName(), equalTo("terms")); - List termsBuckets = terms.getBuckets(); + List termsBuckets = terms.getBuckets(); assertThat(termsBuckets.size(), equalTo(interval)); double aggTermsSum = 0;