Skip to content

Commit cfef0e3

Browse files
committed
Merge branch 'master' into common-stats-flags-ordinal
* master: (21 commits) Remove bulk fallback for write thread pool (elastic#29609) Fix an incorrect reference to 'zero_terms_docs' in match_phrase queries. Update the version compatibility for zero_terms_query in match_phrase. Account translog location to ram usage in version map Remove extra spaces from changelog Add support to match_phrase query for zero_terms_query. (elastic#29598) Fix incorrect references to 'zero_terms_docs' in query parsing error messages. (elastic#29599) Build: Move java home checks to pre-execution phase (elastic#29548) Avoid side-effect in VersionMap when assertion enabled (elastic#29585) [Tests] Remove accidental logger usage Add tests for ranking evaluation with aliases (elastic#29452) Deprecate use of `htmlStrip` as name for HtmlStripCharFilter (elastic#27429) Update plan for the removal of mapping types. (elastic#29586) [Docs] Add rankEval method for Jva HL client Make ranking evaluation details accessible for client Rename the bulk thread pool to write thread pool (elastic#29593) [Test] Minor changes to rank_eval tests (elastic#29577) Fix missing node id prefix in startup logs (elastic#29534) Added painless execute api. (elastic#29164) test: also assert deprecation warning after clusters have been closed. ...
2 parents 2ec7c9e + 5d767e4 commit cfef0e3

File tree

73 files changed

+1445
-354
lines changed

Some content is hidden

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

73 files changed

+1445
-354
lines changed

buildSrc/src/main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import org.gradle.api.artifacts.ModuleVersionIdentifier
3838
import org.gradle.api.artifacts.ProjectDependency
3939
import org.gradle.api.artifacts.ResolvedArtifact
4040
import org.gradle.api.artifacts.dsl.RepositoryHandler
41+
import org.gradle.api.execution.TaskExecutionGraph
4142
import org.gradle.api.plugins.JavaPlugin
4243
import org.gradle.api.publish.maven.MavenPublication
4344
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin
@@ -221,21 +222,34 @@ class BuildPlugin implements Plugin<Project> {
221222
return System.getenv('JAVA' + version + '_HOME')
222223
}
223224

224-
/**
225-
* Get Java home for the project for the specified version. If the specified version is not configured, an exception with the specified
226-
* message is thrown.
227-
*
228-
* @param project the project
229-
* @param version the version of Java home to obtain
230-
* @param message the exception message if Java home for the specified version is not configured
231-
* @return Java home for the specified version
232-
* @throws GradleException if Java home for the specified version is not configured
233-
*/
234-
static String getJavaHome(final Project project, final int version, final String message) {
235-
if (project.javaVersions.get(version) == null) {
236-
throw new GradleException(message)
225+
/** Add a check before gradle execution phase which ensures java home for the given java version is set. */
226+
static void requireJavaHome(Task task, int version) {
227+
Project rootProject = task.project.rootProject // use root project for global accounting
228+
if (rootProject.hasProperty('requiredJavaVersions') == false) {
229+
rootProject.rootProject.ext.requiredJavaVersions = [:].withDefault{key -> return []}
230+
rootProject.gradle.taskGraph.whenReady { TaskExecutionGraph taskGraph ->
231+
List<String> messages = []
232+
for (entry in rootProject.requiredJavaVersions) {
233+
if (rootProject.javaVersions.get(entry.key) != null) {
234+
continue
235+
}
236+
List<String> tasks = entry.value.findAll { taskGraph.hasTask(it) }.collect { " ${it.path}" }
237+
if (tasks.isEmpty() == false) {
238+
messages.add("JAVA${entry.key}_HOME required to run tasks:\n${tasks.join('\n')}")
239+
}
240+
}
241+
if (messages.isEmpty() == false) {
242+
throw new GradleException(messages.join('\n'))
243+
}
244+
}
237245
}
238-
return project.javaVersions.get(version)
246+
rootProject.requiredJavaVersions.get(version).add(task)
247+
}
248+
249+
/** A convenience method for getting java home for a version of java and requiring that version for the given task to execute */
250+
static String getJavaHome(final Task task, final int version) {
251+
requireJavaHome(task, version)
252+
return task.project.javaVersions.get(version)
239253
}
240254

241255
private static String findRuntimeJavaHome(final String compilerJavaHome) {

buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterFormationTasks.groovy

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ package org.elasticsearch.gradle.test
2020

2121
import org.apache.tools.ant.DefaultLogger
2222
import org.apache.tools.ant.taskdefs.condition.Os
23+
import org.elasticsearch.gradle.BuildPlugin
2324
import org.elasticsearch.gradle.LoggedExec
2425
import org.elasticsearch.gradle.Version
2526
import org.elasticsearch.gradle.VersionProperties
@@ -607,6 +608,9 @@ class ClusterFormationTasks {
607608
}
608609

609610
Task start = project.tasks.create(name: name, type: DefaultTask, dependsOn: setup)
611+
if (node.javaVersion != null) {
612+
BuildPlugin.requireJavaHome(start, node.javaVersion)
613+
}
610614
start.doLast(elasticsearchRunner)
611615
return start
612616
}

buildSrc/src/main/groovy/org/elasticsearch/gradle/test/NodeInfo.groovy

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ import static org.elasticsearch.gradle.BuildPlugin.getJavaHome
3636
* A container for the files and configuration associated with a single node in a test cluster.
3737
*/
3838
class NodeInfo {
39+
/** Gradle project this node is part of */
40+
Project project
41+
3942
/** common configuration for all nodes, including this one */
4043
ClusterConfiguration config
4144

@@ -84,6 +87,9 @@ class NodeInfo {
8487
/** directory to install plugins from */
8588
File pluginsTmpDir
8689

90+
/** Major version of java this node runs with, or {@code null} if using the runtime java version */
91+
Integer javaVersion
92+
8793
/** environment variables to start the node with */
8894
Map<String, String> env
8995

@@ -109,6 +115,7 @@ class NodeInfo {
109115
NodeInfo(ClusterConfiguration config, int nodeNum, Project project, String prefix, Version nodeVersion, File sharedDir) {
110116
this.config = config
111117
this.nodeNum = nodeNum
118+
this.project = project
112119
this.sharedDir = sharedDir
113120
if (config.clusterName != null) {
114121
clusterName = config.clusterName
@@ -165,12 +172,11 @@ class NodeInfo {
165172
args.add("${esScript}")
166173
}
167174

175+
168176
if (nodeVersion.before("6.2.0")) {
169-
env = ['JAVA_HOME': "${-> getJavaHome(project, 8, "JAVA8_HOME must be set to run BWC tests against [" + nodeVersion + "]")}"]
177+
javaVersion = 8
170178
} else if (nodeVersion.onOrAfter("6.2.0") && nodeVersion.before("6.3.0")) {
171-
env = ['JAVA_HOME': "${-> getJavaHome(project, 9, "JAVA9_HOME must be set to run BWC tests against [" + nodeVersion + "]")}"]
172-
} else {
173-
env = ['JAVA_HOME': (String) project.runtimeJavaHome]
179+
javaVersion = 9
174180
}
175181

176182
args.addAll("-E", "node.portsfile=true")
@@ -182,7 +188,7 @@ class NodeInfo {
182188
// in the cluster-specific options
183189
esJavaOpts = String.join(" ", "-ea", "-esa", esJavaOpts)
184190
}
185-
env.put('ES_JAVA_OPTS', esJavaOpts)
191+
env = ['ES_JAVA_OPTS': esJavaOpts]
186192
for (Map.Entry<String, String> property : System.properties.entrySet()) {
187193
if (property.key.startsWith('tests.es.')) {
188194
args.add("-E")
@@ -242,13 +248,19 @@ class NodeInfo {
242248
return Native.toString(shortPath).substring(4)
243249
}
244250

251+
/** Return the java home used by this node. */
252+
String getJavaHome() {
253+
return javaVersion == null ? project.runtimeJavaHome : project.javaVersions.get(javaVersion)
254+
}
255+
245256
/** Returns debug string for the command that started this node. */
246257
String getCommandString() {
247258
String esCommandString = "\nNode ${nodeNum} configuration:\n"
248259
esCommandString += "|-----------------------------------------\n"
249260
esCommandString += "| cwd: ${cwd}\n"
250261
esCommandString += "| command: ${executable} ${args.join(' ')}\n"
251262
esCommandString += '| environment:\n'
263+
esCommandString += "| JAVA_HOME: ${javaHome}\n"
252264
env.each { k, v -> esCommandString += "| ${k}: ${v}\n" }
253265
if (config.daemonize) {
254266
esCommandString += "|\n| [${wrapperScript.name}]\n"

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

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@
4444
import org.elasticsearch.index.query.MatchQueryBuilder;
4545
import org.elasticsearch.index.query.QueryBuilder;
4646
import org.elasticsearch.index.query.QueryBuilders;
47+
import org.elasticsearch.index.rankeval.EvalQueryQuality;
48+
import org.elasticsearch.index.rankeval.EvaluationMetric;
49+
import org.elasticsearch.index.rankeval.MetricDetail;
50+
import org.elasticsearch.index.rankeval.PrecisionAtK;
51+
import org.elasticsearch.index.rankeval.RankEvalRequest;
52+
import org.elasticsearch.index.rankeval.RankEvalResponse;
53+
import org.elasticsearch.index.rankeval.RankEvalSpec;
54+
import org.elasticsearch.index.rankeval.RatedDocument;
55+
import org.elasticsearch.index.rankeval.RatedRequest;
56+
import org.elasticsearch.index.rankeval.RatedSearchHit;
4757
import org.elasticsearch.rest.RestStatus;
4858
import org.elasticsearch.search.Scroll;
4959
import org.elasticsearch.search.SearchHit;
@@ -74,6 +84,7 @@
7484
import org.elasticsearch.search.suggest.term.TermSuggestion;
7585

7686
import java.io.IOException;
87+
import java.util.ArrayList;
7788
import java.util.Arrays;
7889
import java.util.Collections;
7990
import java.util.List;
@@ -688,6 +699,77 @@ public void onFailure(Exception e) {
688699
}
689700
}
690701

702+
public void testRankEval() throws Exception {
703+
indexSearchTestData();
704+
RestHighLevelClient client = highLevelClient();
705+
{
706+
// tag::rank-eval-request-basic
707+
EvaluationMetric metric = new PrecisionAtK(); // <1>
708+
List<RatedDocument> ratedDocs = new ArrayList<>();
709+
ratedDocs.add(new RatedDocument("posts", "1", 1)); // <2>
710+
SearchSourceBuilder searchQuery = new SearchSourceBuilder();
711+
searchQuery.query(QueryBuilders.matchQuery("user", "kimchy"));// <3>
712+
RatedRequest ratedRequest = // <4>
713+
new RatedRequest("kimchy_query", ratedDocs, searchQuery);
714+
List<RatedRequest> ratedRequests = Arrays.asList(ratedRequest);
715+
RankEvalSpec specification =
716+
new RankEvalSpec(ratedRequests, metric); // <5>
717+
RankEvalRequest request = // <6>
718+
new RankEvalRequest(specification, new String[] { "posts" });
719+
// end::rank-eval-request-basic
720+
721+
// tag::rank-eval-execute
722+
RankEvalResponse response = client.rankEval(request);
723+
// end::rank-eval-execute
724+
725+
// tag::rank-eval-response
726+
double evaluationResult = response.getEvaluationResult(); // <1>
727+
assertEquals(1.0 / 3.0, evaluationResult, 0.0);
728+
Map<String, EvalQueryQuality> partialResults =
729+
response.getPartialResults();
730+
EvalQueryQuality evalQuality =
731+
partialResults.get("kimchy_query"); // <2>
732+
assertEquals("kimchy_query", evalQuality.getId());
733+
double qualityLevel = evalQuality.getQualityLevel(); // <3>
734+
assertEquals(1.0 / 3.0, qualityLevel, 0.0);
735+
List<RatedSearchHit> hitsAndRatings = evalQuality.getHitsAndRatings();
736+
RatedSearchHit ratedSearchHit = hitsAndRatings.get(0);
737+
assertEquals("3", ratedSearchHit.getSearchHit().getId()); // <4>
738+
assertFalse(ratedSearchHit.getRating().isPresent()); // <5>
739+
MetricDetail metricDetails = evalQuality.getMetricDetails();
740+
String metricName = metricDetails.getMetricName();
741+
assertEquals(PrecisionAtK.NAME, metricName); // <6>
742+
PrecisionAtK.Detail detail = (PrecisionAtK.Detail) metricDetails;
743+
assertEquals(1, detail.getRelevantRetrieved()); // <7>
744+
assertEquals(3, detail.getRetrieved());
745+
// end::rank-eval-response
746+
747+
// tag::rank-eval-execute-listener
748+
ActionListener<RankEvalResponse> listener = new ActionListener<RankEvalResponse>() {
749+
@Override
750+
public void onResponse(RankEvalResponse response) {
751+
// <1>
752+
}
753+
754+
@Override
755+
public void onFailure(Exception e) {
756+
// <2>
757+
}
758+
};
759+
// end::rank-eval-execute-listener
760+
761+
// Replace the empty listener by a blocking listener in test
762+
final CountDownLatch latch = new CountDownLatch(1);
763+
listener = new LatchedActionListener<>(listener, latch);
764+
765+
// tag::rank-eval-execute-async
766+
client.rankEvalAsync(request, listener); // <1>
767+
// end::rank-eval-execute-async
768+
769+
assertTrue(latch.await(30L, TimeUnit.SECONDS));
770+
}
771+
}
772+
691773
public void testMultiSearch() throws Exception {
692774
indexSearchTestData();
693775
RestHighLevelClient client = highLevelClient();

distribution/bwc/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,9 @@ subprojects {
147147
workingDir = checkoutDir
148148
if (["5.6", "6.0", "6.1"].contains(bwcBranch)) {
149149
// we are building branches that are officially built with JDK 8, push JAVA8_HOME to JAVA_HOME for these builds
150-
environment('JAVA_HOME', "${-> getJavaHome(project, 8, "JAVA8_HOME is required to build BWC versions for BWC branch [" + bwcBranch + "]")}")
150+
environment('JAVA_HOME', getJavaHome(it, 8))
151151
} else if ("6.2".equals(bwcBranch)) {
152-
environment('JAVA_HOME', "${-> getJavaHome(project, 9, "JAVA9_HOME is required to build BWC versions for BWC branch [" + bwcBranch + "]")}")
152+
environment('JAVA_HOME', getJavaHome(it, 9))
153153
} else {
154154
environment('JAVA_HOME', project.compilerJavaHome)
155155
}

docs/CHANGELOG.asciidoc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@
99

1010
=== Breaking Changes
1111

12+
<<write-thread-pool-fallback, Removed `thread_pool.bulk.*` settings and
13+
`es.thread_pool.write.use_bulk_as_display_name` system property>> ({pull}29609[#29609])
14+
1215
=== Breaking Java Changes
1316

1417
=== Deprecations
1518

16-
=== New Features
19+
=== New Features
1720

1821
=== Enhancements
1922

@@ -25,7 +28,7 @@
2528

2629
== Elasticsearch version 6.3.0
2730

28-
=== New Features
31+
=== New Features
2932

3033
=== Enhancements
3134

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
[[java-rest-high-rank-eval]]
2+
=== Ranking Evaluation API
3+
4+
The `rankEval` method allows to evaluate the quality of ranked search
5+
results over a set of search request. Given sets of manually rated
6+
documents for each search request, ranking evaluation performs a
7+
<<java-rest-high-multi-search,multi search>> request and calculates
8+
information retrieval metrics like _mean reciprocal rank_, _precision_
9+
or _discounted cumulative gain_ on the returned results.
10+
11+
[[java-rest-high-rank-eval-request]]
12+
==== Ranking Evaluation Request
13+
14+
In order to build a `RankEvalRequest`, you first need to create an
15+
evaluation specification (`RankEvalSpec`). This specification requires
16+
to define the evaluation metric that is going to be calculated, as well
17+
as a list of rated documents per search requests. Creating the ranking
18+
evaluation request then takes the specification and a list of target
19+
indices as arguments:
20+
21+
["source","java",subs="attributes,callouts,macros"]
22+
--------------------------------------------------
23+
include-tagged::{doc-tests}/SearchDocumentationIT.java[rank-eval-request-basic]
24+
--------------------------------------------------
25+
<1> Define the metric used in the evaluation
26+
<2> Add rated documents, specified by index name, id and rating
27+
<3> Create the search query to evaluate
28+
<4> Combine the three former parts into a `RatedRequest`
29+
<5> Create the ranking evaluation specification
30+
<6> Create the ranking evaluation request
31+
32+
[[java-rest-high-rank-eval-sync]]
33+
==== Synchronous Execution
34+
35+
The `rankEval` method executes `RankEvalRequest`s synchronously:
36+
37+
["source","java",subs="attributes,callouts,macros"]
38+
--------------------------------------------------
39+
include-tagged::{doc-tests}/SearchDocumentationIT.java[rank-eval-execute]
40+
--------------------------------------------------
41+
42+
[[java-rest-high-rank-eval-async]]
43+
==== Asynchronous Execution
44+
45+
The `rankEvalAsync` method executes `RankEvalRequest`s asynchronously,
46+
calling the provided `ActionListener` when the response is ready.
47+
48+
["source","java",subs="attributes,callouts,macros"]
49+
--------------------------------------------------
50+
include-tagged::{doc-tests}/SearchDocumentationIT.java[rank-eval-execute-async]
51+
--------------------------------------------------
52+
<1> The `RankEvalRequest` to execute and the `ActionListener` to use when
53+
the execution completes
54+
55+
The asynchronous method does not block and returns immediately. Once it is
56+
completed the `ActionListener` is called back using the `onResponse` method
57+
if the execution successfully completed or using the `onFailure` method if
58+
it failed.
59+
60+
A typical listener for `RankEvalResponse` looks like:
61+
62+
["source","java",subs="attributes,callouts,macros"]
63+
--------------------------------------------------
64+
include-tagged::{doc-tests}/SearchDocumentationIT.java[rank-eval-execute-listener]
65+
--------------------------------------------------
66+
<1> Called when the execution is successfully completed.
67+
<2> Called when the whole `RankEvalRequest` fails.
68+
69+
==== RankEvalResponse
70+
71+
The `RankEvalResponse` that is returned by executing the request
72+
contains information about the overall evaluation score, the
73+
scores of each individual search request in the set of queries and
74+
detailed information about search hits and details about the metric
75+
calculation per partial result.
76+
77+
["source","java",subs="attributes,callouts,macros"]
78+
--------------------------------------------------
79+
include-tagged::{doc-tests}/SearchDocumentationIT.java[rank-eval-response]
80+
--------------------------------------------------
81+
<1> The overall evaluation result
82+
<2> Partial results that are keyed by their query id
83+
<3> The metric score for each partial result
84+
<4> Rated search hits contain a fully fledged `SearchHit`
85+
<5> Rated search hits also contain an `Optional<Interger>` rating that
86+
is not present if the document did not get a rating in the request
87+
<6> Metric details are named after the metric used in the request
88+
<7> After casting to the metric used in the request, the
89+
metric details offers insight into parts of the metric calculation

docs/java-rest/high-level/supported-apis.asciidoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@ The Java High Level REST Client supports the following Search APIs:
3232
* <<java-rest-high-search-scroll>>
3333
* <<java-rest-high-clear-scroll>>
3434
* <<java-rest-high-multi-search>>
35+
* <<java-rest-high-rank-eval>>
3536

3637
include::search/search.asciidoc[]
3738
include::search/scroll.asciidoc[]
3839
include::search/multi-search.asciidoc[]
40+
include::search/rank-eval.asciidoc[]
3941

4042
== Miscellaneous APIs
4143

0 commit comments

Comments
 (0)