Snapshot and Restore
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/XPackClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/XPackClient.java
index 4acaadfdb85d5..1401376527df2 100644
--- a/client/rest-high-level/src/main/java/org/elasticsearch/client/XPackClient.java
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/XPackClient.java
@@ -42,10 +42,12 @@ public final class XPackClient {
private final RestHighLevelClient restHighLevelClient;
private final WatcherClient watcherClient;
+ private final LicenseClient licenseClient;
XPackClient(RestHighLevelClient restHighLevelClient) {
this.restHighLevelClient = restHighLevelClient;
this.watcherClient = new WatcherClient(restHighLevelClient);
+ this.licenseClient = new LicenseClient(restHighLevelClient);
}
public WatcherClient watcher() {
@@ -100,4 +102,15 @@ public void usageAsync(XPackUsageRequest request, RequestOptions options, Action
restHighLevelClient.performRequestAsyncAndParseEntity(request, RequestConverters::xpackUsage, options,
XPackUsageResponse::fromXContent, listener, emptySet());
}
+
+ /**
+ * A wrapper for the {@link RestHighLevelClient} that provides methods for
+ * accessing the Elastic Licensing APIs.
+ *
+ * See the
+ * X-Pack APIs on elastic.co for more information.
+ */
+ public LicenseClient license() {
+ return licenseClient;
+ }
}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RankEvalIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RankEvalIT.java
index 2890257b236cd..0af270cb051ea 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RankEvalIT.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RankEvalIT.java
@@ -22,7 +22,11 @@
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
+import org.elasticsearch.index.rankeval.DiscountedCumulativeGain;
import org.elasticsearch.index.rankeval.EvalQueryQuality;
+import org.elasticsearch.index.rankeval.EvaluationMetric;
+import org.elasticsearch.index.rankeval.ExpectedReciprocalRank;
+import org.elasticsearch.index.rankeval.MeanReciprocalRank;
import org.elasticsearch.index.rankeval.PrecisionAtK;
import org.elasticsearch.index.rankeval.RankEvalRequest;
import org.elasticsearch.index.rankeval.RankEvalResponse;
@@ -35,8 +39,10 @@
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -64,15 +70,7 @@ public void indexDocuments() throws IOException {
* calculation where all unlabeled documents are treated as not relevant.
*/
public void testRankEvalRequest() throws IOException {
- SearchSourceBuilder testQuery = new SearchSourceBuilder();
- testQuery.query(new MatchAllQueryBuilder());
- List amsterdamRatedDocs = createRelevant("index" , "amsterdam1", "amsterdam2", "amsterdam3", "amsterdam4");
- amsterdamRatedDocs.addAll(createRelevant("index2", "amsterdam0"));
- RatedRequest amsterdamRequest = new RatedRequest("amsterdam_query", amsterdamRatedDocs, testQuery);
- RatedRequest berlinRequest = new RatedRequest("berlin_query", createRelevant("index", "berlin"), testQuery);
- List specifications = new ArrayList<>();
- specifications.add(amsterdamRequest);
- specifications.add(berlinRequest);
+ List specifications = createTestEvaluationSpec();
PrecisionAtK metric = new PrecisionAtK(1, false, 10);
RankEvalSpec spec = new RankEvalSpec(specifications, metric);
@@ -80,7 +78,7 @@ public void testRankEvalRequest() throws IOException {
RankEvalResponse response = execute(rankEvalRequest, highLevelClient()::rankEval, highLevelClient()::rankEvalAsync);
// the expected Prec@ for the first query is 5/7 and the expected Prec@ for the second is 1/7, divided by 2 to get the average
double expectedPrecision = (1.0 / 7.0 + 5.0 / 7.0) / 2.0;
- assertEquals(expectedPrecision, response.getEvaluationResult(), Double.MIN_VALUE);
+ assertEquals(expectedPrecision, response.getMetricScore(), Double.MIN_VALUE);
Map partialResults = response.getPartialResults();
assertEquals(2, partialResults.size());
EvalQueryQuality amsterdamQueryQuality = partialResults.get("amsterdam_query");
@@ -114,6 +112,38 @@ public void testRankEvalRequest() throws IOException {
response = execute(rankEvalRequest, highLevelClient()::rankEval, highLevelClient()::rankEvalAsync);
}
+ private static List createTestEvaluationSpec() {
+ SearchSourceBuilder testQuery = new SearchSourceBuilder();
+ testQuery.query(new MatchAllQueryBuilder());
+ List amsterdamRatedDocs = createRelevant("index" , "amsterdam1", "amsterdam2", "amsterdam3", "amsterdam4");
+ amsterdamRatedDocs.addAll(createRelevant("index2", "amsterdam0"));
+ RatedRequest amsterdamRequest = new RatedRequest("amsterdam_query", amsterdamRatedDocs, testQuery);
+ RatedRequest berlinRequest = new RatedRequest("berlin_query", createRelevant("index", "berlin"), testQuery);
+ List specifications = new ArrayList<>();
+ specifications.add(amsterdamRequest);
+ specifications.add(berlinRequest);
+ return specifications;
+ }
+
+ /**
+ * Test case checks that the default metrics are registered and usable
+ */
+ public void testMetrics() throws IOException {
+ List specifications = createTestEvaluationSpec();
+ List> metrics = Arrays.asList(PrecisionAtK::new, MeanReciprocalRank::new, DiscountedCumulativeGain::new,
+ () -> new ExpectedReciprocalRank(1));
+ double expectedScores[] = new double[] {0.4285714285714286, 0.75, 1.6408962261063627, 0.4407738095238095};
+ int i = 0;
+ for (Supplier metricSupplier : metrics) {
+ RankEvalSpec spec = new RankEvalSpec(specifications, metricSupplier.get());
+
+ RankEvalRequest rankEvalRequest = new RankEvalRequest(spec, new String[] { "index", "index2" });
+ RankEvalResponse response = execute(rankEvalRequest, highLevelClient()::rankEval, highLevelClient()::rankEvalAsync);
+ assertEquals(expectedScores[i], response.getMetricScore(), Double.MIN_VALUE);
+ i++;
+ }
+ }
+
private static List createRelevant(String indexName, String... docs) {
return Stream.of(docs).map(s -> new RatedDocument(indexName, s, 1)).collect(Collectors.toList());
}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java
index c1f47feb33d5a..0415d363c54cd 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java
@@ -41,6 +41,7 @@
import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotRequest;
import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotRequest;
import org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsRequest;
+import org.elasticsearch.action.admin.cluster.snapshots.restore.RestoreSnapshotRequest;
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRequest;
import org.elasticsearch.action.admin.cluster.storedscripts.DeleteStoredScriptRequest;
import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptRequest;
@@ -2198,6 +2199,31 @@ public void testSnapshotsStatus() {
assertThat(request.getEntity(), is(nullValue()));
}
+ public void testRestoreSnapshot() throws IOException {
+ Map expectedParams = new HashMap<>();
+ String repository = randomIndicesNames(1, 1)[0];
+ String snapshot = "snapshot-" + randomAlphaOfLengthBetween(2, 5).toLowerCase(Locale.ROOT);
+ String endpoint = String.format(Locale.ROOT, "/_snapshot/%s/%s/_restore", repository, snapshot);
+
+ RestoreSnapshotRequest restoreSnapshotRequest = new RestoreSnapshotRequest(repository, snapshot);
+ setRandomMasterTimeout(restoreSnapshotRequest, expectedParams);
+ if (randomBoolean()) {
+ restoreSnapshotRequest.waitForCompletion(true);
+ expectedParams.put("wait_for_completion", "true");
+ }
+ if (randomBoolean()) {
+ String timeout = randomTimeValue();
+ restoreSnapshotRequest.masterNodeTimeout(timeout);
+ expectedParams.put("master_timeout", timeout);
+ }
+
+ Request request = RequestConverters.restoreSnapshot(restoreSnapshotRequest);
+ assertThat(endpoint, equalTo(request.getEndpoint()));
+ assertThat(HttpPost.METHOD_NAME, equalTo(request.getMethod()));
+ assertThat(expectedParams, equalTo(request.getParameters()));
+ assertToXContentBody(restoreSnapshotRequest, request.getEntity());
+ }
+
public void testDeleteSnapshot() {
Map expectedParams = new HashMap<>();
String repository = randomIndicesNames(1, 1)[0];
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java
index 64a344790caa0..5cf3b35275620 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java
@@ -20,6 +20,7 @@
package org.elasticsearch.client;
import com.fasterxml.jackson.core.JsonParseException;
+
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
@@ -60,6 +61,7 @@
import org.elasticsearch.common.xcontent.smile.SmileXContent;
import org.elasticsearch.index.rankeval.DiscountedCumulativeGain;
import org.elasticsearch.index.rankeval.EvaluationMetric;
+import org.elasticsearch.index.rankeval.ExpectedReciprocalRank;
import org.elasticsearch.index.rankeval.MeanReciprocalRank;
import org.elasticsearch.index.rankeval.MetricDetail;
import org.elasticsearch.index.rankeval.PrecisionAtK;
@@ -616,7 +618,7 @@ public void testDefaultNamedXContents() {
public void testProvidedNamedXContents() {
List namedXContents = RestHighLevelClient.getProvidedNamedXContents();
- assertEquals(8, namedXContents.size());
+ assertEquals(10, namedXContents.size());
Map, Integer> categories = new HashMap<>();
List names = new ArrayList<>();
for (NamedXContentRegistry.Entry namedXContent : namedXContents) {
@@ -630,14 +632,16 @@ public void testProvidedNamedXContents() {
assertEquals(Integer.valueOf(2), categories.get(Aggregation.class));
assertTrue(names.contains(ChildrenAggregationBuilder.NAME));
assertTrue(names.contains(MatrixStatsAggregationBuilder.NAME));
- assertEquals(Integer.valueOf(3), categories.get(EvaluationMetric.class));
+ assertEquals(Integer.valueOf(4), categories.get(EvaluationMetric.class));
assertTrue(names.contains(PrecisionAtK.NAME));
assertTrue(names.contains(DiscountedCumulativeGain.NAME));
assertTrue(names.contains(MeanReciprocalRank.NAME));
- assertEquals(Integer.valueOf(3), categories.get(MetricDetail.class));
+ assertTrue(names.contains(ExpectedReciprocalRank.NAME));
+ assertEquals(Integer.valueOf(4), categories.get(MetricDetail.class));
assertTrue(names.contains(PrecisionAtK.NAME));
assertTrue(names.contains(MeanReciprocalRank.NAME));
assertTrue(names.contains(DiscountedCumulativeGain.NAME));
+ assertTrue(names.contains(ExpectedReciprocalRank.NAME));
}
public void testApiNamingConventions() throws Exception {
@@ -661,7 +665,6 @@ public void testApiNamingConventions() throws Exception {
"reindex_rethrottle",
"render_search_template",
"scripts_painless_execute",
- "snapshot.restore",
"tasks.get",
"termvectors",
"update_by_query"
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/SnapshotIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/SnapshotIT.java
index 5483f055c2c12..06aec70a01884 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/SnapshotIT.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/SnapshotIT.java
@@ -28,6 +28,8 @@
import org.elasticsearch.action.admin.cluster.repositories.put.PutRepositoryResponse;
import org.elasticsearch.action.admin.cluster.repositories.verify.VerifyRepositoryRequest;
import org.elasticsearch.action.admin.cluster.repositories.verify.VerifyRepositoryResponse;
+import org.elasticsearch.action.admin.cluster.snapshots.restore.RestoreSnapshotRequest;
+import org.elasticsearch.action.admin.cluster.snapshots.restore.RestoreSnapshotResponse;
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRequest;
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusResponse;
import org.elasticsearch.common.settings.Settings;
@@ -40,12 +42,15 @@
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.repositories.fs.FsRepository;
import org.elasticsearch.rest.RestStatus;
+import org.elasticsearch.snapshots.RestoreInfo;
import java.io.IOException;
+import java.util.Collections;
import java.util.stream.Collectors;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
public class SnapshotIT extends ESRestHighLevelClientTestCase {
@@ -205,6 +210,42 @@ public void testSnapshotsStatus() throws IOException {
assertThat(response.getSnapshots().get(0).getIndices().containsKey(testIndex), is(true));
}
+ public void testRestoreSnapshot() throws IOException {
+ String testRepository = "test";
+ String testSnapshot = "snapshot_1";
+ String testIndex = "test_index";
+ String restoredIndex = testIndex + "_restored";
+
+ PutRepositoryResponse putRepositoryResponse = createTestRepository(testRepository, FsRepository.TYPE, "{\"location\": \".\"}");
+ assertTrue(putRepositoryResponse.isAcknowledged());
+
+ createIndex(testIndex, Settings.EMPTY);
+ assertTrue("index [" + testIndex + "] should have been created", indexExists(testIndex));
+
+ CreateSnapshotRequest createSnapshotRequest = new CreateSnapshotRequest(testRepository, testSnapshot);
+ createSnapshotRequest.indices(testIndex);
+ createSnapshotRequest.waitForCompletion(true);
+ CreateSnapshotResponse createSnapshotResponse = createTestSnapshot(createSnapshotRequest);
+ assertEquals(RestStatus.OK, createSnapshotResponse.status());
+
+ deleteIndex(testIndex);
+ assertFalse("index [" + testIndex + "] should have been deleted", indexExists(testIndex));
+
+ RestoreSnapshotRequest request = new RestoreSnapshotRequest(testRepository, testSnapshot);
+ request.waitForCompletion(true);
+ request.renamePattern(testIndex);
+ request.renameReplacement(restoredIndex);
+
+ RestoreSnapshotResponse response = execute(request, highLevelClient().snapshot()::restore,
+ highLevelClient().snapshot()::restoreAsync);
+
+ RestoreInfo restoreInfo = response.getRestoreInfo();
+ assertThat(restoreInfo.name(), equalTo(testSnapshot));
+ assertThat(restoreInfo.indices(), equalTo(Collections.singletonList(restoredIndex)));
+ assertThat(restoreInfo.successfulShards(), greaterThan(0));
+ assertThat(restoreInfo.failedShards(), equalTo(0));
+ }
+
public void testDeleteSnapshot() throws IOException {
String repository = "test_repository";
String snapshot = "test_snapshot";
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/LicensingDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/LicensingDocumentationIT.java
new file mode 100644
index 0000000000000..d620adb71312b
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/LicensingDocumentationIT.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.client.documentation;
+
+import org.elasticsearch.action.ActionListener;
+import org.elasticsearch.action.LatchedActionListener;
+import org.elasticsearch.client.ESRestHighLevelClientTestCase;
+import org.elasticsearch.client.RequestOptions;
+import org.elasticsearch.client.RestHighLevelClient;
+import org.elasticsearch.protocol.xpack.license.LicensesStatus;
+import org.elasticsearch.protocol.xpack.license.PutLicenseRequest;
+import org.elasticsearch.protocol.xpack.license.PutLicenseResponse;
+
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.startsWith;
+
+/**
+ * Documentation for Licensing APIs in the high level java client.
+ * Code wrapped in {@code tag} and {@code end} tags is included in the docs.
+ */
+public class LicensingDocumentationIT extends ESRestHighLevelClientTestCase {
+
+ public void testPutLicense() throws Exception {
+ RestHighLevelClient client = highLevelClient();
+ String license = "{\"license\": {\"uid\":\"893361dc-9749-4997-93cb-802e3d7fa4a8\",\"type\":\"gold\"," +
+ "\"issue_date_in_millis\":1411948800000,\"expiry_date_in_millis\":1914278399999,\"max_nodes\":1,\"issued_to\":\"issued_to\"," +
+ "\"issuer\":\"issuer\",\"signature\":\"AAAAAgAAAA3U8+YmnvwC+CWsV/mRAAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSm" +
+ "kxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTn" +
+ "FrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1" +
+ "JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVm" +
+ "ZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQ" +
+ "Be8GfzDm6T537Iuuvjetb3xK5dvg0K5NQapv+rczWcQFxgCuzbF8plkgetP1aAGZP4uRESDQPMlOCsx4d0UqqAm9f7GbBQ3l93P+PogInPFeEH9NvOmaAQovmxVM" +
+ "9SE6DsDqlX4cXSO+bgWpXPTd2LmpoQc1fXd6BZ8GeuyYpVHVKp9hVU0tAYjw6HzYOE7+zuO1oJYOxElqy66AnIfkvHrvni+flym3tE7tDTgsDRaz7W3iBhaqiSnt" +
+ "EqabEkvHdPHQdSR99XGaEvnHO1paK01/35iZF6OXHsF7CCj+558GRXiVxzueOe7TsGSSt8g7YjZwV9bRCyU7oB4B/nidgI\"}}";
+ {
+ //tag::put-license-execute
+ PutLicenseRequest request = new PutLicenseRequest();
+ request.setLicenseDefinition(license); // <1>
+ request.setAcknowledge(false); // <2>
+
+ PutLicenseResponse response = client.xpack().license().putLicense(request, RequestOptions.DEFAULT);
+ //end::put-license-execute
+
+ //tag::put-license-response
+ LicensesStatus status = response.status(); // <1>
+ assertEquals(status, LicensesStatus.VALID); // <2>
+ boolean acknowledged = response.isAcknowledged(); // <3>
+ String acknowledgeHeader = response.acknowledgeHeader(); // <4>
+ Map acknowledgeMessages = response.acknowledgeMessages(); // <5>
+ //end::put-license-response
+
+ assertFalse(acknowledged); // Should fail because we are trying to downgrade from platinum trial to gold
+ assertThat(acknowledgeHeader, startsWith("This license update requires acknowledgement."));
+ assertThat(acknowledgeMessages.keySet(), not(hasSize(0)));
+ }
+ {
+ PutLicenseRequest request = new PutLicenseRequest();
+ // tag::put-license-execute-listener
+ ActionListener listener = new ActionListener() {
+ @Override
+ public void onResponse(PutLicenseResponse indexResponse) {
+ // <1>
+ }
+
+ @Override
+ public void onFailure(Exception e) {
+ // <2>
+ }
+ };
+ // end::put-license-execute-listener
+
+ // Replace the empty listener by a blocking listener in test
+ final CountDownLatch latch = new CountDownLatch(1);
+ listener = new LatchedActionListener<>(listener, latch);
+
+ // tag::put-license-execute-async
+ client.xpack().license().putLicenseAsync(
+ request, RequestOptions.DEFAULT, listener); // <1>
+ // end::put-license-execute-async
+
+ assertTrue(latch.await(30L, TimeUnit.SECONDS));
+ }
+ }
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SearchDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SearchDocumentationIT.java
index c60f2d4c92b87..2f743c786bab8 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SearchDocumentationIT.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SearchDocumentationIT.java
@@ -1136,14 +1136,14 @@ public void testRankEval() throws Exception {
// end::rank-eval-execute
// tag::rank-eval-response
- double evaluationResult = response.getEvaluationResult(); // <1>
+ double evaluationResult = response.getMetricScore(); // <1>
assertEquals(1.0 / 3.0, evaluationResult, 0.0);
Map partialResults =
response.getPartialResults();
EvalQueryQuality evalQuality =
partialResults.get("kimchy_query"); // <2>
assertEquals("kimchy_query", evalQuality.getId());
- double qualityLevel = evalQuality.getQualityLevel(); // <3>
+ double qualityLevel = evalQuality.metricScore(); // <3>
assertEquals(1.0 / 3.0, qualityLevel, 0.0);
List hitsAndRatings = evalQuality.getHitsAndRatings();
RatedSearchHit ratedSearchHit = hitsAndRatings.get(2);
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java
index fff3e7ece7066..922fcb984d94a 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java
@@ -33,6 +33,8 @@
import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotResponse;
import org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsRequest;
import org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsResponse;
+import org.elasticsearch.action.admin.cluster.snapshots.restore.RestoreSnapshotRequest;
+import org.elasticsearch.action.admin.cluster.snapshots.restore.RestoreSnapshotResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotRequest;
@@ -53,12 +55,15 @@
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.repositories.fs.FsRepository;
import org.elasticsearch.rest.RestStatus;
+import org.elasticsearch.snapshots.RestoreInfo;
import org.elasticsearch.snapshots.SnapshotId;
import org.elasticsearch.snapshots.SnapshotInfo;
import org.elasticsearch.snapshots.SnapshotShardFailure;
import org.elasticsearch.snapshots.SnapshotState;
import java.io.IOException;
+import java.util.Collections;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -263,6 +268,107 @@ public void onFailure(Exception e) {
}
}
+ public void testRestoreSnapshot() throws IOException {
+ RestHighLevelClient client = highLevelClient();
+
+ createTestRepositories();
+ createTestIndex();
+ createTestSnapshots();
+
+ // tag::restore-snapshot-request
+ RestoreSnapshotRequest request = new RestoreSnapshotRequest(repositoryName, snapshotName);
+ // end::restore-snapshot-request
+ // we need to restore as a different index name
+
+ // tag::restore-snapshot-request-masterTimeout
+ request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1>
+ request.masterNodeTimeout("1m"); // <2>
+ // end::restore-snapshot-request-masterTimeout
+
+ // tag::restore-snapshot-request-waitForCompletion
+ request.waitForCompletion(true); // <1>
+ // end::restore-snapshot-request-waitForCompletion
+
+ // tag::restore-snapshot-request-partial
+ request.partial(false); // <1>
+ // end::restore-snapshot-request-partial
+
+ // tag::restore-snapshot-request-include-global-state
+ request.includeGlobalState(false); // <1>
+ // end::restore-snapshot-request-include-global-state
+
+ // tag::restore-snapshot-request-include-aliases
+ request.includeAliases(false); // <1>
+ // end::restore-snapshot-request-include-aliases
+
+
+ // tag::restore-snapshot-request-indices
+ request.indices("test_index");
+ // end::restore-snapshot-request-indices
+
+ String restoredIndexName = "restored_index";
+ // tag::restore-snapshot-request-rename
+ request.renamePattern("test_(.+)"); // <1>
+ request.renameReplacement("restored_$1"); // <2>
+ // end::restore-snapshot-request-rename
+
+ // tag::restore-snapshot-request-index-settings
+ request.indexSettings( // <1>
+ Settings.builder()
+ .put("index.number_of_replicas", 0)
+ .build());
+
+ request.ignoreIndexSettings("index.refresh_interval", "index.search.idle.after"); // <2>
+ request.indicesOptions(new IndicesOptions( // <3>
+ EnumSet.of(IndicesOptions.Option.IGNORE_UNAVAILABLE),
+ EnumSet.of(IndicesOptions.WildcardStates.OPEN)));
+ // end::restore-snapshot-request-index-settings
+
+ // tag::restore-snapshot-execute
+ RestoreSnapshotResponse response = client.snapshot().restore(request, RequestOptions.DEFAULT);
+ // end::restore-snapshot-execute
+
+ // tag::restore-snapshot-response
+ RestoreInfo restoreInfo = response.getRestoreInfo();
+ List indices = restoreInfo.indices(); // <1>
+ // end::restore-snapshot-response
+ assertEquals(Collections.singletonList(restoredIndexName), indices);
+ assertEquals(0, restoreInfo.failedShards());
+ assertTrue(restoreInfo.successfulShards() > 0);
+ }
+
+ public void testRestoreSnapshotAsync() throws InterruptedException {
+ RestHighLevelClient client = highLevelClient();
+ {
+ RestoreSnapshotRequest request = new RestoreSnapshotRequest();
+
+ // tag::restore-snapshot-execute-listener
+ ActionListener listener =
+ new ActionListener() {
+ @Override
+ public void onResponse(RestoreSnapshotResponse restoreSnapshotResponse) {
+ // <1>
+ }
+
+ @Override
+ public void onFailure(Exception e) {
+ // <2>
+ }
+ };
+ // end::restore-snapshot-execute-listener
+
+ // Replace the empty listener by a blocking listener in test
+ final CountDownLatch latch = new CountDownLatch(1);
+ listener = new LatchedActionListener<>(listener, latch);
+
+ // tag::restore-snapshot-execute-async
+ client.snapshot().restoreAsync(request, RequestOptions.DEFAULT, listener); // <1>
+ // end::restore-snapshot-execute-async
+
+ assertTrue(latch.await(30L, TimeUnit.SECONDS));
+ }
+ }
+
public void testSnapshotDeleteRepository() throws IOException {
RestHighLevelClient client = highLevelClient();
diff --git a/client/transport/src/main/java/org/elasticsearch/transport/client/PreBuiltTransportClient.java b/client/transport/src/main/java/org/elasticsearch/transport/client/PreBuiltTransportClient.java
index 7f9bcc6ea0818..7bde7fbc06f6b 100644
--- a/client/transport/src/main/java/org/elasticsearch/transport/client/PreBuiltTransportClient.java
+++ b/client/transport/src/main/java/org/elasticsearch/transport/client/PreBuiltTransportClient.java
@@ -21,6 +21,7 @@
import io.netty.util.ThreadDeathWatcher;
import io.netty.util.concurrent.GlobalEventExecutor;
+
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.network.NetworkModule;
diff --git a/distribution/packages/build.gradle b/distribution/packages/build.gradle
index fcd69138da328..4fdaa5c1a013c 100644
--- a/distribution/packages/build.gradle
+++ b/distribution/packages/build.gradle
@@ -125,32 +125,22 @@ Closure commonPackageConfig(String type, boolean oss) {
fileMode 0644
}
into('lib') {
- with copySpec {
- with libFiles(oss)
- // we need to specify every intermediate directory so we iterate through the parents; duplicate calls with the same part are fine
- eachFile { FileCopyDetails fcp ->
- String[] segments = fcp.relativePath.segments
- for (int i = segments.length - 2; i > 0 && segments[i] != 'lib'; --i) {
- directory('/' + segments[0..i].join('/'), 0755)
- }
- fcp.mode = 0644
- }
- }
+ with libFiles(oss)
}
into('modules') {
- with copySpec {
- with modulesFiles(oss)
- // we need to specify every intermediate directory so we iterate through the parents; duplicate calls with the same part are fine
- eachFile { FileCopyDetails fcp ->
- String[] segments = fcp.relativePath.segments
- for (int i = segments.length - 2; i > 0 && segments[i] != 'modules'; --i) {
- directory('/' + segments[0..i].join('/'), 0755)
- }
- if (segments[-2] == 'bin') {
- fcp.mode = 0755
- } else {
- fcp.mode = 0644
- }
+ with modulesFiles(oss)
+ }
+ // we need to specify every intermediate directory in these paths so the package managers know they are explicitly
+ // intended to manage them; otherwise they may be left behind on uninstallation. duplicate calls of the same
+ // directory are fine
+ eachFile { FileCopyDetails fcp ->
+ String[] segments = fcp.relativePath.segments
+ for (int i = segments.length - 2; i > 2; --i) {
+ directory('/' + segments[0..i].join('/'), 0755)
+ if (segments[-2] == 'bin') {
+ fcp.mode = 0755
+ } else {
+ fcp.mode = 0644
}
}
}
@@ -333,12 +323,6 @@ Closure commonRpmConfig(boolean oss) {
// without this the rpm will have parent dirs of any files we copy in, eg /etc/elasticsearch
addParentDirs false
-
- // Declare the folders so that the RPM package manager removes
- // them when upgrading or removing the package
- directory('/usr/share/elasticsearch/bin', 0755)
- directory('/usr/share/elasticsearch/lib', 0755)
- directory('/usr/share/elasticsearch/modules', 0755)
}
}
diff --git a/docs/build.gradle b/docs/build.gradle
index 829db4381b046..a67c0217490b3 100644
--- a/docs/build.gradle
+++ b/docs/build.gradle
@@ -379,9 +379,9 @@ buildRestTests.setups['exams'] = '''
refresh: true
body: |
{"index":{}}
- {"grade": 100}
+ {"grade": 100, "weight": 2}
{"index":{}}
- {"grade": 50}'''
+ {"grade": 50, "weight": 3}'''
buildRestTests.setups['stored_example_script'] = '''
# Simple script to load a field. Not really a good example, but a simple one.
diff --git a/docs/java-rest/high-level/licensing/put-license.asciidoc b/docs/java-rest/high-level/licensing/put-license.asciidoc
new file mode 100644
index 0000000000000..7456fdd3c0236
--- /dev/null
+++ b/docs/java-rest/high-level/licensing/put-license.asciidoc
@@ -0,0 +1,66 @@
+[[java-rest-high-put-license]]
+=== Update License
+
+[[java-rest-high-put-license-execution]]
+==== Execution
+
+The license can be added or updated using the `putLicense()` method:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/LicensingDocumentationIT.java[put-license-execute]
+--------------------------------------------------
+<1> Set the categories of information to retrieve. The the default is to
+return no information which is useful for checking if {xpack} is installed
+but not much else.
+<2> A JSON document containing the license information.
+
+[[java-rest-high-put-license-response]]
+==== Response
+
+The returned `PutLicenseResponse` contains the `LicensesStatus`,
+`acknowledged` flag and possible acknowledge messages. The acknowledge messages
+are present if you previously had a license with more features than one you
+are trying to update and you didn't set the `acknowledge` flag to `true`. In this case
+you need to display the messages to the end user and if they agree, resubmit the
+license with the `acknowledge` flag set to `true`. Please note that the request will
+still return a 200 return code even if requires an acknowledgement. So, it is
+necessary to check the `acknowledged` flag.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/LicensingDocumentationIT.java[put-license-response]
+--------------------------------------------------
+<1> The status of the license
+<2> Make sure that the license is valid.
+<3> Check the acknowledge flag.
+<4> It should be true if license is acknowledge.
+<5> Otherwise we can see the acknowledge messages in `acknowledgeHeader()` and check
+component-specific messages in `acknowledgeMessages()`.
+
+[[java-rest-high-put-license-async]]
+==== Asynchronous Execution
+
+This request can be executed asynchronously:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/LicensingDocumentationIT.java[put-license-execute-async]
+--------------------------------------------------
+<1> The `PutLicenseRequest` to execute and the `ActionListener` to use when
+the execution completes
+
+The asynchronous method does not block and returns immediately. Once it is
+completed the `ActionListener` is called back using the `onResponse` method
+if the execution successfully completed or using the `onFailure` method if
+it failed.
+
+A typical listener for `PutLicenseResponse` looks like:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/LicensingDocumentationIT.java[put-license-execute-listener]
+--------------------------------------------------
+<1> Called when the execution is successfully completed. The response is
+provided as an argument
+<2> Called in case of failure. The raised exception is provided as an argument
diff --git a/docs/java-rest/high-level/snapshot/restore_snapshot.asciidoc b/docs/java-rest/high-level/snapshot/restore_snapshot.asciidoc
new file mode 100644
index 0000000000000..a4b83ca419a41
--- /dev/null
+++ b/docs/java-rest/high-level/snapshot/restore_snapshot.asciidoc
@@ -0,0 +1,144 @@
+[[java-rest-high-snapshot-restore-snapshot]]
+=== Restore Snapshot API
+
+The Restore Snapshot API allows to restore a snapshot.
+
+[[java-rest-high-snapshot-restore-snapshot-request]]
+==== Restore Snapshot Request
+
+A `RestoreSnapshotRequest`:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[restore-snapshot-request]
+--------------------------------------------------
+
+==== Limiting Indices to Restore
+
+By default all indices are restored. With the `indices` property you can
+provide a list of indices that should be restored:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[restore-snapshot-request-indices]
+--------------------------------------------------
+<1> Request that Elasticsearch only restores "test_index".
+
+==== Renaming Indices
+
+You can rename indices using regular expressions when restoring a snapshot:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[restore-snapshot-request-rename]
+--------------------------------------------------
+<1> A regular expression matching the indices that should be renamed.
+<2> A replacement pattern that references the group from the regular
+ expression as `$1`. "test_index" from the snapshot is restored as
+ "restored_index" in this example.
+
+==== Index Settings and Options
+
+You can also customize index settings and options when restoring:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[restore-snapshot-request-index-settings]
+--------------------------------------------------
+<1> Use `#indexSettings()` to set any specific index setting for the indices
+ that are restored.
+<2> Use `#ignoreIndexSettings()` to provide index settings that should be
+ ignored from the original indices.
+<3> Set `IndicesOptions.Option.IGNORE_UNAVAILABLE` in `#indicesOptions()` to
+ have the restore succeed even if indices are missing in the snapshot.
+
+==== Further Arguments
+
+The following arguments can optionally be provided:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[restore-snapshot-request-masterTimeout]
+--------------------------------------------------
+<1> Timeout to connect to the master node as a `TimeValue`
+<2> Timeout to connect to the master node as a `String`
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[restore-snapshot-request-waitForCompletion]
+--------------------------------------------------
+<1> Boolean indicating whether to wait until the snapshot has been restored.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[restore-snapshot-request-partial]
+--------------------------------------------------
+<1> Boolean indicating whether the entire snapshot should succeed although one
+ or more indices participating in the snapshot don’t have all primary
+ shards available.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[restore-snapshot-request-include-global-state]
+--------------------------------------------------
+<1> Boolean indicating whether restored templates that don’t currently exist
+ in the cluster are added and existing templates with the same name are
+ replaced by the restored templates. The restored persistent settings are
+ added to the existing persistent settings.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[restore-snapshot-request-include-aliases]
+--------------------------------------------------
+<1> Boolean to control whether aliases should be restored. Set to `false` to
+ prevent aliases from being restored together with associated indices.
+
+[[java-rest-high-snapshot-restore-snapshot-sync]]
+==== Synchronous Execution
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[restore-snapshot-execute]
+--------------------------------------------------
+
+[[java-rest-high-snapshot-restore-snapshot-async]]
+==== Asynchronous Execution
+
+The asynchronous execution of a restore snapshot request requires both the
+`RestoreSnapshotRequest` instance and an `ActionListener` instance to be
+passed to the asynchronous method:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[restore-snapshot-execute-async]
+--------------------------------------------------
+<1> The `RestoreSnapshotRequest` to execute and the `ActionListener`
+to use when the execution completes
+
+The asynchronous method does not block and returns immediately. Once it is
+completed the `ActionListener` is called back using the `onResponse` method
+if the execution successfully completed or using the `onFailure` method if
+it failed.
+
+A typical listener for `RestoreSnapshotResponse` looks like:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[restore-snapshot-execute-listener]
+--------------------------------------------------
+<1> Called when the execution is successfully completed. The response is
+ provided as an argument.
+<2> Called in case of a failure. The raised exception is provided as an argument.
+
+[[java-rest-high-cluster-restore-snapshot-response]]
+==== Restore Snapshot Response
+
+The returned `RestoreSnapshotResponse` allows to retrieve information about the
+executed operation as follows:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[restore-snapshot-response]
+--------------------------------------------------
+<1> The `RestoreInfo` contains details about the restored snapshot like the indices or
+ the number of successfully restored and failed shards.
diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc
index d952870677b7e..25fbcaaaeaa73 100644
--- a/docs/java-rest/high-level/supported-apis.asciidoc
+++ b/docs/java-rest/high-level/supported-apis.asciidoc
@@ -186,3 +186,12 @@ The Java High Level REST Client supports the following Scripts APIs:
include::script/get_script.asciidoc[]
include::script/delete_script.asciidoc[]
+
+
+== Licensing APIs
+
+The Java High Level REST Client supports the following Licensing APIs:
+
+* <>
+
+include::licensing/put-license.asciidoc[]
diff --git a/docs/plugins/analysis-phonetic.asciidoc b/docs/plugins/analysis-phonetic.asciidoc
index 34f4a933f9f76..a75c21fdac658 100644
--- a/docs/plugins/analysis-phonetic.asciidoc
+++ b/docs/plugins/analysis-phonetic.asciidoc
@@ -17,15 +17,15 @@ The `phonetic` token filter takes the following settings:
`encoder`::
Which phonetic encoder to use. Accepts `metaphone` (default),
- `doublemetaphone`, `soundex`, `refinedsoundex`, `caverphone1`,
+ `double_metaphone`, `soundex`, `refined_soundex`, `caverphone1`,
`caverphone2`, `cologne`, `nysiis`, `koelnerphonetik`, `haasephonetik`,
- `beidermorse`, `daitch_mokotoff`.
+ `beider_morse`, `daitch_mokotoff`.
`replace`::
Whether or not the original token should be replaced by the phonetic
token. Accepts `true` (default) and `false`. Not supported by
- `beidermorse` encoding.
+ `beider_morse` encoding.
[source,js]
--------------------------------------------------
diff --git a/docs/reference/aggregations/metrics.asciidoc b/docs/reference/aggregations/metrics.asciidoc
index ae6bee2eb7d17..96597564dac2d 100644
--- a/docs/reference/aggregations/metrics.asciidoc
+++ b/docs/reference/aggregations/metrics.asciidoc
@@ -13,6 +13,8 @@ bucket aggregations (some bucket aggregations enable you to sort the returned bu
include::metrics/avg-aggregation.asciidoc[]
+include::metrics/weighted-avg-aggregation.asciidoc[]
+
include::metrics/cardinality-aggregation.asciidoc[]
include::metrics/extendedstats-aggregation.asciidoc[]
diff --git a/docs/reference/aggregations/metrics/weighted-avg-aggregation.asciidoc b/docs/reference/aggregations/metrics/weighted-avg-aggregation.asciidoc
new file mode 100644
index 0000000000000..252728a6db367
--- /dev/null
+++ b/docs/reference/aggregations/metrics/weighted-avg-aggregation.asciidoc
@@ -0,0 +1,202 @@
+[[search-aggregations-metrics-weight-avg-aggregation]]
+=== Weighted Avg Aggregation
+
+A `single-value` metrics aggregation that computes the weighted average of numeric values that are extracted from the aggregated documents.
+These values can be extracted either from specific numeric fields in the documents.
+
+When calculating a regular average, each datapoint has an equal "weight" ... it contributes equally to the final value. Weighted averages,
+on the other hand, weight each datapoint differently. The amount that each datapoint contributes to the final value is extracted from the
+document, or provided by a script.
+
+As a formula, a weighted average is the `∑(value * weight) / ∑(weight)`
+
+A regular average can be thought of as a weighted average where every value has an implicit weight of `1`.
+
+.`weighted_avg` Parameters
+|===
+|Parameter Name |Description |Required |Default Value
+|`value` | The configuration for the field or script that provides the values |Required |
+|`weight` | The configuration for the field or script that provides the weights |Required |
+|`format` | The numeric response formatter |Optional |
+|`value_type` | A hint about the values for pure scripts or unmapped fields |Optional |
+|===
+
+The `value` and `weight` objects have per-field specific configuration:
+
+.`value` Parameters
+|===
+|Parameter Name |Description |Required |Default Value
+|`field` | The field that values should be extracted from |Required |
+|`missing` | A value to use if the field is missing entirely |Optional |
+|`script` | A script which provides the values for the document. This is mutually exclusive with `field` |Optional
+|===
+
+.`weight` Parameters
+|===
+|Parameter Name |Description |Required |Default Value
+|`field` | The field that weights should be extracted from |Required |
+|`missing` | A weight to use if the field is missing entirely |Optional |
+|`script` | A script which provides the weights for the document. This is mutually exclusive with `field` |Optional
+|===
+
+
+==== Examples
+
+If our documents have a `"grade"` field that holds a 0-100 numeric score, and a `"weight"` field which holds an arbitrary numeric weight,
+we can calculate the weighted average using:
+
+[source,js]
+--------------------------------------------------
+POST /exams/_search
+{
+ "size": 0,
+ "aggs" : {
+ "weighted_grade": {
+ "weighted_avg": {
+ "value": {
+ "field": "grade"
+ },
+ "weight": {
+ "field": "weight"
+ }
+ }
+ }
+ }
+}
+--------------------------------------------------
+// CONSOLE
+// TEST[setup:exams]
+
+Which yields a response like:
+
+[source,js]
+--------------------------------------------------
+{
+ ...
+ "aggregations": {
+ "weighted_grade": {
+ "value": 70.0
+ }
+ }
+}
+--------------------------------------------------
+// TESTRESPONSE[s/\.\.\./"took": $body.took,"timed_out": false,"_shards": $body._shards,"hits": $body.hits,/]
+
+
+While multiple values-per-field are allowed, only one weight is allowed. If the aggregation encounters
+a document that has more than one weight (e.g. the weight field is a multi-valued field) it will throw an exception.
+If you have this situation, you will need to specify a `script` for the weight field, and use the script
+to combine the multiple values into a single value to be used.
+
+This single weight will be applied independently to each value extracted from the `value` field.
+
+This example show how a single document with multiple values will be averaged with a single weight:
+
+[source,js]
+--------------------------------------------------
+POST /exams/_doc?refresh
+{
+ "grade": [1, 2, 3],
+ "weight": 2
+}
+
+POST /exams/_search
+{
+ "size": 0,
+ "aggs" : {
+ "weighted_grade": {
+ "weighted_avg": {
+ "value": {
+ "field": "grade"
+ },
+ "weight": {
+ "field": "weight"
+ }
+ }
+ }
+ }
+}
+--------------------------------------------------
+// CONSOLE
+// TEST
+
+The three values (`1`, `2`, and `3`) will be included as independent values, all with the weight of `2`:
+
+[source,js]
+--------------------------------------------------
+{
+ ...
+ "aggregations": {
+ "weighted_grade": {
+ "value": 2.0
+ }
+ }
+}
+--------------------------------------------------
+// TESTRESPONSE[s/\.\.\./"took": $body.took,"timed_out": false,"_shards": $body._shards,"hits": $body.hits,/]
+
+The aggregation returns `2.0` as the result, which matches what we would expect when calculating by hand:
+`((1*2) + (2*2) + (3*2)) / (2+2+2) == 2`
+
+==== Script
+
+Both the value and the weight can be derived from a script, instead of a field. As a simple example, the following
+will add one to the grade and weight in the document using a script:
+
+[source,js]
+--------------------------------------------------
+POST /exams/_search
+{
+ "size": 0,
+ "aggs" : {
+ "weighted_grade": {
+ "weighted_avg": {
+ "value": {
+ "script": "doc.grade.value + 1"
+ },
+ "weight": {
+ "script": "doc.weight.value + 1"
+ }
+ }
+ }
+ }
+}
+--------------------------------------------------
+// CONSOLE
+// TEST[setup:exams]
+
+
+==== Missing values
+
+The `missing` parameter defines how documents that are missing a value should be treated.
+The default behavior is different for `value` and `weight`:
+
+By default, if the `value` field is missing the document is ignored and the aggregation moves on to the next document.
+If the `weight` field is missing, it is assumed to have a weight of `1` (like a normal average).
+
+Both of these defaults can be overridden with the `missing` parameter:
+
+[source,js]
+--------------------------------------------------
+POST /exams/_search
+{
+ "size": 0,
+ "aggs" : {
+ "weighted_grade": {
+ "weighted_avg": {
+ "value": {
+ "field": "grade",
+ "missing": 2
+ },
+ "weight": {
+ "field": "weight",
+ "missing": 3
+ }
+ }
+ }
+ }
+}
+--------------------------------------------------
+// CONSOLE
+// TEST[setup:exams]
+
diff --git a/docs/reference/search/rank-eval.asciidoc b/docs/reference/search/rank-eval.asciidoc
index cf13b9f7b0655..81c464b71d575 100644
--- a/docs/reference/search/rank-eval.asciidoc
+++ b/docs/reference/search/rank-eval.asciidoc
@@ -259,6 +259,56 @@ in the query. Defaults to 10.
|`normalize` | If set to `true`, this metric will calculate the https://en.wikipedia.org/wiki/Discounted_cumulative_gain#Normalized_DCG[Normalized DCG].
|=======================================================================
+[float]
+==== Expected Reciprocal Rank (ERR)
+
+Expected Reciprocal Rank (ERR) is an extension of the classical reciprocal rank for the graded relevance case
+(Olivier Chapelle, Donald Metzler, Ya Zhang, and Pierre Grinspan. 2009. http://olivier.chapelle.cc/pub/err.pdf[Expected reciprocal rank for graded relevance].)
+
+It is based on the assumption of a cascade model of search, in which a user scans through ranked search
+results in order and stops at the first document that satisfies the information need. For this reason, it
+is a good metric for question answering and navigation queries, but less so for survey oriented information
+needs where the user is interested in finding many relevant documents in the top k results.
+
+The metric models the expectation of the reciprocal of the position at which a user stops reading through
+the result list. This means that relevant document in top ranking positions will contribute much to the
+overall score. However, the same document will contribute much less to the score if it appears in a lower rank,
+even more so if there are some relevant (but maybe less relevant) documents preceding it.
+In this way, the ERR metric discounts documents which are shown after very relevant documents. This introduces
+a notion of dependency in the ordering of relevant documents that e.g. Precision or DCG don't account for.
+
+[source,js]
+--------------------------------
+GET /twitter/_rank_eval
+{
+ "requests": [
+ {
+ "id": "JFK query",
+ "request": { "query": { "match_all": {}}},
+ "ratings": []
+ }],
+ "metric": {
+ "expected_reciprocal_rank": {
+ "maximum_relevance" : 3,
+ "k" : 20
+ }
+ }
+}
+--------------------------------
+// CONSOLE
+// TEST[setup:twitter]
+
+The `expected_reciprocal_rank` metric takes the following parameters:
+
+[cols="<,<",options="header",]
+|=======================================================================
+|Parameter |Description
+| `maximum_relevance` | Mandatory parameter. The highest relevance grade used in the user supplied
+relevance judgments.
+|`k` | sets the maximum number of documents retrieved per query. This value will act in place of the usual `size` parameter
+in the query. Defaults to 10.
+|=======================================================================
+
[float]
=== Response format
@@ -270,10 +320,10 @@ that shows potential errors of individual queries. The response has the followin
--------------------------------
{
"rank_eval": {
- "quality_level": 0.4, <1>
+ "metric_score": 0.4, <1>
"details": {
"my_query_id1": { <2>
- "quality_level": 0.6, <3>
+ "metric_score": 0.6, <3>
"unrated_docs": [ <4>
{
"_index": "my_index",
@@ -308,7 +358,7 @@ that shows potential errors of individual queries. The response has the followin
<1> the overall evaluation quality calculated by the defined metric
<2> the `details` section contains one entry for every query in the original `requests` section, keyed by the search request id
-<3> the `quality_level` in the `details` section shows the contribution of this query to the global quality score
+<3> the `metric_score` in the `details` section shows the contribution of this query to the global quality metric score
<4> the `unrated_docs` section contains an `_index` and `_id` entry for each document in the search result for this
query that didn't have a ratings value. This can be used to ask the user to supply ratings for these documents
<5> the `hits` section shows a grouping of the search results with their supplied rating
diff --git a/libs/nio/src/test/java/org/elasticsearch/nio/ChannelFactoryTests.java b/libs/nio/src/test/java/org/elasticsearch/nio/ChannelFactoryTests.java
index 8ff0cfcd0c876..af4eabefd94ef 100644
--- a/libs/nio/src/test/java/org/elasticsearch/nio/ChannelFactoryTests.java
+++ b/libs/nio/src/test/java/org/elasticsearch/nio/ChannelFactoryTests.java
@@ -137,7 +137,6 @@ private static class TestChannelFactory extends ChannelFactory {
+ extends ArrayValuesSourceAggregationBuilder.LeafOnly {
public static final String NAME = "matrix_stats";
private MultiValueMode multiValueMode = MultiValueMode.AVG;
diff --git a/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/matrix/stats/MatrixStatsAggregator.java b/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/matrix/stats/MatrixStatsAggregator.java
index 578116d7b5eb2..aa19f62fedc4f 100644
--- a/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/matrix/stats/MatrixStatsAggregator.java
+++ b/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/matrix/stats/MatrixStatsAggregator.java
@@ -30,7 +30,7 @@
import org.elasticsearch.search.aggregations.LeafBucketCollectorBase;
import org.elasticsearch.search.aggregations.metrics.MetricsAggregator;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
-import org.elasticsearch.search.aggregations.support.MultiValuesSource.NumericMultiValuesSource;
+import org.elasticsearch.search.aggregations.support.ArrayValuesSource.NumericArrayValuesSource;
import org.elasticsearch.search.aggregations.support.ValuesSource;
import org.elasticsearch.search.internal.SearchContext;
@@ -43,7 +43,7 @@
**/
final class MatrixStatsAggregator extends MetricsAggregator {
/** Multiple ValuesSource with field names */
- private final NumericMultiValuesSource valuesSources;
+ private final NumericArrayValuesSource valuesSources;
/** array of descriptive stats, per shard, needed to compute the correlation */
ObjectArray stats;
@@ -53,7 +53,7 @@ final class MatrixStatsAggregator extends MetricsAggregator {
Map metaData) throws IOException {
super(name, context, parent, pipelineAggregators, metaData);
if (valuesSources != null && !valuesSources.isEmpty()) {
- this.valuesSources = new NumericMultiValuesSource(valuesSources, multiValueMode);
+ this.valuesSources = new NumericArrayValuesSource(valuesSources, multiValueMode);
stats = context.bigArrays().newObjectArray(1);
} else {
this.valuesSources = null;
diff --git a/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/matrix/stats/MatrixStatsAggregatorFactory.java b/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/matrix/stats/MatrixStatsAggregatorFactory.java
index 2c3ac82a0c1a8..fb456d75bb78b 100644
--- a/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/matrix/stats/MatrixStatsAggregatorFactory.java
+++ b/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/matrix/stats/MatrixStatsAggregatorFactory.java
@@ -23,7 +23,7 @@
import org.elasticsearch.search.aggregations.AggregatorFactories;
import org.elasticsearch.search.aggregations.AggregatorFactory;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
-import org.elasticsearch.search.aggregations.support.MultiValuesSourceAggregatorFactory;
+import org.elasticsearch.search.aggregations.support.ArrayValuesSourceAggregatorFactory;
import org.elasticsearch.search.aggregations.support.ValuesSource;
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
import org.elasticsearch.search.internal.SearchContext;
@@ -33,7 +33,7 @@
import java.util.Map;
final class MatrixStatsAggregatorFactory
- extends MultiValuesSourceAggregatorFactory {
+ extends ArrayValuesSourceAggregatorFactory {
private final MultiValueMode multiValueMode;
diff --git a/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/matrix/stats/MatrixStatsParser.java b/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/matrix/stats/MatrixStatsParser.java
index fd13037e8f922..0f48d1855ae3e 100644
--- a/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/matrix/stats/MatrixStatsParser.java
+++ b/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/matrix/stats/MatrixStatsParser.java
@@ -21,14 +21,14 @@
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.search.MultiValueMode;
-import org.elasticsearch.search.aggregations.support.MultiValuesSourceParser.NumericValuesSourceParser;
+import org.elasticsearch.search.aggregations.support.ArrayValuesSourceParser.NumericValuesSourceParser;
import org.elasticsearch.search.aggregations.support.ValueType;
import org.elasticsearch.search.aggregations.support.ValuesSourceType;
import java.io.IOException;
import java.util.Map;
-import static org.elasticsearch.search.aggregations.support.MultiValuesSourceAggregationBuilder.MULTIVALUE_MODE_FIELD;
+import static org.elasticsearch.search.aggregations.support.ArrayValuesSourceAggregationBuilder.MULTIVALUE_MODE_FIELD;
public class MatrixStatsParser extends NumericValuesSourceParser {
diff --git a/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSource.java b/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/ArrayValuesSource.java
similarity index 87%
rename from modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSource.java
rename to modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/ArrayValuesSource.java
index 86d1836721f10..94bf68c7ae489 100644
--- a/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSource.java
+++ b/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/ArrayValuesSource.java
@@ -28,13 +28,13 @@
/**
* Class to encapsulate a set of ValuesSource objects labeled by field name
*/
-public abstract class MultiValuesSource {
+public abstract class ArrayValuesSource {
protected MultiValueMode multiValueMode;
protected String[] names;
protected VS[] values;
- public static class NumericMultiValuesSource extends MultiValuesSource {
- public NumericMultiValuesSource(Map valuesSources, MultiValueMode multiValueMode) {
+ public static class NumericArrayValuesSource extends ArrayValuesSource {
+ public NumericArrayValuesSource(Map valuesSources, MultiValueMode multiValueMode) {
super(valuesSources, multiValueMode);
if (valuesSources != null) {
this.values = valuesSources.values().toArray(new ValuesSource.Numeric[0]);
@@ -51,8 +51,8 @@ public NumericDoubleValues getField(final int ordinal, LeafReaderContext ctx) th
}
}
- public static class BytesMultiValuesSource extends MultiValuesSource {
- public BytesMultiValuesSource(Map valuesSources, MultiValueMode multiValueMode) {
+ public static class BytesArrayValuesSource extends ArrayValuesSource {
+ public BytesArrayValuesSource(Map valuesSources, MultiValueMode multiValueMode) {
super(valuesSources, multiValueMode);
this.values = valuesSources.values().toArray(new ValuesSource.Bytes[0]);
}
@@ -62,14 +62,14 @@ public Object getField(final int ordinal, LeafReaderContext ctx) throws IOExcept
}
}
- public static class GeoPointValuesSource extends MultiValuesSource {
+ public static class GeoPointValuesSource extends ArrayValuesSource {
public GeoPointValuesSource(Map valuesSources, MultiValueMode multiValueMode) {
super(valuesSources, multiValueMode);
this.values = valuesSources.values().toArray(new ValuesSource.GeoPoint[0]);
}
}
- private MultiValuesSource(Map valuesSources, MultiValueMode multiValueMode) {
+ private ArrayValuesSource(Map valuesSources, MultiValueMode multiValueMode) {
if (valuesSources != null) {
this.names = valuesSources.keySet().toArray(new String[0]);
}
diff --git a/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceAggregationBuilder.java b/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/ArrayValuesSourceAggregationBuilder.java
similarity index 91%
rename from modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceAggregationBuilder.java
rename to modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/ArrayValuesSourceAggregationBuilder.java
index 4cf497c9c02a5..eb8152e0fe0b8 100644
--- a/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceAggregationBuilder.java
+++ b/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/ArrayValuesSourceAggregationBuilder.java
@@ -44,13 +44,13 @@
import java.util.Map;
import java.util.Objects;
-public abstract class MultiValuesSourceAggregationBuilder>
- extends AbstractAggregationBuilder {
+public abstract class ArrayValuesSourceAggregationBuilder>
+ extends AbstractAggregationBuilder {
public static final ParseField MULTIVALUE_MODE_FIELD = new ParseField("mode");
- public abstract static class LeafOnly>
- extends MultiValuesSourceAggregationBuilder {
+ public abstract static class LeafOnly>
+ extends ArrayValuesSourceAggregationBuilder {
protected LeafOnly(String name, ValuesSourceType valuesSourceType, ValueType targetValueType) {
super(name, valuesSourceType, targetValueType);
@@ -94,7 +94,7 @@ public AB subAggregations(Builder subFactories) {
private Object missing = null;
private Map missingMap = Collections.emptyMap();
- protected MultiValuesSourceAggregationBuilder(String name, ValuesSourceType valuesSourceType, ValueType targetValueType) {
+ protected ArrayValuesSourceAggregationBuilder(String name, ValuesSourceType valuesSourceType, ValueType targetValueType) {
super(name);
if (valuesSourceType == null) {
throw new IllegalArgumentException("[valuesSourceType] must not be null: [" + name + "]");
@@ -103,7 +103,7 @@ protected MultiValuesSourceAggregationBuilder(String name, ValuesSourceType valu
this.targetValueType = targetValueType;
}
- protected MultiValuesSourceAggregationBuilder(MultiValuesSourceAggregationBuilder clone,
+ protected ArrayValuesSourceAggregationBuilder(ArrayValuesSourceAggregationBuilder clone,
Builder factoriesBuilder, Map metaData) {
super(clone, factoriesBuilder, metaData);
this.valuesSourceType = clone.valuesSourceType;
@@ -115,7 +115,7 @@ protected MultiValuesSourceAggregationBuilder(MultiValuesSourceAggregationBuilde
this.missing = clone.missing;
}
- protected MultiValuesSourceAggregationBuilder(StreamInput in, ValuesSourceType valuesSourceType, ValueType targetValueType)
+ protected ArrayValuesSourceAggregationBuilder(StreamInput in, ValuesSourceType valuesSourceType, ValueType targetValueType)
throws IOException {
super(in);
assert false == serializeTargetValueType() : "Wrong read constructor called for subclass that provides its targetValueType";
@@ -124,7 +124,7 @@ protected MultiValuesSourceAggregationBuilder(StreamInput in, ValuesSourceType v
read(in);
}
- protected MultiValuesSourceAggregationBuilder(StreamInput in, ValuesSourceType valuesSourceType) throws IOException {
+ protected ArrayValuesSourceAggregationBuilder(StreamInput in, ValuesSourceType valuesSourceType) throws IOException {
super(in);
assert serializeTargetValueType() : "Wrong read constructor called for subclass that serializes its targetValueType";
this.valuesSourceType = valuesSourceType;
@@ -239,10 +239,10 @@ public Map missingMap() {
}
@Override
- protected final MultiValuesSourceAggregatorFactory doBuild(SearchContext context, AggregatorFactory> parent,
- AggregatorFactories.Builder subFactoriesBuilder) throws IOException {
+ protected final ArrayValuesSourceAggregatorFactory doBuild(SearchContext context, AggregatorFactory> parent,
+ AggregatorFactories.Builder subFactoriesBuilder) throws IOException {
Map> configs = resolveConfig(context);
- MultiValuesSourceAggregatorFactory factory = innerBuild(context, configs, parent, subFactoriesBuilder);
+ ArrayValuesSourceAggregatorFactory factory = innerBuild(context, configs, parent, subFactoriesBuilder);
return factory;
}
@@ -255,9 +255,10 @@ protected Map> resolveConfig(SearchContext contex
return configs;
}
- protected abstract MultiValuesSourceAggregatorFactory innerBuild(SearchContext context,
- Map> configs, AggregatorFactory> parent,
- AggregatorFactories.Builder subFactoriesBuilder) throws IOException;
+ protected abstract ArrayValuesSourceAggregatorFactory innerBuild(SearchContext context,
+ Map> configs,
+ AggregatorFactory> parent,
+ AggregatorFactories.Builder subFactoriesBuilder) throws IOException;
public ValuesSourceConfig config(SearchContext context, String field, Script script) {
@@ -355,14 +356,14 @@ public final XContentBuilder internalXContent(XContentBuilder builder, Params pa
@Override
protected final int doHashCode() {
return Objects.hash(fields, format, missing, targetValueType, valueType, valuesSourceType,
- innerHashCode());
+ innerHashCode());
}
protected abstract int innerHashCode();
@Override
protected final boolean doEquals(Object obj) {
- MultiValuesSourceAggregationBuilder, ?> other = (MultiValuesSourceAggregationBuilder, ?>) obj;
+ ArrayValuesSourceAggregationBuilder, ?> other = (ArrayValuesSourceAggregationBuilder, ?>) obj;
if (!Objects.equals(fields, other.fields))
return false;
if (!Objects.equals(format, other.format))
diff --git a/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceAggregatorFactory.java b/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/ArrayValuesSourceAggregatorFactory.java
similarity index 78%
rename from modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceAggregatorFactory.java
rename to modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/ArrayValuesSourceAggregatorFactory.java
index 7d5c56a571bbe..ce8eeecd19036 100644
--- a/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceAggregatorFactory.java
+++ b/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/ArrayValuesSourceAggregatorFactory.java
@@ -30,14 +30,15 @@
import java.util.List;
import java.util.Map;
-public abstract class MultiValuesSourceAggregatorFactory>
- extends AggregatorFactory {
+public abstract class ArrayValuesSourceAggregatorFactory>
+ extends AggregatorFactory {
protected Map> configs;
- public MultiValuesSourceAggregatorFactory(String name, Map> configs,
- SearchContext context, AggregatorFactory> parent, AggregatorFactories.Builder subFactoriesBuilder,
- Map metaData) throws IOException {
+ public ArrayValuesSourceAggregatorFactory(String name, Map> configs,
+ SearchContext context, AggregatorFactory> parent,
+ AggregatorFactories.Builder subFactoriesBuilder,
+ Map metaData) throws IOException {
super(name, context, parent, subFactoriesBuilder, metaData);
this.configs = configs;
}
@@ -63,6 +64,7 @@ protected abstract Aggregator createUnmapped(Aggregator parent, List metaData) throws IOException;
protected abstract Aggregator doCreateInternal(Map valuesSources, Aggregator parent, boolean collectsFromSingleBucket,
- List pipelineAggregators, Map metaData) throws IOException;
+ List pipelineAggregators,
+ Map metaData) throws IOException;
}
diff --git a/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceParser.java b/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/ArrayValuesSourceParser.java
similarity index 86%
rename from modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceParser.java
rename to modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/ArrayValuesSourceParser.java
index 22a90b552d920..1100884cf8ace 100644
--- a/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceParser.java
+++ b/modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/ArrayValuesSourceParser.java
@@ -33,30 +33,30 @@
import java.util.List;
import java.util.Map;
-public abstract class MultiValuesSourceParser implements Aggregator.Parser {
+public abstract class ArrayValuesSourceParser implements Aggregator.Parser {
- public abstract static class AnyValuesSourceParser extends MultiValuesSourceParser {
+ public abstract static class AnyValuesSourceParser extends ArrayValuesSourceParser {
protected AnyValuesSourceParser(boolean formattable) {
super(formattable, ValuesSourceType.ANY, null);
}
}
- public abstract static class NumericValuesSourceParser extends MultiValuesSourceParser {
+ public abstract static class NumericValuesSourceParser extends ArrayValuesSourceParser {
protected NumericValuesSourceParser(boolean formattable) {
super(formattable, ValuesSourceType.NUMERIC, ValueType.NUMERIC);
}
}
- public abstract static class BytesValuesSourceParser extends MultiValuesSourceParser {
+ public abstract static class BytesValuesSourceParser extends ArrayValuesSourceParser {
protected BytesValuesSourceParser(boolean formattable) {
super(formattable, ValuesSourceType.BYTES, ValueType.STRING);
}
}
- public abstract static class GeoPointValuesSourceParser extends MultiValuesSourceParser {
+ public abstract static class GeoPointValuesSourceParser extends ArrayValuesSourceParser {
protected GeoPointValuesSourceParser(boolean formattable) {
super(formattable, ValuesSourceType.GEOPOINT, ValueType.GEOPOINT);
@@ -67,15 +67,15 @@ protected GeoPointValuesSourceParser(boolean formattable) {
private ValuesSourceType valuesSourceType = null;
private ValueType targetValueType = null;
- private MultiValuesSourceParser(boolean formattable, ValuesSourceType valuesSourceType, ValueType targetValueType) {
+ private ArrayValuesSourceParser(boolean formattable, ValuesSourceType valuesSourceType, ValueType targetValueType) {
this.valuesSourceType = valuesSourceType;
this.targetValueType = targetValueType;
this.formattable = formattable;
}
@Override
- public final MultiValuesSourceAggregationBuilder parse(String aggregationName, XContentParser parser)
- throws IOException {
+ public final ArrayValuesSourceAggregationBuilder parse(String aggregationName, XContentParser parser)
+ throws IOException {
List fields = null;
ValueType valueType = null;
@@ -98,7 +98,7 @@ private MultiValuesSourceParser(boolean formattable, ValuesSourceType valuesSour
"Multi-field aggregations do not support scripts.");
} else if (!token(aggregationName, currentFieldName, token, parser, otherOptions)) {
throw new ParsingException(parser.getTokenLocation(),
- "Unexpected token " + token + " [" + currentFieldName + "] in [" + aggregationName + "].");
+ "Unexpected token " + token + " [" + currentFieldName + "] in [" + aggregationName + "].");
}
} else if (token == XContentParser.Token.START_OBJECT) {
if (CommonFields.MISSING.match(currentFieldName, parser.getDeprecationHandler())) {
@@ -113,7 +113,7 @@ private MultiValuesSourceParser(boolean formattable, ValuesSourceType valuesSour
} else if (!token(aggregationName, currentFieldName, token, parser, otherOptions)) {
throw new ParsingException(parser.getTokenLocation(),
- "Unexpected token " + token + " [" + currentFieldName + "] in [" + aggregationName + "].");
+ "Unexpected token " + token + " [" + currentFieldName + "] in [" + aggregationName + "].");
}
} else if (token == XContentParser.Token.START_ARRAY) {
if (Script.SCRIPT_PARSE_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
@@ -127,21 +127,21 @@ private MultiValuesSourceParser(boolean formattable, ValuesSourceType valuesSour
fields.add(parser.text());
} else {
throw new ParsingException(parser.getTokenLocation(),
- "Unexpected token " + token + " [" + currentFieldName + "] in [" + aggregationName + "].");
+ "Unexpected token " + token + " [" + currentFieldName + "] in [" + aggregationName + "].");
}
}
} else if (!token(aggregationName, currentFieldName, token, parser, otherOptions)) {
throw new ParsingException(parser.getTokenLocation(),
- "Unexpected token " + token + " [" + currentFieldName + "] in [" + aggregationName + "].");
+ "Unexpected token " + token + " [" + currentFieldName + "] in [" + aggregationName + "].");
}
} else if (!token(aggregationName, currentFieldName, token, parser, otherOptions)) {
throw new ParsingException(parser.getTokenLocation(),
- "Unexpected token " + token + " [" + currentFieldName + "] in [" + aggregationName + "].");
+ "Unexpected token " + token + " [" + currentFieldName + "] in [" + aggregationName + "].");
}
}
- MultiValuesSourceAggregationBuilder factory = createFactory(aggregationName, this.valuesSourceType, this.targetValueType,
- otherOptions);
+ ArrayValuesSourceAggregationBuilder factory = createFactory(aggregationName, this.valuesSourceType, this.targetValueType,
+ otherOptions);
if (fields != null) {
factory.fields(fields);
}
@@ -182,7 +182,7 @@ private void parseMissingAndAdd(final String aggregationName, final String curre
/**
* Creates a {@link ValuesSourceAggregationBuilder} from the information
* gathered by the subclass. Options parsed in
- * {@link MultiValuesSourceParser} itself will be added to the factory
+ * {@link ArrayValuesSourceParser} itself will be added to the factory
* after it has been returned by this method.
*
* @param aggregationName
@@ -197,11 +197,13 @@ private void parseMissingAndAdd(final String aggregationName, final String curre
* method
* @return the created factory
*/
- protected abstract MultiValuesSourceAggregationBuilder createFactory(String aggregationName, ValuesSourceType valuesSourceType,
- ValueType targetValueType, Map otherOptions);
+ protected abstract ArrayValuesSourceAggregationBuilder createFactory(String aggregationName,
+ ValuesSourceType valuesSourceType,
+ ValueType targetValueType,
+ Map otherOptions);
/**
- * Allows subclasses of {@link MultiValuesSourceParser} to parse extra
+ * Allows subclasses of {@link ArrayValuesSourceParser} to parse extra
* parameters and store them in a {@link Map} which will later be passed to
* {@link #createFactory(String, ValuesSourceType, ValueType, Map)}.
*
diff --git a/modules/aggs-matrix-stats/src/test/java/org/elasticsearch/search/aggregations/matrix/stats/MultiPassStats.java b/modules/aggs-matrix-stats/src/test/java/org/elasticsearch/search/aggregations/matrix/stats/MultiPassStats.java
index 70e2172ce92d9..b5a348f45eb54 100644
--- a/modules/aggs-matrix-stats/src/test/java/org/elasticsearch/search/aggregations/matrix/stats/MultiPassStats.java
+++ b/modules/aggs-matrix-stats/src/test/java/org/elasticsearch/search/aggregations/matrix/stats/MultiPassStats.java
@@ -43,7 +43,6 @@ class MultiPassStats {
this.fieldBKey = fieldBName;
}
- @SuppressWarnings("unchecked")
void computeStats(final List fieldA, final List fieldB) {
// set count
count = fieldA.size();
diff --git a/modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/ConvertProcessor.java b/modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/ConvertProcessor.java
index 264df6f4c5f24..2e881b82b59de 100644
--- a/modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/ConvertProcessor.java
+++ b/modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/ConvertProcessor.java
@@ -42,7 +42,11 @@ enum Type {
@Override
public Object convert(Object value) {
try {
- return Integer.parseInt(value.toString());
+ String strValue = value.toString();
+ if (strValue.startsWith("0x") || strValue.startsWith("-0x")) {
+ return Integer.decode(strValue);
+ }
+ return Integer.parseInt(strValue);
} catch(NumberFormatException e) {
throw new IllegalArgumentException("unable to convert [" + value + "] to integer", e);
}
@@ -52,7 +56,11 @@ public Object convert(Object value) {
@Override
public Object convert(Object value) {
try {
- return Long.parseLong(value.toString());
+ String strValue = value.toString();
+ if (strValue.startsWith("0x") || strValue.startsWith("-0x")) {
+ return Long.decode(strValue);
+ }
+ return Long.parseLong(strValue);
} catch(NumberFormatException e) {
throw new IllegalArgumentException("unable to convert [" + value + "] to long", e);
}
diff --git a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ConvertProcessorTests.java b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ConvertProcessorTests.java
index 292a03d7d9033..f0fc31dab3533 100644
--- a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ConvertProcessorTests.java
+++ b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ConvertProcessorTests.java
@@ -49,6 +49,33 @@ public void testConvertInt() throws Exception {
assertThat(ingestDocument.getFieldValue(fieldName, Integer.class), equalTo(randomInt));
}
+ public void testConvertIntHex() throws Exception {
+ IngestDocument ingestDocument = RandomDocumentPicks.randomIngestDocument(random());
+ int randomInt = randomInt();
+ String intString = randomInt < 0 ? "-0x" + Integer.toHexString(-randomInt) : "0x" + Integer.toHexString(randomInt);
+ String fieldName = RandomDocumentPicks.addRandomField(random(), ingestDocument, intString);
+ Processor processor = new ConvertProcessor(randomAlphaOfLength(10), fieldName, fieldName, Type.INTEGER, false);
+ processor.execute(ingestDocument);
+ assertThat(ingestDocument.getFieldValue(fieldName, Integer.class), equalTo(randomInt));
+ }
+
+ public void testConvertIntLeadingZero() throws Exception {
+ IngestDocument ingestDocument = RandomDocumentPicks.randomIngestDocument(random());
+ String fieldName = RandomDocumentPicks.addRandomField(random(), ingestDocument, "010");
+ Processor processor = new ConvertProcessor(randomAlphaOfLength(10), fieldName, fieldName, Type.INTEGER, false);
+ processor.execute(ingestDocument);
+ assertThat(ingestDocument.getFieldValue(fieldName, Integer.class), equalTo(10));
+ }
+
+ public void testConvertIntHexError() {
+ IngestDocument ingestDocument = RandomDocumentPicks.randomIngestDocument(random());
+ String value = "0x" + randomAlphaOfLengthBetween(1, 10);
+ String fieldName = RandomDocumentPicks.addRandomField(random(), ingestDocument, value);
+ Processor processor = new ConvertProcessor(randomAlphaOfLength(10), fieldName, fieldName, Type.INTEGER, false);
+ IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> processor.execute(ingestDocument));
+ assertThat(e.getMessage(), equalTo("unable to convert [" + value + "] to integer"));
+ }
+
public void testConvertIntList() throws Exception {
IngestDocument ingestDocument = RandomDocumentPicks.randomIngestDocument(random());
int numItems = randomIntBetween(1, 10);
@@ -92,6 +119,33 @@ public void testConvertLong() throws Exception {
assertThat(ingestDocument.getFieldValue(fieldName, Long.class), equalTo(randomLong));
}
+ public void testConvertLongHex() throws Exception {
+ IngestDocument ingestDocument = RandomDocumentPicks.randomIngestDocument(random());
+ long randomLong = randomLong();
+ String longString = randomLong < 0 ? "-0x" + Long.toHexString(-randomLong) : "0x" + Long.toHexString(randomLong);
+ String fieldName = RandomDocumentPicks.addRandomField(random(), ingestDocument, longString);
+ Processor processor = new ConvertProcessor(randomAlphaOfLength(10), fieldName, fieldName, Type.LONG, false);
+ processor.execute(ingestDocument);
+ assertThat(ingestDocument.getFieldValue(fieldName, Long.class), equalTo(randomLong));
+ }
+
+ public void testConvertLongLeadingZero() throws Exception {
+ IngestDocument ingestDocument = RandomDocumentPicks.randomIngestDocument(random());
+ String fieldName = RandomDocumentPicks.addRandomField(random(), ingestDocument, "010");
+ Processor processor = new ConvertProcessor(randomAlphaOfLength(10), fieldName, fieldName, Type.LONG, false);
+ processor.execute(ingestDocument);
+ assertThat(ingestDocument.getFieldValue(fieldName, Long.class), equalTo(10L));
+ }
+
+ public void testConvertLongHexError() {
+ IngestDocument ingestDocument = RandomDocumentPicks.randomIngestDocument(random());
+ String value = "0x" + randomAlphaOfLengthBetween(1, 10);
+ String fieldName = RandomDocumentPicks.addRandomField(random(), ingestDocument, value);
+ Processor processor = new ConvertProcessor(randomAlphaOfLength(10), fieldName, fieldName, Type.LONG, false);
+ IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> processor.execute(ingestDocument));
+ assertThat(e.getMessage(), equalTo("unable to convert [" + value + "] to long"));
+ }
+
public void testConvertLongList() throws Exception {
IngestDocument ingestDocument = RandomDocumentPicks.randomIngestDocument(random());
int numItems = randomIntBetween(1, 10);
diff --git a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/JsonProcessorTests.java b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/JsonProcessorTests.java
index 2867ed1d24053..099e8e1866b8e 100644
--- a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/JsonProcessorTests.java
+++ b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/JsonProcessorTests.java
@@ -146,7 +146,6 @@ public void testFieldMissing() {
assertThat(exception.getMessage(), equalTo("field [field] not present as part of path [field]"));
}
- @SuppressWarnings("unchecked")
public void testAddToRoot() throws Exception {
String processorTag = randomAlphaOfLength(3);
String randomTargetField = randomAlphaOfLength(2);
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookup.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookup.java
index 752c0c205dd89..bcecd7bbdc78e 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookup.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookup.java
@@ -30,30 +30,30 @@
public final class PainlessLookup {
public Collection getStructs() {
- return javaClassesToPainlessStructs.values();
+ return classesToPainlessClasses.values();
}
- private final Map> painlessTypesToJavaClasses;
- private final Map, PainlessClass> javaClassesToPainlessStructs;
+ private final Map> canonicalClassNamesToClasses;
+ private final Map, PainlessClass> classesToPainlessClasses;
- PainlessLookup(Map> painlessTypesToJavaClasses, Map, PainlessClass> javaClassesToPainlessStructs) {
- this.painlessTypesToJavaClasses = Collections.unmodifiableMap(painlessTypesToJavaClasses);
- this.javaClassesToPainlessStructs = Collections.unmodifiableMap(javaClassesToPainlessStructs);
+ PainlessLookup(Map> canonicalClassNamesToClasses, Map, PainlessClass> classesToPainlessClasses) {
+ this.canonicalClassNamesToClasses = Collections.unmodifiableMap(canonicalClassNamesToClasses);
+ this.classesToPainlessClasses = Collections.unmodifiableMap(classesToPainlessClasses);
}
public Class> getClassFromBinaryName(String painlessType) {
- return painlessTypesToJavaClasses.get(painlessType.replace('$', '.'));
+ return canonicalClassNamesToClasses.get(painlessType.replace('$', '.'));
}
public boolean isSimplePainlessType(String painlessType) {
- return painlessTypesToJavaClasses.containsKey(painlessType);
+ return canonicalClassNamesToClasses.containsKey(painlessType);
}
public PainlessClass getPainlessStructFromJavaClass(Class> clazz) {
- return javaClassesToPainlessStructs.get(clazz);
+ return classesToPainlessClasses.get(clazz);
}
public Class> getJavaClassFromPainlessType(String painlessType) {
- return PainlessLookupUtility.canonicalTypeNameToType(painlessType, painlessTypesToJavaClasses);
+ return PainlessLookupUtility.canonicalTypeNameToType(painlessType, canonicalClassNamesToClasses);
}
}
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java
index 06773d3ffddf9..b15f1f13f203a 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java
@@ -24,10 +24,12 @@
import org.elasticsearch.painless.spi.WhitelistConstructor;
import org.elasticsearch.painless.spi.WhitelistField;
import org.elasticsearch.painless.spi.WhitelistMethod;
-import org.objectweb.asm.Type;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
@@ -35,11 +37,15 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.Stack;
import java.util.regex.Pattern;
-import static org.elasticsearch.painless.lookup.PainlessLookupUtility.DEF_TYPE_NAME;
+import static org.elasticsearch.painless.lookup.PainlessLookupUtility.CONSTRUCTOR_NAME;
+import static org.elasticsearch.painless.lookup.PainlessLookupUtility.DEF_CLASS_NAME;
+import static org.elasticsearch.painless.lookup.PainlessLookupUtility.buildPainlessFieldKey;
import static org.elasticsearch.painless.lookup.PainlessLookupUtility.buildPainlessMethodKey;
+import static org.elasticsearch.painless.lookup.PainlessLookupUtility.typeToCanonicalTypeName;
+import static org.elasticsearch.painless.lookup.PainlessLookupUtility.typeToJavaType;
+import static org.elasticsearch.painless.lookup.PainlessLookupUtility.typesToCanonicalTypeNames;
public class PainlessLookupBuilder {
@@ -123,17 +129,17 @@ public int hashCode() {
private final List whitelists;
private final Map> canonicalClassNamesToClasses;
- private final Map, PainlessClassBuilder> classesToPainlessClasses;
+ private final Map, PainlessClassBuilder> classesToPainlessClassBuilders;
public PainlessLookupBuilder(List whitelists) {
this.whitelists = whitelists;
canonicalClassNamesToClasses = new HashMap<>();
- classesToPainlessClasses = new HashMap<>();
+ classesToPainlessClassBuilders = new HashMap<>();
- canonicalClassNamesToClasses.put(DEF_TYPE_NAME, def.class);
- classesToPainlessClasses.put(def.class,
- new PainlessClassBuilder(DEF_TYPE_NAME, Object.class, Type.getType(Object.class)));
+ canonicalClassNamesToClasses.put(DEF_CLASS_NAME, def.class);
+ classesToPainlessClassBuilders.put(def.class,
+ new PainlessClassBuilder(DEF_CLASS_NAME, Object.class, org.objectweb.asm.Type.getType(Object.class)));
}
private Class> canonicalTypeNameToType(String canonicalTypeName) {
@@ -141,7 +147,7 @@ private Class> canonicalTypeNameToType(String canonicalTypeName) {
}
private void validateType(Class> type) {
- PainlessLookupUtility.validateType(type, classesToPainlessClasses.keySet());
+ PainlessLookupUtility.validateType(type, classesToPainlessClassBuilders.keySet());
}
public void addPainlessClass(ClassLoader classLoader, String javaClassName, boolean importClassName) {
@@ -174,10 +180,10 @@ public void addPainlessClass(Class> clazz, boolean importClassName) {
Objects.requireNonNull(clazz);
if (clazz == def.class) {
- throw new IllegalArgumentException("cannot add reserved class [" + DEF_TYPE_NAME + "]");
+ throw new IllegalArgumentException("cannot add reserved class [" + DEF_CLASS_NAME + "]");
}
- String canonicalClassName = clazz.getCanonicalName();
+ String canonicalClassName = typeToCanonicalTypeName(clazz);
if (clazz.isArray()) {
throw new IllegalArgumentException("cannot add array type [" + canonicalClassName + "] as a class");
@@ -187,13 +193,14 @@ public void addPainlessClass(Class> clazz, boolean importClassName) {
throw new IllegalArgumentException("invalid class name [" + canonicalClassName + "]");
}
- PainlessClassBuilder existingPainlessClassBuilder = classesToPainlessClasses.get(clazz);
+ PainlessClassBuilder existingPainlessClassBuilder = classesToPainlessClassBuilders.get(clazz);
if (existingPainlessClassBuilder == null) {
- PainlessClassBuilder painlessClassBuilder = new PainlessClassBuilder(canonicalClassName, clazz, Type.getType(clazz));
+ PainlessClassBuilder painlessClassBuilder =
+ new PainlessClassBuilder(canonicalClassName, clazz, org.objectweb.asm.Type.getType(clazz));
canonicalClassNamesToClasses.put(canonicalClassName, clazz);
- classesToPainlessClasses.put(clazz, painlessClassBuilder);
+ classesToPainlessClassBuilders.put(clazz, painlessClassBuilder);
} else if (existingPainlessClassBuilder.clazz.equals(clazz) == false) {
throw new IllegalArgumentException("class [" + canonicalClassName + "] " +
"cannot represent multiple java classes with the same name from different class loaders");
@@ -207,477 +214,455 @@ public void addPainlessClass(Class> clazz, boolean importClassName) {
throw new IllegalArgumentException("must use only_fqn parameter on class [" + canonicalClassName + "] with no package");
}
} else {
- Class> importedPainlessType = canonicalClassNamesToClasses.get(importedCanonicalClassName);
+ Class> importedPainlessClass = canonicalClassNamesToClasses.get(importedCanonicalClassName);
- if (importedPainlessType == null) {
+ if (importedPainlessClass == null) {
if (importClassName) {
if (existingPainlessClassBuilder != null) {
- throw new IllegalArgumentException(
- "inconsistent only_fqn parameters found for painless type [" + canonicalClassName + "]");
+ throw new IllegalArgumentException("inconsistent only_fqn parameters found for class [" + canonicalClassName + "]");
}
canonicalClassNamesToClasses.put(importedCanonicalClassName, clazz);
}
- } else if (importedPainlessType.equals(clazz) == false) {
- throw new IllegalArgumentException("painless type [" + importedCanonicalClassName + "] illegally represents multiple " +
- "java types [" + clazz.getCanonicalName() + "] and [" + importedPainlessType.getCanonicalName() + "]");
+ } else if (importedPainlessClass.equals(clazz) == false) {
+ throw new IllegalArgumentException("imported class [" + importedCanonicalClassName + "] cannot represent multiple " +
+ "classes [" + canonicalClassName + "] and [" + typeToCanonicalTypeName(importedPainlessClass) + "]");
} else if (importClassName == false) {
- throw new IllegalArgumentException("inconsistent only_fqn parameters found for painless type [" + canonicalClassName + "]");
+ throw new IllegalArgumentException("inconsistent only_fqn parameters found for class [" + canonicalClassName + "]");
}
}
}
- private void addConstructor(String ownerStructName, WhitelistConstructor whitelistConstructor) {
- PainlessClassBuilder ownerStruct = classesToPainlessClasses.get(canonicalClassNamesToClasses.get(ownerStructName));
+ public void addPainlessConstructor(String targetCanonicalClassName, List typeNameParameters) {
+ Objects.requireNonNull(targetCanonicalClassName);
+ Objects.requireNonNull(typeNameParameters);
- if (ownerStruct == null) {
- throw new IllegalArgumentException("owner struct [" + ownerStructName + "] not defined for constructor with " +
- "parameters " + whitelistConstructor.painlessParameterTypeNames);
- }
+ Class> targetClass = canonicalClassNamesToClasses.get(targetCanonicalClassName);
- List> painlessParametersTypes = new ArrayList<>(whitelistConstructor.painlessParameterTypeNames.size());
- Class>[] javaClassParameters = new Class>[whitelistConstructor.painlessParameterTypeNames.size()];
+ if (targetClass == null) {
+ throw new IllegalArgumentException("target class [" + targetCanonicalClassName + "] not found" +
+ "for constructor [[" + targetCanonicalClassName + "], " + typeNameParameters + "]");
+ }
- for (int parameterCount = 0; parameterCount < whitelistConstructor.painlessParameterTypeNames.size(); ++parameterCount) {
- String painlessParameterTypeName = whitelistConstructor.painlessParameterTypeNames.get(parameterCount);
+ List> typeParameters = new ArrayList<>(typeNameParameters.size());
+ for (String typeNameParameter : typeNameParameters) {
try {
- Class> painlessParameterClass = canonicalTypeNameToType(painlessParameterTypeName);
+ Class> typeParameter = canonicalTypeNameToType(typeNameParameter);
+ typeParameters.add(typeParameter);
+ } catch (IllegalArgumentException iae) {
+ throw new IllegalArgumentException("type parameter [" + typeNameParameter + "] not found " +
+ "for constructor [[" + targetCanonicalClassName + "], " + typeNameParameters + "]", iae);
+ }
+ }
+
+ addPainlessConstructor(targetClass, typeParameters);
+ }
+
+ public void addPainlessConstructor(Class> targetClass, List> typeParameters) {
+ Objects.requireNonNull(targetClass);
+ Objects.requireNonNull(typeParameters);
+
+ if (targetClass == def.class) {
+ throw new IllegalArgumentException("cannot add constructor to reserved class [" + DEF_CLASS_NAME + "]");
+ }
+
+ String targetCanonicalClassName = targetClass.getCanonicalName();
+ PainlessClassBuilder painlessClassBuilder = classesToPainlessClassBuilders.get(targetClass);
+
+ if (painlessClassBuilder == null) {
+ throw new IllegalArgumentException("target class [" + targetCanonicalClassName + "] not found" +
+ "for constructor [[" + targetCanonicalClassName + "], " + typesToCanonicalTypeNames(typeParameters) + "]");
+ }
+
+ int typeParametersSize = typeParameters.size();
+ List> javaTypeParameters = new ArrayList<>(typeParametersSize);
- painlessParametersTypes.add(painlessParameterClass);
- javaClassParameters[parameterCount] = PainlessLookupUtility.typeToJavaType(painlessParameterClass);
+ for (Class> typeParameter : typeParameters) {
+ try {
+ validateType(typeParameter);
} catch (IllegalArgumentException iae) {
- throw new IllegalArgumentException("struct not defined for constructor parameter [" + painlessParameterTypeName + "] " +
- "with owner struct [" + ownerStructName + "] and constructor parameters " +
- whitelistConstructor.painlessParameterTypeNames, iae);
+ throw new IllegalArgumentException("type parameter [" + typeToCanonicalTypeName(typeParameter) + "] not found " +
+ "for constructor [[" + targetCanonicalClassName + "], " + typesToCanonicalTypeNames(typeParameters) + "]", iae);
}
+
+ javaTypeParameters.add(typeToJavaType(typeParameter));
}
- java.lang.reflect.Constructor> javaConstructor;
+ Constructor> javaConstructor;
try {
- javaConstructor = ownerStruct.clazz.getConstructor(javaClassParameters);
- } catch (NoSuchMethodException exception) {
- throw new IllegalArgumentException("constructor not defined for owner struct [" + ownerStructName + "] " +
- " with constructor parameters " + whitelistConstructor.painlessParameterTypeNames, exception);
+ javaConstructor = targetClass.getConstructor(javaTypeParameters.toArray(new Class>[typeParametersSize]));
+ } catch (NoSuchMethodException nsme) {
+ throw new IllegalArgumentException("constructor reflection object " +
+ "[[" + targetCanonicalClassName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found", nsme);
}
- String painlessMethodKey = buildPainlessMethodKey("", whitelistConstructor.painlessParameterTypeNames.size());
- PainlessMethod painlessConstructor = ownerStruct.constructors.get(painlessMethodKey);
+ String painlessMethodKey = buildPainlessMethodKey(CONSTRUCTOR_NAME, typeParametersSize);
+ PainlessMethod painlessConstructor = painlessClassBuilder.constructors.get(painlessMethodKey);
if (painlessConstructor == null) {
org.objectweb.asm.commons.Method asmConstructor = org.objectweb.asm.commons.Method.getMethod(javaConstructor);
- MethodHandle javaHandle;
+ MethodHandle methodHandle;
try {
- javaHandle = MethodHandles.publicLookup().in(ownerStruct.clazz).unreflectConstructor(javaConstructor);
- } catch (IllegalAccessException exception) {
- throw new IllegalArgumentException("constructor not defined for owner struct [" + ownerStructName + "] " +
- " with constructor parameters " + whitelistConstructor.painlessParameterTypeNames);
+ methodHandle = MethodHandles.publicLookup().in(targetClass).unreflectConstructor(javaConstructor);
+ } catch (IllegalAccessException iae) {
+ throw new IllegalArgumentException("constructor method handle " +
+ "[[" + targetCanonicalClassName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found", iae);
}
painlessConstructor = painlessMethodCache.computeIfAbsent(
- new PainlessMethodCacheKey(ownerStruct.clazz, "", painlessParametersTypes),
- key -> new PainlessMethod("", ownerStruct.clazz, null, void.class, painlessParametersTypes,
- asmConstructor, javaConstructor.getModifiers(), javaHandle));
- ownerStruct.constructors.put(painlessMethodKey, painlessConstructor);
- } else if (painlessConstructor.arguments.equals(painlessParametersTypes) == false){
- throw new IllegalArgumentException(
- "illegal duplicate constructors [" + painlessMethodKey + "] found within the struct [" + ownerStruct.name + "] " +
- "with parameters " + painlessParametersTypes + " and " + painlessConstructor.arguments);
+ new PainlessMethodCacheKey(targetClass, CONSTRUCTOR_NAME, typeParameters),
+ key -> new PainlessMethod(CONSTRUCTOR_NAME, targetClass, null, void.class, typeParameters,
+ asmConstructor, javaConstructor.getModifiers(), methodHandle)
+ );
+
+ painlessClassBuilder.constructors.put(painlessMethodKey, painlessConstructor);
+ } else if (painlessConstructor.arguments.equals(typeParameters) == false){
+ throw new IllegalArgumentException("cannot have constructors " +
+ "[[" + targetCanonicalClassName + "], " + typesToCanonicalTypeNames(typeParameters) + "] and " +
+ "[[" + targetCanonicalClassName + "], " + typesToCanonicalTypeNames(painlessConstructor.arguments) + "] " +
+ "with the same arity and different type parameters");
}
}
- private void addMethod(ClassLoader whitelistClassLoader, String ownerStructName, WhitelistMethod whitelistMethod) {
- PainlessClassBuilder ownerStruct = classesToPainlessClasses.get(canonicalClassNamesToClasses.get(ownerStructName));
+ public void addPainlessMethod(ClassLoader classLoader, String targetCanonicalClassName, String augmentedCanonicalClassName,
+ String methodName, String returnCanonicalTypeName, List typeNameParameters) {
- if (ownerStruct == null) {
- throw new IllegalArgumentException("owner struct [" + ownerStructName + "] not defined for method with " +
- "name [" + whitelistMethod.javaMethodName + "] and parameters " + whitelistMethod.painlessParameterTypeNames);
- }
+ Objects.requireNonNull(classLoader);
+ Objects.requireNonNull(targetCanonicalClassName);
+ Objects.requireNonNull(methodName);
+ Objects.requireNonNull(returnCanonicalTypeName);
+ Objects.requireNonNull(typeNameParameters);
+
+ Class> targetClass = canonicalClassNamesToClasses.get(targetCanonicalClassName);
- if (METHOD_NAME_PATTERN.matcher(whitelistMethod.javaMethodName).matches() == false) {
- throw new IllegalArgumentException("invalid method name" +
- " [" + whitelistMethod.javaMethodName + "] for owner struct [" + ownerStructName + "].");
+ if (targetClass == null) {
+ throw new IllegalArgumentException("target class [" + targetCanonicalClassName + "] not found for method " +
+ "[[" + targetCanonicalClassName + "], [" + methodName + "], " + typeNameParameters + "]");
}
- Class> javaAugmentedClass;
+ Class> augmentedClass = null;
- if (whitelistMethod.javaAugmentedClassName != null) {
+ if (augmentedCanonicalClassName != null) {
try {
- javaAugmentedClass = Class.forName(whitelistMethod.javaAugmentedClassName, true, whitelistClassLoader);
+ augmentedClass = Class.forName(augmentedCanonicalClassName, true, classLoader);
} catch (ClassNotFoundException cnfe) {
- throw new IllegalArgumentException("augmented class [" + whitelistMethod.javaAugmentedClassName + "] " +
- "not found for method with name [" + whitelistMethod.javaMethodName + "] " +
- "and parameters " + whitelistMethod.painlessParameterTypeNames, cnfe);
+ throw new IllegalArgumentException("augmented class [" + augmentedCanonicalClassName + "] not found for method " +
+ "[[" + targetCanonicalClassName + "], [" + methodName + "], " + typeNameParameters + "]", cnfe);
}
- } else {
- javaAugmentedClass = null;
}
- int augmentedOffset = javaAugmentedClass == null ? 0 : 1;
+ List> typeParameters = new ArrayList<>(typeNameParameters.size());
+
+ for (String typeNameParameter : typeNameParameters) {
+ try {
+ Class> typeParameter = canonicalTypeNameToType(typeNameParameter);
+ typeParameters.add(typeParameter);
+ } catch (IllegalArgumentException iae) {
+ throw new IllegalArgumentException("parameter type [" + typeNameParameter + "] not found for method " +
+ "[[" + targetCanonicalClassName + "], [" + methodName + "], " + typeNameParameters + "]", iae);
+ }
+ }
- List> painlessParametersTypes = new ArrayList<>(whitelistMethod.painlessParameterTypeNames.size());
- Class>[] javaClassParameters = new Class>[whitelistMethod.painlessParameterTypeNames.size() + augmentedOffset];
+ Class> returnType;
- if (javaAugmentedClass != null) {
- javaClassParameters[0] = ownerStruct.clazz;
+ try {
+ returnType = canonicalTypeNameToType(returnCanonicalTypeName);
+ } catch (IllegalArgumentException iae) {
+ throw new IllegalArgumentException("parameter type [" + returnCanonicalTypeName + "] not found for method " +
+ "[[" + targetCanonicalClassName + "], [" + methodName + "], " + typeNameParameters + "]", iae);
}
- for (int parameterCount = 0; parameterCount < whitelistMethod.painlessParameterTypeNames.size(); ++parameterCount) {
- String painlessParameterTypeName = whitelistMethod.painlessParameterTypeNames.get(parameterCount);
+ addPainlessMethod(targetClass, augmentedClass, methodName, returnType, typeParameters);
+ }
- try {
- Class> painlessParameterClass = canonicalTypeNameToType(painlessParameterTypeName);
+ public void addPainlessMethod(Class> targetClass, Class> augmentedClass, String methodName,
+ Class> returnType, List> typeParameters) {
+ Objects.requireNonNull(targetClass);
+ Objects.requireNonNull(methodName);
+ Objects.requireNonNull(returnType);
+ Objects.requireNonNull(typeParameters);
- painlessParametersTypes.add(painlessParameterClass);
- javaClassParameters[parameterCount + augmentedOffset] =
- PainlessLookupUtility.typeToJavaType(painlessParameterClass);
- } catch (IllegalArgumentException iae) {
- throw new IllegalArgumentException("struct not defined for method parameter [" + painlessParameterTypeName + "] " +
- "with owner struct [" + ownerStructName + "] and method with name [" + whitelistMethod.javaMethodName + "] " +
- "and parameters " + whitelistMethod.painlessParameterTypeNames, iae);
- }
+ if (targetClass == def.class) {
+ throw new IllegalArgumentException("cannot add method to reserved class [" + DEF_CLASS_NAME + "]");
}
- Class> javaImplClass = javaAugmentedClass == null ? ownerStruct.clazz : javaAugmentedClass;
- java.lang.reflect.Method javaMethod;
+ String targetCanonicalClassName = typeToCanonicalTypeName(targetClass);
- try {
- javaMethod = javaImplClass.getMethod(whitelistMethod.javaMethodName, javaClassParameters);
- } catch (NoSuchMethodException nsme) {
- throw new IllegalArgumentException("method with name [" + whitelistMethod.javaMethodName + "] " +
- "and parameters " + whitelistMethod.painlessParameterTypeNames + " not found for class [" +
- javaImplClass.getName() + "]", nsme);
+ if (METHOD_NAME_PATTERN.matcher(methodName).matches() == false) {
+ throw new IllegalArgumentException(
+ "invalid method name [" + methodName + "] for target class [" + targetCanonicalClassName + "].");
}
- Class> painlessReturnClass;
+ PainlessClassBuilder painlessClassBuilder = classesToPainlessClassBuilders.get(targetClass);
+
+ if (painlessClassBuilder == null) {
+ throw new IllegalArgumentException("target class [" + targetCanonicalClassName + "] not found for method " +
+ "[[" + targetCanonicalClassName + "], [" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "]");
+ }
+
+ int typeParametersSize = typeParameters.size();
+ int augmentedParameterOffset = augmentedClass == null ? 0 : 1;
+ List> javaTypeParameters = new ArrayList<>(typeParametersSize + augmentedParameterOffset);
+
+ if (augmentedClass != null) {
+ javaTypeParameters.add(targetClass);
+ }
+
+ for (Class> typeParameter : typeParameters) {
+ try {
+ validateType(typeParameter);
+ } catch (IllegalArgumentException iae) {
+ throw new IllegalArgumentException("type parameter [" + typeToCanonicalTypeName(typeParameter) + "] " +
+ "not found for method [[" + targetCanonicalClassName + "], [" + methodName + "], " +
+ typesToCanonicalTypeNames(typeParameters) + "]", iae);
+ }
+
+ javaTypeParameters.add(typeToJavaType(typeParameter));
+ }
try {
- painlessReturnClass = canonicalTypeNameToType(whitelistMethod.painlessReturnTypeName);
+ validateType(returnType);
} catch (IllegalArgumentException iae) {
- throw new IllegalArgumentException("struct not defined for return type [" + whitelistMethod.painlessReturnTypeName + "] " +
- "with owner struct [" + ownerStructName + "] and method with name [" + whitelistMethod.javaMethodName + "] " +
- "and parameters " + whitelistMethod.painlessParameterTypeNames, iae);
+ throw new IllegalArgumentException("return type [" + typeToCanonicalTypeName(returnType) + "] not found for method " +
+ "[[" + targetCanonicalClassName + "], [" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "]", iae);
}
- if (javaMethod.getReturnType() != PainlessLookupUtility.typeToJavaType(painlessReturnClass)) {
- throw new IllegalArgumentException("specified return type class [" + painlessReturnClass + "] " +
- "does not match the return type class [" + javaMethod.getReturnType() + "] for the " +
- "method with name [" + whitelistMethod.javaMethodName + "] " +
- "and parameters " + whitelistMethod.painlessParameterTypeNames);
+ Method javaMethod;
+
+ if (augmentedClass == null) {
+ try {
+ javaMethod = targetClass.getMethod(methodName, javaTypeParameters.toArray(new Class>[typeParametersSize]));
+ } catch (NoSuchMethodException nsme) {
+ throw new IllegalArgumentException("method reflection object [[" + targetCanonicalClassName + "], " +
+ "[" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found", nsme);
+ }
+ } else {
+ try {
+ javaMethod = augmentedClass.getMethod(methodName, javaTypeParameters.toArray(new Class>[typeParametersSize]));
+ } catch (NoSuchMethodException nsme) {
+ throw new IllegalArgumentException("method reflection object [[" + targetCanonicalClassName + "], " +
+ "[" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found " +
+ "with augmented target class [" + typeToCanonicalTypeName(augmentedClass) + "]", nsme);
+ }
}
- String painlessMethodKey =
- buildPainlessMethodKey(whitelistMethod.javaMethodName, whitelistMethod.painlessParameterTypeNames.size());
+ if (javaMethod.getReturnType() != typeToJavaType(returnType)) {
+ throw new IllegalArgumentException("return type [" + typeToCanonicalTypeName(javaMethod.getReturnType()) + "] " +
+ "does not match the specified returned type [" + typeToCanonicalTypeName(returnType) + "] " +
+ "for method [[" + targetClass.getCanonicalName() + "], [" + methodName + "], " +
+ typesToCanonicalTypeNames(typeParameters) + "]");
+ }
+
+ String painlessMethodKey = buildPainlessMethodKey(methodName, typeParametersSize);
- if (javaAugmentedClass == null && Modifier.isStatic(javaMethod.getModifiers())) {
- PainlessMethod painlessMethod = ownerStruct.staticMethods.get(painlessMethodKey);
+ if (augmentedClass == null && Modifier.isStatic(javaMethod.getModifiers())) {
+ PainlessMethod painlessMethod = painlessClassBuilder.staticMethods.get(painlessMethodKey);
if (painlessMethod == null) {
org.objectweb.asm.commons.Method asmMethod = org.objectweb.asm.commons.Method.getMethod(javaMethod);
MethodHandle javaMethodHandle;
try {
- javaMethodHandle = MethodHandles.publicLookup().in(javaImplClass).unreflect(javaMethod);
- } catch (IllegalAccessException exception) {
- throw new IllegalArgumentException("method handle not found for method with name " +
- "[" + whitelistMethod.javaMethodName + "] and parameters " + whitelistMethod.painlessParameterTypeNames);
+ javaMethodHandle = MethodHandles.publicLookup().in(targetClass).unreflect(javaMethod);
+ } catch (IllegalAccessException iae) {
+ throw new IllegalArgumentException("static method handle [[" + targetClass.getCanonicalName() + "], " +
+ "[" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found", iae);
}
painlessMethod = painlessMethodCache.computeIfAbsent(
- new PainlessMethodCacheKey(ownerStruct.clazz, whitelistMethod.javaMethodName, painlessParametersTypes),
- key -> new PainlessMethod(whitelistMethod.javaMethodName, ownerStruct.clazz, null, painlessReturnClass,
- painlessParametersTypes, asmMethod, javaMethod.getModifiers(), javaMethodHandle));
- ownerStruct.staticMethods.put(painlessMethodKey, painlessMethod);
- } else if ((painlessMethod.name.equals(whitelistMethod.javaMethodName) && painlessMethod.rtn == painlessReturnClass &&
- painlessMethod.arguments.equals(painlessParametersTypes)) == false) {
- throw new IllegalArgumentException("illegal duplicate static methods [" + painlessMethodKey + "] " +
- "found within the struct [" + ownerStruct.name + "] with name [" + whitelistMethod.javaMethodName + "], " +
- "return types [" + painlessReturnClass + "] and [" + painlessMethod.rtn + "], " +
- "and parameters " + painlessParametersTypes + " and " + painlessMethod.arguments);
+ new PainlessMethodCacheKey(targetClass, methodName, typeParameters),
+ key -> new PainlessMethod(methodName, targetClass, null, returnType,
+ typeParameters, asmMethod, javaMethod.getModifiers(), javaMethodHandle));
+
+ painlessClassBuilder.staticMethods.put(painlessMethodKey, painlessMethod);
+ } else if ((painlessMethod.name.equals(methodName) && painlessMethod.rtn == returnType &&
+ painlessMethod.arguments.equals(typeParameters)) == false) {
+ throw new IllegalArgumentException("cannot have static methods " +
+ "[[" + targetCanonicalClassName + "], [" + methodName + "], " +
+ "[" + typeToCanonicalTypeName(returnType) + "], " +
+ typesToCanonicalTypeNames(typeParameters) + "] and " +
+ "[[" + targetCanonicalClassName + "], [" + methodName + "], " +
+ "[" + typeToCanonicalTypeName(painlessMethod.rtn) + "], " +
+ typesToCanonicalTypeNames(painlessMethod.arguments) + "] " +
+ "with the same arity and different return type or type parameters");
}
} else {
- PainlessMethod painlessMethod = ownerStruct.methods.get(painlessMethodKey);
+ PainlessMethod painlessMethod = painlessClassBuilder.staticMethods.get(painlessMethodKey);
if (painlessMethod == null) {
org.objectweb.asm.commons.Method asmMethod = org.objectweb.asm.commons.Method.getMethod(javaMethod);
MethodHandle javaMethodHandle;
- try {
- javaMethodHandle = MethodHandles.publicLookup().in(javaImplClass).unreflect(javaMethod);
- } catch (IllegalAccessException exception) {
- throw new IllegalArgumentException("method handle not found for method with name " +
- "[" + whitelistMethod.javaMethodName + "] and parameters " + whitelistMethod.painlessParameterTypeNames);
+ if (augmentedClass == null) {
+ try {
+ javaMethodHandle = MethodHandles.publicLookup().in(targetClass).unreflect(javaMethod);
+ } catch (IllegalAccessException iae) {
+ throw new IllegalArgumentException("method handle [[" + targetClass.getCanonicalName() + "], " +
+ "[" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found", iae);
+ }
+ } else {
+ try {
+ javaMethodHandle = MethodHandles.publicLookup().in(augmentedClass).unreflect(javaMethod);
+ } catch (IllegalAccessException iae) {
+ throw new IllegalArgumentException("method handle [[" + targetClass.getCanonicalName() + "], " +
+ "[" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found " +
+ "with augmented target class [" + typeToCanonicalTypeName(augmentedClass) + "]", iae);
+ }
}
painlessMethod = painlessMethodCache.computeIfAbsent(
- new PainlessMethodCacheKey(ownerStruct.clazz, whitelistMethod.javaMethodName, painlessParametersTypes),
- key -> new PainlessMethod(whitelistMethod.javaMethodName, ownerStruct.clazz, javaAugmentedClass, painlessReturnClass,
- painlessParametersTypes, asmMethod, javaMethod.getModifiers(), javaMethodHandle));
- ownerStruct.methods.put(painlessMethodKey, painlessMethod);
- } else if ((painlessMethod.name.equals(whitelistMethod.javaMethodName) && painlessMethod.rtn.equals(painlessReturnClass) &&
- painlessMethod.arguments.equals(painlessParametersTypes)) == false) {
- throw new IllegalArgumentException("illegal duplicate member methods [" + painlessMethodKey + "] " +
- "found within the struct [" + ownerStruct.name + "] with name [" + whitelistMethod.javaMethodName + "], " +
- "return types [" + painlessReturnClass + "] and [" + painlessMethod.rtn + "], " +
- "and parameters " + painlessParametersTypes + " and " + painlessMethod.arguments);
+ new PainlessMethodCacheKey(targetClass, methodName, typeParameters),
+ key -> new PainlessMethod(methodName, targetClass, augmentedClass, returnType,
+ typeParameters, asmMethod, javaMethod.getModifiers(), javaMethodHandle));
+
+ painlessClassBuilder.methods.put(painlessMethodKey, painlessMethod);
+ } else if ((painlessMethod.name.equals(methodName) && painlessMethod.rtn == returnType &&
+ painlessMethod.arguments.equals(typeParameters)) == false) {
+ throw new IllegalArgumentException("cannot have methods " +
+ "[[" + targetCanonicalClassName + "], [" + methodName + "], " +
+ "[" + typeToCanonicalTypeName(returnType) + "], " +
+ typesToCanonicalTypeNames(typeParameters) + "] and " +
+ "[[" + targetCanonicalClassName + "], [" + methodName + "], " +
+ "[" + typeToCanonicalTypeName(painlessMethod.rtn) + "], " +
+ typesToCanonicalTypeNames(painlessMethod.arguments) + "] " +
+ "with the same arity and different return type or type parameters");
}
}
}
- private void addField(String ownerStructName, WhitelistField whitelistField) {
- PainlessClassBuilder ownerStruct = classesToPainlessClasses.get(canonicalClassNamesToClasses.get(ownerStructName));
+ public void addPainlessField(String targetCanonicalClassName, String fieldName, String typeNameParameter) {
+ Objects.requireNonNull(targetCanonicalClassName);
+ Objects.requireNonNull(fieldName);
+ Objects.requireNonNull(typeNameParameter);
- if (ownerStruct == null) {
- throw new IllegalArgumentException("owner struct [" + ownerStructName + "] not defined for method with " +
- "name [" + whitelistField.javaFieldName + "] and type " + whitelistField.painlessFieldTypeName);
- }
+ Class> targetClass = canonicalClassNamesToClasses.get(targetCanonicalClassName);
- if (FIELD_NAME_PATTERN.matcher(whitelistField.javaFieldName).matches() == false) {
- throw new IllegalArgumentException("invalid field name " +
- "[" + whitelistField.painlessFieldTypeName + "] for owner struct [" + ownerStructName + "].");
+ if (targetClass == null) {
+ throw new IllegalArgumentException("class [" + targetCanonicalClassName + "] not found");
}
- java.lang.reflect.Field javaField;
+ Class> typeParameter;
try {
- javaField = ownerStruct.clazz.getField(whitelistField.javaFieldName);
- } catch (NoSuchFieldException exception) {
- throw new IllegalArgumentException("field [" + whitelistField.javaFieldName + "] " +
- "not found for class [" + ownerStruct.clazz.getName() + "].");
+ typeParameter = canonicalTypeNameToType(typeNameParameter);
+ } catch (IllegalArgumentException iae) {
+ throw new IllegalArgumentException("type parameter [" + typeNameParameter + "] not found " +
+ "for field [[" + targetCanonicalClassName + "], [" + fieldName + "]");
+ }
+
+
+ addPainlessField(targetClass, fieldName, typeParameter);
+ }
+
+ public void addPainlessField(Class> targetClass, String fieldName, Class> typeParameter) {
+ Objects.requireNonNull(targetClass);
+ Objects.requireNonNull(fieldName);
+ Objects.requireNonNull(typeParameter);
+
+ if (targetClass == def.class) {
+ throw new IllegalArgumentException("cannot add field to reserved class [" + DEF_CLASS_NAME + "]");
+ }
+
+ String targetCanonicalClassName = typeToCanonicalTypeName(targetClass);
+
+ if (FIELD_NAME_PATTERN.matcher(fieldName).matches() == false) {
+ throw new IllegalArgumentException(
+ "invalid field name [" + fieldName + "] for target class [" + targetCanonicalClassName + "].");
}
- Class> painlessFieldClass;
+
+ PainlessClassBuilder painlessClassBuilder = classesToPainlessClassBuilders.get(targetClass);
+
+ if (painlessClassBuilder == null) {
+ throw new IllegalArgumentException("class [" + targetCanonicalClassName + "] not found");
+ }
try {
- painlessFieldClass = canonicalTypeNameToType(whitelistField.painlessFieldTypeName);
+ validateType(typeParameter);
} catch (IllegalArgumentException iae) {
- throw new IllegalArgumentException("struct not defined for return type [" + whitelistField.painlessFieldTypeName + "] " +
- "with owner struct [" + ownerStructName + "] and field with name [" + whitelistField.javaFieldName + "]", iae);
+ throw new IllegalArgumentException("type parameter [" + typeToCanonicalTypeName(typeParameter) + "] not found " +
+ "for field [[" + targetCanonicalClassName + "], [" + fieldName + "]", iae);
+ }
+
+ Field javaField;
+
+ try {
+ javaField = targetClass.getField(fieldName);
+ } catch (NoSuchFieldException nsme) {
+ throw new IllegalArgumentException(
+ "field reflection object [[" + targetCanonicalClassName + "], [" + fieldName + "] not found", nsme);
}
+ if (javaField.getType() != typeToJavaType(typeParameter)) {
+ throw new IllegalArgumentException("type parameter [" + typeToCanonicalTypeName(javaField.getType()) + "] " +
+ "does not match the specified type parameter [" + typeToCanonicalTypeName(typeParameter) + "] " +
+ "for field [[" + targetCanonicalClassName + "], [" + fieldName + "]");
+ }
+
+ String painlessFieldKey = buildPainlessFieldKey(fieldName);
+
if (Modifier.isStatic(javaField.getModifiers())) {
if (Modifier.isFinal(javaField.getModifiers()) == false) {
- throw new IllegalArgumentException("static [" + whitelistField.javaFieldName + "] " +
- "with owner struct [" + ownerStruct.name + "] is not final");
+ throw new IllegalArgumentException("static field [[" + targetCanonicalClassName + "]. [" + fieldName + "]] must be final");
}
- PainlessField painlessField = ownerStruct.staticMembers.get(whitelistField.javaFieldName);
+ PainlessField painlessField = painlessClassBuilder.staticMembers.get(painlessFieldKey);
if (painlessField == null) {
painlessField = painlessFieldCache.computeIfAbsent(
- new PainlessFieldCacheKey(ownerStruct.clazz, whitelistField.javaFieldName, painlessFieldClass),
- key -> new PainlessField(whitelistField.javaFieldName, javaField.getName(),
- ownerStruct.clazz, painlessFieldClass, javaField.getModifiers(), null, null));
- ownerStruct.staticMembers.put(whitelistField.javaFieldName, painlessField);
- } else if (painlessField.clazz != painlessFieldClass) {
- throw new IllegalArgumentException("illegal duplicate static fields [" + whitelistField.javaFieldName + "] " +
- "found within the struct [" + ownerStruct.name + "] with type [" + whitelistField.painlessFieldTypeName + "]");
+ new PainlessFieldCacheKey(targetClass, fieldName, typeParameter),
+ key -> new PainlessField(fieldName, javaField.getName(), targetClass,
+ typeParameter, javaField.getModifiers(), null, null));
+
+ painlessClassBuilder.staticMembers.put(painlessFieldKey, painlessField);
+ } else if (painlessField.clazz != typeParameter) {
+ throw new IllegalArgumentException("cannot have static fields " +
+ "[[" + targetCanonicalClassName + "], [" + fieldName + "], [" +
+ typeToCanonicalTypeName(typeParameter) + "] and " +
+ "[[" + targetCanonicalClassName + "], [" + painlessField.name + "], " +
+ typeToCanonicalTypeName(painlessField.clazz) + "] " +
+ "with the same and different type parameters");
}
} else {
- MethodHandle javaMethodHandleGetter;
- MethodHandle javaMethodHandleSetter;
+ MethodHandle methodHandleGetter;
try {
- if (Modifier.isStatic(javaField.getModifiers()) == false) {
- javaMethodHandleGetter = MethodHandles.publicLookup().unreflectGetter(javaField);
- javaMethodHandleSetter = MethodHandles.publicLookup().unreflectSetter(javaField);
- } else {
- javaMethodHandleGetter = null;
- javaMethodHandleSetter = null;
- }
- } catch (IllegalAccessException exception) {
- throw new IllegalArgumentException("getter/setter [" + whitelistField.javaFieldName + "]" +
- " not found for class [" + ownerStruct.clazz.getName() + "].");
+ methodHandleGetter = MethodHandles.publicLookup().unreflectGetter(javaField);
+ } catch (IllegalAccessException iae) {
+ throw new IllegalArgumentException(
+ "method handle getter not found for field [[" + targetCanonicalClassName + "], [" + fieldName + "]]");
}
- PainlessField painlessField = ownerStruct.members.get(whitelistField.javaFieldName);
+ MethodHandle methodHandleSetter;
- if (painlessField == null) {
- painlessField = painlessFieldCache.computeIfAbsent(
- new PainlessFieldCacheKey(ownerStruct.clazz, whitelistField.javaFieldName, painlessFieldClass),
- key -> new PainlessField(whitelistField.javaFieldName, javaField.getName(),
- ownerStruct.clazz, painlessFieldClass, javaField.getModifiers(), javaMethodHandleGetter, javaMethodHandleSetter));
- ownerStruct.members.put(whitelistField.javaFieldName, painlessField);
- } else if (painlessField.clazz != painlessFieldClass) {
- throw new IllegalArgumentException("illegal duplicate member fields [" + whitelistField.javaFieldName + "] " +
- "found within the struct [" + ownerStruct.name + "] with type [" + whitelistField.painlessFieldTypeName + "]");
- }
- }
- }
-
- private void copyStruct(String struct, List children) {
- final PainlessClassBuilder owner = classesToPainlessClasses.get(canonicalClassNamesToClasses.get(struct));
-
- if (owner == null) {
- throw new IllegalArgumentException("Owner struct [" + struct + "] not defined for copy.");
- }
-
- for (int count = 0; count < children.size(); ++count) {
- final PainlessClassBuilder child =
- classesToPainlessClasses.get(canonicalClassNamesToClasses.get(children.get(count)));
-
- if (child == null) {
- throw new IllegalArgumentException("Child struct [" + children.get(count) + "]" +
- " not defined for copy to owner struct [" + owner.name + "].");
- }
-
- if (!child.clazz.isAssignableFrom(owner.clazz)) {
- throw new ClassCastException("Child struct [" + child.name + "]" +
- " is not a super type of owner struct [" + owner.name + "] in copy.");
- }
-
- for (Map.Entry kvPair : child.methods.entrySet()) {
- String methodKey = kvPair.getKey();
- PainlessMethod method = kvPair.getValue();
- if (owner.methods.get(methodKey) == null) {
- // TODO: some of these are no longer valid or outright don't work
- // TODO: since classes may not come from the Painless classloader
- // TODO: and it was dependent on the order of the extends which
- // TODO: which no longer exists since this is generated automatically
- // sanity check, look for missing covariant/generic override
- /*if (owner.clazz.isInterface() && child.clazz == Object.class) {
- // ok
- } else if (child.clazz == Spliterator.OfPrimitive.class || child.clazz == PrimitiveIterator.class) {
- // ok, we rely on generics erasure for these (its guaranteed in the javadocs though!!!!)
- } else if (Constants.JRE_IS_MINIMUM_JAVA9 && owner.clazz == LocalDate.class) {
- // ok, java 9 added covariant override for LocalDate.getEra() to return IsoEra:
- // https://bugs.openjdk.java.net/browse/JDK-8072746
- } else {
- try {
- // TODO: we *have* to remove all these public members and use getter methods to encapsulate!
- final Class> impl;
- final Class> arguments[];
- if (method.augmentation != null) {
- impl = method.augmentation;
- arguments = new Class>[method.arguments.size() + 1];
- arguments[0] = method.owner.clazz;
- for (int i = 0; i < method.arguments.size(); i++) {
- arguments[i + 1] = method.arguments.get(i).clazz;
- }
- } else {
- impl = owner.clazz;
- arguments = new Class>[method.arguments.size()];
- for (int i = 0; i < method.arguments.size(); i++) {
- arguments[i] = method.arguments.get(i).clazz;
- }
- }
- java.lang.reflect.Method m = impl.getMethod(method.method.getName(), arguments);
- if (m.getReturnType() != method.rtn.clazz) {
- throw new IllegalStateException("missing covariant override for: " + m + " in " + owner.name);
- }
- if (m.isBridge() && !Modifier.isVolatile(method.modifiers)) {
- // its a bridge in the destination, but not in the source, but it might still be ok, check generics:
- java.lang.reflect.Method source = child.clazz.getMethod(method.method.getName(), arguments);
- if (!Arrays.equals(source.getGenericParameterTypes(), source.getParameterTypes())) {
- throw new IllegalStateException("missing generic override for: " + m + " in " + owner.name);
- }
- }
- } catch (ReflectiveOperationException e) {
- throw new AssertionError(e);
- }
- }*/
- owner.methods.put(methodKey, method);
- }
+ try {
+ methodHandleSetter = MethodHandles.publicLookup().unreflectSetter(javaField);
+ } catch (IllegalAccessException iae) {
+ throw new IllegalArgumentException(
+ "method handle setter not found for field [[" + targetCanonicalClassName + "], [" + fieldName + "]]");
}
- for (PainlessField field : child.members.values()) {
- if (owner.members.get(field.name) == null) {
- owner.members.put(field.name, new PainlessField(
- field.name, field.javaName, owner.clazz, field.clazz, field.modifiers, field.getter, field.setter));
- }
- }
- }
- }
+ PainlessField painlessField = painlessClassBuilder.members.get(painlessFieldKey);
- /**
- * Precomputes a more efficient structure for dynamic method/field access.
- */
- private void addRuntimeClass(final PainlessClassBuilder struct) {
- // add all getters/setters
- for (Map.Entry method : struct.methods.entrySet()) {
- String name = method.getValue().name;
- PainlessMethod m = method.getValue();
-
- if (m.arguments.size() == 0 &&
- name.startsWith("get") &&
- name.length() > 3 &&
- Character.isUpperCase(name.charAt(3))) {
- StringBuilder newName = new StringBuilder();
- newName.append(Character.toLowerCase(name.charAt(3)));
- newName.append(name.substring(4));
- struct.getters.putIfAbsent(newName.toString(), m.handle);
- } else if (m.arguments.size() == 0 &&
- name.startsWith("is") &&
- name.length() > 2 &&
- Character.isUpperCase(name.charAt(2))) {
- StringBuilder newName = new StringBuilder();
- newName.append(Character.toLowerCase(name.charAt(2)));
- newName.append(name.substring(3));
- struct.getters.putIfAbsent(newName.toString(), m.handle);
- }
-
- if (m.arguments.size() == 1 &&
- name.startsWith("set") &&
- name.length() > 3 &&
- Character.isUpperCase(name.charAt(3))) {
- StringBuilder newName = new StringBuilder();
- newName.append(Character.toLowerCase(name.charAt(3)));
- newName.append(name.substring(4));
- struct.setters.putIfAbsent(newName.toString(), m.handle);
- }
- }
-
- // add all members
- for (Map.Entry member : struct.members.entrySet()) {
- struct.getters.put(member.getKey(), member.getValue().getter);
- struct.setters.put(member.getKey(), member.getValue().setter);
- }
- }
+ if (painlessField == null) {
+ painlessField = painlessFieldCache.computeIfAbsent(
+ new PainlessFieldCacheKey(targetClass, painlessFieldKey, typeParameter),
+ key -> new PainlessField(fieldName, javaField.getName(), targetClass,
+ typeParameter, javaField.getModifiers(), methodHandleGetter, methodHandleSetter));
- /** computes the functional interface method for a class, or returns null */
- private PainlessMethod computeFunctionalInterfaceMethod(PainlessClassBuilder clazz) {
- if (!clazz.clazz.isInterface()) {
- return null;
- }
- // if its marked with this annotation, we fail if the conditions don't hold (means whitelist bug)
- // otherwise, this annotation is pretty useless.
- boolean hasAnnotation = clazz.clazz.isAnnotationPresent(FunctionalInterface.class);
- List methods = new ArrayList<>();
- for (java.lang.reflect.Method m : clazz.clazz.getMethods()) {
- // default interface methods don't count
- if (m.isDefault()) {
- continue;
- }
- // static methods don't count
- if (Modifier.isStatic(m.getModifiers())) {
- continue;
- }
- // if its from Object, it doesn't count
- try {
- Object.class.getMethod(m.getName(), m.getParameterTypes());
- continue;
- } catch (ReflectiveOperationException e) {
- // it counts
+ painlessClassBuilder.members.put(fieldName, painlessField);
+ } else if (painlessField.clazz != typeParameter) {
+ throw new IllegalArgumentException("cannot have fields " +
+ "[[" + targetCanonicalClassName + "], [" + fieldName + "], [" +
+ typeToCanonicalTypeName(typeParameter) + "] and " +
+ "[[" + targetCanonicalClassName + "], [" + painlessField.name + "], " +
+ typeToCanonicalTypeName(painlessField.clazz) + "] " +
+ "with the same and different type parameters");
}
- methods.add(m);
}
- if (methods.size() != 1) {
- if (hasAnnotation) {
- throw new IllegalArgumentException("Class: " + clazz.name +
- " is marked with FunctionalInterface but doesn't fit the bill: " + methods);
- }
- return null;
- }
- // inspect the one method found from the reflection API, it should match the whitelist!
- java.lang.reflect.Method oneMethod = methods.get(0);
- PainlessMethod painless = clazz.methods.get(buildPainlessMethodKey(oneMethod.getName(), oneMethod.getParameterCount()));
- if (painless == null || painless.method.equals(org.objectweb.asm.commons.Method.getMethod(oneMethod)) == false) {
- throw new IllegalArgumentException("Class: " + clazz.name + " is functional but the functional " +
- "method is not whitelisted!");
- }
- return painless;
}
public PainlessLookup build() {
@@ -690,19 +675,19 @@ public PainlessLookup build() {
for (WhitelistClass whitelistStruct : whitelist.whitelistStructs) {
String painlessTypeName = whitelistStruct.javaClassName.replace('$', '.');
PainlessClassBuilder painlessStruct =
- classesToPainlessClasses.get(canonicalClassNamesToClasses.get(painlessTypeName));
+ classesToPainlessClassBuilders.get(canonicalClassNamesToClasses.get(painlessTypeName));
if (painlessStruct != null && painlessStruct.clazz.getName().equals(whitelistStruct.javaClassName) == false) {
throw new IllegalArgumentException("struct [" + painlessStruct.name + "] cannot represent multiple classes " +
- "[" + painlessStruct.clazz.getName() + "] and [" + whitelistStruct.javaClassName + "]");
+ "[" + painlessStruct.clazz.getName() + "] and [" + whitelistStruct.javaClassName + "]");
}
origin = whitelistStruct.origin;
addPainlessClass(
whitelist.javaClassLoader, whitelistStruct.javaClassName, whitelistStruct.onlyFQNJavaClassName == false);
- painlessStruct = classesToPainlessClasses.get(canonicalClassNamesToClasses.get(painlessTypeName));
- classesToPainlessClasses.put(painlessStruct.clazz, painlessStruct);
+ painlessStruct = classesToPainlessClassBuilders.get(canonicalClassNamesToClasses.get(painlessTypeName));
+ classesToPainlessClassBuilders.put(painlessStruct.clazz, painlessStruct);
}
}
@@ -715,17 +700,19 @@ public PainlessLookup build() {
for (WhitelistConstructor whitelistConstructor : whitelistStruct.whitelistConstructors) {
origin = whitelistConstructor.origin;
- addConstructor(painlessTypeName, whitelistConstructor);
+ addPainlessConstructor(painlessTypeName, whitelistConstructor.painlessParameterTypeNames);
}
for (WhitelistMethod whitelistMethod : whitelistStruct.whitelistMethods) {
origin = whitelistMethod.origin;
- addMethod(whitelist.javaClassLoader, painlessTypeName, whitelistMethod);
+ addPainlessMethod(whitelist.javaClassLoader, painlessTypeName, whitelistMethod.javaAugmentedClassName,
+ whitelistMethod.javaMethodName, whitelistMethod.painlessReturnTypeName,
+ whitelistMethod.painlessParameterTypeNames);
}
for (WhitelistField whitelistField : whitelistStruct.whitelistFields) {
origin = whitelistField.origin;
- addField(painlessTypeName, whitelistField);
+ addPainlessField(painlessTypeName, whitelistField.javaFieldName, whitelistField.painlessFieldTypeName);
}
}
}
@@ -733,78 +720,144 @@ public PainlessLookup build() {
throw new IllegalArgumentException("error loading whitelist(s) " + origin, exception);
}
- // goes through each Painless struct and determines the inheritance list,
- // and then adds all inherited types to the Painless struct's whitelist
- for (Class> javaClass : classesToPainlessClasses.keySet()) {
- PainlessClassBuilder painlessStruct = classesToPainlessClasses.get(javaClass);
+ copyPainlessClassMembers();
+ cacheRuntimeHandles();
+ setFunctionalInterfaceMethods();
+
+ Map, PainlessClass> classesToPainlessClasses = new HashMap<>(classesToPainlessClassBuilders.size());
- List painlessSuperStructs = new ArrayList<>();
- Class> javaSuperClass = painlessStruct.clazz.getSuperclass();
+ for (Map.Entry, PainlessClassBuilder> painlessClassBuilderEntry : classesToPainlessClassBuilders.entrySet()) {
+ classesToPainlessClasses.put(painlessClassBuilderEntry.getKey(), painlessClassBuilderEntry.getValue().build());
+ }
- Stack> javaInteraceLookups = new Stack<>();
- javaInteraceLookups.push(painlessStruct.clazz);
+ return new PainlessLookup(canonicalClassNamesToClasses, classesToPainlessClasses);
+ }
- // adds super classes to the inheritance list
- if (javaSuperClass != null && javaSuperClass.isInterface() == false) {
- while (javaSuperClass != null) {
- PainlessClassBuilder painlessSuperStruct = classesToPainlessClasses.get(javaSuperClass);
+ private void copyPainlessClassMembers() {
+ for (Class> parentClass : classesToPainlessClassBuilders.keySet()) {
+ copyPainlessInterfaceMembers(parentClass, parentClass);
- if (painlessSuperStruct != null) {
- painlessSuperStructs.add(painlessSuperStruct.name);
- }
+ Class> childClass = parentClass.getSuperclass();
- javaInteraceLookups.push(javaSuperClass);
- javaSuperClass = javaSuperClass.getSuperclass();
+ while (childClass != null) {
+ if (classesToPainlessClassBuilders.containsKey(childClass)) {
+ copyPainlessClassMembers(childClass, parentClass);
}
+
+ copyPainlessInterfaceMembers(childClass, parentClass);
+ childClass = childClass.getSuperclass();
+ }
+ }
+
+ for (Class> javaClass : classesToPainlessClassBuilders.keySet()) {
+ if (javaClass.isInterface()) {
+ copyPainlessClassMembers(Object.class, javaClass);
+ }
+ }
+ }
+
+ private void copyPainlessInterfaceMembers(Class> parentClass, Class> targetClass) {
+ for (Class> childClass : parentClass.getInterfaces()) {
+ if (classesToPainlessClassBuilders.containsKey(childClass)) {
+ copyPainlessClassMembers(childClass, targetClass);
}
- // adds all super interfaces to the inheritance list
- while (javaInteraceLookups.isEmpty() == false) {
- Class> javaInterfaceLookup = javaInteraceLookups.pop();
+ copyPainlessInterfaceMembers(childClass, targetClass);
+ }
+ }
- for (Class> javaSuperInterface : javaInterfaceLookup.getInterfaces()) {
- PainlessClassBuilder painlessInterfaceStruct = classesToPainlessClasses.get(javaSuperInterface);
+ private void copyPainlessClassMembers(Class> originalClass, Class> targetClass) {
+ PainlessClassBuilder originalPainlessClassBuilder = classesToPainlessClassBuilders.get(originalClass);
+ PainlessClassBuilder targetPainlessClassBuilder = classesToPainlessClassBuilders.get(targetClass);
- if (painlessInterfaceStruct != null) {
- String painlessInterfaceStructName = painlessInterfaceStruct.name;
+ Objects.requireNonNull(originalPainlessClassBuilder);
+ Objects.requireNonNull(targetPainlessClassBuilder);
- if (painlessSuperStructs.contains(painlessInterfaceStructName) == false) {
- painlessSuperStructs.add(painlessInterfaceStructName);
- }
+ for (Map.Entry painlessMethodEntry : originalPainlessClassBuilder.methods.entrySet()) {
+ String painlessMethodKey = painlessMethodEntry.getKey();
+ PainlessMethod newPainlessMethod = painlessMethodEntry.getValue();
+ PainlessMethod existingPainlessMethod = targetPainlessClassBuilder.methods.get(painlessMethodKey);
- for (Class> javaPushInterface : javaInterfaceLookup.getInterfaces()) {
- javaInteraceLookups.push(javaPushInterface);
- }
- }
- }
+ if (existingPainlessMethod == null || existingPainlessMethod.target != newPainlessMethod.target &&
+ existingPainlessMethod.target.isAssignableFrom(newPainlessMethod.target)) {
+ targetPainlessClassBuilder.methods.put(painlessMethodKey, newPainlessMethod);
}
+ }
- // copies methods and fields from super structs to the parent struct
- copyStruct(painlessStruct.name, painlessSuperStructs);
-
- // copies methods and fields from Object into interface types
- if (painlessStruct.clazz.isInterface() || (def.class.getSimpleName()).equals(painlessStruct.name)) {
- PainlessClassBuilder painlessObjectStruct = classesToPainlessClasses.get(Object.class);
+ for (Map.Entry painlessFieldEntry : originalPainlessClassBuilder.members.entrySet()) {
+ String painlessFieldKey = painlessFieldEntry.getKey();
+ PainlessField newPainlessField = painlessFieldEntry.getValue();
+ PainlessField existingPainlessField = targetPainlessClassBuilder.members.get(painlessFieldKey);
- if (painlessObjectStruct != null) {
- copyStruct(painlessStruct.name, Collections.singletonList(painlessObjectStruct.name));
- }
+ if (existingPainlessField == null || existingPainlessField.target != newPainlessField.target &&
+ existingPainlessField.target.isAssignableFrom(newPainlessField.target)) {
+ targetPainlessClassBuilder.members.put(painlessFieldKey, newPainlessField);
}
}
+ }
- // precompute runtime classes
- for (PainlessClassBuilder painlessStruct : classesToPainlessClasses.values()) {
- addRuntimeClass(painlessStruct);
+ private void cacheRuntimeHandles() {
+ for (PainlessClassBuilder painlessClassBuilder : classesToPainlessClassBuilders.values()) {
+ cacheRuntimeHandles(painlessClassBuilder);
}
+ }
+
+ private void cacheRuntimeHandles(PainlessClassBuilder painlessClassBuilder) {
+ for (PainlessMethod painlessMethod : painlessClassBuilder.methods.values()) {
+ String methodName = painlessMethod.name;
+ int typeParametersSize = painlessMethod.arguments.size();
- Map, PainlessClass> javaClassesToPainlessClasses = new HashMap<>();
+ if (typeParametersSize == 0 && methodName.startsWith("get") && methodName.length() > 3 &&
+ Character.isUpperCase(methodName.charAt(3))) {
+ painlessClassBuilder.getters.putIfAbsent(
+ Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4), painlessMethod.handle);
+ } else if (typeParametersSize == 0 && methodName.startsWith("is") && methodName.length() > 2 &&
+ Character.isUpperCase(methodName.charAt(2))) {
+ painlessClassBuilder.getters.putIfAbsent(
+ Character.toLowerCase(methodName.charAt(2)) + methodName.substring(3), painlessMethod.handle);
+ } else if (typeParametersSize == 1 && methodName.startsWith("set") && methodName.length() > 3 &&
+ Character.isUpperCase(methodName.charAt(3))) {
+ painlessClassBuilder.setters.putIfAbsent(
+ Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4), painlessMethod.handle);
+ }
+ }
- // copy all structs to make them unmodifiable for outside users:
- for (Map.Entry,PainlessClassBuilder> entry : classesToPainlessClasses.entrySet()) {
- entry.getValue().functionalMethod = computeFunctionalInterfaceMethod(entry.getValue());
- javaClassesToPainlessClasses.put(entry.getKey(), entry.getValue().build());
+ for (PainlessField painlessField : painlessClassBuilder.members.values()) {
+ painlessClassBuilder.getters.put(painlessField.name, painlessField.getter);
+ painlessClassBuilder.setters.put(painlessField.name, painlessField.setter);
}
+ }
+
+ private void setFunctionalInterfaceMethods() {
+ for (Map.Entry, PainlessClassBuilder> painlessClassBuilderEntry : classesToPainlessClassBuilders.entrySet()) {
+ setFunctionalInterfaceMethod(painlessClassBuilderEntry.getValue());
+ }
+ }
- return new PainlessLookup(canonicalClassNamesToClasses, javaClassesToPainlessClasses);
+ private void setFunctionalInterfaceMethod(PainlessClassBuilder painlessClassBuilder) {
+ Class> targetClass = painlessClassBuilder.clazz;
+
+ if (targetClass.isInterface()) {
+ List javaMethods = new ArrayList<>();
+
+ for (java.lang.reflect.Method javaMethod : targetClass.getMethods()) {
+ if (javaMethod.isDefault() == false && Modifier.isStatic(javaMethod.getModifiers()) == false) {
+ try {
+ Object.class.getMethod(javaMethod.getName(), javaMethod.getParameterTypes());
+ } catch (ReflectiveOperationException roe) {
+ javaMethods.add(javaMethod);
+ }
+ }
+ }
+
+ if (javaMethods.size() != 1 && targetClass.isAnnotationPresent(FunctionalInterface.class)) {
+ throw new IllegalArgumentException("class [" + typeToCanonicalTypeName(targetClass) + "] " +
+ "is illegally marked as a FunctionalInterface with java methods " + javaMethods);
+ } else if (javaMethods.size() == 1) {
+ java.lang.reflect.Method javaMethod = javaMethods.get(0);
+ String painlessMethodKey = buildPainlessMethodKey(javaMethod.getName(), javaMethod.getParameterCount());
+ painlessClassBuilder.functionalMethod = painlessClassBuilder.methods.get(painlessMethodKey);
+ }
+ }
}
}
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupUtility.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupUtility.java
index 1f698b7c673f5..86d3f87663867 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupUtility.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupUtility.java
@@ -33,10 +33,12 @@
*
* A class is a set of methods and fields under a specific class name. A type is either a class or an array under a specific type name.
* Note the distinction between class versus type is class means that no array classes will be be represented whereas type allows array
- * classes to be represented. The set of available classes will always be a subset of the available types.
+ * classes to be represented. The set of available classes will always be a subset of the available types.
*
* Under ambiguous circumstances most variable names are prefixed with asm, java, or painless. If the variable value is the same for asm,
- * java, and painless, no prefix is used.
+ * java, and painless, no prefix is used. Target is used as a prefix to represent if a constructor, method, or field is being
+ * called/accessed on that specific class. Parameter is often a postfix used to represent if a type is used as a parameter to a
+ * constructor, method, or field.
*
*
* - - javaClassName (String) - the fully qualified java class name where '$' tokens represent inner classes excluding
@@ -150,8 +152,8 @@ public static String typeToCanonicalTypeName(Class> type) {
String canonicalTypeName = type.getCanonicalName();
- if (canonicalTypeName.startsWith(def.class.getName())) {
- canonicalTypeName = canonicalTypeName.replace(def.class.getName(), DEF_TYPE_NAME);
+ if (canonicalTypeName.startsWith(def.class.getCanonicalName())) {
+ canonicalTypeName = canonicalTypeName.replace(def.class.getCanonicalName(), DEF_CLASS_NAME);
}
return canonicalTypeName;
@@ -351,7 +353,7 @@ public static String buildPainlessFieldKey(String fieldName) {
/**
* The def type name as specified in the source for a script.
*/
- public static final String DEF_TYPE_NAME = "def";
+ public static final String DEF_CLASS_NAME = "def";
/**
* The method name for all constructors.
diff --git a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/spi/java.lang.txt b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/spi/java.lang.txt
index a793ef847f9c7..ef2d462127f36 100644
--- a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/spi/java.lang.txt
+++ b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/spi/java.lang.txt
@@ -148,7 +148,7 @@ class java.lang.Character {
int MAX_RADIX
char MAX_SURROGATE
char MAX_VALUE
- char MIN_CODE_POINT
+ int MIN_CODE_POINT
char MIN_HIGH_SURROGATE
char MIN_LOW_SURROGATE
int MIN_RADIX
diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/InitializerTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/InitializerTests.java
index 5d881632deeee..d0d0b2165ca10 100644
--- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/InitializerTests.java
+++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/InitializerTests.java
@@ -26,7 +26,7 @@
public class InitializerTests extends ScriptTestCase {
- @SuppressWarnings({"unchecked", "rawtypes"})
+ @SuppressWarnings({"rawtypes"})
public void testArrayInitializers() {
int[] ints = (int[])exec("new int[] {}");
@@ -59,7 +59,7 @@ public void testArrayInitializers() {
assertEquals("aaaaaa", objects[3]);
}
- @SuppressWarnings({"unchecked", "rawtypes"})
+ @SuppressWarnings({"rawtypes"})
public void testListInitializers() {
List list = (List)exec("[]");
@@ -91,7 +91,7 @@ public void testListInitializers() {
assertEquals("aaaaaa", list.get(3));
}
- @SuppressWarnings({"unchecked", "rawtypes"})
+ @SuppressWarnings({"rawtypes"})
public void testMapInitializers() {
Map map = (Map)exec("[:]");
diff --git a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/DiscountedCumulativeGain.java b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/DiscountedCumulativeGain.java
index cab3237732301..a6a6830a99c5f 100644
--- a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/DiscountedCumulativeGain.java
+++ b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/DiscountedCumulativeGain.java
@@ -126,8 +126,6 @@ public Optional forcedSearchSize() {
@Override
public EvalQueryQuality evaluate(String taskId, SearchHit[] hits,
List ratedDocs) {
- List allRatings = ratedDocs.stream().mapToInt(RatedDocument::getRating).boxed()
- .collect(Collectors.toList());
List ratedHits = joinHitsWithRatings(hits, ratedDocs);
List ratingsInSearchHits = new ArrayList<>(ratedHits.size());
int unratedResults = 0;
@@ -144,6 +142,8 @@ public EvalQueryQuality evaluate(String taskId, SearchHit[] hits,
double idcg = 0;
if (normalize) {
+ List allRatings = ratedDocs.stream().mapToInt(RatedDocument::getRating).boxed()
+ .collect(Collectors.toList());
Collections.sort(allRatings, Comparator.nullsLast(Collections.reverseOrder()));
idcg = computeDCG(allRatings.subList(0, Math.min(ratingsInSearchHits.size(), allRatings.size())));
if (idcg != 0) {
diff --git a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/EvalQueryQuality.java b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/EvalQueryQuality.java
index 91ba1ce61692b..f065a34787cbe 100644
--- a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/EvalQueryQuality.java
+++ b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/EvalQueryQuality.java
@@ -41,19 +41,19 @@
public class EvalQueryQuality implements ToXContentFragment, Writeable {
private final String queryId;
- private final double evaluationResult;
+ private final double metricScore;
private MetricDetail optionalMetricDetails;
private final List ratedHits;
- public EvalQueryQuality(String id, double evaluationResult) {
+ public EvalQueryQuality(String id, double metricScore) {
this.queryId = id;
- this.evaluationResult = evaluationResult;
+ this.metricScore = metricScore;
this.ratedHits = new ArrayList<>();
}
public EvalQueryQuality(StreamInput in) throws IOException {
this.queryId = in.readString();
- this.evaluationResult = in.readDouble();
+ this.metricScore = in.readDouble();
this.ratedHits = in.readList(RatedSearchHit::new);
this.optionalMetricDetails = in.readOptionalNamedWriteable(MetricDetail.class);
}
@@ -61,7 +61,7 @@ public EvalQueryQuality(StreamInput in) throws IOException {
// only used for parsing internally
private EvalQueryQuality(String queryId, ParsedEvalQueryQuality builder) {
this.queryId = queryId;
- this.evaluationResult = builder.evaluationResult;
+ this.metricScore = builder.evaluationResult;
this.optionalMetricDetails = builder.optionalMetricDetails;
this.ratedHits = builder.ratedHits;
}
@@ -69,7 +69,7 @@ private EvalQueryQuality(String queryId, ParsedEvalQueryQuality builder) {
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeString(queryId);
- out.writeDouble(evaluationResult);
+ out.writeDouble(metricScore);
out.writeList(ratedHits);
out.writeOptionalNamedWriteable(this.optionalMetricDetails);
}
@@ -78,8 +78,8 @@ public String getId() {
return queryId;
}
- public double getQualityLevel() {
- return evaluationResult;
+ public double metricScore() {
+ return metricScore;
}
public void setMetricDetails(MetricDetail breakdown) {
@@ -101,7 +101,7 @@ public List getHitsAndRatings() {
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(queryId);
- builder.field(QUALITY_LEVEL_FIELD.getPreferredName(), this.evaluationResult);
+ builder.field(METRIC_SCORE_FIELD.getPreferredName(), this.metricScore);
builder.startArray(UNRATED_DOCS_FIELD.getPreferredName());
for (DocumentKey key : EvaluationMetric.filterUnratedDocuments(ratedHits)) {
builder.startObject();
@@ -122,7 +122,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
return builder;
}
- private static final ParseField QUALITY_LEVEL_FIELD = new ParseField("quality_level");
+ static final ParseField METRIC_SCORE_FIELD = new ParseField("metric_score");
private static final ParseField UNRATED_DOCS_FIELD = new ParseField("unrated_docs");
private static final ParseField HITS_FIELD = new ParseField("hits");
private static final ParseField METRIC_DETAILS_FIELD = new ParseField("metric_details");
@@ -136,7 +136,7 @@ private static class ParsedEvalQueryQuality {
}
static {
- PARSER.declareDouble((obj, value) -> obj.evaluationResult = value, QUALITY_LEVEL_FIELD);
+ PARSER.declareDouble((obj, value) -> obj.evaluationResult = value, METRIC_SCORE_FIELD);
PARSER.declareObject((obj, value) -> obj.optionalMetricDetails = value, (p, c) -> parseMetricDetail(p),
METRIC_DETAILS_FIELD);
PARSER.declareObjectArray((obj, list) -> obj.ratedHits = list, (p, c) -> RatedSearchHit.parse(p), HITS_FIELD);
@@ -164,13 +164,13 @@ public final boolean equals(Object obj) {
}
EvalQueryQuality other = (EvalQueryQuality) obj;
return Objects.equals(queryId, other.queryId) &&
- Objects.equals(evaluationResult, other.evaluationResult) &&
+ Objects.equals(metricScore, other.metricScore) &&
Objects.equals(ratedHits, other.ratedHits) &&
Objects.equals(optionalMetricDetails, other.optionalMetricDetails);
}
@Override
public final int hashCode() {
- return Objects.hash(queryId, evaluationResult, ratedHits, optionalMetricDetails);
+ return Objects.hash(queryId, metricScore, ratedHits, optionalMetricDetails);
}
}
diff --git a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/EvaluationMetric.java b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/EvaluationMetric.java
index 37898fd951638..d1e8989047716 100644
--- a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/EvaluationMetric.java
+++ b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/EvaluationMetric.java
@@ -39,23 +39,22 @@
public interface EvaluationMetric extends ToXContentObject, NamedWriteable {
/**
- * Returns a single metric representing the ranking quality of a set of returned
- * documents wrt. to a set of document ids labeled as relevant for this search.
+ * Evaluates a single ranking evaluation case.
*
* @param taskId
- * the id of the query for which the ranking is currently evaluated
+ * an identifier of the query for which the search ranking is
+ * evaluated
* @param hits
- * the result hits as returned by a search request
+ * the search result hits
* @param ratedDocs
- * the documents that were ranked by human annotators for this query
- * case
- * @return some metric representing the quality of the result hit list wrt. to
- * relevant doc ids.
+ * the documents that contain the document rating for this query case
+ * @return an {@link EvalQueryQuality} instance that contains the metric score
+ * with respect to the provided search hits and ratings
*/
EvalQueryQuality evaluate(String taskId, SearchHit[] hits, List ratedDocs);
/**
- * join hits with rated documents using the joint _index/_id document key
+ * Joins hits with rated documents using the joint _index/_id document key.
*/
static List joinHitsWithRatings(SearchHit[] hits, List ratedDocs) {
Map ratedDocumentMap = ratedDocs.stream()
@@ -74,7 +73,7 @@ static List joinHitsWithRatings(SearchHit[] hits, List filterUnratedDocuments(List ratedHits) {
return ratedHits.stream().filter(hit -> hit.getRating().isPresent() == false)
@@ -82,11 +81,11 @@ static List filterUnratedDocuments(List ratedHits)
}
/**
- * how evaluation metrics for particular search queries get combined for the overall evaluation score.
- * Defaults to averaging over the partial results.
+ * Combine several {@link EvalQueryQuality} results into the overall evaluation score.
+ * This defaults to averaging over the partial results, but can be overwritten to obtain a different behavior.
*/
default double combine(Collection partialResults) {
- return partialResults.stream().mapToDouble(EvalQueryQuality::getQualityLevel).sum() / partialResults.size();
+ return partialResults.stream().mapToDouble(EvalQueryQuality::metricScore).sum() / partialResults.size();
}
/**
diff --git a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/ExpectedReciprocalRank.java b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/ExpectedReciprocalRank.java
index 4aac29f299d67..39e1266504d9a 100644
--- a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/ExpectedReciprocalRank.java
+++ b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/ExpectedReciprocalRank.java
@@ -65,6 +65,9 @@ public class ExpectedReciprocalRank implements EvaluationMetric {
public static final String NAME = "expected_reciprocal_rank";
+ /**
+ * @param maxRelevance the highest expected relevance in the data
+ */
public ExpectedReciprocalRank(int maxRelevance) {
this(maxRelevance, null, DEFAULT_K);
}
diff --git a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/MeanReciprocalRank.java b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/MeanReciprocalRank.java
index eb20dc8c680f9..5781f13dafe0c 100644
--- a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/MeanReciprocalRank.java
+++ b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/MeanReciprocalRank.java
@@ -110,8 +110,7 @@ public int getRelevantRatingThreshold() {
* Compute ReciprocalRank based on provided relevant document IDs.
**/
@Override
- public EvalQueryQuality evaluate(String taskId, SearchHit[] hits,
- List ratedDocs) {
+ public EvalQueryQuality evaluate(String taskId, SearchHit[] hits, List ratedDocs) {
List ratedHits = joinHitsWithRatings(hits, ratedDocs);
int firstRelevant = -1;
int rank = 1;
diff --git a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RankEvalNamedXContentProvider.java b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RankEvalNamedXContentProvider.java
index f2176113cdf9d..7eddcf9dff644 100644
--- a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RankEvalNamedXContentProvider.java
+++ b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RankEvalNamedXContentProvider.java
@@ -37,12 +37,17 @@ public List getNamedXContentParsers() {
MeanReciprocalRank::fromXContent));
namedXContent.add(new NamedXContentRegistry.Entry(EvaluationMetric.class, new ParseField(DiscountedCumulativeGain.NAME),
DiscountedCumulativeGain::fromXContent));
+ namedXContent.add(new NamedXContentRegistry.Entry(EvaluationMetric.class, new ParseField(ExpectedReciprocalRank.NAME),
+ ExpectedReciprocalRank::fromXContent));
+
namedXContent.add(new NamedXContentRegistry.Entry(MetricDetail.class, new ParseField(PrecisionAtK.NAME),
PrecisionAtK.Detail::fromXContent));
namedXContent.add(new NamedXContentRegistry.Entry(MetricDetail.class, new ParseField(MeanReciprocalRank.NAME),
MeanReciprocalRank.Detail::fromXContent));
namedXContent.add(new NamedXContentRegistry.Entry(MetricDetail.class, new ParseField(DiscountedCumulativeGain.NAME),
DiscountedCumulativeGain.Detail::fromXContent));
+ namedXContent.add(new NamedXContentRegistry.Entry(MetricDetail.class, new ParseField(ExpectedReciprocalRank.NAME),
+ ExpectedReciprocalRank.Detail::fromXContent));
return namedXContent;
}
}
diff --git a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RankEvalPlugin.java b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RankEvalPlugin.java
index 8ac2b7fbee528..0e5d754778f84 100644
--- a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RankEvalPlugin.java
+++ b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RankEvalPlugin.java
@@ -60,10 +60,14 @@ public List getNamedWriteables() {
namedWriteables.add(new NamedWriteableRegistry.Entry(EvaluationMetric.class, MeanReciprocalRank.NAME, MeanReciprocalRank::new));
namedWriteables.add(
new NamedWriteableRegistry.Entry(EvaluationMetric.class, DiscountedCumulativeGain.NAME, DiscountedCumulativeGain::new));
+ namedWriteables.add(
+ new NamedWriteableRegistry.Entry(EvaluationMetric.class, ExpectedReciprocalRank.NAME, ExpectedReciprocalRank::new));
namedWriteables.add(new NamedWriteableRegistry.Entry(MetricDetail.class, PrecisionAtK.NAME, PrecisionAtK.Detail::new));
namedWriteables.add(new NamedWriteableRegistry.Entry(MetricDetail.class, MeanReciprocalRank.NAME, MeanReciprocalRank.Detail::new));
namedWriteables.add(
new NamedWriteableRegistry.Entry(MetricDetail.class, DiscountedCumulativeGain.NAME, DiscountedCumulativeGain.Detail::new));
+ namedWriteables.add(
+ new NamedWriteableRegistry.Entry(MetricDetail.class, ExpectedReciprocalRank.NAME, ExpectedReciprocalRank.Detail::new));
return namedWriteables;
}
diff --git a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RankEvalResponse.java b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RankEvalResponse.java
index 6dd3c1338fa6a..6efff154b6253 100644
--- a/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RankEvalResponse.java
+++ b/modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RankEvalResponse.java
@@ -48,15 +48,15 @@
public class RankEvalResponse extends ActionResponse implements ToXContentObject {
/** The overall evaluation result. */
- private double evaluationResult;
+ private double metricScore;
/** details about individual ranking evaluation queries, keyed by their id */
private Map details;
/** exceptions for specific ranking evaluation queries, keyed by their id */
private Map failures;
- public RankEvalResponse(double qualityLevel, Map partialResults,
+ public RankEvalResponse(double metricScore, Map partialResults,
Map failures) {
- this.evaluationResult = qualityLevel;
+ this.metricScore = metricScore;
this.details = new HashMap<>(partialResults);
this.failures = new HashMap<>(failures);
}
@@ -65,8 +65,8 @@ public RankEvalResponse(double qualityLevel, Map parti
// only used in RankEvalAction#newResponse()
}
- public double getEvaluationResult() {
- return evaluationResult;
+ public double getMetricScore() {
+ return metricScore;
}
public Map getPartialResults() {
@@ -85,7 +85,7 @@ public String toString() {
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
- out.writeDouble(evaluationResult);
+ out.writeDouble(metricScore);
out.writeVInt(details.size());
for (String queryId : details.keySet()) {
out.writeString(queryId);
@@ -101,7 +101,7 @@ public void writeTo(StreamOutput out) throws IOException {
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
- this.evaluationResult = in.readDouble();
+ this.metricScore = in.readDouble();
int partialResultSize = in.readVInt();
this.details = new HashMap<>(partialResultSize);
for (int i = 0; i < partialResultSize; i++) {
@@ -120,7 +120,7 @@ public void readFrom(StreamInput in) throws IOException {
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
- builder.field("quality_level", evaluationResult);
+ builder.field("metric_score", metricScore);
builder.startObject("details");
for (String key : details.keySet()) {
details.get(key).toXContent(builder, params);
@@ -137,7 +137,6 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
return builder;
}
- private static final ParseField QUALITY_LEVEL_FIELD = new ParseField("quality_level");
private static final ParseField DETAILS_FIELD = new ParseField("details");
private static final ParseField FAILURES_FIELD = new ParseField("failures");
@SuppressWarnings("unchecked")
@@ -147,7 +146,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
((List) a[1]).stream().collect(Collectors.toMap(EvalQueryQuality::getId, Function.identity())),
((List>) a[2]).stream().collect(Collectors.toMap(Tuple::v1, Tuple::v2))));
static {
- PARSER.declareDouble(ConstructingObjectParser.constructorArg(), QUALITY_LEVEL_FIELD);
+ PARSER.declareDouble(ConstructingObjectParser.constructorArg(), EvalQueryQuality.METRIC_SCORE_FIELD);
PARSER.declareNamedObjects(ConstructingObjectParser.optionalConstructorArg(), (p, c, n) -> EvalQueryQuality.fromXContent(p, n),
DETAILS_FIELD);
PARSER.declareNamedObjects(ConstructingObjectParser.optionalConstructorArg(), (p, c, n) -> {
diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/DiscountedCumulativeGainTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/DiscountedCumulativeGainTests.java
index e768c2973330e..468a1ac2e5721 100644
--- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/DiscountedCumulativeGainTests.java
+++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/DiscountedCumulativeGainTests.java
@@ -76,7 +76,7 @@ public void testDCGAt() {
hits[i].shard(new SearchShardTarget("testnode", new Index("index", "uuid"), 0, null));
}
DiscountedCumulativeGain dcg = new DiscountedCumulativeGain();
- assertEquals(EXPECTED_DCG, dcg.evaluate("id", hits, rated).getQualityLevel(), DELTA);
+ assertEquals(EXPECTED_DCG, dcg.evaluate("id", hits, rated).metricScore(), DELTA);
/**
* Check with normalization: to get the maximal possible dcg, sort documents by
@@ -94,7 +94,7 @@ public void testDCGAt() {
* idcg = 14.595390756454922 (sum of last column)
*/
dcg = new DiscountedCumulativeGain(true, null, 10);
- assertEquals(EXPECTED_NDCG, dcg.evaluate("id", hits, rated).getQualityLevel(), DELTA);
+ assertEquals(EXPECTED_NDCG, dcg.evaluate("id", hits, rated).metricScore(), DELTA);
}
/**
@@ -127,7 +127,7 @@ public void testDCGAtSixMissingRatings() {
}
DiscountedCumulativeGain dcg = new DiscountedCumulativeGain();
EvalQueryQuality result = dcg.evaluate("id", hits, rated);
- assertEquals(12.779642067948913, result.getQualityLevel(), DELTA);
+ assertEquals(12.779642067948913, result.metricScore(), DELTA);
assertEquals(2, filterUnratedDocuments(result.getHitsAndRatings()).size());
/**
@@ -146,7 +146,7 @@ public void testDCGAtSixMissingRatings() {
* idcg = 13.347184833073591 (sum of last column)
*/
dcg = new DiscountedCumulativeGain(true, null, 10);
- assertEquals(12.779642067948913 / 13.347184833073591, dcg.evaluate("id", hits, rated).getQualityLevel(), DELTA);
+ assertEquals(12.779642067948913 / 13.347184833073591, dcg.evaluate("id", hits, rated).metricScore(), DELTA);
}
/**
@@ -184,7 +184,7 @@ public void testDCGAtFourMoreRatings() {
}
DiscountedCumulativeGain dcg = new DiscountedCumulativeGain();
EvalQueryQuality result = dcg.evaluate("id", hits, ratedDocs);
- assertEquals(12.392789260714371, result.getQualityLevel(), DELTA);
+ assertEquals(12.392789260714371, result.metricScore(), DELTA);
assertEquals(1, filterUnratedDocuments(result.getHitsAndRatings()).size());
/**
@@ -204,7 +204,7 @@ public void testDCGAtFourMoreRatings() {
* idcg = 13.347184833073591 (sum of last column)
*/
dcg = new DiscountedCumulativeGain(true, null, 10);
- assertEquals(12.392789260714371 / 13.347184833073591, dcg.evaluate("id", hits, ratedDocs).getQualityLevel(), DELTA);
+ assertEquals(12.392789260714371 / 13.347184833073591, dcg.evaluate("id", hits, ratedDocs).metricScore(), DELTA);
}
/**
@@ -223,13 +223,13 @@ public void testNoResults() throws Exception {
SearchHit[] hits = new SearchHit[0];
DiscountedCumulativeGain dcg = new DiscountedCumulativeGain();
EvalQueryQuality result = dcg.evaluate("id", hits, ratedDocs);
- assertEquals(0.0d, result.getQualityLevel(), DELTA);
+ assertEquals(0.0d, result.metricScore(), DELTA);
assertEquals(0, filterUnratedDocuments(result.getHitsAndRatings()).size());
// also check normalized
dcg = new DiscountedCumulativeGain(true, null, 10);
result = dcg.evaluate("id", hits, ratedDocs);
- assertEquals(0.0d, result.getQualityLevel(), DELTA);
+ assertEquals(0.0d, result.metricScore(), DELTA);
assertEquals(0, filterUnratedDocuments(result.getHitsAndRatings()).size());
}
diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/EvalQueryQualityTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/EvalQueryQualityTests.java
index c9251bb80903d..7424542ac26aa 100644
--- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/EvalQueryQualityTests.java
+++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/EvalQueryQualityTests.java
@@ -129,7 +129,7 @@ public void testEqualsAndHash() throws IOException {
private static EvalQueryQuality mutateTestItem(EvalQueryQuality original) {
String id = original.getId();
- double qualityLevel = original.getQualityLevel();
+ double metricScore = original.metricScore();
List ratedHits = new ArrayList<>(original.getHitsAndRatings());
MetricDetail metricDetails = original.getMetricDetails();
switch (randomIntBetween(0, 3)) {
@@ -137,7 +137,7 @@ private static EvalQueryQuality mutateTestItem(EvalQueryQuality original) {
id = id + "_";
break;
case 1:
- qualityLevel = qualityLevel + 0.1;
+ metricScore = metricScore + 0.1;
break;
case 2:
if (metricDetails == null) {
@@ -152,7 +152,7 @@ private static EvalQueryQuality mutateTestItem(EvalQueryQuality original) {
default:
throw new IllegalStateException("The test should only allow four parameters mutated");
}
- EvalQueryQuality evalQueryQuality = new EvalQueryQuality(id, qualityLevel);
+ EvalQueryQuality evalQueryQuality = new EvalQueryQuality(id, metricScore);
evalQueryQuality.setMetricDetails(metricDetails);
evalQueryQuality.addHitsAndRatings(ratedHits);
return evalQueryQuality;
diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/ExpectedReciprocalRankTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/ExpectedReciprocalRankTests.java
index e2be8696e66f1..fe33c246f7d7a 100644
--- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/ExpectedReciprocalRankTests.java
+++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/ExpectedReciprocalRankTests.java
@@ -76,10 +76,10 @@ public void testERRAt() {
Integer[] relevanceRatings = new Integer[] { 3, 2, 0, 1};
SearchHit[] hits = createSearchHits(rated, relevanceRatings);
ExpectedReciprocalRank err = new ExpectedReciprocalRank(3, 0, 3);
- assertEquals(0.8984375, err.evaluate("id", hits, rated).getQualityLevel(), DELTA);
+ assertEquals(0.8984375, err.evaluate("id", hits, rated).metricScore(), DELTA);
// take 4th rank into window
err = new ExpectedReciprocalRank(3, 0, 4);
- assertEquals(0.8984375 + 0.00244140625, err.evaluate("id", hits, rated).getQualityLevel(), DELTA);
+ assertEquals(0.8984375 + 0.00244140625, err.evaluate("id", hits, rated).metricScore(), DELTA);
}
/**
@@ -102,11 +102,11 @@ public void testERRMissingRatings() {
SearchHit[] hits = createSearchHits(rated, relevanceRatings);
ExpectedReciprocalRank err = new ExpectedReciprocalRank(3, null, 4);
EvalQueryQuality evaluation = err.evaluate("id", hits, rated);
- assertEquals(0.875 + 0.00390625, evaluation.getQualityLevel(), DELTA);
+ assertEquals(0.875 + 0.00390625, evaluation.metricScore(), DELTA);
assertEquals(1, ((ExpectedReciprocalRank.Detail) evaluation.getMetricDetails()).getUnratedDocs());
// if we supply e.g. 2 as unknown docs rating, it should be the same as in the other test above
err = new ExpectedReciprocalRank(3, 2, 4);
- assertEquals(0.8984375 + 0.00244140625, err.evaluate("id", hits, rated).getQualityLevel(), DELTA);
+ assertEquals(0.8984375 + 0.00244140625, err.evaluate("id", hits, rated).metricScore(), DELTA);
}
private SearchHit[] createSearchHits(List rated, Integer[] relevanceRatings) {
@@ -126,7 +126,7 @@ private SearchHit[] createSearchHits(List rated, Integer[] releva
*/
public void testNoResults() throws Exception {
ExpectedReciprocalRank err = new ExpectedReciprocalRank(5, 0, 10);
- assertEquals(0.0, err.evaluate("id", new SearchHit[0], Collections.emptyList()).getQualityLevel(), DELTA);
+ assertEquals(0.0, err.evaluate("id", new SearchHit[0], Collections.emptyList()).metricScore(), DELTA);
}
public void testParseFromXContent() throws IOException {
diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/MeanReciprocalRankTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/MeanReciprocalRankTests.java
index f88b0cc663489..fdb64806d5c9e 100644
--- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/MeanReciprocalRankTests.java
+++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/MeanReciprocalRankTests.java
@@ -95,14 +95,14 @@ public void testMaxAcceptableRank() {
int rankAtFirstRelevant = relevantAt + 1;
EvalQueryQuality evaluation = reciprocalRank.evaluate("id", hits, ratedDocs);
- assertEquals(1.0 / rankAtFirstRelevant, evaluation.getQualityLevel(), Double.MIN_VALUE);
+ assertEquals(1.0 / rankAtFirstRelevant, evaluation.metricScore(), Double.MIN_VALUE);
assertEquals(rankAtFirstRelevant, ((MeanReciprocalRank.Detail) evaluation.getMetricDetails()).getFirstRelevantRank());
// check that if we have fewer search hits than relevant doc position,
- // we don't find any result and get 0.0 quality level
+ // we don't find any result and get 0.0 score
reciprocalRank = new MeanReciprocalRank();
evaluation = reciprocalRank.evaluate("id", Arrays.copyOfRange(hits, 0, relevantAt), ratedDocs);
- assertEquals(0.0, evaluation.getQualityLevel(), Double.MIN_VALUE);
+ assertEquals(0.0, evaluation.metricScore(), Double.MIN_VALUE);
}
public void testEvaluationOneRelevantInResults() {
@@ -120,7 +120,7 @@ public void testEvaluationOneRelevantInResults() {
}
EvalQueryQuality evaluation = reciprocalRank.evaluate("id", hits, ratedDocs);
- assertEquals(1.0 / (relevantAt + 1), evaluation.getQualityLevel(), Double.MIN_VALUE);
+ assertEquals(1.0 / (relevantAt + 1), evaluation.metricScore(), Double.MIN_VALUE);
assertEquals(relevantAt + 1, ((MeanReciprocalRank.Detail) evaluation.getMetricDetails()).getFirstRelevantRank());
}
@@ -140,7 +140,7 @@ public void testPrecisionAtFiveRelevanceThreshold() {
MeanReciprocalRank reciprocalRank = new MeanReciprocalRank(2, 10);
EvalQueryQuality evaluation = reciprocalRank.evaluate("id", hits, rated);
- assertEquals((double) 1 / 3, evaluation.getQualityLevel(), 0.00001);
+ assertEquals((double) 1 / 3, evaluation.metricScore(), 0.00001);
assertEquals(3, ((MeanReciprocalRank.Detail) evaluation.getMetricDetails()).getFirstRelevantRank());
}
@@ -158,13 +158,13 @@ public void testEvaluationNoRelevantInResults() {
SearchHit[] hits = createSearchHits(0, 9, "test");
List ratedDocs = new ArrayList<>();
EvalQueryQuality evaluation = reciprocalRank.evaluate("id", hits, ratedDocs);
- assertEquals(0.0, evaluation.getQualityLevel(), Double.MIN_VALUE);
+ assertEquals(0.0, evaluation.metricScore(), Double.MIN_VALUE);
}
public void testNoResults() throws Exception {
SearchHit[] hits = new SearchHit[0];
EvalQueryQuality evaluated = (new MeanReciprocalRank()).evaluate("id", hits, Collections.emptyList());
- assertEquals(0.0d, evaluated.getQualityLevel(), 0.00001);
+ assertEquals(0.0d, evaluated.metricScore(), 0.00001);
assertEquals(-1, ((MeanReciprocalRank.Detail) evaluated.getMetricDetails()).getFirstRelevantRank());
}
diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/PrecisionAtKTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/PrecisionAtKTests.java
index c0035d5dbb72e..73149d5a8aa7e 100644
--- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/PrecisionAtKTests.java
+++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/PrecisionAtKTests.java
@@ -53,7 +53,7 @@ public void testPrecisionAtFiveCalculation() {
List rated = new ArrayList<>();
rated.add(createRatedDoc("test", "0", RELEVANT_RATING_1));
EvalQueryQuality evaluated = (new PrecisionAtK()).evaluate("id", toSearchHits(rated, "test"), rated);
- assertEquals(1, evaluated.getQualityLevel(), 0.00001);
+ assertEquals(1, evaluated.metricScore(), 0.00001);
assertEquals(1, ((PrecisionAtK.Detail) evaluated.getMetricDetails()).getRelevantRetrieved());
assertEquals(1, ((PrecisionAtK.Detail) evaluated.getMetricDetails()).getRetrieved());
}
@@ -66,7 +66,7 @@ public void testPrecisionAtFiveIgnoreOneResult() {
rated.add(createRatedDoc("test", "3", RELEVANT_RATING_1));
rated.add(createRatedDoc("test", "4", IRRELEVANT_RATING_0));
EvalQueryQuality evaluated = (new PrecisionAtK()).evaluate("id", toSearchHits(rated, "test"), rated);
- assertEquals((double) 4 / 5, evaluated.getQualityLevel(), 0.00001);
+ assertEquals((double) 4 / 5, evaluated.metricScore(), 0.00001);
assertEquals(4, ((PrecisionAtK.Detail) evaluated.getMetricDetails()).getRelevantRetrieved());
assertEquals(5, ((PrecisionAtK.Detail) evaluated.getMetricDetails()).getRetrieved());
}
@@ -85,7 +85,7 @@ public void testPrecisionAtFiveRelevanceThreshold() {
rated.add(createRatedDoc("test", "4", 4));
PrecisionAtK precisionAtN = new PrecisionAtK(2, false, 5);
EvalQueryQuality evaluated = precisionAtN.evaluate("id", toSearchHits(rated, "test"), rated);
- assertEquals((double) 3 / 5, evaluated.getQualityLevel(), 0.00001);
+ assertEquals((double) 3 / 5, evaluated.metricScore(), 0.00001);
assertEquals(3, ((PrecisionAtK.Detail) evaluated.getMetricDetails()).getRelevantRetrieved());
assertEquals(5, ((PrecisionAtK.Detail) evaluated.getMetricDetails()).getRetrieved());
}
@@ -99,7 +99,7 @@ public void testPrecisionAtFiveCorrectIndex() {
rated.add(createRatedDoc("test", "2", IRRELEVANT_RATING_0));
// the following search hits contain only the last three documents
EvalQueryQuality evaluated = (new PrecisionAtK()).evaluate("id", toSearchHits(rated.subList(2, 5), "test"), rated);
- assertEquals((double) 2 / 3, evaluated.getQualityLevel(), 0.00001);
+ assertEquals((double) 2 / 3, evaluated.metricScore(), 0.00001);
assertEquals(2, ((PrecisionAtK.Detail) evaluated.getMetricDetails()).getRelevantRetrieved());
assertEquals(3, ((PrecisionAtK.Detail) evaluated.getMetricDetails()).getRetrieved());
}
@@ -114,14 +114,14 @@ public void testIgnoreUnlabeled() {
searchHits[2].shard(new SearchShardTarget("testnode", new Index("index", "uuid"), 0, null));
EvalQueryQuality evaluated = (new PrecisionAtK()).evaluate("id", searchHits, rated);
- assertEquals((double) 2 / 3, evaluated.getQualityLevel(), 0.00001);
+ assertEquals((double) 2 / 3, evaluated.metricScore(), 0.00001);
assertEquals(2, ((PrecisionAtK.Detail) evaluated.getMetricDetails()).getRelevantRetrieved());
assertEquals(3, ((PrecisionAtK.Detail) evaluated.getMetricDetails()).getRetrieved());
// also try with setting `ignore_unlabeled`
PrecisionAtK prec = new PrecisionAtK(1, true, 10);
evaluated = prec.evaluate("id", searchHits, rated);
- assertEquals((double) 2 / 2, evaluated.getQualityLevel(), 0.00001);
+ assertEquals((double) 2 / 2, evaluated.metricScore(), 0.00001);
assertEquals(2, ((PrecisionAtK.Detail) evaluated.getMetricDetails()).getRelevantRetrieved());
assertEquals(2, ((PrecisionAtK.Detail) evaluated.getMetricDetails()).getRetrieved());
}
@@ -133,14 +133,14 @@ public void testNoRatedDocs() throws Exception {
hits[i].shard(new SearchShardTarget("testnode", new Index("index", "uuid"), 0, null));
}
EvalQueryQuality evaluated = (new PrecisionAtK()).evaluate("id", hits, Collections.emptyList());
- assertEquals(0.0d, evaluated.getQualityLevel(), 0.00001);
+ assertEquals(0.0d, evaluated.metricScore(), 0.00001);
assertEquals(0, ((PrecisionAtK.Detail) evaluated.getMetricDetails()).getRelevantRetrieved());
assertEquals(5, ((PrecisionAtK.Detail) evaluated.getMetricDetails()).getRetrieved());
// also try with setting `ignore_unlabeled`
PrecisionAtK prec = new PrecisionAtK(1, true, 10);
evaluated = prec.evaluate("id", hits, Collections.emptyList());
- assertEquals(0.0d, evaluated.getQualityLevel(), 0.00001);
+ assertEquals(0.0d, evaluated.metricScore(), 0.00001);
assertEquals(0, ((PrecisionAtK.Detail) evaluated.getMetricDetails()).getRelevantRetrieved());
assertEquals(0, ((PrecisionAtK.Detail) evaluated.getMetricDetails()).getRetrieved());
}
@@ -148,7 +148,7 @@ public void testNoRatedDocs() throws Exception {
public void testNoResults() throws Exception {
SearchHit[] hits = new SearchHit[0];
EvalQueryQuality evaluated = (new PrecisionAtK()).evaluate("id", hits, Collections.emptyList());
- assertEquals(0.0d, evaluated.getQualityLevel(), 0.00001);
+ assertEquals(0.0d, evaluated.metricScore(), 0.00001);
assertEquals(0, ((PrecisionAtK.Detail) evaluated.getMetricDetails()).getRelevantRetrieved());
assertEquals(0, ((PrecisionAtK.Detail) evaluated.getMetricDetails()).getRetrieved());
}
diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalRequestIT.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalRequestIT.java
index 28200e7d5a0e6..7d594c852da5b 100644
--- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalRequestIT.java
+++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalRequestIT.java
@@ -114,7 +114,7 @@ public void testPrecisionAtRequest() {
// the expected Prec@ for the first query is 4/6 and the expected Prec@ for the
// second is 1/6, divided by 2 to get the average
double expectedPrecision = (1.0 / 6.0 + 4.0 / 6.0) / 2.0;
- assertEquals(expectedPrecision, response.getEvaluationResult(), Double.MIN_VALUE);
+ assertEquals(expectedPrecision, response.getMetricScore(), Double.MIN_VALUE);
Set> entrySet = response.getPartialResults().entrySet();
assertEquals(2, entrySet.size());
for (Entry entry : entrySet) {
@@ -157,7 +157,7 @@ public void testPrecisionAtRequest() {
// if we look only at top 3 documente, the expected P@3 for the first query is
// 2/3 and the expected Prec@ for the second is 1/3, divided by 2 to get the average
expectedPrecision = (1.0 / 3.0 + 2.0 / 3.0) / 2.0;
- assertEquals(expectedPrecision, response.getEvaluationResult(), Double.MIN_VALUE);
+ assertEquals(expectedPrecision, response.getMetricScore(), Double.MIN_VALUE);
}
/**
@@ -186,7 +186,7 @@ public void testDCGRequest() {
new RankEvalRequest(task, new String[] { TEST_INDEX }));
RankEvalResponse response = client().execute(RankEvalAction.INSTANCE, builder.request()).actionGet();
- assertEquals(DiscountedCumulativeGainTests.EXPECTED_DCG, response.getEvaluationResult(), 10E-14);
+ assertEquals(DiscountedCumulativeGainTests.EXPECTED_DCG, response.getMetricScore(), 10E-14);
// test that a different window size k affects the result
metric = new DiscountedCumulativeGain(false, null, 3);
@@ -195,7 +195,7 @@ public void testDCGRequest() {
builder = new RankEvalRequestBuilder(client(), RankEvalAction.INSTANCE, new RankEvalRequest(task, new String[] { TEST_INDEX }));
response = client().execute(RankEvalAction.INSTANCE, builder.request()).actionGet();
- assertEquals(12.39278926071437, response.getEvaluationResult(), 10E-14);
+ assertEquals(12.39278926071437, response.getMetricScore(), 10E-14);
}
public void testMRRRequest() {
@@ -218,7 +218,7 @@ public void testMRRRequest() {
// the expected reciprocal rank for the berlin_query is 1/1
// dividing by 2 to get the average
double expectedMRR = (1.0 + 1.0 / 5.0) / 2.0;
- assertEquals(expectedMRR, response.getEvaluationResult(), 0.0);
+ assertEquals(expectedMRR, response.getMetricScore(), 0.0);
// test that a different window size k affects the result
metric = new MeanReciprocalRank(1, 3);
@@ -231,7 +231,7 @@ public void testMRRRequest() {
// the reciprocal rank for the berlin_query is 1/1
// dividing by 2 to get the average
expectedMRR = 1.0 / 2.0;
- assertEquals(expectedMRR, response.getEvaluationResult(), 0.0);
+ assertEquals(expectedMRR, response.getMetricScore(), 0.0);
}
/**
diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalResponseTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalResponseTests.java
index 1e94e869d2594..673808f836976 100644
--- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalResponseTests.java
+++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalResponseTests.java
@@ -102,7 +102,7 @@ public void testSerialization() throws IOException {
try (StreamInput in = output.bytes().streamInput()) {
RankEvalResponse deserializedResponse = new RankEvalResponse();
deserializedResponse.readFrom(in);
- assertEquals(randomResponse.getEvaluationResult(), deserializedResponse.getEvaluationResult(), Double.MIN_VALUE);
+ assertEquals(randomResponse.getMetricScore(), deserializedResponse.getMetricScore(), Double.MIN_VALUE);
assertEquals(randomResponse.getPartialResults(), deserializedResponse.getPartialResults());
assertEquals(randomResponse.getFailures().keySet(), deserializedResponse.getFailures().keySet());
assertNotSame(randomResponse, deserializedResponse);
@@ -130,7 +130,7 @@ public void testXContentParsing() throws IOException {
assertNotSame(testItem, parsedItem);
// We cannot check equality of object here because some information (e.g.
// SearchHit#shard) cannot fully be parsed back.
- assertEquals(testItem.getEvaluationResult(), parsedItem.getEvaluationResult(), 0.0);
+ assertEquals(testItem.getMetricScore(), parsedItem.getMetricScore(), 0.0);
assertEquals(testItem.getPartialResults().keySet(), parsedItem.getPartialResults().keySet());
for (EvalQueryQuality metricDetail : testItem.getPartialResults().values()) {
EvalQueryQuality parsedEvalQueryQuality = parsedItem.getPartialResults().get(metricDetail.getId());
@@ -154,10 +154,10 @@ public void testToXContent() throws IOException {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
String xContent = BytesReference.bytes(response.toXContent(builder, ToXContent.EMPTY_PARAMS)).utf8ToString();
assertEquals(("{" +
- " \"quality_level\": 0.123," +
+ " \"metric_score\": 0.123," +
" \"details\": {" +
" \"coffee_query\": {" +
- " \"quality_level\": 0.1," +
+ " \"metric_score\": 0.1," +
" \"unrated_docs\": [{\"_index\":\"index\",\"_id\":\"456\"}]," +
" \"hits\":[{\"hit\":{\"_index\":\"index\",\"_type\":\"\",\"_id\":\"123\",\"_score\":1.0}," +
" \"rating\":5}," +
diff --git a/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/10_basic.yml b/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/10_basic.yml
index 62c246fb32066..ebe23ae53f411 100644
--- a/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/10_basic.yml
+++ b/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/10_basic.yml
@@ -71,8 +71,8 @@ setup:
"metric" : { "precision": { "ignore_unlabeled" : true }}
}
- - match: { quality_level: 1}
- - match: { details.amsterdam_query.quality_level: 1.0}
+ - match: { metric_score: 1}
+ - match: { details.amsterdam_query.metric_score: 1.0}
- match: { details.amsterdam_query.unrated_docs: [ {"_index": "foo", "_id": "doc4"}]}
- match: { details.amsterdam_query.metric_details.precision: {"relevant_docs_retrieved": 2, "docs_retrieved": 2}}
@@ -84,7 +84,7 @@ setup:
- match: { details.amsterdam_query.hits.2.hit._id: "doc4"}
- is_false: details.amsterdam_query.hits.2.rating
- - match: { details.berlin_query.quality_level: 1.0}
+ - match: { details.berlin_query.metric_score: 1.0}
- match: { details.berlin_query.unrated_docs: [ {"_index": "foo", "_id": "doc4"}]}
- match: { details.berlin_query.metric_details.precision: {"relevant_docs_retrieved": 1, "docs_retrieved": 1}}
- length: { details.berlin_query.hits: 2}
@@ -118,9 +118,9 @@ setup:
"metric" : { "precision": { "ignore_unlabeled" : true }}
}
- - match: { quality_level: 1}
- - match: { details.amsterdam_query.quality_level: 1.0}
- - match: { details.berlin_query.quality_level: 1.0}
+ - match: { metric_score: 1}
+ - match: { details.amsterdam_query.metric_score: 1.0}
+ - match: { details.berlin_query.metric_score: 1.0}
---
"Mean Reciprocal Rank":
@@ -150,14 +150,48 @@ setup:
}
# average is (1/3 + 1/2)/2 = 5/12 ~ 0.41666666666666663
- - gt: {quality_level: 0.416}
- - lt: {quality_level: 0.417}
- - gt: {details.amsterdam_query.quality_level: 0.333}
- - lt: {details.amsterdam_query.quality_level: 0.334}
+ - gt: {metric_score: 0.416}
+ - lt: {metric_score: 0.417}
+ - gt: {details.amsterdam_query.metric_score: 0.333}
+ - lt: {details.amsterdam_query.metric_score: 0.334}
- match: {details.amsterdam_query.metric_details.mean_reciprocal_rank: {"first_relevant": 3}}
- match: {details.amsterdam_query.unrated_docs: [ {"_index": "foo", "_id": "doc2"},
{"_index": "foo", "_id": "doc3"} ]}
- - match: {details.berlin_query.quality_level: 0.5}
+ - match: {details.berlin_query.metric_score: 0.5}
- match: {details.berlin_query.metric_details.mean_reciprocal_rank: {"first_relevant": 2}}
- match: {details.berlin_query.unrated_docs: [ {"_index": "foo", "_id": "doc1"}]}
+---
+"Expected Reciprocal Rank":
+
+ - skip:
+ version: " - 6.3.99"
+ reason: ERR was introduced in 6.4
+
+ - do:
+ rank_eval:
+ body: {
+ "requests" : [
+ {
+ "id": "amsterdam_query",
+ "request": { "query": { "match" : {"text" : "amsterdam" }}},
+ "ratings": [{"_index": "foo", "_id": "doc4", "rating": 1}]
+ },
+ {
+ "id" : "berlin_query",
+ "request": { "query": { "match" : { "text" : "berlin" } }, "size" : 10 },
+ "ratings": [{"_index": "foo", "_id": "doc4", "rating": 1}]
+ }
+ ],
+ "metric" : {
+ "expected_reciprocal_rank": {
+ "maximum_relevance" : 1,
+ "k" : 5
+ }
+ }
+ }
+
+ - gt: {metric_score: 0.2083333}
+ - lt: {metric_score: 0.2083334}
+ - match: {details.amsterdam_query.metric_details.expected_reciprocal_rank.unrated_docs: 2}
+ - match: {details.berlin_query.metric_details.expected_reciprocal_rank.unrated_docs: 1}
diff --git a/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/20_dcg.yml b/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/20_dcg.yml
index baf10f1542cfb..1b159775d5c94 100644
--- a/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/20_dcg.yml
+++ b/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/20_dcg.yml
@@ -69,10 +69,10 @@
"metric" : { "dcg": {}}
}
- - gt: {quality_level: 13.848263 }
- - lt: {quality_level: 13.848264 }
- - gt: {details.dcg_query.quality_level: 13.848263}
- - lt: {details.dcg_query.quality_level: 13.848264}
+ - gt: {metric_score: 13.848263 }
+ - lt: {metric_score: 13.848264 }
+ - gt: {details.dcg_query.metric_score: 13.848263}
+ - lt: {details.dcg_query.metric_score: 13.848264}
- match: {details.dcg_query.unrated_docs: [ ]}
# reverse the order in which the results are returned (less relevant docs first)
@@ -96,10 +96,10 @@
"metric" : { "dcg": { }}
}
- - gt: {quality_level: 10.299674}
- - lt: {quality_level: 10.299675}
- - gt: {details.dcg_query_reverse.quality_level: 10.299674}
- - lt: {details.dcg_query_reverse.quality_level: 10.299675}
+ - gt: {metric_score: 10.299674}
+ - lt: {metric_score: 10.299675}
+ - gt: {details.dcg_query_reverse.metric_score: 10.299674}
+ - lt: {details.dcg_query_reverse.metric_score: 10.299675}
- match: {details.dcg_query_reverse.unrated_docs: [ ]}
# if we mix both, we should get the average
@@ -134,11 +134,11 @@
"metric" : { "dcg": { }}
}
- - gt: {quality_level: 12.073969}
- - lt: {quality_level: 12.073970}
- - gt: {details.dcg_query.quality_level: 13.848263}
- - lt: {details.dcg_query.quality_level: 13.848264}
+ - gt: {metric_score: 12.073969}
+ - lt: {metric_score: 12.073970}
+ - gt: {details.dcg_query.metric_score: 13.848263}
+ - lt: {details.dcg_query.metric_score: 13.848264}
- match: {details.dcg_query.unrated_docs: [ ]}
- - gt: {details.dcg_query_reverse.quality_level: 10.299674}
- - lt: {details.dcg_query_reverse.quality_level: 10.299675}
+ - gt: {details.dcg_query_reverse.metric_score: 10.299674}
+ - lt: {details.dcg_query_reverse.metric_score: 10.299675}
- match: {details.dcg_query_reverse.unrated_docs: [ ]}
diff --git a/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/30_failures.yml b/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/30_failures.yml
index d6119ad3a9e95..42627a2590e1c 100644
--- a/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/30_failures.yml
+++ b/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/30_failures.yml
@@ -34,8 +34,8 @@
"metric" : { "precision": { "ignore_unlabeled" : true }}
}
- - match: { quality_level: 1}
- - match: { details.amsterdam_query.quality_level: 1.0}
+ - match: { metric_score: 1}
+ - match: { details.amsterdam_query.metric_score: 1.0}
- match: { details.amsterdam_query.unrated_docs: [ ]}
- match: { details.amsterdam_query.metric_details.precision: {"relevant_docs_retrieved": 1, "docs_retrieved": 1}}
diff --git a/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/40_rank_eval_templated.yml b/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/40_rank_eval_templated.yml
index 5e0082d213c90..fef25c3fc41a5 100644
--- a/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/40_rank_eval_templated.yml
+++ b/modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/40_rank_eval_templated.yml
@@ -84,7 +84,7 @@ setup:
"metric" : { "precision": { }}
}
- - match: {quality_level: 0.9}
+ - match: {metric_score: 0.9}
- match: {details.amsterdam_query.unrated_docs.0._id: "6"}
---
diff --git a/modules/reindex/src/main/java/org/elasticsearch/index/reindex/RestUpdateByQueryAction.java b/modules/reindex/src/main/java/org/elasticsearch/index/reindex/RestUpdateByQueryAction.java
index 8f09afbb17c6c..bf0adc6e1429f 100644
--- a/modules/reindex/src/main/java/org/elasticsearch/index/reindex/RestUpdateByQueryAction.java
+++ b/modules/reindex/src/main/java/org/elasticsearch/index/reindex/RestUpdateByQueryAction.java
@@ -57,7 +57,6 @@ public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client
}
@Override
- @SuppressWarnings("unchecked")
protected UpdateByQueryRequest buildRequest(RestRequest request) throws IOException {
/*
* Passing the search request through UpdateByQueryRequest first allows
diff --git a/modules/transport-netty4/src/test/java/org/elasticsearch/http/netty4/Netty4HttpServerPipeliningTests.java b/modules/transport-netty4/src/test/java/org/elasticsearch/http/netty4/Netty4HttpServerPipeliningTests.java
index 3101f660d056e..50be7f7ce4509 100644
--- a/modules/transport-netty4/src/test/java/org/elasticsearch/http/netty4/Netty4HttpServerPipeliningTests.java
+++ b/modules/transport-netty4/src/test/java/org/elasticsearch/http/netty4/Netty4HttpServerPipeliningTests.java
@@ -181,27 +181,32 @@ class PossiblySlowRunnable implements Runnable {
@Override
public void run() {
- final String uri = fullHttpRequest.uri();
-
- final ByteBuf buffer = Unpooled.copiedBuffer(uri, StandardCharsets.UTF_8);
-
- Netty4HttpRequest httpRequest = new Netty4HttpRequest(fullHttpRequest, pipelinedRequest.getSequence());
- Netty4HttpResponse response = httpRequest.createResponse(RestStatus.OK, new BytesArray(uri.getBytes(StandardCharsets.UTF_8)));
- response.headers().add(HttpHeaderNames.CONTENT_LENGTH, buffer.readableBytes());
-
- final boolean slow = uri.matches("/slow/\\d+");
- if (slow) {
- try {
- Thread.sleep(scaledRandomIntBetween(500, 1000));
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
+ try {
+ final String uri = fullHttpRequest.uri();
+
+ final ByteBuf buffer = Unpooled.copiedBuffer(uri, StandardCharsets.UTF_8);
+
+ Netty4HttpRequest httpRequest = new Netty4HttpRequest(fullHttpRequest, pipelinedRequest.getSequence());
+ Netty4HttpResponse response =
+ httpRequest.createResponse(RestStatus.OK, new BytesArray(uri.getBytes(StandardCharsets.UTF_8)));
+ response.headers().add(HttpHeaderNames.CONTENT_LENGTH, buffer.readableBytes());
+
+ final boolean slow = uri.matches("/slow/\\d+");
+ if (slow) {
+ try {
+ Thread.sleep(scaledRandomIntBetween(500, 1000));
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ } else {
+ assert uri.matches("/\\d+");
}
- } else {
- assert uri.matches("/\\d+");
- }
- final ChannelPromise promise = ctx.newPromise();
- ctx.writeAndFlush(response, promise);
+ final ChannelPromise promise = ctx.newPromise();
+ ctx.writeAndFlush(response, promise);
+ } finally {
+ fullHttpRequest.release();
+ }
}
}
diff --git a/modules/transport-netty4/src/test/java/org/elasticsearch/transport/netty4/SimpleNetty4TransportTests.java b/modules/transport-netty4/src/test/java/org/elasticsearch/transport/netty4/SimpleNetty4TransportTests.java
index 760ac1253c6fe..8d628ace2ee38 100644
--- a/modules/transport-netty4/src/test/java/org/elasticsearch/transport/netty4/SimpleNetty4TransportTests.java
+++ b/modules/transport-netty4/src/test/java/org/elasticsearch/transport/netty4/SimpleNetty4TransportTests.java
@@ -90,7 +90,6 @@ protected MockTransportService build(Settings settings, Version version, Cluster
@Override
protected void closeConnectionChannel(Transport transport, Transport.Connection connection) throws IOException {
final Netty4Transport t = (Netty4Transport) transport;
- @SuppressWarnings("unchecked")
final TcpTransport.NodeChannels channels = (TcpTransport.NodeChannels) connection;
CloseableChannel.closeChannels(channels.getChannels().subList(0, randomIntBetween(1, channels.getChannels().size())), true);
}
diff --git a/plugins/analysis-phonetic/src/test/resources/org/elasticsearch/index/analysis/phonetic-1.yml b/plugins/analysis-phonetic/src/test/resources/org/elasticsearch/index/analysis/phonetic-1.yml
index 1909c7ee06390..14cdbbe2440ae 100644
--- a/plugins/analysis-phonetic/src/test/resources/org/elasticsearch/index/analysis/phonetic-1.yml
+++ b/plugins/analysis-phonetic/src/test/resources/org/elasticsearch/index/analysis/phonetic-1.yml
@@ -3,7 +3,7 @@ index:
filter:
doublemetaphonefilter:
type: phonetic
- encoder: doublemetaphone
+ encoder: double_metaphone
metaphonefilter:
type: phonetic
encoder: metaphone
@@ -12,16 +12,16 @@ index:
encoder: soundex
refinedsoundexfilter:
type: phonetic
- encoder: refinedsoundex
+ encoder: refined_soundex
caverphonefilter:
type: phonetic
encoder: caverphone
beidermorsefilter:
type: phonetic
- encoder: beidermorse
+ encoder: beider_morse
beidermorsefilterfrench:
type: phonetic
- encoder: beidermorse
+ encoder: beider_morse
languageset : [ "french" ]
koelnerphonetikfilter:
type: phonetic
diff --git a/plugins/discovery-gce/build.gradle b/plugins/discovery-gce/build.gradle
index 82de9ba031b25..fa8005dfa4759 100644
--- a/plugins/discovery-gce/build.gradle
+++ b/plugins/discovery-gce/build.gradle
@@ -22,36 +22,6 @@ dependencies {
compile "commons-codec:commons-codec:${versions.commonscodec}"
}
-
-// needed to be consistent with ssl host checking
-String host = InetAddress.getLoopbackAddress().getHostAddress();
-
-// location of keystore and files to generate it
-File keystore = new File(project.buildDir, 'keystore/test-node.jks')
-
-// generate the keystore
-task createKey(type: LoggedExec) {
- doFirst {
- project.delete(keystore.parentFile)
- keystore.parentFile.mkdirs()
- }
- executable = new File(project.runtimeJavaHome, 'bin/keytool')
- standardInput = new ByteArrayInputStream('FirstName LastName\nUnit\nOrganization\nCity\nState\nNL\nyes\n\n'.getBytes('UTF-8'))
- args '-genkey',
- '-alias', 'test-node',
- '-keystore', keystore,
- '-keyalg', 'RSA',
- '-keysize', '2048',
- '-validity', '712',
- '-dname', 'CN=' + host,
- '-keypass', 'keypass',
- '-storepass', 'keypass'
-}
-
-// add keystore to test classpath: it expects it there
-sourceSets.test.resources.srcDir(keystore.parentFile)
-processTestResources.dependsOn(createKey)
-
dependencyLicenses {
mapping from: /google-.*/, to: 'google'
}
diff --git a/plugins/repository-hdfs/build.gradle b/plugins/repository-hdfs/build.gradle
index b3ae34012aa38..8856ae1526a21 100644
--- a/plugins/repository-hdfs/build.gradle
+++ b/plugins/repository-hdfs/build.gradle
@@ -1,4 +1,4 @@
-1/*
+/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
@@ -214,25 +214,6 @@ RestIntegTestTask integTestSecureHa = project.tasks.create('integTestSecureHa',
description = "Runs rest tests against an elasticsearch cluster with HDFS configured with HA Namenode and secured by MIT Kerberos."
}
-if (rootProject.ext.compilerJavaVersion.isJava11()) {
- // TODO remove when: https://github.com/elastic/elasticsearch/issues/31498
- integTestRunner {
- systemProperty 'tests.rest.blacklist', [
- 'hdfs_repository/30_snapshot/take snapshot',
- 'hdfs_repository/40_restore/Create a snapshot and then restore it',
- 'hdfs_repository/20_repository_verify/HDFS Repository Verify',
- 'hdfs_repository/30_snapshot_get/Get a snapshot',
- 'hdfs_repository/20_repository_create/HDFS Repository Creation',
- 'hdfs_repository/20_repository_delete/HDFS Delete Repository',
- 'hdfs_repository/30_snapshot_readonly/Get a snapshot - readonly',
- ].join(',')
- }
-}
-if (rootProject.ext.runtimeJavaVersion.isJava11() || rootProject.ext.compilerJavaVersion.isJava11()) {
- // TODO remove when: https://github.com/elastic/elasticsearch/issues/31498
- integTestHa.enabled = false
-}
-
// Determine HDFS Fixture compatibility for the current build environment.
boolean fixtureSupported = false
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
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 f6476f290bc34..897596bbd8546 100644
--- a/plugins/repository-hdfs/src/main/plugin-metadata/plugin-security.policy
+++ b/plugins/repository-hdfs/src/main/plugin-metadata/plugin-security.policy
@@ -61,6 +61,7 @@ grant {
// 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";
permission java.lang.RuntimePermission "loadLibrary.jaas_unix";
// Windows: NTLoginModule: com.sun.security.auth.module.NTSystem.loadNative
permission java.lang.RuntimePermission "loadLibrary.jaas_nt";
diff --git a/plugins/repository-s3/build.gradle b/plugins/repository-s3/build.gradle
index 181891e20564d..13119913672af 100644
--- a/plugins/repository-s3/build.gradle
+++ b/plugins/repository-s3/build.gradle
@@ -114,9 +114,7 @@ if (!s3PermanentAccessKey && !s3PermanentSecretKey && !s3PermanentBucket && !s3P
useFixture = true
-} else if (!s3PermanentAccessKey || !s3PermanentSecretKey || !s3PermanentBucket || !s3PermanentBasePath
- || !s3EC2Bucket || !s3EC2BasePath
- || !s3ECSBucket || !s3ECSBasePath) {
+} else if (!s3PermanentAccessKey || !s3PermanentSecretKey || !s3PermanentBucket || !s3PermanentBasePath) {
throw new IllegalArgumentException("not all options specified to run against external S3 service")
}
@@ -349,8 +347,13 @@ processTestResources {
project.afterEvaluate {
if (useFixture == false) {
- // 30_repository_temporary_credentials is not ready for CI yet
- integTestRunner.systemProperty 'tests.rest.blacklist', 'repository_s3/30_repository_temporary_credentials/*'
+ // temporary_credentials, ec2_credentials and ecs_credentials are not ready for third-party-tests yet
+ integTestRunner.systemProperty 'tests.rest.blacklist',
+ [
+ 'repository_s3/30_repository_temporary_credentials/*',
+ 'repository_s3/40_repository_ec2_credentials/*',
+ 'repository_s3/50_repository_ecs_credentials/*'
+ ].join(",")
}
}
diff --git a/plugins/transport-nio/src/test/java/org/elasticsearch/http/nio/HttpReadWriteHandlerTests.java b/plugins/transport-nio/src/test/java/org/elasticsearch/http/nio/HttpReadWriteHandlerTests.java
index 5bda7e1b83d81..0a09b6b8789f7 100644
--- a/plugins/transport-nio/src/test/java/org/elasticsearch/http/nio/HttpReadWriteHandlerTests.java
+++ b/plugins/transport-nio/src/test/java/org/elasticsearch/http/nio/HttpReadWriteHandlerTests.java
@@ -32,6 +32,7 @@
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.HttpVersion;
+
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.ByteSizeValue;
@@ -89,7 +90,6 @@ public class HttpReadWriteHandlerTests extends ESTestCase {
private final ResponseDecoder responseDecoder = new ResponseDecoder();
@Before
- @SuppressWarnings("unchecked")
public void setMocks() {
transport = mock(NioHttpServerTransport.class);
Settings settings = Settings.EMPTY;
diff --git a/plugins/transport-nio/src/test/java/org/elasticsearch/transport/nio/SimpleNioTransportTests.java b/plugins/transport-nio/src/test/java/org/elasticsearch/transport/nio/SimpleNioTransportTests.java
index 090fc579c4899..9322bfd71222a 100644
--- a/plugins/transport-nio/src/test/java/org/elasticsearch/transport/nio/SimpleNioTransportTests.java
+++ b/plugins/transport-nio/src/test/java/org/elasticsearch/transport/nio/SimpleNioTransportTests.java
@@ -95,7 +95,6 @@ protected MockTransportService build(Settings settings, Version version, Cluster
@Override
protected void closeConnectionChannel(Transport transport, Transport.Connection connection) throws IOException {
- @SuppressWarnings("unchecked")
TcpTransport.NodeChannels channels = (TcpTransport.NodeChannels) connection;
CloseableChannel.closeChannels(channels.getChannels().subList(0, randomIntBetween(1, channels.getChannels().size())), true);
}
diff --git a/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/RecoveryIT.java b/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/RecoveryIT.java
index de5681ebe1a29..062016909b651 100644
--- a/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/RecoveryIT.java
+++ b/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/RecoveryIT.java
@@ -47,6 +47,8 @@
* In depth testing of the recovery mechanism during a rolling restart.
*/
public class RecoveryIT extends AbstractRollingTestCase {
+
+ @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/31291")
public void testHistoryUUIDIsGenerated() throws Exception {
final String index = "index_history_uuid";
if (CLUSTER_TYPE == ClusterType.OLD) {
diff --git a/qa/vagrant/src/main/java/org/elasticsearch/packaging/test/ArchiveTestCase.java b/qa/vagrant/src/main/java/org/elasticsearch/packaging/test/ArchiveTestCase.java
index 2056111554225..83edc8a0a9390 100644
--- a/qa/vagrant/src/main/java/org/elasticsearch/packaging/test/ArchiveTestCase.java
+++ b/qa/vagrant/src/main/java/org/elasticsearch/packaging/test/ArchiveTestCase.java
@@ -129,7 +129,7 @@ public void test30AbortWhenJavaMissing() {
});
Platforms.onLinux(() -> {
- final String javaPath = sh.run("which java").stdout.trim();
+ final String javaPath = sh.run("command -v java").stdout.trim();
try {
sh.run("chmod -x '" + javaPath + "'");
diff --git a/qa/vagrant/src/main/java/org/elasticsearch/packaging/test/PackageTestCase.java b/qa/vagrant/src/main/java/org/elasticsearch/packaging/test/PackageTestCase.java
index 28a767e95aef2..95705e94a432c 100644
--- a/qa/vagrant/src/main/java/org/elasticsearch/packaging/test/PackageTestCase.java
+++ b/qa/vagrant/src/main/java/org/elasticsearch/packaging/test/PackageTestCase.java
@@ -30,16 +30,20 @@
import java.io.IOException;
import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.elasticsearch.packaging.util.Cleanup.cleanEverything;
import static org.elasticsearch.packaging.util.FileUtils.assertPathsDontExist;
+import static org.elasticsearch.packaging.util.FileUtils.mv;
import static org.elasticsearch.packaging.util.Packages.SYSTEMD_SERVICE;
import static org.elasticsearch.packaging.util.Packages.assertInstalled;
import static org.elasticsearch.packaging.util.Packages.assertRemoved;
import static org.elasticsearch.packaging.util.Packages.install;
import static org.elasticsearch.packaging.util.Packages.remove;
+import static org.elasticsearch.packaging.util.Packages.runInstallCommand;
import static org.elasticsearch.packaging.util.Packages.startElasticsearch;
import static org.elasticsearch.packaging.util.Packages.verifyPackageInstallation;
import static org.elasticsearch.packaging.util.Platforms.getOsRelease;
@@ -75,6 +79,21 @@ public void onlyCompatibleDistributions() {
assumeTrue("only compatible distributions", distribution().packaging.compatible);
}
+ public void test05InstallFailsWhenJavaMissing() {
+ final Shell sh = new Shell();
+ final Result java = sh.run("command -v java");
+
+ final Path originalJavaPath = Paths.get(java.stdout.trim());
+ final Path relocatedJavaPath = originalJavaPath.getParent().resolve("java.relocated");
+ try {
+ mv(originalJavaPath, relocatedJavaPath);
+ final Result installResult = runInstallCommand(distribution());
+ assertThat(installResult.exitCode, is(1));
+ } finally {
+ mv(relocatedJavaPath, originalJavaPath);
+ }
+ }
+
public void test10InstallPackage() {
assertRemoved(distribution());
installation = install(distribution());
diff --git a/qa/vagrant/src/main/java/org/elasticsearch/packaging/util/Packages.java b/qa/vagrant/src/main/java/org/elasticsearch/packaging/util/Packages.java
index 6e80d9e027df2..be7edc5e8f9e4 100644
--- a/qa/vagrant/src/main/java/org/elasticsearch/packaging/util/Packages.java
+++ b/qa/vagrant/src/main/java/org/elasticsearch/packaging/util/Packages.java
@@ -67,7 +67,10 @@ public static void assertRemoved(Distribution distribution) {
Platforms.onDPKG(() -> {
assertThat(status.exitCode, anyOf(is(0), is(1)));
if (status.exitCode == 0) {
- assertTrue(Pattern.compile("(?m)^Status:.+deinstall ok").matcher(status.stdout).find());
+ assertTrue("an uninstalled status should be indicated: " + status.stdout,
+ Pattern.compile("(?m)^Status:.+deinstall ok").matcher(status.stdout).find() ||
+ Pattern.compile("(?m)^Status:.+ok not-installed").matcher(status.stdout).find()
+ );
}
});
}
@@ -90,13 +93,27 @@ public static Installation install(Distribution distribution) {
}
public static Installation install(Distribution distribution, String version) {
+ final Result result = runInstallCommand(distribution, version);
+ if (result.exitCode != 0) {
+ throw new RuntimeException("Installing distribution " + distribution + " version " + version + " failed: " + result);
+ }
+
+ return Installation.ofPackage(distribution.packaging);
+ }
+
+ public static Result runInstallCommand(Distribution distribution) {
+ return runInstallCommand(distribution, getCurrentVersion());
+ }
+
+ public static Result runInstallCommand(Distribution distribution, String version) {
final Shell sh = new Shell();
final Path distributionFile = getDistributionFile(distribution, version);
- Platforms.onRPM(() -> sh.run("rpm -i " + distributionFile));
- Platforms.onDPKG(() -> sh.run("dpkg -i " + distributionFile));
-
- return Installation.ofPackage(distribution.packaging);
+ if (Platforms.isRPM()) {
+ return sh.runIgnoreExitCode("rpm -i " + distributionFile);
+ } else {
+ return sh.runIgnoreExitCode("dpkg -i " + distributionFile);
+ }
}
public static void remove(Distribution distribution) {
diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/260_weighted_avg.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/260_weighted_avg.yml
new file mode 100644
index 0000000000000..6f8ea9565e346
--- /dev/null
+++ b/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/260_weighted_avg.yml
@@ -0,0 +1,74 @@
+setup:
+ - skip:
+ version: " - 6.3.99"
+ reason: weighted_avg is only available as of 6.4.0
+ - do:
+ indices.create:
+ index: test_1
+ body:
+ settings:
+ number_of_replicas: 0
+ mappings:
+ doc:
+ properties:
+ int_field:
+ type : integer
+ double_field:
+ type : double
+ string_field:
+ type: keyword
+
+ - do:
+ bulk:
+ refresh: true
+ body:
+ - index:
+ _index: test_1
+ _type: doc
+ _id: 1
+ - int_field: 1
+ double_field: 1.0
+ - index:
+ _index: test_1
+ _type: doc
+ _id: 2
+ - int_field: 2
+ double_field: 2.0
+ - index:
+ _index: test_1
+ _type: doc
+ _id: 3
+ - int_field: 3
+ double_field: 3.0
+ - index:
+ _index: test_1
+ _type: doc
+ _id: 4
+ - int_field: 4
+ double_field: 4.0
+
+---
+"Basic test":
+
+ - do:
+ search:
+ body:
+ aggs:
+ the_int_avg:
+ weighted_avg:
+ value:
+ field: "int_field"
+ weight:
+ field: "int_field"
+ the_double_avg:
+ weighted_avg:
+ value:
+ field: "double_field"
+ weight:
+ field: "double_field"
+
+ - match: { hits.total: 4 }
+ - length: { hits.hits: 4 }
+ - match: { aggregations.the_int_avg.value: 3.0 }
+ - match: { aggregations.the_double_avg.value: 3.0 }
+
diff --git a/server/src/main/java/org/elasticsearch/Version.java b/server/src/main/java/org/elasticsearch/Version.java
index 281ba9eaee820..4c75f0a1c19e0 100644
--- a/server/src/main/java/org/elasticsearch/Version.java
+++ b/server/src/main/java/org/elasticsearch/Version.java
@@ -174,6 +174,8 @@ public class Version implements Comparable, ToXContentFragment {
public static final Version V_6_3_1 = new Version(V_6_3_1_ID, org.apache.lucene.util.Version.LUCENE_7_3_1);
public static final int V_6_3_2_ID = 6030299;
public static final Version V_6_3_2 = new Version(V_6_3_2_ID, org.apache.lucene.util.Version.LUCENE_7_3_1);
+ public static final int V_6_3_3_ID = 6030399;
+ public static final Version V_6_3_3 = new Version(V_6_3_3_ID, org.apache.lucene.util.Version.LUCENE_7_3_1);
public static final int V_6_4_0_ID = 6040099;
public static final Version V_6_4_0 = new Version(V_6_4_0_ID, org.apache.lucene.util.Version.LUCENE_7_4_0);
public static final int V_7_0_0_alpha1_ID = 7000001;
@@ -196,6 +198,8 @@ public static Version fromId(int id) {
return V_7_0_0_alpha1;
case V_6_4_0_ID:
return V_6_4_0;
+ case V_6_3_3_ID:
+ return V_6_3_3;
case V_6_3_2_ID:
return V_6_3_2;
case V_6_3_1_ID:
diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/settings/ClusterGetSettingsResponse.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/settings/ClusterGetSettingsResponse.java
index 19b0517d96c95..173a44b67cdfc 100644
--- a/server/src/main/java/org/elasticsearch/action/admin/cluster/settings/ClusterGetSettingsResponse.java
+++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/settings/ClusterGetSettingsResponse.java
@@ -48,7 +48,6 @@ public class ClusterGetSettingsResponse extends ActionResponse implements ToXCon
static final String TRANSIENT_FIELD = "transient";
static final String DEFAULTS_FIELD = "defaults";
- @SuppressWarnings("unchecked")
private static final ConstructingObjectParser PARSER =
new ConstructingObjectParser<>(
"cluster_get_settings_response",
diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequest.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequest.java
index c1b8c73c9ef0f..53aa522772aac 100644
--- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequest.java
+++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequest.java
@@ -27,14 +27,17 @@
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import static org.elasticsearch.action.ValidateActions.addValidationError;
import static org.elasticsearch.common.settings.Settings.readSettingsFromStream;
@@ -45,7 +48,7 @@
/**
* Restore snapshot request
*/
-public class RestoreSnapshotRequest extends MasterNodeRequest {
+public class RestoreSnapshotRequest extends MasterNodeRequest implements ToXContentObject {
private String snapshot;
private String repository;
@@ -563,6 +566,49 @@ public RestoreSnapshotRequest source(Map source) {
return this;
}
+ @Override
+ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+ builder.startObject();
+ builder.startArray("indices");
+ for (String index : indices) {
+ builder.value(index);
+ }
+ builder.endArray();
+ if (indicesOptions != null) {
+ indicesOptions.toXContent(builder, params);
+ }
+ if (renamePattern != null) {
+ builder.field("rename_pattern", renamePattern);
+ }
+ if (renameReplacement != null) {
+ builder.field("rename_replacement", renameReplacement);
+ }
+ builder.field("include_global_state", includeGlobalState);
+ builder.field("partial", partial);
+ builder.field("include_aliases", includeAliases);
+ if (settings != null) {
+ builder.startObject("settings");
+ if (settings.isEmpty() == false) {
+ settings.toXContent(builder, params);
+ }
+ builder.endObject();
+ }
+ if (indexSettings != null) {
+ builder.startObject("index_settings");
+ if (indexSettings.isEmpty() == false) {
+ indexSettings.toXContent(builder, params);
+ }
+ builder.endObject();
+ }
+ builder.startArray("ignore_index_settings");
+ for (String ignoreIndexSetting : ignoreIndexSettings) {
+ builder.value(ignoreIndexSetting);
+ }
+ builder.endArray();
+ builder.endObject();
+ return builder;
+ }
+
@Override
public void readFrom(StreamInput in) throws IOException {
throw new UnsupportedOperationException("usage of Streamable is to be replaced by Writeable");
@@ -573,4 +619,37 @@ public String getDescription() {
return "snapshot [" + repository + ":" + snapshot + "]";
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ RestoreSnapshotRequest that = (RestoreSnapshotRequest) o;
+ return waitForCompletion == that.waitForCompletion &&
+ includeGlobalState == that.includeGlobalState &&
+ partial == that.partial &&
+ includeAliases == that.includeAliases &&
+ Objects.equals(snapshot, that.snapshot) &&
+ Objects.equals(repository, that.repository) &&
+ Arrays.equals(indices, that.indices) &&
+ Objects.equals(indicesOptions, that.indicesOptions) &&
+ Objects.equals(renamePattern, that.renamePattern) &&
+ Objects.equals(renameReplacement, that.renameReplacement) &&
+ Objects.equals(settings, that.settings) &&
+ Objects.equals(indexSettings, that.indexSettings) &&
+ Arrays.equals(ignoreIndexSettings, that.ignoreIndexSettings);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(snapshot, repository, indicesOptions, renamePattern, renameReplacement, waitForCompletion,
+ includeGlobalState, partial, includeAliases, settings, indexSettings);
+ result = 31 * result + Arrays.hashCode(indices);
+ result = 31 * result + Arrays.hashCode(ignoreIndexSettings);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return Strings.toString(this);
+ }
}
diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotResponse.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotResponse.java
index 5a02e4bcb1387..171509c018228 100644
--- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotResponse.java
+++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotResponse.java
@@ -21,15 +21,21 @@
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.common.Nullable;
+import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
+import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.snapshots.RestoreInfo;
import java.io.IOException;
+import java.util.Objects;
+
+import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
/**
* Contains information about restores snapshot
@@ -86,4 +92,42 @@ public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params par
builder.endObject();
return builder;
}
+
+ public static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(
+ "restore_snapshot", true, v -> {
+ RestoreInfo restoreInfo = (RestoreInfo) v[0];
+ Boolean accepted = (Boolean) v[1];
+ assert (accepted == null && restoreInfo != null) ||
+ (accepted != null && accepted && restoreInfo == null) :
+ "accepted: [" + accepted + "], restoreInfo: [" + restoreInfo + "]";
+ return new RestoreSnapshotResponse(restoreInfo);
+ });
+
+ static {
+ PARSER.declareObject(optionalConstructorArg(), (parser, context) -> RestoreInfo.fromXContent(parser), new ParseField("snapshot"));
+ PARSER.declareBoolean(optionalConstructorArg(), new ParseField("accepted"));
+ }
+
+
+ public static RestoreSnapshotResponse fromXContent(XContentParser parser) throws IOException {
+ return PARSER.parse(parser, null);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ RestoreSnapshotResponse that = (RestoreSnapshotResponse) o;
+ return Objects.equals(restoreInfo, that.restoreInfo);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(restoreInfo);
+ }
+
+ @Override
+ public String toString() {
+ return "RestoreSnapshotResponse{" + "restoreInfo=" + restoreInfo + '}';
+ }
}
diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/QueryExplanation.java b/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/QueryExplanation.java
index e330a0b8565fc..d0a62fe771d1f 100644
--- a/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/QueryExplanation.java
+++ b/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/QueryExplanation.java
@@ -45,7 +45,6 @@ public class QueryExplanation implements Streamable, ToXContentFragment {
public static final int RANDOM_SHARD = -1;
- @SuppressWarnings("unchecked")
static ConstructingObjectParser PARSER = new ConstructingObjectParser<>(
"query_explanation",
true,
diff --git a/server/src/main/java/org/elasticsearch/action/get/GetResponse.java b/server/src/main/java/org/elasticsearch/action/get/GetResponse.java
index 9ee59cf70d05e..455aab7f6e3d6 100644
--- a/server/src/main/java/org/elasticsearch/action/get/GetResponse.java
+++ b/server/src/main/java/org/elasticsearch/action/get/GetResponse.java
@@ -129,7 +129,6 @@ public String getSourceAsString() {
/**
* The source of the document (As a map).
*/
- @SuppressWarnings({"unchecked"})
public Map getSourceAsMap() throws ElasticsearchParseException {
return getResult.sourceAsMap();
}
diff --git a/server/src/main/java/org/elasticsearch/action/get/TransportShardMultiGetAction.java b/server/src/main/java/org/elasticsearch/action/get/TransportShardMultiGetAction.java
index d15b7b92d62aa..e0a6cd827863a 100644
--- a/server/src/main/java/org/elasticsearch/action/get/TransportShardMultiGetAction.java
+++ b/server/src/main/java/org/elasticsearch/action/get/TransportShardMultiGetAction.java
@@ -20,7 +20,6 @@
package org.elasticsearch.action.get;
import org.apache.logging.log4j.message.ParameterizedMessage;
-import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.TransportActions;
import org.elasticsearch.action.support.single.shard.TransportSingleShardAction;
@@ -90,9 +89,9 @@ protected MultiGetShardResponse shardOperation(MultiGetShardRequest request, Sha
GetResult getResult = indexShard.getService().get(item.type(), item.id(), item.storedFields(), request.realtime(), item.version(),
item.versionType(), item.fetchSourceContext());
response.add(request.locations.get(i), new GetResponse(getResult));
- } catch (Exception e) {
+ } catch (RuntimeException e) {
if (TransportActions.isShardNotAvailableException(e)) {
- throw (ElasticsearchException) e;
+ throw e;
} else {
logger.debug(() -> new ParameterizedMessage("{} failed to execute multi_get for [{}]/[{}]", shardId,
item.type(), item.id()), e);
diff --git a/server/src/main/java/org/elasticsearch/action/ingest/SimulateProcessorResult.java b/server/src/main/java/org/elasticsearch/action/ingest/SimulateProcessorResult.java
index 101ce7ec260e1..3f41aaddfb7cb 100644
--- a/server/src/main/java/org/elasticsearch/action/ingest/SimulateProcessorResult.java
+++ b/server/src/main/java/org/elasticsearch/action/ingest/SimulateProcessorResult.java
@@ -32,8 +32,8 @@
import java.io.IOException;
-import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
+import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
public class SimulateProcessorResult implements Writeable, ToXContentObject {
@@ -42,7 +42,6 @@ public class SimulateProcessorResult implements Writeable, ToXContentObject {
private final WriteableIngestDocument ingestDocument;
private final Exception failure;
- @SuppressWarnings("unchecked")
private static final ConstructingObjectParser IGNORED_ERROR_PARSER =
new ConstructingObjectParser<>(
"ignored_error_parser",
@@ -57,7 +56,6 @@ public class SimulateProcessorResult implements Writeable, ToXContentObject {
);
}
- @SuppressWarnings("unchecked")
public static final ConstructingObjectParser PARSER =
new ConstructingObjectParser<>(
"simulate_processor_result",
diff --git a/server/src/main/java/org/elasticsearch/action/ingest/WriteableIngestDocument.java b/server/src/main/java/org/elasticsearch/action/ingest/WriteableIngestDocument.java
index 2430868bb5909..6331097024c69 100644
--- a/server/src/main/java/org/elasticsearch/action/ingest/WriteableIngestDocument.java
+++ b/server/src/main/java/org/elasticsearch/action/ingest/WriteableIngestDocument.java
@@ -94,7 +94,6 @@ final class WriteableIngestDocument implements Writeable, ToXContentFragment {
);
}
- @SuppressWarnings("unchecked")
public static final ConstructingObjectParser PARSER =
new ConstructingObjectParser<>(
"writeable_ingest_document",
diff --git a/server/src/main/java/org/elasticsearch/action/support/ActiveShardCount.java b/server/src/main/java/org/elasticsearch/action/support/ActiveShardCount.java
index cdd895ff8cd2c..8598ab3e4be06 100644
--- a/server/src/main/java/org/elasticsearch/action/support/ActiveShardCount.java
+++ b/server/src/main/java/org/elasticsearch/action/support/ActiveShardCount.java
@@ -20,6 +20,7 @@
package org.elasticsearch.action.support;
import com.carrotsearch.hppc.cursors.IntObjectCursor;
+
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.routing.IndexRoutingTable;
@@ -205,7 +206,7 @@ public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
- @SuppressWarnings("unchecked") ActiveShardCount that = (ActiveShardCount) o;
+ ActiveShardCount that = (ActiveShardCount) o;
return value == that.value;
}
diff --git a/server/src/main/java/org/elasticsearch/action/support/replication/ReplicationRequestBuilder.java b/server/src/main/java/org/elasticsearch/action/support/replication/ReplicationRequestBuilder.java
index 9dc7a899d033c..7b137fb418c2b 100644
--- a/server/src/main/java/org/elasticsearch/action/support/replication/ReplicationRequestBuilder.java
+++ b/server/src/main/java/org/elasticsearch/action/support/replication/ReplicationRequestBuilder.java
@@ -72,7 +72,6 @@ public RequestBuilder setWaitForActiveShards(ActiveShardCount waitForActiveShard
* shard count is passed in, instead of having to first call {@link ActiveShardCount#from(int)}
* to get the ActiveShardCount.
*/
- @SuppressWarnings("unchecked")
public RequestBuilder setWaitForActiveShards(final int waitForActiveShards) {
return setWaitForActiveShards(ActiveShardCount.from(waitForActiveShards));
}
diff --git a/server/src/main/java/org/elasticsearch/action/termvectors/TransportShardMultiTermsVectorAction.java b/server/src/main/java/org/elasticsearch/action/termvectors/TransportShardMultiTermsVectorAction.java
index b83ac3881fda5..f1641fdd25c98 100644
--- a/server/src/main/java/org/elasticsearch/action/termvectors/TransportShardMultiTermsVectorAction.java
+++ b/server/src/main/java/org/elasticsearch/action/termvectors/TransportShardMultiTermsVectorAction.java
@@ -20,7 +20,6 @@
package org.elasticsearch.action.termvectors;
import org.apache.logging.log4j.message.ParameterizedMessage;
-import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.TransportActions;
import org.elasticsearch.action.support.single.shard.TransportSingleShardAction;
@@ -84,13 +83,13 @@ protected MultiTermVectorsShardResponse shardOperation(MultiTermVectorsShardRequ
try {
TermVectorsResponse termVectorsResponse = TermVectorsService.getTermVectors(indexShard, termVectorsRequest);
response.add(request.locations.get(i), termVectorsResponse);
- } catch (Exception t) {
- if (TransportActions.isShardNotAvailableException(t)) {
- throw (ElasticsearchException) t;
+ } catch (RuntimeException e) {
+ if (TransportActions.isShardNotAvailableException(e)) {
+ throw e;
} else {
- logger.debug(() -> new ParameterizedMessage("{} failed to execute multi term vectors for [{}]/[{}]", shardId, termVectorsRequest.type(), termVectorsRequest.id()), t);
+ logger.debug(() -> new ParameterizedMessage("{} failed to execute multi term vectors for [{}]/[{}]", shardId, termVectorsRequest.type(), termVectorsRequest.id()), e);
response.add(request.locations.get(i),
- new MultiTermVectorsResponse.Failure(request.index(), termVectorsRequest.type(), termVectorsRequest.id(), t));
+ new MultiTermVectorsResponse.Failure(request.index(), termVectorsRequest.type(), termVectorsRequest.id(), e));
}
}
}
diff --git a/server/src/main/java/org/elasticsearch/cluster/RestoreInProgress.java b/server/src/main/java/org/elasticsearch/cluster/RestoreInProgress.java
index 138788251c90a..066f00c2cd1c7 100644
--- a/server/src/main/java/org/elasticsearch/cluster/RestoreInProgress.java
+++ b/server/src/main/java/org/elasticsearch/cluster/RestoreInProgress.java
@@ -20,6 +20,7 @@
package org.elasticsearch.cluster;
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
+
import org.elasticsearch.Version;
import org.elasticsearch.cluster.ClusterState.Custom;
import org.elasticsearch.common.collect.ImmutableOpenMap;
@@ -165,7 +166,7 @@ public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
- @SuppressWarnings("unchecked") Entry entry = (Entry) o;
+ Entry entry = (Entry) o;
return snapshot.equals(entry.snapshot) &&
state == entry.state &&
indices.equals(entry.indices) &&
@@ -291,7 +292,7 @@ public boolean equals(Object o) {
return false;
}
- @SuppressWarnings("unchecked") ShardRestoreStatus status = (ShardRestoreStatus) o;
+ ShardRestoreStatus status = (ShardRestoreStatus) o;
return state == status.state &&
Objects.equals(nodeId, status.nodeId) &&
Objects.equals(reason, status.reason);
diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexGraveyard.java b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexGraveyard.java
index 74789aada3a46..3bb9d42a5786d 100644
--- a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexGraveyard.java
+++ b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexGraveyard.java
@@ -161,7 +161,6 @@ public void writeTo(final StreamOutput out) throws IOException {
}
@Override
- @SuppressWarnings("unchecked")
public Diff diff(final MetaData.Custom previous) {
return new IndexGraveyardDiff((IndexGraveyard) previous, this);
}
@@ -321,7 +320,7 @@ public void writeTo(final StreamOutput out) throws IOException {
@Override
public IndexGraveyard apply(final MetaData.Custom previous) {
- @SuppressWarnings("unchecked") final IndexGraveyard old = (IndexGraveyard) previous;
+ final IndexGraveyard old = (IndexGraveyard) previous;
if (removedCount > old.tombstones.size()) {
throw new IllegalStateException("IndexGraveyardDiff cannot remove [" + removedCount + "] entries from [" +
old.tombstones.size() + "] tombstones.");
@@ -416,7 +415,7 @@ public boolean equals(final Object other) {
if (other == null || getClass() != other.getClass()) {
return false;
}
- @SuppressWarnings("unchecked") Tombstone that = (Tombstone) other;
+ Tombstone that = (Tombstone) other;
return index.equals(that.index) && deleteDateInMillis == that.deleteDateInMillis;
}
diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java
index 903802050127e..18b89db72a391 100644
--- a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java
+++ b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java
@@ -23,6 +23,7 @@
import com.carrotsearch.hppc.cursors.IntObjectCursor;
import com.carrotsearch.hppc.cursors.ObjectCursor;
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
+
import org.elasticsearch.Version;
import org.elasticsearch.action.admin.indices.rollover.RolloverInfo;
import org.elasticsearch.action.support.ActiveShardCount;
@@ -685,7 +686,6 @@ public Custom read(StreamInput in, String key) throws IOException {
return lookupPrototypeSafe(key).readFrom(in);
}
- @SuppressWarnings("unchecked")
@Override
public Diff readDiff(StreamInput in, String key) throws IOException {
return lookupPrototypeSafe(key).readDiffFrom(in);
diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexTemplateMetaData.java b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexTemplateMetaData.java
index ae58d2885bb7b..d35a4baa1e680 100644
--- a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexTemplateMetaData.java
+++ b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexTemplateMetaData.java
@@ -381,7 +381,6 @@ public IndexTemplateMetaData build() {
aliases.build(), customs.build());
}
- @SuppressWarnings("unchecked")
public static void toXContent(IndexTemplateMetaData indexTemplateMetaData, XContentBuilder builder, ToXContent.Params params)
throws IOException {
builder.startObject(indexTemplateMetaData.name());
diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java b/server/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java
index 4333959973496..c3da63886140a 100644
--- a/server/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java
+++ b/server/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java
@@ -22,6 +22,7 @@
import com.carrotsearch.hppc.ObjectHashSet;
import com.carrotsearch.hppc.cursors.ObjectCursor;
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
+
import org.apache.logging.log4j.Logger;
import org.apache.lucene.util.CollectionUtil;
import org.elasticsearch.action.AliasesRequest;
@@ -169,7 +170,6 @@ public interface Custom extends NamedDiffable, ToXContentFragment, Clust
private final SortedMap aliasAndIndexLookup;
- @SuppressWarnings("unchecked")
MetaData(String clusterUUID, long version, Settings transientSettings, Settings persistentSettings,
ImmutableOpenMap indices, ImmutableOpenMap templates,
ImmutableOpenMap customs, String[] allIndices, String[] allOpenIndices, String[] allClosedIndices,
@@ -1000,7 +1000,7 @@ public Builder indexGraveyard(final IndexGraveyard indexGraveyard) {
}
public IndexGraveyard indexGraveyard() {
- @SuppressWarnings("unchecked") IndexGraveyard graveyard = (IndexGraveyard) getCustom(IndexGraveyard.TYPE);
+ IndexGraveyard graveyard = (IndexGraveyard) getCustom(IndexGraveyard.TYPE);
return graveyard;
}
diff --git a/server/src/main/java/org/elasticsearch/cluster/routing/RecoverySource.java b/server/src/main/java/org/elasticsearch/cluster/routing/RecoverySource.java
index ff7aab4a25622..13cb85ea399d5 100644
--- a/server/src/main/java/org/elasticsearch/cluster/routing/RecoverySource.java
+++ b/server/src/main/java/org/elasticsearch/cluster/routing/RecoverySource.java
@@ -217,7 +217,7 @@ public boolean equals(Object o) {
return false;
}
- @SuppressWarnings("unchecked") SnapshotRecoverySource that = (SnapshotRecoverySource) o;
+ SnapshotRecoverySource that = (SnapshotRecoverySource) o;
return snapshot.equals(that.snapshot) && index.equals(that.index) && version.equals(that.version);
}
diff --git a/server/src/main/java/org/elasticsearch/cluster/routing/allocation/AbstractAllocationDecision.java b/server/src/main/java/org/elasticsearch/cluster/routing/allocation/AbstractAllocationDecision.java
index 850e8c9c14202..7ce971958c9d2 100644
--- a/server/src/main/java/org/elasticsearch/cluster/routing/allocation/AbstractAllocationDecision.java
+++ b/server/src/main/java/org/elasticsearch/cluster/routing/allocation/AbstractAllocationDecision.java
@@ -175,7 +175,7 @@ public boolean equals(Object other) {
if (other == null || other instanceof AbstractAllocationDecision == false) {
return false;
}
- @SuppressWarnings("unchecked") AbstractAllocationDecision that = (AbstractAllocationDecision) other;
+ AbstractAllocationDecision that = (AbstractAllocationDecision) other;
return Objects.equals(targetNode, that.targetNode) && Objects.equals(nodeDecisions, that.nodeDecisions);
}
diff --git a/server/src/main/java/org/elasticsearch/cluster/routing/allocation/AllocateUnassignedDecision.java b/server/src/main/java/org/elasticsearch/cluster/routing/allocation/AllocateUnassignedDecision.java
index fc2d81b38c493..c32d3e1518ded 100644
--- a/server/src/main/java/org/elasticsearch/cluster/routing/allocation/AllocateUnassignedDecision.java
+++ b/server/src/main/java/org/elasticsearch/cluster/routing/allocation/AllocateUnassignedDecision.java
@@ -316,7 +316,7 @@ public boolean equals(Object other) {
if (other instanceof AllocateUnassignedDecision == false) {
return false;
}
- @SuppressWarnings("unchecked") AllocateUnassignedDecision that = (AllocateUnassignedDecision) other;
+ AllocateUnassignedDecision that = (AllocateUnassignedDecision) other;
return Objects.equals(allocationStatus, that.allocationStatus)
&& Objects.equals(allocationId, that.allocationId)
&& reuseStore == that.reuseStore
diff --git a/server/src/main/java/org/elasticsearch/cluster/routing/allocation/MoveDecision.java b/server/src/main/java/org/elasticsearch/cluster/routing/allocation/MoveDecision.java
index de9795ff4c253..9439187d7395c 100644
--- a/server/src/main/java/org/elasticsearch/cluster/routing/allocation/MoveDecision.java
+++ b/server/src/main/java/org/elasticsearch/cluster/routing/allocation/MoveDecision.java
@@ -300,7 +300,7 @@ public boolean equals(Object other) {
if (other instanceof MoveDecision == false) {
return false;
}
- @SuppressWarnings("unchecked") MoveDecision that = (MoveDecision) other;
+ MoveDecision that = (MoveDecision) other;
return Objects.equals(allocationDecision, that.allocationDecision)
&& Objects.equals(canRemainDecision, that.canRemainDecision)
&& Objects.equals(clusterRebalanceDecision, that.clusterRebalanceDecision)
diff --git a/server/src/main/java/org/elasticsearch/common/component/AbstractLifecycleComponent.java b/server/src/main/java/org/elasticsearch/common/component/AbstractLifecycleComponent.java
index de14e0cd53db6..3c4b35d5c3477 100644
--- a/server/src/main/java/org/elasticsearch/common/component/AbstractLifecycleComponent.java
+++ b/server/src/main/java/org/elasticsearch/common/component/AbstractLifecycleComponent.java
@@ -54,7 +54,6 @@ public void removeLifecycleListener(LifecycleListener listener) {
listeners.remove(listener);
}
- @SuppressWarnings({"unchecked"})
@Override
public void start() {
if (!lifecycle.canMoveToStarted()) {
@@ -72,7 +71,6 @@ public void start() {
protected abstract void doStart();
- @SuppressWarnings({"unchecked"})
@Override
public void stop() {
if (!lifecycle.canMoveToStopped()) {
diff --git a/server/src/main/java/org/elasticsearch/common/inject/ConstructorInjectorStore.java b/server/src/main/java/org/elasticsearch/common/inject/ConstructorInjectorStore.java
index ce63da62d8dfc..dfc216028c100 100644
--- a/server/src/main/java/org/elasticsearch/common/inject/ConstructorInjectorStore.java
+++ b/server/src/main/java/org/elasticsearch/common/inject/ConstructorInjectorStore.java
@@ -32,7 +32,6 @@ class ConstructorInjectorStore {
private final FailableCache, ConstructorInjector>> cache
= new FailableCache, ConstructorInjector>>() {
@Override
- @SuppressWarnings("unchecked")
protected ConstructorInjector> create(TypeLiteral> type, Errors errors)
throws ErrorsException {
return createConstructor(type, errors);
diff --git a/server/src/main/java/org/elasticsearch/common/inject/TypeConverterBindingProcessor.java b/server/src/main/java/org/elasticsearch/common/inject/TypeConverterBindingProcessor.java
index e42082817c1eb..e296386408518 100644
--- a/server/src/main/java/org/elasticsearch/common/inject/TypeConverterBindingProcessor.java
+++ b/server/src/main/java/org/elasticsearch/common/inject/TypeConverterBindingProcessor.java
@@ -101,7 +101,6 @@ public String toString() {
},
new TypeConverter() {
@Override
- @SuppressWarnings("unchecked")
public Object convert(String value, TypeLiteral> toType) {
try {
return Class.forName(value);
@@ -128,7 +127,6 @@ private void convertToPrimitiveType(Class primitiveType, final Class w
TypeConverter typeConverter = new TypeConverter() {
@Override
- @SuppressWarnings("unchecked")
public Object convert(String value, TypeLiteral> toType) {
try {
return parser.invoke(null, value);
diff --git a/server/src/main/java/org/elasticsearch/common/inject/assistedinject/AssistedConstructor.java b/server/src/main/java/org/elasticsearch/common/inject/assistedinject/AssistedConstructor.java
index cb434a90369d3..d676b19dddb64 100644
--- a/server/src/main/java/org/elasticsearch/common/inject/assistedinject/AssistedConstructor.java
+++ b/server/src/main/java/org/elasticsearch/common/inject/assistedinject/AssistedConstructor.java
@@ -42,7 +42,6 @@ class AssistedConstructor {
private final ParameterListKey assistedParameters;
private final List allParameters;
- @SuppressWarnings("unchecked")
AssistedConstructor(Constructor constructor, List> parameterTypes) {
this.constructor = constructor;
diff --git a/server/src/main/java/org/elasticsearch/common/inject/internal/ProviderMethod.java b/server/src/main/java/org/elasticsearch/common/inject/internal/ProviderMethod.java
index 0cfafc4a30ad5..349935ac7c484 100644
--- a/server/src/main/java/org/elasticsearch/common/inject/internal/ProviderMethod.java
+++ b/server/src/main/java/org/elasticsearch/common/inject/internal/ProviderMethod.java
@@ -97,7 +97,7 @@ public T get() {
try {
// We know this cast is safe because T is the method's return type.
- @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
+ @SuppressWarnings({"unchecked"})
T result = (T) method.invoke(instance, parameters);
return result;
} catch (IllegalAccessException e) {
diff --git a/server/src/main/java/org/elasticsearch/common/inject/multibindings/Multibinder.java b/server/src/main/java/org/elasticsearch/common/inject/multibindings/Multibinder.java
index 5bc1595be5f5c..5447f2ca39962 100644
--- a/server/src/main/java/org/elasticsearch/common/inject/multibindings/Multibinder.java
+++ b/server/src/main/java/org/elasticsearch/common/inject/multibindings/Multibinder.java
@@ -220,7 +220,6 @@ private RealMultibinder(Binder binder, TypeLiteral elementType,
}
@Override
- @SuppressWarnings("unchecked")
public void configure(Binder binder) {
checkConfiguration(!isInitialized(), "Multibinder was already initialized");
diff --git a/server/src/main/java/org/elasticsearch/common/inject/spi/DefaultBindingTargetVisitor.java b/server/src/main/java/org/elasticsearch/common/inject/spi/DefaultBindingTargetVisitor.java
index 75a3b615a1063..0e4f7a801314e 100644
--- a/server/src/main/java/org/elasticsearch/common/inject/spi/DefaultBindingTargetVisitor.java
+++ b/server/src/main/java/org/elasticsearch/common/inject/spi/DefaultBindingTargetVisitor.java
@@ -78,8 +78,7 @@ public V visit(ConvertedConstantBinding extends T> convertedConstantBinding) {
// javac says it's an error to cast ProviderBinding extends T> to Binding extends T>
@Override
- @SuppressWarnings("unchecked")
public V visit(ProviderBinding extends T> providerBinding) {
- return visitOther((Binding extends T>) providerBinding);
+ return visitOther(providerBinding);
}
}
diff --git a/server/src/main/java/org/elasticsearch/common/io/stream/StreamInput.java b/server/src/main/java/org/elasticsearch/common/io/stream/StreamInput.java
index b11aa9d4a9693..fd9ffdfd31d16 100644
--- a/server/src/main/java/org/elasticsearch/common/io/stream/StreamInput.java
+++ b/server/src/main/java/org/elasticsearch/common/io/stream/StreamInput.java
@@ -59,6 +59,7 @@
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.EnumSet;
@@ -518,7 +519,6 @@ public Map readMap() throws IOException {
return (Map) readGenericValue();
}
- @SuppressWarnings({"unchecked"})
@Nullable
public Object readGenericValue() throws IOException {
byte type = readByte();
@@ -932,8 +932,23 @@ public List readStreamableList(Supplier constructor
* Reads a list of objects
*/
public List readList(Writeable.Reader reader) throws IOException {
+ return readCollection(reader, ArrayList::new);
+ }
+
+ /**
+ * Reads a set of objects
+ */
+ public Set readSet(Writeable.Reader reader) throws IOException {
+ return readCollection(reader, HashSet::new);
+ }
+
+ /**
+ * Reads a collection of objects
+ */
+ private > C readCollection(Writeable.Reader reader,
+ IntFunction constructor) throws IOException {
int count = readArraySize();
- List builder = new ArrayList<>(count);
+ C builder = constructor.apply(count);
for (int i=0; i list) throws IOException {
}
}
+ /**
+ * Writes a collection of generic objects via a {@link Writer}
+ */
+ public void writeCollection(Collection collection, Writer writer) throws IOException {
+ writeVInt(collection.size());
+ for (T val: collection) {
+ writer.write(this, val);
+ }
+ }
+
/**
* Writes a list of strings
*/
diff --git a/server/src/main/java/org/elasticsearch/common/settings/KeyStoreWrapper.java b/server/src/main/java/org/elasticsearch/common/settings/KeyStoreWrapper.java
index 3a8a06949b29c..eee45743ee32e 100644
--- a/server/src/main/java/org/elasticsearch/common/settings/KeyStoreWrapper.java
+++ b/server/src/main/java/org/elasticsearch/common/settings/KeyStoreWrapper.java
@@ -166,6 +166,13 @@ private KeyStoreWrapper(int formatVersion, boolean hasPassword, byte[] dataBytes
this.dataBytes = dataBytes;
}
+ /**
+ * Get the metadata format version for the keystore
+ **/
+ public int getFormatVersion() {
+ return formatVersion;
+ }
+
/** Returns a path representing the ES keystore in the given config dir. */
public static Path keystorePath(Path configDir) {
return configDir.resolve(KEYSTORE_FILENAME);
@@ -593,8 +600,10 @@ private void ensureOpen() {
@Override
public synchronized void close() {
this.closed = true;
- for (Entry entry : entries.get().values()) {
- Arrays.fill(entry.bytes, (byte)0);
+ if (null != entries.get() && entries.get().isEmpty() == false) {
+ for (Entry entry : entries.get().values()) {
+ Arrays.fill(entry.bytes, (byte) 0);
+ }
}
}
}
diff --git a/server/src/main/java/org/elasticsearch/index/get/GetResult.java b/server/src/main/java/org/elasticsearch/index/get/GetResult.java
index 021e97767d840..a3f83609037e1 100644
--- a/server/src/main/java/org/elasticsearch/index/get/GetResult.java
+++ b/server/src/main/java/org/elasticsearch/index/get/GetResult.java
@@ -178,7 +178,6 @@ public String sourceAsString() {
/**
* The source of the document (As a map).
*/
- @SuppressWarnings({"unchecked"})
public Map sourceAsMap() throws ElasticsearchParseException {
if (source == null) {
return null;
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java
index 467ce2a4c1203..663aa7e6f9e10 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java
@@ -214,7 +214,6 @@ public RootObjectMapper root() {
return mapping.root;
}
- @SuppressWarnings({"unchecked"})
public T metadataMapper(Class type) {
return mapping.metadataMapper(type);
}
diff --git a/server/src/main/java/org/elasticsearch/index/shard/IndexShard.java b/server/src/main/java/org/elasticsearch/index/shard/IndexShard.java
index 21982d429752b..b82c3781859d3 100644
--- a/server/src/main/java/org/elasticsearch/index/shard/IndexShard.java
+++ b/server/src/main/java/org/elasticsearch/index/shard/IndexShard.java
@@ -919,6 +919,7 @@ public StoreStats storeStats() {
try {
return store.stats();
} catch (IOException e) {
+ failShard("Failing shard because of exception during storeStats", e);
throw new ElasticsearchException("io exception while building 'store stats'", e);
}
}
diff --git a/server/src/main/java/org/elasticsearch/persistent/NodePersistentTasksExecutor.java b/server/src/main/java/org/elasticsearch/persistent/NodePersistentTasksExecutor.java
index 87ea08dc74d2c..59523f3390167 100644
--- a/server/src/main/java/org/elasticsearch/persistent/NodePersistentTasksExecutor.java
+++ b/server/src/main/java/org/elasticsearch/persistent/NodePersistentTasksExecutor.java
@@ -45,7 +45,6 @@ public void onFailure(Exception e) {
task.markAsFailed(e);
}
- @SuppressWarnings("unchecked")
@Override
protected void doRun() throws Exception {
try {
diff --git a/server/src/main/java/org/elasticsearch/persistent/PersistentTasksClusterService.java b/server/src/main/java/org/elasticsearch/persistent/PersistentTasksClusterService.java
index 9ed0af010b530..4cb8c722f2620 100644
--- a/server/src/main/java/org/elasticsearch/persistent/PersistentTasksClusterService.java
+++ b/server/src/main/java/org/elasticsearch/persistent/PersistentTasksClusterService.java
@@ -85,7 +85,6 @@ public void onFailure(String source, Exception e) {
listener.onFailure(e);
}
- @SuppressWarnings("unchecked")
@Override
public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) {
PersistentTasksCustomMetaData tasks = newState.getMetaData().custom(PersistentTasksCustomMetaData.TYPE);
diff --git a/server/src/main/java/org/elasticsearch/persistent/PersistentTasksExecutorRegistry.java b/server/src/main/java/org/elasticsearch/persistent/PersistentTasksExecutorRegistry.java
index 2ac57e074b7bf..a8f9c73ab3266 100644
--- a/server/src/main/java/org/elasticsearch/persistent/PersistentTasksExecutorRegistry.java
+++ b/server/src/main/java/org/elasticsearch/persistent/PersistentTasksExecutorRegistry.java
@@ -33,7 +33,6 @@ public class PersistentTasksExecutorRegistry extends AbstractComponent {
private final Map> taskExecutors;
- @SuppressWarnings("unchecked")
public PersistentTasksExecutorRegistry(Settings settings, Collection> taskExecutors) {
super(settings);
Map> map = new HashMap<>();
diff --git a/server/src/main/java/org/elasticsearch/repositories/IndexId.java b/server/src/main/java/org/elasticsearch/repositories/IndexId.java
index 469caa26b645c..2a3d9f15d1637 100644
--- a/server/src/main/java/org/elasticsearch/repositories/IndexId.java
+++ b/server/src/main/java/org/elasticsearch/repositories/IndexId.java
@@ -89,7 +89,7 @@ public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
- @SuppressWarnings("unchecked") IndexId that = (IndexId) o;
+ IndexId that = (IndexId) o;
return Objects.equals(name, that.name) && Objects.equals(id, that.id);
}
diff --git a/server/src/main/java/org/elasticsearch/repositories/RepositoryData.java b/server/src/main/java/org/elasticsearch/repositories/RepositoryData.java
index 7a8d8327d5e3a..a97cf4bb419a2 100644
--- a/server/src/main/java/org/elasticsearch/repositories/RepositoryData.java
+++ b/server/src/main/java/org/elasticsearch/repositories/RepositoryData.java
@@ -238,7 +238,7 @@ public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) {
return false;
}
- @SuppressWarnings("unchecked") RepositoryData that = (RepositoryData) obj;
+ RepositoryData that = (RepositoryData) obj;
return snapshotIds.equals(that.snapshotIds)
&& snapshotStates.equals(that.snapshotStates)
&& indices.equals(that.indices)
diff --git a/server/src/main/java/org/elasticsearch/search/SearchModule.java b/server/src/main/java/org/elasticsearch/search/SearchModule.java
index efef1aeb04f76..99b47cf83e2ac 100644
--- a/server/src/main/java/org/elasticsearch/search/SearchModule.java
+++ b/server/src/main/java/org/elasticsearch/search/SearchModule.java
@@ -181,6 +181,8 @@
import org.elasticsearch.search.aggregations.metrics.tophits.TopHitsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.valuecount.InternalValueCount;
import org.elasticsearch.search.aggregations.metrics.valuecount.ValueCountAggregationBuilder;
+import org.elasticsearch.search.aggregations.metrics.weighted_avg.InternalWeightedAvg;
+import org.elasticsearch.search.aggregations.metrics.weighted_avg.WeightedAvgAggregationBuilder;
import org.elasticsearch.search.aggregations.pipeline.InternalSimpleValue;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
import org.elasticsearch.search.aggregations.pipeline.bucketmetrics.InternalBucketMetricValue;
@@ -335,6 +337,8 @@ public ParseFieldRegistry getMovingAverageModel
private void registerAggregations(List plugins) {
registerAggregation(new AggregationSpec(AvgAggregationBuilder.NAME, AvgAggregationBuilder::new, AvgAggregationBuilder::parse)
.addResultReader(InternalAvg::new));
+ registerAggregation(new AggregationSpec(WeightedAvgAggregationBuilder.NAME, WeightedAvgAggregationBuilder::new,
+ WeightedAvgAggregationBuilder::parse).addResultReader(InternalWeightedAvg::new));
registerAggregation(new AggregationSpec(SumAggregationBuilder.NAME, SumAggregationBuilder::new, SumAggregationBuilder::parse)
.addResultReader(InternalSum::new));
registerAggregation(new AggregationSpec(MinAggregationBuilder.NAME, MinAggregationBuilder::new, MinAggregationBuilder::parse)
diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/AggregationBuilders.java b/server/src/main/java/org/elasticsearch/search/aggregations/AggregationBuilders.java
index 26d8bb1a1bdf5..b4e416f4d7789 100644
--- a/server/src/main/java/org/elasticsearch/search/aggregations/AggregationBuilders.java
+++ b/server/src/main/java/org/elasticsearch/search/aggregations/AggregationBuilders.java
@@ -82,6 +82,7 @@
import org.elasticsearch.search.aggregations.metrics.tophits.TopHitsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.valuecount.ValueCount;
import org.elasticsearch.search.aggregations.metrics.valuecount.ValueCountAggregationBuilder;
+import org.elasticsearch.search.aggregations.metrics.weighted_avg.WeightedAvgAggregationBuilder;
import java.util.Map;
@@ -107,6 +108,13 @@ public static AvgAggregationBuilder avg(String name) {
return new AvgAggregationBuilder(name);
}
+ /**
+ * Create a new {@link Avg} aggregation with the given name.
+ */
+ public static WeightedAvgAggregationBuilder weightedAvg(String name) {
+ return new WeightedAvgAggregationBuilder(name);
+ }
+
/**
* Create a new {@link Max} aggregation with the given name.
*/
diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/InternalComposite.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/InternalComposite.java
index 1428a31a8dedc..e93266db805dc 100644
--- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/InternalComposite.java
+++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/InternalComposite.java
@@ -247,7 +247,6 @@ static class InternalBucket extends InternalMultiBucketAggregation.InternalBucke
this.formats = formats;
}
- @SuppressWarnings("unchecked")
InternalBucket(StreamInput in, List