From a649cb4c36ad060f13c605d25d84933b2519dc0b Mon Sep 17 00:00:00 2001 From: Benjamin Trent Date: Thu, 16 Aug 2018 15:49:12 -0500 Subject: [PATCH 1/7] HLRC: Adding GET ML Job info API --- .../protocol/xpack/ml/GetJobRequest.java | 86 ++++++++++++++++ .../protocol/xpack/ml/GetJobResponse.java | 97 +++++++++++++++++++ .../protocol/xpack/ml/QueryPage.java | 81 ++++++++++++++++ .../protocol/xpack/ml/GetJobRequestTests.java | 35 +++++++ .../xpack/ml/GetJobResponseTests.java | 56 +++++++++++ .../xpack/ml/job/config/JobTests.java | 8 +- 6 files changed, 361 insertions(+), 2 deletions(-) create mode 100644 x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobRequest.java create mode 100644 x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobResponse.java create mode 100644 x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/QueryPage.java create mode 100644 x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobRequestTests.java create mode 100644 x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobResponseTests.java diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobRequest.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobRequest.java new file mode 100644 index 0000000000000..2c906d5a43e37 --- /dev/null +++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobRequest.java @@ -0,0 +1,86 @@ +/* + * 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.protocol.xpack.ml; + +import org.elasticsearch.action.ActionRequest; +import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.common.Strings; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class GetJobRequest extends ActionRequest { + + public final static String ALL_JOBS = "_all"; + private List jobIds = new ArrayList<>(); + private boolean allowNoJobs = true; + + public static GetJobRequest getAllJobsRequest() { + return new GetJobRequest(ALL_JOBS); + } + + public GetJobRequest(String jobId) { + jobIds.add(Objects.requireNonNull(jobId, "[jobId] must not be null")); + } + + public GetJobRequest() { + } + + public String getCommaDelimitedJobIdsString() { + return jobIds.isEmpty() ? null : Strings.collectionToCommaDelimitedString(jobIds); + } + + public void addJobId(String jobId) { + jobIds.add(Objects.requireNonNull(jobId, "[jobId] must not be null")); + } + + public void setAllowNoJobs(boolean allowNoJobs) { + this.allowNoJobs = allowNoJobs; + } + + public boolean isAllowNoJobs() { + return allowNoJobs; + } + + @Override + public ActionRequestValidationException validate() { + return null; + } + + @Override + public int hashCode() { + return Objects.hash(jobIds, allowNoJobs); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || obj.getClass() != getClass()) { + return false; + } + + GetJobRequest other = (GetJobRequest) obj; + return Objects.equals(jobIds, other.jobIds) && allowNoJobs == other.allowNoJobs; + } + +} diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobResponse.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobResponse.java new file mode 100644 index 0000000000000..a403cf52f58e1 --- /dev/null +++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobResponse.java @@ -0,0 +1,97 @@ +/* + * 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.protocol.xpack.ml; + +import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.xcontent.ObjectParser; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.protocol.xpack.ml.job.config.Job; + +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public class GetJobResponse extends ActionResponse implements ToXContentObject { + + public static final ParseField RESULTS_FIELD = new ParseField("jobs"); + public static final ObjectParser PARSER = new ObjectParser<>("jobs_response", true, GetJobResponse::new); + + static { + PARSER.declareObjectArray(GetJobResponse::setJobs, Job.PARSER, RESULTS_FIELD); + PARSER.declareLong(GetJobResponse::setCount, QueryPage.COUNT); + } + + private QueryPage jobs; + + public GetJobResponse(QueryPage jobs) { + this.jobs = jobs; + } + + public GetJobResponse() { + jobs = new QueryPage<>(RESULTS_FIELD); + } + + public QueryPage getResponse() { + return jobs; + } + + public static GetJobResponse fromXContent(XContentParser parser) throws IOException { + return PARSER.parse(parser, null); + } + + void setJobs(List jobs) { + this.jobs.setResults(jobs.stream().map(Job.Builder::build).collect(Collectors.toList())); + } + + void setCount(long count) { + this.jobs.setCount(count); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + return jobs.toXContent(builder, params); + } + + @Override + public int hashCode() { + return Objects.hash(jobs); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + GetJobResponse other = (GetJobResponse) obj; + return Objects.equals(jobs, other.jobs); + } + + @Override + public final String toString() { + return Strings.toString(this); + } +} diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/QueryPage.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/QueryPage.java new file mode 100644 index 0000000000000..c4cf1a7b1d495 --- /dev/null +++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/QueryPage.java @@ -0,0 +1,81 @@ +package org.elasticsearch.protocol.xpack.ml; + +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Generic wrapper class for a page of query results and the total number of + * query results.
+ * {@linkplain #count()} is the total number of results but that value may + * not be equal to the actual length of the {@linkplain #results()} list if from + * & take or some cursor was used in the database query. + */ +public final class QueryPage implements ToXContentObject { + + public static final ParseField COUNT = new ParseField("count"); + + private final ParseField resultsField; + private List results; + private long count; + + public QueryPage(ParseField resultsField) { + this.resultsField = Objects.requireNonNull(resultsField, + "[results_field] must not be null"); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.field(COUNT.getPreferredName(), count); + builder.field(resultsField.getPreferredName(), results); + builder.endObject(); + return builder; + } + + public List results() { + return results; + } + + void setResults(List results) { + this.results = new ArrayList<>(results); + } + + public long count() { + return count; + } + + void setCount(long count) { + this.count = count; + } + + public ParseField getResultsField() { + return resultsField; + } + + @Override + public int hashCode() { + return Objects.hash(results, count); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + + if (getClass() != obj.getClass()) { + return false; + } + + @SuppressWarnings("unchecked") + QueryPage other = (QueryPage) obj; + return Objects.equals(results, other.results) && Objects.equals(count, other.count); + } +} diff --git a/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobRequestTests.java b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobRequestTests.java new file mode 100644 index 0000000000000..14c0c485923c0 --- /dev/null +++ b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobRequestTests.java @@ -0,0 +1,35 @@ +/* + * 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.protocol.xpack.ml; + +import org.elasticsearch.test.ESTestCase; + +public class GetJobRequestTests extends ESTestCase { + + public void test_AllJobsRequest() { + + } + + public void test_AddJobId() { + + } + + public void test_getCommaDelimitedJobIdsString() { + } +} diff --git a/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobResponseTests.java b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobResponseTests.java new file mode 100644 index 0000000000000..dec621e7f5535 --- /dev/null +++ b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobResponseTests.java @@ -0,0 +1,56 @@ +/* + * 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.protocol.xpack.ml; + +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.protocol.xpack.ml.job.config.Job; +import org.elasticsearch.protocol.xpack.ml.job.config.JobTests; +import org.elasticsearch.test.AbstractXContentTestCase; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class GetJobResponseTests extends AbstractXContentTestCase { + + @Override + protected GetJobResponse createTestInstance() { + + int count = randomIntBetween(1, 5); + List results = new ArrayList<>(count); + for(int i = 0; i < count; i++) { + results.add(JobTests.createRandomizedJobBuilder()); + } + + GetJobResponse response = new GetJobResponse(); + response.setCount(count); + response.setJobs(results); + return response; + } + + @Override + protected GetJobResponse doParseInstance(XContentParser parser) throws IOException { + return GetJobResponse.fromXContent(parser); + } + + @Override + protected boolean supportsUnknownFields() { + return true; + } +} diff --git a/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/job/config/JobTests.java b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/job/config/JobTests.java index 7ba4946efa753..61931743403e0 100644 --- a/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/job/config/JobTests.java +++ b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/job/config/JobTests.java @@ -210,7 +210,7 @@ public static AnalysisConfig.Builder createAnalysisConfig() { return new AnalysisConfig.Builder(Arrays.asList(d1.build(), d2.build())); } - public static Job createRandomizedJob() { + public static Job.Builder createRandomizedJobBuilder() { String jobId = randomValidJobId(); Job.Builder builder = new Job.Builder(jobId); if (randomBoolean()) { @@ -265,7 +265,11 @@ public static Job createRandomizedJob() { if (randomBoolean()) { builder.setResultsIndexName(randomValidJobId()); } - return builder.build(); + return builder; + } + + public static Job createRandomizedJob() { + return createRandomizedJobBuilder().build(); } @Override From 04e25836c8b7adf326e071cf9acdbce78efdd106 Mon Sep 17 00:00:00 2001 From: Benjamin Trent Date: Fri, 17 Aug 2018 11:03:36 -0500 Subject: [PATCH 2/7] HLRC: Adding GET Job ML API --- .../client/MLRequestConverters.java | 17 +++++ .../client/MachineLearningClient.java | 43 ++++++++++++ .../client/MLRequestConvertersTests.java | 22 ++++++- .../client/MachineLearningIT.java | 42 ++++++++++++ .../MlClientDocumentationIT.java | 66 +++++++++++++++++++ docs/java-rest/high-level/ml/get-job.asciidoc | 59 +++++++++++++++++ .../high-level/supported-apis.asciidoc | 2 + .../protocol/xpack/ml/GetJobRequest.java | 39 ++++++++++- .../protocol/xpack/ml/GetJobResponse.java | 17 +++-- .../protocol/xpack/ml/GetJobRequestTests.java | 15 ++++- .../xpack/ml/GetJobResponseTests.java | 2 +- 11 files changed, 311 insertions(+), 13 deletions(-) create mode 100644 docs/java-rest/high-level/ml/get-job.asciidoc diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/MLRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/MLRequestConverters.java index e26a4c629a0b0..1cc280a10984b 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/MLRequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/MLRequestConverters.java @@ -20,10 +20,12 @@ package org.elasticsearch.client; import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.elasticsearch.client.RequestConverters.EndpointBuilder; import org.elasticsearch.protocol.xpack.ml.DeleteJobRequest; +import org.elasticsearch.protocol.xpack.ml.GetJobRequest; import org.elasticsearch.protocol.xpack.ml.OpenJobRequest; import org.elasticsearch.protocol.xpack.ml.PutJobRequest; @@ -48,6 +50,21 @@ static Request putJob(PutJobRequest putJobRequest) throws IOException { return request; } + static Request getJob(GetJobRequest getJobRequest) { + String endpoint = new EndpointBuilder() + .addPathPartAsIs("_xpack") + .addPathPartAsIs("ml") + .addPathPartAsIs("anomaly_detectors") + .addPathPart(getJobRequest.getCommaDelimitedJobIdsString()) + .build(); + Request request = new Request(HttpGet.METHOD_NAME, endpoint); + + RequestConverters.Params params = new RequestConverters.Params(request); + params.putParam("allow_no_jobs", Boolean.toString(getJobRequest.isAllowNoJobs())); + + return request; + } + static Request openJob(OpenJobRequest openJobRequest) throws IOException { String endpoint = new EndpointBuilder() .addPathPartAsIs("_xpack") diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/MachineLearningClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/MachineLearningClient.java index 32b6cd6cf2c67..7d733d92901bf 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/MachineLearningClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/MachineLearningClient.java @@ -21,6 +21,8 @@ import org.elasticsearch.action.ActionListener; import org.elasticsearch.protocol.xpack.ml.DeleteJobRequest; import org.elasticsearch.protocol.xpack.ml.DeleteJobResponse; +import org.elasticsearch.protocol.xpack.ml.GetJobRequest; +import org.elasticsearch.protocol.xpack.ml.GetJobResponse; import org.elasticsearch.protocol.xpack.ml.OpenJobRequest; import org.elasticsearch.protocol.xpack.ml.OpenJobResponse; import org.elasticsearch.protocol.xpack.ml.PutJobRequest; @@ -82,6 +84,47 @@ public void putJobAsync(PutJobRequest request, RequestOptions options, ActionLis Collections.emptySet()); } + /** + * Gets Machine Learning job configuration info. + * + *

+ * For additional info + * see + *

+ * @param request {@link GetJobRequest} request containing a list of jobId(s) + * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @return {@link GetJobResponse} response object containing + * the {@link org.elasticsearch.protocol.xpack.ml.job.config.Job} objects and the number of jobs found + * @throws IOException when there is a serialization issue sending the request or receiving the response + */ + public GetJobResponse getJob(GetJobRequest request, RequestOptions options) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(request, + MLRequestConverters::getJob, + options, + GetJobResponse::fromXContent, + Collections.emptySet()); + } + + /** + * Gets Machine Learning job configuration info, asynchronously. + * + *

+ * For additional info + * see + *

+ * @param request {@link GetJobRequest} request containing a list of jobId(s) and optional additional parameters + * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param listener Listener to be notified with {@link GetJobResponse} upon request completion + */ + public void getJobAsync(GetJobRequest request, RequestOptions options, ActionListener listener) { + restHighLevelClient.performRequestAsyncAndParseEntity(request, + MLRequestConverters::getJob, + options, + GetJobResponse::fromXContent, + listener, + Collections.emptySet()); + } + /** * Deletes the given Machine Learning Job *

diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/MLRequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/MLRequestConvertersTests.java index 43a41960e003c..b9aabf8f08733 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/MLRequestConvertersTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/MLRequestConvertersTests.java @@ -20,11 +20,13 @@ package org.elasticsearch.client; import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.protocol.xpack.ml.DeleteJobRequest; +import org.elasticsearch.protocol.xpack.ml.GetJobRequest; import org.elasticsearch.protocol.xpack.ml.OpenJobRequest; import org.elasticsearch.protocol.xpack.ml.PutJobRequest; import org.elasticsearch.protocol.xpack.ml.job.config.AnalysisConfig; @@ -53,6 +55,24 @@ public void testPutJob() throws IOException { } } + public void testGetJob() { + GetJobRequest getJobRequest = new GetJobRequest(); + + Request request = MLRequestConverters.getJob(getJobRequest); + + assertEquals(HttpGet.METHOD_NAME, request.getMethod()); + assertEquals("/_xpack/ml/anomaly_detectors", request.getEndpoint()); + assertEquals(Boolean.toString(getJobRequest.isAllowNoJobs()), request.getParameters().get("allow_no_jobs")); + + getJobRequest.setAllowNoJobs(false); + getJobRequest.addJobId("job1"); + getJobRequest.addJobId("jobs*"); + request = MLRequestConverters.getJob(getJobRequest); + + assertEquals("/_xpack/ml/anomaly_detectors/job1,jobs*", request.getEndpoint()); + assertEquals(Boolean.toString(false), request.getParameters().get("allow_no_jobs")); + } + public void testOpenJob() throws Exception { String jobId = "some-job-id"; OpenJobRequest openJobRequest = new OpenJobRequest(jobId); @@ -87,4 +107,4 @@ private static Job createValidJob(String jobId) { jobBuilder.setAnalysisConfig(analysisConfig); return jobBuilder.build(); } -} \ No newline at end of file +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java index 0037460150f1a..c8ea1c54ad55e 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java @@ -22,6 +22,8 @@ import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.protocol.xpack.ml.DeleteJobRequest; import org.elasticsearch.protocol.xpack.ml.DeleteJobResponse; +import org.elasticsearch.protocol.xpack.ml.GetJobRequest; +import org.elasticsearch.protocol.xpack.ml.GetJobResponse; import org.elasticsearch.protocol.xpack.ml.OpenJobRequest; import org.elasticsearch.protocol.xpack.ml.OpenJobResponse; import org.elasticsearch.protocol.xpack.ml.PutJobRequest; @@ -33,7 +35,11 @@ import java.util.Arrays; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import static org.hamcrest.CoreMatchers.hasItems; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; public class MachineLearningIT extends ESRestHighLevelClientTestCase { @@ -50,6 +56,42 @@ public void testPutJob() throws Exception { assertThat(createdJob.getJobType(), is(Job.ANOMALY_DETECTOR_JOB_TYPE)); } + public void testGetJob() throws Exception { + String jobId1 = randomValidJobId(); + String jobId2 = randomValidJobId(); + + Job job1 = buildJob(jobId1); + Job job2 = buildJob(jobId2); + MachineLearningClient machineLearningClient = highLevelClient().machineLearning(); + machineLearningClient.putJob(new PutJobRequest(job1), RequestOptions.DEFAULT); + machineLearningClient.putJob(new PutJobRequest(job2), RequestOptions.DEFAULT); + + GetJobRequest request = new GetJobRequest(jobId1); + request.addJobId(jobId2); + + // Test getting specific jobs + GetJobResponse response = execute(request, machineLearningClient::getJob, machineLearningClient::getJobAsync); + + assertEquals(2, response.getCount()); + assertThat(response.getJobs(), hasSize(2)); + assertThat(response.getJobs().stream().map(Job::getId).collect(Collectors.toList()), containsInAnyOrder(jobId1, jobId2)); + + // Test getting all jobs explicitly + request = GetJobRequest.getAllJobsRequest(); + response = execute(request, machineLearningClient::getJob, machineLearningClient::getJobAsync); + + assertTrue(response.getCount() >= 2L); + assertTrue(response.getJobs().size() >= 2L); + assertThat(response.getJobs().stream().map(Job::getId).collect(Collectors.toList()), hasItems(jobId1, jobId2)); + + // Test getting all jobs implicitly + response = execute(new GetJobRequest(), machineLearningClient::getJob, machineLearningClient::getJobAsync); + + assertTrue(response.getCount() >= 2L); + assertTrue(response.getJobs().size() >= 2L); + assertThat(response.getJobs().stream().map(Job::getId).collect(Collectors.toList()), hasItems(jobId1, jobId2)); + } + public void testDeleteJob() throws Exception { String jobId = randomValidJobId(); Job job = buildJob(jobId); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java index a77d8b43e5737..94e05be4805bd 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java @@ -27,6 +27,8 @@ import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.protocol.xpack.ml.DeleteJobRequest; import org.elasticsearch.protocol.xpack.ml.DeleteJobResponse; +import org.elasticsearch.protocol.xpack.ml.GetJobRequest; +import org.elasticsearch.protocol.xpack.ml.GetJobResponse; import org.elasticsearch.protocol.xpack.ml.OpenJobRequest; import org.elasticsearch.protocol.xpack.ml.OpenJobResponse; import org.elasticsearch.protocol.xpack.ml.PutJobRequest; @@ -41,8 +43,11 @@ import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.hasSize; public class MlClientDocumentationIT extends ESRestHighLevelClientTestCase { @@ -124,6 +129,67 @@ public void onFailure(Exception e) { } } + public void testGetJob() throws Exception { + RestHighLevelClient client = highLevelClient(); + + String jobId = "get-machine-learning-job1"; + + Job job = MachineLearningIT.buildJob("get-machine-learning-job1"); + client.machineLearning().putJob(new PutJobRequest(job), RequestOptions.DEFAULT); + + Job secondJob = MachineLearningIT.buildJob("get-machine-learning-job2"); + client.machineLearning().putJob(new PutJobRequest(secondJob), RequestOptions.DEFAULT); + + { + //tag::x-pack-ml-get-job-request + GetJobRequest request = new GetJobRequest(); //<1> + request.addJobId("get-machine-learning-job1"); //<2> + request.addJobId("get-machine-learning-job*"); //<3> + request.setAllowNoJobs(true); //<4> + //end::x-pack-ml-get-job-request + + //tag::x-pack-ml-get-job-execute + GetJobResponse response = client.machineLearning().getJob(request, RequestOptions.DEFAULT); + long numberOfJobs = response.getCount(); //<1> + List jobs = response.getJobs(); //<2> + //end::x-pack-ml-get-job-execute + + assertEquals(2, response.getCount()); + assertThat(response.getJobs(), hasSize(2)); + assertThat(response.getJobs().stream().map(Job::getId).collect(Collectors.toList()), + containsInAnyOrder(job.getId(), secondJob.getId())); + } + { + GetJobRequest request = new GetJobRequest(); + request.addJobId("get-machine-learning-job1"); + request.addJobId("get-machine-learning-job*"); + + // tag::x-pack-ml-get-job-listener + ActionListener listener = new ActionListener() { + @Override + public void onResponse(GetJobResponse response) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }; + // end::x-pack-ml-get-job-listener + + // Replace the empty listener by a blocking listener in test + final CountDownLatch latch = new CountDownLatch(1); + listener = new LatchedActionListener<>(listener, latch); + + // tag::x-pack-ml-get-job-execute-async + client.machineLearning().getJobAsync(request, RequestOptions.DEFAULT, listener); // <1> + // end::x-pack-ml-get-job-execute-async + + assertTrue(latch.await(30L, TimeUnit.SECONDS)); + } + } + public void testDeleteJob() throws Exception { RestHighLevelClient client = highLevelClient(); diff --git a/docs/java-rest/high-level/ml/get-job.asciidoc b/docs/java-rest/high-level/ml/get-job.asciidoc new file mode 100644 index 0000000000000..7f64589c85de4 --- /dev/null +++ b/docs/java-rest/high-level/ml/get-job.asciidoc @@ -0,0 +1,59 @@ +[[java-rest-high-x-pack-ml-get-job]] +=== Get Job API + +The Get Job API provides the ability to get {ml} jobs in the cluster. +It accepts a `GetJobRequest` object and responds +with a `GetJobResponse` object. + +[[java-rest-high-x-pack-ml-get-job-request]] +==== Get Job Request + +An `GetJobRequest` object gets can have any number of `jobId` or `groupName` +entries. However, they all must be non-null. An empty list is the same as +requesting for all jobs. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-get-job-request] +-------------------------------------------------- +<1> Constructing a new request referencing no `jobId` +<2> Adding a new specific `jobId` we want to find +<3> Adding a new wildcard matching `jobId` we want to find +<4> Whether to ignore if a wildcard expression matches no jobs. + (This includes `_all` string or when no jobs have been specified) + +[[java-rest-high-x-pack-ml-get-job-execution]] +==== Execution + +The request can be executed through the `MachineLearningClient` contained +in the `RestHighLevelClient` object, accessed via the `machineLearningClient()` method. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-get-job-execute] +-------------------------------------------------- +<1> `getCount()` from the `GetJobResponse` indicates the number of jobs found +<2> `getJobs()` is the collection of {ml} `Job` objects found + +[[java-rest-high-x-pack-ml-get-job-execution-async]] +==== Asynchronous Execution + +The request can also be executed asynchronously: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-get-job-execute-async] +-------------------------------------------------- +<1> The `GetJobRequest` to execute and the `ActionListener` to use when +the execution completes + +The method does not block and returns immediately. The passed `ActionListener` is used +to notify the caller of completion. A typical `ActionListener` for `GetJobResponse` may +look like + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-get-job-listener] +-------------------------------------------------- +<1> `onResponse` is called back when the action is completed successfully +<2> `onFailure` is called back when some unexpected error occurs diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc index 6bcb736243a7c..87b1e17446f28 100644 --- a/docs/java-rest/high-level/supported-apis.asciidoc +++ b/docs/java-rest/high-level/supported-apis.asciidoc @@ -205,10 +205,12 @@ include::licensing/delete-license.asciidoc[] The Java High Level REST Client supports the following Machine Learning APIs: * <> +* <> * <> * <> include::ml/put-job.asciidoc[] +include::ml/get-job.asciidoc[] include::ml/delete-job.asciidoc[] include::ml/open-job.asciidoc[] diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobRequest.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobRequest.java index 2c906d5a43e37..7e22220336936 100644 --- a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobRequest.java +++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobRequest.java @@ -26,12 +26,24 @@ import java.util.List; import java.util.Objects; +/** + * Request object to get {@link org.elasticsearch.protocol.xpack.ml.job.config.Job} objects with the matching `jobId`s or + * `groupName`s. + * + * `_all` (see {@link GetJobRequest#ALL_JOBS}) `jobId` explicitly gets all the jobs in the cluster + * An empty request (no `jobId`s) implicitly gets all the jobs in the cluster + * + */ public class GetJobRequest extends ActionRequest { - public final static String ALL_JOBS = "_all"; + public static final String ALL_JOBS = "_all"; private List jobIds = new ArrayList<>(); private boolean allowNoJobs = true; + /** + * Helper method to create a query that will get ALL jobs + * @return new {@link GetJobRequest} object searching for the jobId "_all" + */ public static GetJobRequest getAllJobsRequest() { return new GetJobRequest(ALL_JOBS); } @@ -43,14 +55,37 @@ public GetJobRequest(String jobId) { public GetJobRequest() { } + /** + * Is a comma delimited representation of the list of `jobId`/`groupName` to get. + * + * @return String of jobIds/groupNames. example: "job1,other-jobs*" + */ public String getCommaDelimitedJobIdsString() { - return jobIds.isEmpty() ? null : Strings.collectionToCommaDelimitedString(jobIds); + return Strings.collectionToCommaDelimitedString(jobIds); } + /** + * Adds a new non-null `jobId` or `groupName` to be included in the request. + * + * Can include wildcards, and can explicitly ask for all jobs by requesting with + * the reserved {@link GetJobRequest#ALL_JOBS} name. + * + * @param jobId non-null jobId or groupName, accepts wildcards + */ public void addJobId(String jobId) { jobIds.add(Objects.requireNonNull(jobId, "[jobId] must not be null")); } + /** + * Whether to ignore if a wildcard expression matches no jobs. + * This includes {@link GetJobRequest#ALL_JOBS} string or when no jobs have been specified. + * + * If this is `false`, then an error is returned when a wildcard (or `_all`) does not match any jobs + * + * Default value: `true` + * + * @param allowNoJobs Ignore finding no jobs or not + */ public void setAllowNoJobs(boolean allowNoJobs) { this.allowNoJobs = allowNoJobs; } diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobResponse.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobResponse.java index a403cf52f58e1..3fbaa7a5b38a9 100644 --- a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobResponse.java +++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobResponse.java @@ -32,6 +32,9 @@ import java.util.Objects; import java.util.stream.Collectors; +/** + * Contains a {@link List} of the found {@link Job} objects and the total count found + */ public class GetJobResponse extends ActionResponse implements ToXContentObject { public static final ParseField RESULTS_FIELD = new ParseField("jobs"); @@ -44,16 +47,12 @@ public class GetJobResponse extends ActionResponse implements ToXContentObject { private QueryPage jobs; - public GetJobResponse(QueryPage jobs) { - this.jobs = jobs; - } - - public GetJobResponse() { + GetJobResponse() { jobs = new QueryPage<>(RESULTS_FIELD); } - public QueryPage getResponse() { - return jobs; + public List getJobs() { + return jobs.results(); } public static GetJobResponse fromXContent(XContentParser parser) throws IOException { @@ -68,6 +67,10 @@ void setCount(long count) { this.jobs.setCount(count); } + public long getCount() { + return this.jobs.count(); + } + @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { return jobs.toXContent(builder, params); diff --git a/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobRequestTests.java b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobRequestTests.java index 14c0c485923c0..7dc9cfcfd6ccf 100644 --- a/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobRequestTests.java +++ b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobRequestTests.java @@ -23,13 +23,24 @@ public class GetJobRequestTests extends ESTestCase { public void test_AllJobsRequest() { - + assertEquals(GetJobRequest.getAllJobsRequest() + .getCommaDelimitedJobIdsString(), GetJobRequest.ALL_JOBS); } public void test_AddJobId() { - + expectThrows(NullPointerException.class, () -> new GetJobRequest(null)); + expectThrows(NullPointerException.class, () -> new GetJobRequest("job").addJobId(null)); } public void test_getCommaDelimitedJobIdsString() { + GetJobRequest request = new GetJobRequest(); + + assertTrue(request.getCommaDelimitedJobIdsString().isEmpty()); + + request.addJobId("job1"); + assertEquals(request.getCommaDelimitedJobIdsString(), "job1"); + + request.addJobId("jobs*"); + assertEquals(request.getCommaDelimitedJobIdsString(), "job1,jobs*"); } } diff --git a/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobResponseTests.java b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobResponseTests.java index dec621e7f5535..a2d3475679ad6 100644 --- a/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobResponseTests.java +++ b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobResponseTests.java @@ -51,6 +51,6 @@ protected GetJobResponse doParseInstance(XContentParser parser) throws IOExcepti @Override protected boolean supportsUnknownFields() { - return true; + return false; } } From 0189fcd7ed68a2f7bc3ec6c8471de899f5a0fc7d Mon Sep 17 00:00:00 2001 From: Benjamin Trent Date: Fri, 17 Aug 2018 14:06:14 -0500 Subject: [PATCH 3/7] Fixing QueryPage license header --- .../protocol/xpack/ml/QueryPage.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/QueryPage.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/QueryPage.java index c4cf1a7b1d495..3ea5c0a21e311 100644 --- a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/QueryPage.java +++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/QueryPage.java @@ -1,3 +1,21 @@ +/* + * 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.protocol.xpack.ml; import org.elasticsearch.common.ParseField; From 681f6b724c37a7b20fc25897690c28068e1df324 Mon Sep 17 00:00:00 2001 From: Benjamin Trent Date: Mon, 20 Aug 2018 13:28:57 -0500 Subject: [PATCH 4/7] Adding serialization tests, addressing minor issues --- .../client/MLRequestConverters.java | 7 +- .../client/MachineLearningClient.java | 8 +- .../client/MLRequestConvertersTests.java | 9 +- .../client/MachineLearningIT.java | 3 +- .../MlClientDocumentationIT.java | 10 +- docs/java-rest/high-level/ml/get-job.asciidoc | 8 +- .../protocol/xpack/ml/GetJobRequest.java | 103 +++++++++++------- .../protocol/xpack/ml/GetJobRequestTests.java | 53 ++++++--- 8 files changed, 123 insertions(+), 78 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/MLRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/MLRequestConverters.java index 1cc280a10984b..38d3d3b735e88 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/MLRequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/MLRequestConverters.java @@ -24,6 +24,7 @@ import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.elasticsearch.client.RequestConverters.EndpointBuilder; +import org.elasticsearch.common.Strings; import org.elasticsearch.protocol.xpack.ml.DeleteJobRequest; import org.elasticsearch.protocol.xpack.ml.GetJobRequest; import org.elasticsearch.protocol.xpack.ml.OpenJobRequest; @@ -55,12 +56,14 @@ static Request getJob(GetJobRequest getJobRequest) { .addPathPartAsIs("_xpack") .addPathPartAsIs("ml") .addPathPartAsIs("anomaly_detectors") - .addPathPart(getJobRequest.getCommaDelimitedJobIdsString()) + .addPathPart(Strings.collectionToCommaDelimitedString(getJobRequest.getJobIds())) .build(); Request request = new Request(HttpGet.METHOD_NAME, endpoint); RequestConverters.Params params = new RequestConverters.Params(request); - params.putParam("allow_no_jobs", Boolean.toString(getJobRequest.isAllowNoJobs())); + if (getJobRequest.isAllowNoJobs() != null) { + params.putParam("allow_no_jobs", Boolean.toString(getJobRequest.isAllowNoJobs())); + } return request; } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/MachineLearningClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/MachineLearningClient.java index 7d733d92901bf..595646b44a69f 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/MachineLearningClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/MachineLearningClient.java @@ -85,13 +85,13 @@ public void putJobAsync(PutJobRequest request, RequestOptions options, ActionLis } /** - * Gets Machine Learning job configuration info. + * Gets one or more Machine Learning job configuration info. * *

* For additional info * see *

- * @param request {@link GetJobRequest} request containing a list of jobId(s) + * @param request {@link GetJobRequest} request containing a list of jobId(s) and additional options * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @return {@link GetJobResponse} response object containing * the {@link org.elasticsearch.protocol.xpack.ml.job.config.Job} objects and the number of jobs found @@ -106,13 +106,13 @@ public GetJobResponse getJob(GetJobRequest request, RequestOptions options) thro } /** - * Gets Machine Learning job configuration info, asynchronously. + * Gets one or more Machine Learning job configuration info, asynchronously. * *

* For additional info * see *

- * @param request {@link GetJobRequest} request containing a list of jobId(s) and optional additional parameters + * @param request {@link GetJobRequest} request containing a list of jobId(s) and additional options * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @param listener Listener to be notified with {@link GetJobResponse} upon request completion */ diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/MLRequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/MLRequestConvertersTests.java index b9aabf8f08733..8fc508567e66d 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/MLRequestConvertersTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/MLRequestConvertersTests.java @@ -62,15 +62,14 @@ public void testGetJob() { assertEquals(HttpGet.METHOD_NAME, request.getMethod()); assertEquals("/_xpack/ml/anomaly_detectors", request.getEndpoint()); - assertEquals(Boolean.toString(getJobRequest.isAllowNoJobs()), request.getParameters().get("allow_no_jobs")); + assertFalse(request.getParameters().containsKey("allow_no_jobs")); - getJobRequest.setAllowNoJobs(false); - getJobRequest.addJobId("job1"); - getJobRequest.addJobId("jobs*"); + getJobRequest = new GetJobRequest("job1", "jobs*"); + getJobRequest.setAllowNoJobs(true); request = MLRequestConverters.getJob(getJobRequest); assertEquals("/_xpack/ml/anomaly_detectors/job1,jobs*", request.getEndpoint()); - assertEquals(Boolean.toString(false), request.getParameters().get("allow_no_jobs")); + assertEquals(Boolean.toString(true), request.getParameters().get("allow_no_jobs")); } public void testOpenJob() throws Exception { diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java index c8ea1c54ad55e..fac6c3bfa9714 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java @@ -66,8 +66,7 @@ public void testGetJob() throws Exception { machineLearningClient.putJob(new PutJobRequest(job1), RequestOptions.DEFAULT); machineLearningClient.putJob(new PutJobRequest(job2), RequestOptions.DEFAULT); - GetJobRequest request = new GetJobRequest(jobId1); - request.addJobId(jobId2); + GetJobRequest request = new GetJobRequest(jobId1, jobId2); // Test getting specific jobs GetJobResponse response = execute(request, machineLearningClient::getJob, machineLearningClient::getJobAsync); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java index 94e05be4805bd..b53640bd3e569 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java @@ -142,10 +142,8 @@ public void testGetJob() throws Exception { { //tag::x-pack-ml-get-job-request - GetJobRequest request = new GetJobRequest(); //<1> - request.addJobId("get-machine-learning-job1"); //<2> - request.addJobId("get-machine-learning-job*"); //<3> - request.setAllowNoJobs(true); //<4> + GetJobRequest request = new GetJobRequest("get-machine-learning-job1", "get-machine-learning-job*"); //<1> + request.setAllowNoJobs(true); //<2> //end::x-pack-ml-get-job-request //tag::x-pack-ml-get-job-execute @@ -160,9 +158,7 @@ public void testGetJob() throws Exception { containsInAnyOrder(job.getId(), secondJob.getId())); } { - GetJobRequest request = new GetJobRequest(); - request.addJobId("get-machine-learning-job1"); - request.addJobId("get-machine-learning-job*"); + GetJobRequest request = new GetJobRequest("get-machine-learning-job1", "get-machine-learning-job*"); // tag::x-pack-ml-get-job-listener ActionListener listener = new ActionListener() { diff --git a/docs/java-rest/high-level/ml/get-job.asciidoc b/docs/java-rest/high-level/ml/get-job.asciidoc index 7f64589c85de4..4ecf70e8e6538 100644 --- a/docs/java-rest/high-level/ml/get-job.asciidoc +++ b/docs/java-rest/high-level/ml/get-job.asciidoc @@ -8,7 +8,7 @@ with a `GetJobResponse` object. [[java-rest-high-x-pack-ml-get-job-request]] ==== Get Job Request -An `GetJobRequest` object gets can have any number of `jobId` or `groupName` +A `GetJobRequest` object gets can have any number of `jobId` or `groupName` entries. However, they all must be non-null. An empty list is the same as requesting for all jobs. @@ -16,10 +16,8 @@ requesting for all jobs. -------------------------------------------------- include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-get-job-request] -------------------------------------------------- -<1> Constructing a new request referencing no `jobId` -<2> Adding a new specific `jobId` we want to find -<3> Adding a new wildcard matching `jobId` we want to find -<4> Whether to ignore if a wildcard expression matches no jobs. +<1> Constructing a new request referencing existing `jobIds`, can contain wildcards +<2> Whether to ignore if a wildcard expression matches no jobs. (This includes `_all` string or when no jobs have been specified) [[java-rest-high-x-pack-ml-get-job-execution]] diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobRequest.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobRequest.java index 7e22220336936..b0377c86fdc78 100644 --- a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobRequest.java +++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobRequest.java @@ -20,9 +20,14 @@ import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionRequestValidationException; -import org.elasticsearch.common.Strings; +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; +import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -30,15 +35,27 @@ * Request object to get {@link org.elasticsearch.protocol.xpack.ml.job.config.Job} objects with the matching `jobId`s or * `groupName`s. * - * `_all` (see {@link GetJobRequest#ALL_JOBS}) `jobId` explicitly gets all the jobs in the cluster + * `_all` explicitly gets all the jobs in the cluster * An empty request (no `jobId`s) implicitly gets all the jobs in the cluster - * */ -public class GetJobRequest extends ActionRequest { +public class GetJobRequest extends ActionRequest implements ToXContentObject { + + public static final ParseField JOB_IDS = new ParseField("job_ids"); + public static final ParseField ALLOW_NO_JOBS = new ParseField("allow_no_jobs"); - public static final String ALL_JOBS = "_all"; - private List jobIds = new ArrayList<>(); - private boolean allowNoJobs = true; + private static final String ALL_JOBS = "_all"; + private final List jobIds; + private Boolean allowNoJobs; + + @SuppressWarnings("unchecked") + public static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( + "get_job_request", + true, a -> new GetJobRequest(a[0] == null ? new ArrayList<>() : (List) a[0])); + + static { + PARSER.declareStringArray(ConstructingObjectParser.optionalConstructorArg(), JOB_IDS); + PARSER.declareBoolean(GetJobRequest::setAllowNoJobs, ALLOW_NO_JOBS); + } /** * Helper method to create a query that will get ALL jobs @@ -48,49 +65,43 @@ public static GetJobRequest getAllJobsRequest() { return new GetJobRequest(ALL_JOBS); } - public GetJobRequest(String jobId) { - jobIds.add(Objects.requireNonNull(jobId, "[jobId] must not be null")); + /** + * Get the specified {@link org.elasticsearch.protocol.xpack.ml.job.config.Job} configurations via their unique jobIds + * @param jobIds must not contain any null values + */ + public GetJobRequest(String... jobIds) { + this(Arrays.asList(jobIds)); } - public GetJobRequest() { + GetJobRequest(List jobIds) { + if (jobIds.stream().anyMatch(Objects::isNull)) { + throw new NullPointerException("jobIds must not contain null values"); + } + this.jobIds = new ArrayList<>(jobIds); } /** - * Is a comma delimited representation of the list of `jobId`/`groupName` to get. - * - * @return String of jobIds/groupNames. example: "job1,other-jobs*" + * All the jobIds for which to get configuration information */ - public String getCommaDelimitedJobIdsString() { - return Strings.collectionToCommaDelimitedString(jobIds); + public List getJobIds() { + return jobIds; } + /** - * Adds a new non-null `jobId` or `groupName` to be included in the request. - * - * Can include wildcards, and can explicitly ask for all jobs by requesting with - * the reserved {@link GetJobRequest#ALL_JOBS} name. - * - * @param jobId non-null jobId or groupName, accepts wildcards + * See {@link GetJobRequest#isAllowNoJobs()} + * @param allowNoJobs */ - public void addJobId(String jobId) { - jobIds.add(Objects.requireNonNull(jobId, "[jobId] must not be null")); + public void setAllowNoJobs(boolean allowNoJobs) { + this.allowNoJobs = allowNoJobs; } /** * Whether to ignore if a wildcard expression matches no jobs. - * This includes {@link GetJobRequest#ALL_JOBS} string or when no jobs have been specified. * * If this is `false`, then an error is returned when a wildcard (or `_all`) does not match any jobs - * - * Default value: `true` - * - * @param allowNoJobs Ignore finding no jobs or not */ - public void setAllowNoJobs(boolean allowNoJobs) { - this.allowNoJobs = allowNoJobs; - } - - public boolean isAllowNoJobs() { + public Boolean isAllowNoJobs() { return allowNoJobs; } @@ -105,17 +116,33 @@ public int hashCode() { } @Override - public boolean equals(Object obj) { - if (this == obj) { + public boolean equals(Object other) { + if (this == other) { return true; } - if (obj == null || obj.getClass() != getClass()) { + if (other == null || other.getClass() != getClass()) { return false; } - GetJobRequest other = (GetJobRequest) obj; - return Objects.equals(jobIds, other.jobIds) && allowNoJobs == other.allowNoJobs; + GetJobRequest that = (GetJobRequest) other; + return Objects.equals(jobIds, that.jobIds) && + Objects.equals(allowNoJobs, that.allowNoJobs); } + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + + if (jobIds.isEmpty() == false) { + builder.field(JOB_IDS.getPreferredName(), jobIds); + } + + if (allowNoJobs != null) { + builder.field(ALLOW_NO_JOBS.getPreferredName(), allowNoJobs); + } + + builder.endObject(); + return builder; + } } diff --git a/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobRequestTests.java b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobRequestTests.java index 7dc9cfcfd6ccf..b94b704fbf6e8 100644 --- a/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobRequestTests.java +++ b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobRequestTests.java @@ -18,29 +18,52 @@ */ package org.elasticsearch.protocol.xpack.ml; -import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.test.AbstractXContentTestCase; -public class GetJobRequestTests extends ESTestCase { +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; - public void test_AllJobsRequest() { - assertEquals(GetJobRequest.getAllJobsRequest() - .getCommaDelimitedJobIdsString(), GetJobRequest.ALL_JOBS); +public class GetJobRequestTests extends AbstractXContentTestCase { + + public void testAllJobsRequest() { + GetJobRequest request = GetJobRequest.getAllJobsRequest(); + + assertEquals(request.getJobIds().size(), 1); + assertEquals(request.getJobIds().get(0), "_all"); } - public void test_AddJobId() { - expectThrows(NullPointerException.class, () -> new GetJobRequest(null)); - expectThrows(NullPointerException.class, () -> new GetJobRequest("job").addJobId(null)); + public void testNewWithJobId() { + Exception exception = expectThrows(NullPointerException.class, () -> new GetJobRequest("job",null)); + assertEquals(exception.getMessage(), "jobIds must not contain null values"); } - public void test_getCommaDelimitedJobIdsString() { - GetJobRequest request = new GetJobRequest(); + @Override + protected GetJobRequest createTestInstance() { + int jobCount = randomIntBetween(0, 10); + List jobIds = new ArrayList<>(jobCount); + + for (int i = 0; i < jobCount; i++) { + jobIds.add(randomAlphaOfLength(10)); + } + + GetJobRequest request = new GetJobRequest(jobIds); - assertTrue(request.getCommaDelimitedJobIdsString().isEmpty()); + if (randomBoolean()) { + request.setAllowNoJobs(randomBoolean()); + } - request.addJobId("job1"); - assertEquals(request.getCommaDelimitedJobIdsString(), "job1"); + return request; + } + + @Override + protected GetJobRequest doParseInstance(XContentParser parser) throws IOException { + return GetJobRequest.PARSER.parse(parser, null); + } - request.addJobId("jobs*"); - assertEquals(request.getCommaDelimitedJobIdsString(), "job1,jobs*"); + @Override + protected boolean supportsUnknownFields() { + return true; } } From d44a834b1d2b038a1510bcbaa29891484ea7085b Mon Sep 17 00:00:00 2001 From: Benjamin Trent Date: Tue, 21 Aug 2018 08:13:09 -0500 Subject: [PATCH 5/7] Renaming querypage, changing the dependency on it --- ...yPage.java => AbstractResultResponse.java} | 48 +++---------------- .../protocol/xpack/ml/GetJobResponse.java | 45 +++++++---------- 2 files changed, 22 insertions(+), 71 deletions(-) rename x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/{QueryPage.java => AbstractResultResponse.java} (59%) diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/QueryPage.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/AbstractResultResponse.java similarity index 59% rename from x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/QueryPage.java rename to x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/AbstractResultResponse.java index 3ea5c0a21e311..7901515f22957 100644 --- a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/QueryPage.java +++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/AbstractResultResponse.java @@ -18,32 +18,28 @@ */ package org.elasticsearch.protocol.xpack.ml; +import org.elasticsearch.action.ActionResponse; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.XContentBuilder; import java.io.IOException; -import java.util.ArrayList; import java.util.List; import java.util.Objects; /** - * Generic wrapper class for a page of query results and the total number of - * query results.
- * {@linkplain #count()} is the total number of results but that value may - * not be equal to the actual length of the {@linkplain #results()} list if from - * & take or some cursor was used in the database query. + * Abstract class that provides a list of results and their count. */ -public final class QueryPage implements ToXContentObject { +public abstract class AbstractResultResponse extends ActionResponse implements ToXContentObject { public static final ParseField COUNT = new ParseField("count"); private final ParseField resultsField; - private List results; - private long count; + protected List results; + protected long count; - public QueryPage(ParseField resultsField) { + AbstractResultResponse(ParseField resultsField) { this.resultsField = Objects.requireNonNull(resultsField, "[results_field] must not be null"); } @@ -57,14 +53,6 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws return builder; } - public List results() { - return results; - } - - void setResults(List results) { - this.results = new ArrayList<>(results); - } - public long count() { return count; } @@ -72,28 +60,4 @@ public long count() { void setCount(long count) { this.count = count; } - - public ParseField getResultsField() { - return resultsField; - } - - @Override - public int hashCode() { - return Objects.hash(results, count); - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - - if (getClass() != obj.getClass()) { - return false; - } - - @SuppressWarnings("unchecked") - QueryPage other = (QueryPage) obj; - return Objects.equals(results, other.results) && Objects.equals(count, other.count); - } } diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobResponse.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobResponse.java index 3fbaa7a5b38a9..b3f35c496f68e 100644 --- a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobResponse.java +++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobResponse.java @@ -18,12 +18,9 @@ */ package org.elasticsearch.protocol.xpack.ml; -import org.elasticsearch.action.ActionResponse; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.Strings; import org.elasticsearch.common.xcontent.ObjectParser; -import org.elasticsearch.common.xcontent.ToXContentObject; -import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.protocol.xpack.ml.job.config.Job; @@ -35,24 +32,25 @@ /** * Contains a {@link List} of the found {@link Job} objects and the total count found */ -public class GetJobResponse extends ActionResponse implements ToXContentObject { +public class GetJobResponse extends AbstractResultResponse { public static final ParseField RESULTS_FIELD = new ParseField("jobs"); public static final ObjectParser PARSER = new ObjectParser<>("jobs_response", true, GetJobResponse::new); static { PARSER.declareObjectArray(GetJobResponse::setJobs, Job.PARSER, RESULTS_FIELD); - PARSER.declareLong(GetJobResponse::setCount, QueryPage.COUNT); + PARSER.declareLong(GetJobResponse::setCount, AbstractResultResponse.COUNT); } - private QueryPage jobs; - GetJobResponse() { - jobs = new QueryPage<>(RESULTS_FIELD); + super(RESULTS_FIELD); } - public List getJobs() { - return jobs.results(); + /** + * The collection of {@link Job} objects found in the query + */ + public List jobs() { + return results; } public static GetJobResponse fromXContent(XContentParser parser) throws IOException { @@ -60,37 +58,26 @@ public static GetJobResponse fromXContent(XContentParser parser) throws IOExcept } void setJobs(List jobs) { - this.jobs.setResults(jobs.stream().map(Job.Builder::build).collect(Collectors.toList())); - } - - void setCount(long count) { - this.jobs.setCount(count); - } - - public long getCount() { - return this.jobs.count(); - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - return jobs.toXContent(builder, params); + this.results = jobs.stream().map(Job.Builder::build).collect(Collectors.toList()); } @Override public int hashCode() { - return Objects.hash(jobs); + return Objects.hash(results, count); } @Override public boolean equals(Object obj) { - if (obj == null) { - return false; + if (this == obj) { + return true; } - if (getClass() != obj.getClass()) { + + if (obj == null || getClass() != obj.getClass()) { return false; } + GetJobResponse other = (GetJobResponse) obj; - return Objects.equals(jobs, other.jobs); + return Objects.equals(results, other.results) && count == other.count; } @Override From 822a4ca45f7f6e933962418bd7494e322739e061 Mon Sep 17 00:00:00 2001 From: Benjamin Trent Date: Tue, 21 Aug 2018 08:49:27 -0500 Subject: [PATCH 6/7] Making things immutable --- .../xpack/ml/AbstractResultResponse.java | 13 +++++------ .../protocol/xpack/ml/GetJobResponse.java | 22 ++++++++++--------- .../xpack/ml/GetJobResponseTests.java | 5 +---- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/AbstractResultResponse.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/AbstractResultResponse.java index 7901515f22957..64f350933c9c4 100644 --- a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/AbstractResultResponse.java +++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/AbstractResultResponse.java @@ -25,6 +25,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import java.io.IOException; +import java.util.Collections; import java.util.List; import java.util.Objects; @@ -36,12 +37,14 @@ public abstract class AbstractResultResponse extends Actio public static final ParseField COUNT = new ParseField("count"); private final ParseField resultsField; - protected List results; - protected long count; + protected final List results; + protected final long count; - AbstractResultResponse(ParseField resultsField) { + AbstractResultResponse(ParseField resultsField, List results, long count) { this.resultsField = Objects.requireNonNull(resultsField, "[results_field] must not be null"); + this.results = Collections.unmodifiableList(results); + this.count = count; } @Override @@ -56,8 +59,4 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws public long count() { return count; } - - void setCount(long count) { - this.count = count; - } } diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobResponse.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobResponse.java index b3f35c496f68e..4db542dc1526d 100644 --- a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobResponse.java +++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/GetJobResponse.java @@ -20,7 +20,7 @@ import org.elasticsearch.common.ParseField; import org.elasticsearch.common.Strings; -import org.elasticsearch.common.xcontent.ObjectParser; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.protocol.xpack.ml.job.config.Job; @@ -29,21 +29,27 @@ import java.util.Objects; import java.util.stream.Collectors; +import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg; + /** * Contains a {@link List} of the found {@link Job} objects and the total count found */ public class GetJobResponse extends AbstractResultResponse { public static final ParseField RESULTS_FIELD = new ParseField("jobs"); - public static final ObjectParser PARSER = new ObjectParser<>("jobs_response", true, GetJobResponse::new); + + @SuppressWarnings("unchecked") + public static final ConstructingObjectParser PARSER = + new ConstructingObjectParser<>("jobs_response", true, + a -> new GetJobResponse((List) a[0], (long) a[1])); static { - PARSER.declareObjectArray(GetJobResponse::setJobs, Job.PARSER, RESULTS_FIELD); - PARSER.declareLong(GetJobResponse::setCount, AbstractResultResponse.COUNT); + PARSER.declareObjectArray(constructorArg(), Job.PARSER, RESULTS_FIELD); + PARSER.declareLong(constructorArg(), AbstractResultResponse.COUNT); } - GetJobResponse() { - super(RESULTS_FIELD); + GetJobResponse(List jobBuilders, long count) { + super(RESULTS_FIELD, jobBuilders.stream().map(Job.Builder::build).collect(Collectors.toList()), count); } /** @@ -57,10 +63,6 @@ public static GetJobResponse fromXContent(XContentParser parser) throws IOExcept return PARSER.parse(parser, null); } - void setJobs(List jobs) { - this.results = jobs.stream().map(Job.Builder::build).collect(Collectors.toList()); - } - @Override public int hashCode() { return Objects.hash(results, count); diff --git a/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobResponseTests.java b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobResponseTests.java index a2d3475679ad6..79d4d678b9295 100644 --- a/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobResponseTests.java +++ b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/GetJobResponseTests.java @@ -38,10 +38,7 @@ protected GetJobResponse createTestInstance() { results.add(JobTests.createRandomizedJobBuilder()); } - GetJobResponse response = new GetJobResponse(); - response.setCount(count); - response.setJobs(results); - return response; + return new GetJobResponse(results, count); } @Override From b250857d18bee93c756dfbc82c30edeb3960052d Mon Sep 17 00:00:00 2001 From: Benjamin Trent Date: Tue, 21 Aug 2018 10:09:58 -0500 Subject: [PATCH 7/7] Fixing build failure due to method rename --- .../client/MachineLearningIT.java | 18 +++++++++--------- .../documentation/MlClientDocumentationIT.java | 10 +++++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java index 661026ca84f4d..3f5063ffce8d8 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java @@ -75,24 +75,24 @@ public void testGetJob() throws Exception { // Test getting specific jobs GetJobResponse response = execute(request, machineLearningClient::getJob, machineLearningClient::getJobAsync); - assertEquals(2, response.getCount()); - assertThat(response.getJobs(), hasSize(2)); - assertThat(response.getJobs().stream().map(Job::getId).collect(Collectors.toList()), containsInAnyOrder(jobId1, jobId2)); + assertEquals(2, response.count()); + assertThat(response.jobs(), hasSize(2)); + assertThat(response.jobs().stream().map(Job::getId).collect(Collectors.toList()), containsInAnyOrder(jobId1, jobId2)); // Test getting all jobs explicitly request = GetJobRequest.getAllJobsRequest(); response = execute(request, machineLearningClient::getJob, machineLearningClient::getJobAsync); - assertTrue(response.getCount() >= 2L); - assertTrue(response.getJobs().size() >= 2L); - assertThat(response.getJobs().stream().map(Job::getId).collect(Collectors.toList()), hasItems(jobId1, jobId2)); + assertTrue(response.count() >= 2L); + assertTrue(response.jobs().size() >= 2L); + assertThat(response.jobs().stream().map(Job::getId).collect(Collectors.toList()), hasItems(jobId1, jobId2)); // Test getting all jobs implicitly response = execute(new GetJobRequest(), machineLearningClient::getJob, machineLearningClient::getJobAsync); - assertTrue(response.getCount() >= 2L); - assertTrue(response.getJobs().size() >= 2L); - assertThat(response.getJobs().stream().map(Job::getId).collect(Collectors.toList()), hasItems(jobId1, jobId2)); + assertTrue(response.count() >= 2L); + assertTrue(response.jobs().size() >= 2L); + assertThat(response.jobs().stream().map(Job::getId).collect(Collectors.toList()), hasItems(jobId1, jobId2)); } public void testDeleteJob() throws Exception { diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java index 05b220afddd02..4a61cdc4e2994 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java @@ -150,13 +150,13 @@ public void testGetJob() throws Exception { //tag::x-pack-ml-get-job-execute GetJobResponse response = client.machineLearning().getJob(request, RequestOptions.DEFAULT); - long numberOfJobs = response.getCount(); //<1> - List jobs = response.getJobs(); //<2> + long numberOfJobs = response.count(); //<1> + List jobs = response.jobs(); //<2> //end::x-pack-ml-get-job-execute - assertEquals(2, response.getCount()); - assertThat(response.getJobs(), hasSize(2)); - assertThat(response.getJobs().stream().map(Job::getId).collect(Collectors.toList()), + assertEquals(2, response.count()); + assertThat(response.jobs(), hasSize(2)); + assertThat(response.jobs().stream().map(Job::getId).collect(Collectors.toList()), containsInAnyOrder(job.getId(), secondJob.getId())); } {