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 81b1f6b570969..6a54d52c7d989 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 @@ -35,6 +35,7 @@ import org.elasticsearch.client.ml.ForecastJobRequest; import org.elasticsearch.client.ml.GetBucketsRequest; import org.elasticsearch.client.ml.GetCategoriesRequest; +import org.elasticsearch.client.ml.GetDatafeedRequest; import org.elasticsearch.client.ml.GetInfluencersRequest; import org.elasticsearch.client.ml.GetJobRequest; import org.elasticsearch.client.ml.GetJobStatsRequest; @@ -196,6 +197,24 @@ static Request putDatafeed(PutDatafeedRequest putDatafeedRequest) throws IOExcep return request; } + static Request getDatafeed(GetDatafeedRequest getDatafeedRequest) { + String endpoint = new EndpointBuilder() + .addPathPartAsIs("_xpack") + .addPathPartAsIs("ml") + .addPathPartAsIs("datafeeds") + .addPathPart(Strings.collectionToCommaDelimitedString(getDatafeedRequest.getDatafeedIds())) + .build(); + Request request = new Request(HttpGet.METHOD_NAME, endpoint); + + RequestConverters.Params params = new RequestConverters.Params(request); + if (getDatafeedRequest.isAllowNoDatafeeds() != null) { + params.putParam(GetDatafeedRequest.ALLOW_NO_DATAFEEDS.getPreferredName(), + Boolean.toString(getDatafeedRequest.isAllowNoDatafeeds())); + } + + return request; + } + static Request deleteDatafeed(DeleteDatafeedRequest deleteDatafeedRequest) { 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 4d2167ce063d8..fa912a8178362 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 @@ -33,6 +33,8 @@ import org.elasticsearch.client.ml.GetBucketsResponse; import org.elasticsearch.client.ml.GetCategoriesRequest; import org.elasticsearch.client.ml.GetCategoriesResponse; +import org.elasticsearch.client.ml.GetDatafeedRequest; +import org.elasticsearch.client.ml.GetDatafeedResponse; import org.elasticsearch.client.ml.GetInfluencersRequest; import org.elasticsearch.client.ml.GetInfluencersResponse; import org.elasticsearch.client.ml.GetJobRequest; @@ -479,8 +481,8 @@ public PutDatafeedResponse putDatafeed(PutDatafeedRequest request, RequestOption * For additional info * see ML PUT datafeed documentation * - * @param request The request containing the {@link org.elasticsearch.client.ml.datafeed.DatafeedConfig} settings - * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param request The request containing the {@link org.elasticsearch.client.ml.datafeed.DatafeedConfig} settings + * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @param listener Listener to be notified upon request completion */ public void putDatafeedAsync(PutDatafeedRequest request, RequestOptions options, ActionListener listener) { @@ -492,6 +494,47 @@ public void putDatafeedAsync(PutDatafeedRequest request, RequestOptions options, Collections.emptySet()); } + /** + * Gets one or more Machine Learning datafeed configuration info. + * + *

+ * For additional info + * see ML GET datafeed documentation + * + * @param request {@link GetDatafeedRequest} Request containing a list of datafeedId(s) and additional options + * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @return {@link GetDatafeedResponse} response object containing + * the {@link org.elasticsearch.client.ml.datafeed.DatafeedConfig} objects and the number of jobs found + * @throws IOException when there is a serialization issue sending the request or receiving the response + */ + public GetDatafeedResponse getDatafeed(GetDatafeedRequest request, RequestOptions options) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(request, + MLRequestConverters::getDatafeed, + options, + GetDatafeedResponse::fromXContent, + Collections.emptySet()); + } + + /** + * Gets one or more Machine Learning datafeed configuration info, asynchronously. + * + *

+ * For additional info + * see ML GET datafeed documentation + * + * @param request {@link GetDatafeedRequest} Request containing a list of datafeedId(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 GetDatafeedResponse} upon request completion + */ + public void getDatafeedAsync(GetDatafeedRequest request, RequestOptions options, ActionListener listener) { + restHighLevelClient.performRequestAsyncAndParseEntity(request, + MLRequestConverters::getDatafeed, + options, + GetDatafeedResponse::fromXContent, + listener, + Collections.emptySet()); + } + /** * Deletes the given Machine Learning Datafeed *

diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/CloseJobRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/CloseJobRequest.java index 19f3df8e4320f..aa6b4fe6c9a0d 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/CloseJobRequest.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/CloseJobRequest.java @@ -136,9 +136,9 @@ public Boolean isAllowNoJobs() { /** * Whether to ignore if a wildcard expression matches no jobs. * - * This includes `_all` string or when no jobs have been specified + * This includes {@code _all} string or when no jobs have been specified * - * @param allowNoJobs When {@code true} ignore if wildcard or `_all` matches no jobs. Defaults to {@code true} + * @param allowNoJobs When {@code true} ignore if wildcard or {@code _all} matches no jobs. Defaults to {@code true} */ public void setAllowNoJobs(boolean allowNoJobs) { this.allowNoJobs = allowNoJobs; diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/DeleteForecastRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/DeleteForecastRequest.java index f7c8a6c0733f8..f1d87fa45d6e7 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/DeleteForecastRequest.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/DeleteForecastRequest.java @@ -109,7 +109,7 @@ public Boolean isAllowNoForecasts() { } /** - * Sets the `allow_no_forecasts` field. + * Sets the value of "allow_no_forecasts". * * @param allowNoForecasts when {@code true} no error is thrown when {@link DeleteForecastRequest#ALL} does not find any forecasts */ diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetDatafeedRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetDatafeedRequest.java new file mode 100644 index 0000000000000..d9750d9616ddf --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetDatafeedRequest.java @@ -0,0 +1,144 @@ +/* + * 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.ml; + +import org.elasticsearch.action.ActionRequest; +import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.client.ml.datafeed.DatafeedConfig; +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; + +/** + * Request object to get {@link DatafeedConfig} objects with the matching {@code datafeedId}s. + * + * {@code _all} explicitly gets all the datafeeds in the cluster + * An empty request (no {@code datafeedId}s) implicitly gets all the datafeeds in the cluster + */ +public class GetDatafeedRequest extends ActionRequest implements ToXContentObject { + + public static final ParseField DATAFEED_IDS = new ParseField("datafeed_ids"); + public static final ParseField ALLOW_NO_DATAFEEDS = new ParseField("allow_no_datafeeds"); + + private static final String ALL_DATAFEEDS = "_all"; + private final List datafeedIds; + private Boolean allowNoDatafeeds; + + @SuppressWarnings("unchecked") + public static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( + "get_datafeed_request", + true, a -> new GetDatafeedRequest(a[0] == null ? new ArrayList<>() : (List) a[0])); + + static { + PARSER.declareStringArray(ConstructingObjectParser.optionalConstructorArg(), DATAFEED_IDS); + PARSER.declareBoolean(GetDatafeedRequest::setAllowNoDatafeeds, ALLOW_NO_DATAFEEDS); + } + + /** + * Helper method to create a query that will get ALL datafeeds + * @return new {@link GetDatafeedRequest} object searching for the datafeedId "_all" + */ + public static GetDatafeedRequest getAllDatafeedsRequest() { + return new GetDatafeedRequest(ALL_DATAFEEDS); + } + + /** + * Get the specified {@link DatafeedConfig} configurations via their unique datafeedIds + * @param datafeedIds must not contain any null values + */ + public GetDatafeedRequest(String... datafeedIds) { + this(Arrays.asList(datafeedIds)); + } + + GetDatafeedRequest(List datafeedIds) { + if (datafeedIds.stream().anyMatch(Objects::isNull)) { + throw new NullPointerException("datafeedIds must not contain null values"); + } + this.datafeedIds = new ArrayList<>(datafeedIds); + } + + /** + * All the datafeedIds for which to get configuration information + */ + public List getDatafeedIds() { + return datafeedIds; + } + + /** + * Whether to ignore if a wildcard expression matches no datafeeds. + * + * @param allowNoDatafeeds If this is {@code false}, then an error is returned when a wildcard (or {@code _all}) + * does not match any datafeeds + */ + public void setAllowNoDatafeeds(boolean allowNoDatafeeds) { + this.allowNoDatafeeds = allowNoDatafeeds; + } + + public Boolean isAllowNoDatafeeds() { + return allowNoDatafeeds; + } + + @Override + public ActionRequestValidationException validate() { + return null; + } + + @Override + public int hashCode() { + return Objects.hash(datafeedIds, allowNoDatafeeds); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (other == null || other.getClass() != getClass()) { + return false; + } + + GetDatafeedRequest that = (GetDatafeedRequest) other; + return Objects.equals(datafeedIds, that.datafeedIds) && + Objects.equals(allowNoDatafeeds, that.allowNoDatafeeds); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + + if (datafeedIds.isEmpty() == false) { + builder.field(DATAFEED_IDS.getPreferredName(), datafeedIds); + } + + if (allowNoDatafeeds != null) { + builder.field(ALLOW_NO_DATAFEEDS.getPreferredName(), allowNoDatafeeds); + } + + builder.endObject(); + return builder; + } +} diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetDatafeedResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetDatafeedResponse.java new file mode 100644 index 0000000000000..0aadd7a576662 --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetDatafeedResponse.java @@ -0,0 +1,89 @@ +/* + * 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.ml; + +import org.elasticsearch.client.ml.datafeed.DatafeedConfig; +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.XContentParser; + +import java.io.IOException; +import java.util.List; +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 DatafeedConfig} objects and the total count found + */ +public class GetDatafeedResponse extends AbstractResultResponse { + + public static final ParseField RESULTS_FIELD = new ParseField("datafeeds"); + + @SuppressWarnings("unchecked") + public static final ConstructingObjectParser PARSER = + new ConstructingObjectParser<>("get_datafeed_response", true, + a -> new GetDatafeedResponse((List) a[0], (long) a[1])); + + static { + PARSER.declareObjectArray(constructorArg(), DatafeedConfig.PARSER, RESULTS_FIELD); + PARSER.declareLong(constructorArg(), AbstractResultResponse.COUNT); + } + + GetDatafeedResponse(List datafeedBuilders, long count) { + super(RESULTS_FIELD, datafeedBuilders.stream().map(DatafeedConfig.Builder::build).collect(Collectors.toList()), count); + } + + /** + * The collection of {@link DatafeedConfig} objects found in the query + */ + public List datafeeds() { + return results; + } + + public static GetDatafeedResponse fromXContent(XContentParser parser) throws IOException { + return PARSER.parse(parser, null); + } + + @Override + public int hashCode() { + return Objects.hash(results, count); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + GetDatafeedResponse other = (GetDatafeedResponse) obj; + return Objects.equals(results, other.results) && count == other.count; + } + + @Override + public final String toString() { + return Strings.toString(this); + } +} diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetJobRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetJobRequest.java index 3de7037e5c8f3..46153061e2803 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetJobRequest.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetJobRequest.java @@ -33,11 +33,11 @@ import java.util.Objects; /** - * Request object to get {@link Job} objects with the matching `jobId`s or - * `groupName`s. + * Request object to get {@link Job} objects with the matching {@code jobId}s or + * {@code groupName}s. * - * `_all` explicitly gets all the jobs in the cluster - * An empty request (no `jobId`s) implicitly gets all the jobs in the cluster + * {@code _all} explicitly gets all the jobs in the cluster + * An empty request (no {@code jobId}s) implicitly gets all the jobs in the cluster */ public class GetJobRequest extends ActionRequest implements ToXContentObject { @@ -91,7 +91,7 @@ public List getJobIds() { /** * Whether to ignore if a wildcard expression matches no jobs. * - * @param allowNoJobs If this is {@code false}, then an error is returned when a wildcard (or `_all`) does not match any jobs + * @param allowNoJobs If this is {@code false}, then an error is returned when a wildcard (or {@code _all}) does not match any jobs */ public void setAllowNoJobs(boolean allowNoJobs) { this.allowNoJobs = allowNoJobs; diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetJobStatsRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetJobStatsRequest.java index d8eb350755dcb..fc3af822163a1 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetJobStatsRequest.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetJobStatsRequest.java @@ -38,8 +38,8 @@ /** * Request object to get {@link org.elasticsearch.client.ml.job.stats.JobStats} by their respective jobIds * - * `_all` explicitly gets all the jobs' statistics in the cluster - * An empty request (no `jobId`s) implicitly gets all the jobs' statistics in the cluster + * {@code _all} explicitly gets all the jobs' statistics in the cluster + * An empty request (no {@code jobId}s) implicitly gets all the jobs' statistics in the cluster */ public class GetJobStatsRequest extends ActionRequest implements ToXContentObject { @@ -100,9 +100,9 @@ public Boolean isAllowNoJobs() { /** * Whether to ignore if a wildcard expression matches no jobs. * - * This includes `_all` string or when no jobs have been specified + * This includes {@code _all} string or when no jobs have been specified * - * @param allowNoJobs When {@code true} ignore if wildcard or `_all` matches no jobs. Defaults to {@code true} + * @param allowNoJobs When {@code true} ignore if wildcard or {@code _all} matches no jobs. Defaults to {@code true} */ public void setAllowNoJobs(boolean allowNoJobs) { this.allowNoJobs = allowNoJobs; diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetOverallBucketsRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetOverallBucketsRequest.java index 97bde11d8c6cd..490bdd4fbaeb3 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetOverallBucketsRequest.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetOverallBucketsRequest.java @@ -109,7 +109,7 @@ public Integer getTopN() { } /** - * Sets the value of `top_n`. + * Sets the value of "top_n". * @param topN The number of top job bucket scores to be used in the overall_score calculation. Defaults to 1. */ public void setTopN(Integer topN) { @@ -121,7 +121,7 @@ public TimeValue getBucketSpan() { } /** - * Sets the value of `bucket_span`. + * Sets the value of "bucket_span". * @param bucketSpan The span of the overall buckets. Must be greater or equal to the largest job’s bucket_span. * Defaults to the largest job’s bucket_span. */ @@ -197,7 +197,7 @@ public void setAllowNoJobs(boolean allowNoJobs) { /** * Whether to ignore if a wildcard expression matches no jobs. * - * If this is `false`, then an error is returned when a wildcard (or `_all`) does not match any jobs + * If this is {@code false}, then an error is returned when a wildcard (or {@code _all}) does not match any jobs */ public Boolean isAllowNoJobs() { return allowNoJobs; diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PostDataRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PostDataRequest.java index e84ff878437aa..c8e043cc1e569 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PostDataRequest.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PostDataRequest.java @@ -40,7 +40,7 @@ import java.util.Objects; /** - * POJO for posting data to a Machine Learning job + * Request to post data to a Machine Learning job */ public class PostDataRequest extends ActionRequest implements ToXContentObject { 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 547bc2e9a934f..b363e633657b9 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 @@ -31,6 +31,7 @@ import org.elasticsearch.client.ml.ForecastJobRequest; import org.elasticsearch.client.ml.GetBucketsRequest; import org.elasticsearch.client.ml.GetCategoriesRequest; +import org.elasticsearch.client.ml.GetDatafeedRequest; import org.elasticsearch.client.ml.GetInfluencersRequest; import org.elasticsearch.client.ml.GetJobRequest; import org.elasticsearch.client.ml.GetJobStatsRequest; @@ -224,6 +225,23 @@ public void testPutDatafeed() throws IOException { } } + public void testGetDatafeed() { + GetDatafeedRequest getDatafeedRequest = new GetDatafeedRequest(); + + Request request = MLRequestConverters.getDatafeed(getDatafeedRequest); + + assertEquals(HttpGet.METHOD_NAME, request.getMethod()); + assertEquals("/_xpack/ml/datafeeds", request.getEndpoint()); + assertFalse(request.getParameters().containsKey("allow_no_datafeeds")); + + getDatafeedRequest = new GetDatafeedRequest("feed-1", "feed-*"); + getDatafeedRequest.setAllowNoDatafeeds(true); + request = MLRequestConverters.getDatafeed(getDatafeedRequest); + + assertEquals("/_xpack/ml/datafeeds/feed-1,feed-*", request.getEndpoint()); + assertEquals(Boolean.toString(true), request.getParameters().get("allow_no_datafeeds")); + } + public void testDeleteDatafeed() { String datafeedId = randomAlphaOfLength(10); DeleteDatafeedRequest deleteDatafeedRequest = new DeleteDatafeedRequest(datafeedId); 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 a07b441484386..cefd725a5e543 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 @@ -32,6 +32,8 @@ import org.elasticsearch.client.ml.FlushJobResponse; import org.elasticsearch.client.ml.ForecastJobRequest; import org.elasticsearch.client.ml.ForecastJobResponse; +import org.elasticsearch.client.ml.GetDatafeedRequest; +import org.elasticsearch.client.ml.GetDatafeedResponse; import org.elasticsearch.client.ml.GetJobRequest; import org.elasticsearch.client.ml.GetJobResponse; import org.elasticsearch.client.ml.GetJobStatsRequest; @@ -54,6 +56,7 @@ import org.elasticsearch.client.ml.job.config.JobUpdate; import org.elasticsearch.client.ml.job.stats.JobStats; import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.rest.RestStatus; import org.junit.After; import java.io.IOException; @@ -312,6 +315,84 @@ public void testPutDatafeed() throws Exception { assertThat(createdDatafeed.getIndices(), equalTo(datafeedConfig.getIndices())); } + public void testGetDatafeed() throws Exception { + String jobId1 = "test-get-datafeed-job-1"; + String jobId2 = "test-get-datafeed-job-2"; + 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); + + String datafeedId1 = jobId1 + "-feed"; + String datafeedId2 = jobId2 + "-feed"; + DatafeedConfig datafeed1 = DatafeedConfig.builder(datafeedId1, jobId1).setIndices("data_1").build(); + DatafeedConfig datafeed2 = DatafeedConfig.builder(datafeedId2, jobId2).setIndices("data_2").build(); + machineLearningClient.putDatafeed(new PutDatafeedRequest(datafeed1), RequestOptions.DEFAULT); + machineLearningClient.putDatafeed(new PutDatafeedRequest(datafeed2), RequestOptions.DEFAULT); + + // Test getting specific datafeeds + { + GetDatafeedRequest request = new GetDatafeedRequest(datafeedId1, datafeedId2); + GetDatafeedResponse response = execute(request, machineLearningClient::getDatafeed, machineLearningClient::getDatafeedAsync); + + assertEquals(2, response.count()); + assertThat(response.datafeeds(), hasSize(2)); + assertThat(response.datafeeds().stream().map(DatafeedConfig::getId).collect(Collectors.toList()), + containsInAnyOrder(datafeedId1, datafeedId2)); + } + + // Test getting a single one + { + GetDatafeedRequest request = new GetDatafeedRequest(datafeedId1); + GetDatafeedResponse response = execute(request, machineLearningClient::getDatafeed, machineLearningClient::getDatafeedAsync); + + assertTrue(response.count() == 1L); + assertThat(response.datafeeds().get(0).getId(), equalTo(datafeedId1)); + } + + // Test getting all datafeeds explicitly + { + GetDatafeedRequest request = GetDatafeedRequest.getAllDatafeedsRequest(); + GetDatafeedResponse response = execute(request, machineLearningClient::getDatafeed, machineLearningClient::getDatafeedAsync); + + assertTrue(response.count() == 2L); + assertTrue(response.datafeeds().size() == 2L); + assertThat(response.datafeeds().stream().map(DatafeedConfig::getId).collect(Collectors.toList()), + hasItems(datafeedId1, datafeedId2)); + } + + // Test getting all datafeeds implicitly + { + GetDatafeedResponse response = execute(new GetDatafeedRequest(), machineLearningClient::getDatafeed, + machineLearningClient::getDatafeedAsync); + + assertTrue(response.count() >= 2L); + assertTrue(response.datafeeds().size() >= 2L); + assertThat(response.datafeeds().stream().map(DatafeedConfig::getId).collect(Collectors.toList()), + hasItems(datafeedId1, datafeedId2)); + } + + // Test get missing pattern with allow_no_datafeeds set to true + { + GetDatafeedRequest request = new GetDatafeedRequest("missing-*"); + + GetDatafeedResponse response = execute(request, machineLearningClient::getDatafeed, machineLearningClient::getDatafeedAsync); + + assertThat(response.count(), equalTo(0L)); + } + + // Test get missing pattern with allow_no_datafeeds set to false + { + GetDatafeedRequest request = new GetDatafeedRequest("missing-*"); + request.setAllowNoDatafeeds(false); + + ElasticsearchStatusException e = expectThrows(ElasticsearchStatusException.class, + () -> execute(request, machineLearningClient::getDatafeed, machineLearningClient::getDatafeedAsync)); + assertThat(e.status(), equalTo(RestStatus.NOT_FOUND)); + } + } + public void testDeleteDatafeed() 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 09d32710eb176..cd2f5a813cdd0 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 @@ -45,6 +45,8 @@ import org.elasticsearch.client.ml.GetBucketsResponse; import org.elasticsearch.client.ml.GetCategoriesRequest; import org.elasticsearch.client.ml.GetCategoriesResponse; +import org.elasticsearch.client.ml.GetDatafeedRequest; +import org.elasticsearch.client.ml.GetDatafeedResponse; import org.elasticsearch.client.ml.GetInfluencersRequest; import org.elasticsearch.client.ml.GetInfluencersResponse; import org.elasticsearch.client.ml.GetJobRequest; @@ -205,14 +207,14 @@ public void testGetJob() throws Exception { { //tag::x-pack-ml-get-job-request - GetJobRequest request = new GetJobRequest("get-machine-learning-job1", "get-machine-learning-job*"); //<1> - request.setAllowNoJobs(true); //<2> + 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 GetJobResponse response = client.machineLearning().getJob(request, RequestOptions.DEFAULT); - long numberOfJobs = response.count(); //<1> - List jobs = response.jobs(); //<2> + long numberOfJobs = response.count(); // <1> + List jobs = response.jobs(); // <2> //end::x-pack-ml-get-job-execute assertEquals(2, response.count()); @@ -263,12 +265,12 @@ public void testDeleteJob() throws Exception { { //tag::x-pack-delete-ml-job-request DeleteJobRequest deleteJobRequest = new DeleteJobRequest("my-first-machine-learning-job"); - deleteJobRequest.setForce(false); //<1> + deleteJobRequest.setForce(false); // <1> AcknowledgedResponse deleteJobResponse = client.machineLearning().deleteJob(deleteJobRequest, RequestOptions.DEFAULT); //end::x-pack-delete-ml-job-request //tag::x-pack-delete-ml-job-response - boolean isAcknowledged = deleteJobResponse.isAcknowledged(); //<1> + boolean isAcknowledged = deleteJobResponse.isAcknowledged(); // <1> //end::x-pack-delete-ml-job-response } { @@ -310,13 +312,13 @@ public void testOpenJob() throws Exception { { //tag::x-pack-ml-open-job-request - OpenJobRequest openJobRequest = new OpenJobRequest("opening-my-first-machine-learning-job"); //<1> - openJobRequest.setTimeout(TimeValue.timeValueMinutes(10)); //<2> + OpenJobRequest openJobRequest = new OpenJobRequest("opening-my-first-machine-learning-job"); // <1> + openJobRequest.setTimeout(TimeValue.timeValueMinutes(10)); // <2> //end::x-pack-ml-open-job-request //tag::x-pack-ml-open-job-execute OpenJobResponse openJobResponse = client.machineLearning().openJob(openJobRequest, RequestOptions.DEFAULT); - boolean isOpened = openJobResponse.isOpened(); //<1> + boolean isOpened = openJobResponse.isOpened(); // <1> //end::x-pack-ml-open-job-execute } @@ -325,7 +327,7 @@ public void testOpenJob() throws Exception { ActionListener listener = new ActionListener() { @Override public void onResponse(OpenJobResponse openJobResponse) { - //<1> + // <1> } @Override @@ -340,7 +342,7 @@ public void onFailure(Exception e) { listener = new LatchedActionListener<>(listener, latch); // tag::x-pack-ml-open-job-execute-async - client.machineLearning().openJobAsync(openJobRequest, RequestOptions.DEFAULT, listener); //<1> + client.machineLearning().openJobAsync(openJobRequest, RequestOptions.DEFAULT, listener); // <1> // end::x-pack-ml-open-job-execute-async assertTrue(latch.await(30L, TimeUnit.SECONDS)); @@ -356,15 +358,15 @@ public void testCloseJob() throws Exception { client.machineLearning().openJob(new OpenJobRequest(job.getId()), RequestOptions.DEFAULT); //tag::x-pack-ml-close-job-request - CloseJobRequest closeJobRequest = new CloseJobRequest("closing-my-first-machine-learning-job", "otherjobs*"); //<1> - closeJobRequest.setForce(false); //<2> - closeJobRequest.setAllowNoJobs(true); //<3> - closeJobRequest.setTimeout(TimeValue.timeValueMinutes(10)); //<4> + CloseJobRequest closeJobRequest = new CloseJobRequest("closing-my-first-machine-learning-job", "otherjobs*"); // <1> + closeJobRequest.setForce(false); // <2> + closeJobRequest.setAllowNoJobs(true); // <3> + closeJobRequest.setTimeout(TimeValue.timeValueMinutes(10)); // <4> //end::x-pack-ml-close-job-request //tag::x-pack-ml-close-job-execute CloseJobResponse closeJobResponse = client.machineLearning().closeJob(closeJobRequest, RequestOptions.DEFAULT); - boolean isClosed = closeJobResponse.isClosed(); //<1> + boolean isClosed = closeJobResponse.isClosed(); // <1> //end::x-pack-ml-close-job-execute } @@ -377,7 +379,7 @@ public void testCloseJob() throws Exception { ActionListener listener = new ActionListener() { @Override public void onResponse(CloseJobResponse closeJobResponse) { - //<1> + // <1> } @Override @@ -393,7 +395,7 @@ public void onFailure(Exception e) { listener = new LatchedActionListener<>(listener, latch); // tag::x-pack-ml-close-job-execute-async - client.machineLearning().closeJobAsync(closeJobRequest, RequestOptions.DEFAULT, listener); //<1> + client.machineLearning().closeJobAsync(closeJobRequest, RequestOptions.DEFAULT, listener); // <1> // end::x-pack-ml-close-job-execute-async assertTrue(latch.await(30L, TimeUnit.SECONDS)); @@ -424,37 +426,37 @@ public void testUpdateJob() throws Exception { customSettings.put("custom-setting-1", "custom-value"); //tag::x-pack-ml-update-job-detector-options - JobUpdate.DetectorUpdate detectorUpdate = new JobUpdate.DetectorUpdate(0, //<1> - "detector description", //<2> - detectionRules); //<3> + JobUpdate.DetectorUpdate detectorUpdate = new JobUpdate.DetectorUpdate(0, // <1> + "detector description", // <2> + detectionRules); // <3> //end::x-pack-ml-update-job-detector-options //tag::x-pack-ml-update-job-options - JobUpdate update = new JobUpdate.Builder(jobId) //<1> - .setDescription("My description") //<2> - .setAnalysisLimits(new AnalysisLimits(1000L, null)) //<3> - .setBackgroundPersistInterval(TimeValue.timeValueHours(3)) //<4> - .setCategorizationFilters(Arrays.asList("categorization-filter")) //<5> - .setDetectorUpdates(Arrays.asList(detectorUpdate)) //<6> - .setGroups(Arrays.asList("job-group-1")) //<7> - .setResultsRetentionDays(10L) //<8> - .setModelPlotConfig(new ModelPlotConfig(true, null)) //<9> - .setModelSnapshotRetentionDays(7L) //<10> - .setCustomSettings(customSettings) //<11> - .setRenormalizationWindowDays(3L) //<12> + JobUpdate update = new JobUpdate.Builder(jobId) // <1> + .setDescription("My description") // <2> + .setAnalysisLimits(new AnalysisLimits(1000L, null)) // <3> + .setBackgroundPersistInterval(TimeValue.timeValueHours(3)) // <4> + .setCategorizationFilters(Arrays.asList("categorization-filter")) // <5> + .setDetectorUpdates(Arrays.asList(detectorUpdate)) // <6> + .setGroups(Arrays.asList("job-group-1")) // <7> + .setResultsRetentionDays(10L) // <8> + .setModelPlotConfig(new ModelPlotConfig(true, null)) // <9> + .setModelSnapshotRetentionDays(7L) // <10> + .setCustomSettings(customSettings) // <11> + .setRenormalizationWindowDays(3L) // <12> .build(); //end::x-pack-ml-update-job-options //tag::x-pack-ml-update-job-request - UpdateJobRequest updateJobRequest = new UpdateJobRequest(update); //<1> + UpdateJobRequest updateJobRequest = new UpdateJobRequest(update); // <1> //end::x-pack-ml-update-job-request //tag::x-pack-ml-update-job-execute PutJobResponse updateJobResponse = client.machineLearning().updateJob(updateJobRequest, RequestOptions.DEFAULT); //end::x-pack-ml-update-job-execute //tag::x-pack-ml-update-job-response - Job updatedJob = updateJobResponse.getResponse(); //<1> + Job updatedJob = updateJobResponse.getResponse(); // <1> //end::x-pack-ml-update-job-response assertEquals(update.getDescription(), updatedJob.getDescription()); @@ -464,7 +466,7 @@ public void testUpdateJob() throws Exception { ActionListener listener = new ActionListener() { @Override public void onResponse(PutJobResponse updateJobResponse) { - //<1> + // <1> } @Override @@ -480,7 +482,7 @@ public void onFailure(Exception e) { listener = new LatchedActionListener<>(listener, latch); // tag::x-pack-ml-update-job-execute-async - client.machineLearning().updateJobAsync(updateJobRequest, RequestOptions.DEFAULT, listener); //<1> + client.machineLearning().updateJobAsync(updateJobRequest, RequestOptions.DEFAULT, listener); // <1> // end::x-pack-ml-update-job-execute-async assertTrue(latch.await(30L, TimeUnit.SECONDS)); @@ -587,6 +589,59 @@ public void onFailure(Exception e) { } } + public void testGetDatafeed() throws Exception { + RestHighLevelClient client = highLevelClient(); + + Job job = MachineLearningIT.buildJob("get-datafeed-job"); + client.machineLearning().putJob(new PutJobRequest(job), RequestOptions.DEFAULT); + String datafeedId = job.getId() + "-feed"; + DatafeedConfig datafeed = DatafeedConfig.builder(datafeedId, job.getId()).setIndices("foo").build(); + client.machineLearning().putDatafeed(new PutDatafeedRequest(datafeed), RequestOptions.DEFAULT); + + { + //tag::x-pack-ml-get-datafeed-request + GetDatafeedRequest request = new GetDatafeedRequest(datafeedId); // <1> + request.setAllowNoDatafeeds(true); // <2> + //end::x-pack-ml-get-datafeed-request + + //tag::x-pack-ml-get-datafeed-execute + GetDatafeedResponse response = client.machineLearning().getDatafeed(request, RequestOptions.DEFAULT); + long numberOfDatafeeds = response.count(); // <1> + List datafeeds = response.datafeeds(); // <2> + //end::x-pack-ml-get-datafeed-execute + + assertEquals(1, numberOfDatafeeds); + assertEquals(1, datafeeds.size()); + } + { + GetDatafeedRequest request = new GetDatafeedRequest(datafeedId); + + // tag::x-pack-ml-get-datafeed-listener + ActionListener listener = new ActionListener() { + @Override + public void onResponse(GetDatafeedResponse response) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }; + // end::x-pack-ml-get-datafeed-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-datafeed-execute-async + client.machineLearning().getDatafeedAsync(request, RequestOptions.DEFAULT, listener); // <1> + // end::x-pack-ml-get-datafeed-execute-async + + assertTrue(latch.await(30L, TimeUnit.SECONDS)); + } + } + public void testDeleteDatafeed() throws Exception { RestHighLevelClient client = highLevelClient(); @@ -601,13 +656,13 @@ public void testDeleteDatafeed() throws Exception { { //tag::x-pack-delete-ml-datafeed-request DeleteDatafeedRequest deleteDatafeedRequest = new DeleteDatafeedRequest(datafeedId); - deleteDatafeedRequest.setForce(false); //<1> + deleteDatafeedRequest.setForce(false); // <1> AcknowledgedResponse deleteDatafeedResponse = client.machineLearning().deleteDatafeed( deleteDatafeedRequest, RequestOptions.DEFAULT); //end::x-pack-delete-ml-datafeed-request //tag::x-pack-delete-ml-datafeed-response - boolean isAcknowledged = deleteDatafeedResponse.isAcknowledged(); //<1> + boolean isAcknowledged = deleteDatafeedResponse.isAcknowledged(); // <1> //end::x-pack-delete-ml-datafeed-response } @@ -756,15 +811,15 @@ public void testFlushJob() throws Exception { { //tag::x-pack-ml-flush-job-request - FlushJobRequest flushJobRequest = new FlushJobRequest("flushing-my-first-machine-learning-job"); //<1> + FlushJobRequest flushJobRequest = new FlushJobRequest("flushing-my-first-machine-learning-job"); // <1> //end::x-pack-ml-flush-job-request //tag::x-pack-ml-flush-job-request-options - flushJobRequest.setCalcInterim(true); //<1> - flushJobRequest.setAdvanceTime("2018-08-31T16:35:07+00:00"); //<2> - flushJobRequest.setStart("2018-08-31T16:35:17+00:00"); //<3> - flushJobRequest.setEnd("2018-08-31T16:35:27+00:00"); //<4> - flushJobRequest.setSkipTime("2018-08-31T16:35:00+00:00"); //<5> + flushJobRequest.setCalcInterim(true); // <1> + flushJobRequest.setAdvanceTime("2018-08-31T16:35:07+00:00"); // <2> + flushJobRequest.setStart("2018-08-31T16:35:17+00:00"); // <3> + flushJobRequest.setEnd("2018-08-31T16:35:27+00:00"); // <4> + flushJobRequest.setSkipTime("2018-08-31T16:35:00+00:00"); // <5> //end::x-pack-ml-flush-job-request-options //tag::x-pack-ml-flush-job-execute @@ -772,8 +827,8 @@ public void testFlushJob() throws Exception { //end::x-pack-ml-flush-job-execute //tag::x-pack-ml-flush-job-response - boolean isFlushed = flushJobResponse.isFlushed(); //<1> - Date lastFinalizedBucketEnd = flushJobResponse.getLastFinalizedBucketEnd(); //<2> + boolean isFlushed = flushJobResponse.isFlushed(); // <1> + Date lastFinalizedBucketEnd = flushJobResponse.getLastFinalizedBucketEnd(); // <2> //end::x-pack-ml-flush-job-response } @@ -782,7 +837,7 @@ public void testFlushJob() throws Exception { ActionListener listener = new ActionListener() { @Override public void onResponse(FlushJobResponse FlushJobResponse) { - //<1> + // <1> } @Override @@ -798,7 +853,7 @@ public void onFailure(Exception e) { listener = new LatchedActionListener<>(listener, latch); // tag::x-pack-ml-flush-job-execute-async - client.machineLearning().flushJobAsync(flushJobRequest, RequestOptions.DEFAULT, listener); //<1> + client.machineLearning().flushJobAsync(flushJobRequest, RequestOptions.DEFAULT, listener); // <1> // end::x-pack-ml-flush-job-execute-async assertTrue(latch.await(30L, TimeUnit.SECONDS)); @@ -836,13 +891,13 @@ public void testDeleteForecast() throws Exception { { //tag::x-pack-ml-delete-forecast-request - DeleteForecastRequest deleteForecastRequest = new DeleteForecastRequest("deleting-forecast-for-job"); //<1> + DeleteForecastRequest deleteForecastRequest = new DeleteForecastRequest("deleting-forecast-for-job"); // <1> //end::x-pack-ml-delete-forecast-request //tag::x-pack-ml-delete-forecast-request-options - deleteForecastRequest.setForecastIds(forecastId); //<1> - deleteForecastRequest.timeout("30s"); //<2> - deleteForecastRequest.setAllowNoForecasts(true); //<3> + deleteForecastRequest.setForecastIds(forecastId); // <1> + deleteForecastRequest.timeout("30s"); // <2> + deleteForecastRequest.setAllowNoForecasts(true); // <3> //end::x-pack-ml-delete-forecast-request-options //tag::x-pack-ml-delete-forecast-execute @@ -851,7 +906,7 @@ public void testDeleteForecast() throws Exception { //end::x-pack-ml-delete-forecast-execute //tag::x-pack-ml-delete-forecast-response - boolean isAcknowledged = deleteForecastResponse.isAcknowledged(); //<1> + boolean isAcknowledged = deleteForecastResponse.isAcknowledged(); // <1> //end::x-pack-ml-delete-forecast-response } { @@ -859,7 +914,7 @@ public void testDeleteForecast() throws Exception { ActionListener listener = new ActionListener() { @Override public void onResponse(AcknowledgedResponse DeleteForecastResponse) { - //<1> + // <1> } @Override @@ -876,7 +931,7 @@ public void onFailure(Exception e) { listener = new LatchedActionListener<>(listener, latch); // tag::x-pack-ml-delete-forecast-execute-async - client.machineLearning().deleteForecastAsync(deleteForecastRequest, RequestOptions.DEFAULT, listener); //<1> + client.machineLearning().deleteForecastAsync(deleteForecastRequest, RequestOptions.DEFAULT, listener); // <1> // end::x-pack-ml-delete-forecast-execute-async assertTrue(latch.await(30L, TimeUnit.SECONDS)); @@ -894,8 +949,8 @@ public void testGetJobStats() throws Exception { { //tag::x-pack-ml-get-job-stats-request - GetJobStatsRequest request = new GetJobStatsRequest("get-machine-learning-job-stats1", "get-machine-learning-job-*"); //<1> - request.setAllowNoJobs(true); //<2> + GetJobStatsRequest request = new GetJobStatsRequest("get-machine-learning-job-stats1", "get-machine-learning-job-*"); // <1> + request.setAllowNoJobs(true); // <2> //end::x-pack-ml-get-job-stats-request //tag::x-pack-ml-get-job-stats-execute @@ -903,8 +958,8 @@ public void testGetJobStats() throws Exception { //end::x-pack-ml-get-job-stats-execute //tag::x-pack-ml-get-job-stats-response - long numberOfJobStats = response.count(); //<1> - List jobStats = response.jobStats(); //<2> + long numberOfJobStats = response.count(); // <1> + List jobStats = response.jobStats(); // <2> //end::x-pack-ml-get-job-stats-response assertEquals(2, response.count()); @@ -961,12 +1016,12 @@ public void testForecastJob() throws Exception { { //tag::x-pack-ml-forecast-job-request - ForecastJobRequest forecastJobRequest = new ForecastJobRequest("forecasting-my-first-machine-learning-job"); //<1> + ForecastJobRequest forecastJobRequest = new ForecastJobRequest("forecasting-my-first-machine-learning-job"); // <1> //end::x-pack-ml-forecast-job-request //tag::x-pack-ml-forecast-job-request-options - forecastJobRequest.setExpiresIn(TimeValue.timeValueHours(48)); //<1> - forecastJobRequest.setDuration(TimeValue.timeValueHours(24)); //<2> + forecastJobRequest.setExpiresIn(TimeValue.timeValueHours(48)); // <1> + forecastJobRequest.setDuration(TimeValue.timeValueHours(24)); // <2> //end::x-pack-ml-forecast-job-request-options //tag::x-pack-ml-forecast-job-execute @@ -974,8 +1029,8 @@ public void testForecastJob() throws Exception { //end::x-pack-ml-forecast-job-execute //tag::x-pack-ml-forecast-job-response - boolean isAcknowledged = forecastJobResponse.isAcknowledged(); //<1> - String forecastId = forecastJobResponse.getForecastId(); //<2> + boolean isAcknowledged = forecastJobResponse.isAcknowledged(); // <1> + String forecastId = forecastJobResponse.getForecastId(); // <2> //end::x-pack-ml-forecast-job-response assertTrue(isAcknowledged); assertNotNull(forecastId); @@ -985,7 +1040,7 @@ public void testForecastJob() throws Exception { ActionListener listener = new ActionListener() { @Override public void onResponse(ForecastJobResponse forecastJobResponse) { - //<1> + // <1> } @Override @@ -1001,7 +1056,7 @@ public void onFailure(Exception e) { listener = new LatchedActionListener<>(listener, latch); // tag::x-pack-ml-forecast-job-execute-async - client.machineLearning().forecastJobAsync(forecastJobRequest, RequestOptions.DEFAULT, listener); //<1> + client.machineLearning().forecastJobAsync(forecastJobRequest, RequestOptions.DEFAULT, listener); // <1> // end::x-pack-ml-forecast-job-execute-async assertTrue(latch.await(30L, TimeUnit.SECONDS)); @@ -1208,18 +1263,18 @@ public void testPostData() throws Exception { { //tag::x-pack-ml-post-data-request - PostDataRequest.JsonBuilder jsonBuilder = new PostDataRequest.JsonBuilder(); //<1> + PostDataRequest.JsonBuilder jsonBuilder = new PostDataRequest.JsonBuilder(); // <1> Map mapData = new HashMap<>(); mapData.put("total", 109); - jsonBuilder.addDoc(mapData); //<2> - jsonBuilder.addDoc("{\"total\":1000}"); //<3> - PostDataRequest postDataRequest = new PostDataRequest("test-post-data", jsonBuilder); //<4> + jsonBuilder.addDoc(mapData); // <2> + jsonBuilder.addDoc("{\"total\":1000}"); // <3> + PostDataRequest postDataRequest = new PostDataRequest("test-post-data", jsonBuilder); // <4> //end::x-pack-ml-post-data-request //tag::x-pack-ml-post-data-request-options - postDataRequest.setResetStart("2018-08-31T16:35:07+00:00"); //<1> - postDataRequest.setResetEnd("2018-08-31T16:35:17+00:00"); //<2> + postDataRequest.setResetStart("2018-08-31T16:35:07+00:00"); // <1> + postDataRequest.setResetEnd("2018-08-31T16:35:17+00:00"); // <2> //end::x-pack-ml-post-data-request-options postDataRequest.setResetEnd(null); postDataRequest.setResetStart(null); @@ -1229,7 +1284,7 @@ public void testPostData() throws Exception { //end::x-pack-ml-post-data-execute //tag::x-pack-ml-post-data-response - DataCounts dataCounts = postDataResponse.getDataCounts(); //<1> + DataCounts dataCounts = postDataResponse.getDataCounts(); // <1> //end::x-pack-ml-post-data-response assertEquals(2, dataCounts.getInputRecordCount()); @@ -1239,7 +1294,7 @@ public void testPostData() throws Exception { ActionListener listener = new ActionListener() { @Override public void onResponse(PostDataResponse postDataResponse) { - //<1> + // <1> } @Override @@ -1252,14 +1307,14 @@ public void onFailure(Exception e) { Map mapData = new HashMap<>(); mapData.put("total", 109); jsonBuilder.addDoc(mapData); - PostDataRequest postDataRequest = new PostDataRequest("test-post-data", jsonBuilder); //<1> + PostDataRequest postDataRequest = new PostDataRequest("test-post-data", jsonBuilder); // <1> // 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-post-data-execute-async - client.machineLearning().postDataAsync(postDataRequest, RequestOptions.DEFAULT, listener); //<1> + client.machineLearning().postDataAsync(postDataRequest, RequestOptions.DEFAULT, listener); // <1> // end::x-pack-ml-post-data-execute-async assertTrue(latch.await(30L, TimeUnit.SECONDS)); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/GetDatafeedRequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/GetDatafeedRequestTests.java new file mode 100644 index 0000000000000..cca63d2f29efd --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/GetDatafeedRequestTests.java @@ -0,0 +1,70 @@ +/* + * 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.ml; + +import org.elasticsearch.client.ml.datafeed.DatafeedConfigTests; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.test.AbstractXContentTestCase; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class GetDatafeedRequestTests extends AbstractXContentTestCase { + + public void testAllDatafeedRequest() { + GetDatafeedRequest request = GetDatafeedRequest.getAllDatafeedsRequest(); + + assertEquals(request.getDatafeedIds().size(), 1); + assertEquals(request.getDatafeedIds().get(0), "_all"); + } + + public void testNewWithDatafeedId() { + Exception exception = expectThrows(NullPointerException.class, () -> new GetDatafeedRequest("feed",null)); + assertEquals(exception.getMessage(), "datafeedIds must not contain null values"); + } + + @Override + protected GetDatafeedRequest createTestInstance() { + int count = randomIntBetween(0, 10); + List datafeedIds = new ArrayList<>(count); + + for (int i = 0; i < count; i++) { + datafeedIds.add(DatafeedConfigTests.randomValidDatafeedId()); + } + + GetDatafeedRequest request = new GetDatafeedRequest(datafeedIds); + + if (randomBoolean()) { + request.setAllowNoDatafeeds(randomBoolean()); + } + + return request; + } + + @Override + protected GetDatafeedRequest doParseInstance(XContentParser parser) throws IOException { + return GetDatafeedRequest.PARSER.parse(parser, null); + } + + @Override + protected boolean supportsUnknownFields() { + return false; + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/GetDatafeedResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/GetDatafeedResponseTests.java new file mode 100644 index 0000000000000..e4c93c9d8aca8 --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/GetDatafeedResponseTests.java @@ -0,0 +1,58 @@ +/* + * 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.ml; + +import org.elasticsearch.client.ml.datafeed.DatafeedConfig; +import org.elasticsearch.client.ml.datafeed.DatafeedConfigTests; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.test.AbstractXContentTestCase; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; + +public class GetDatafeedResponseTests extends AbstractXContentTestCase { + + @Override + protected GetDatafeedResponse createTestInstance() { + int count = randomIntBetween(1, 5); + List results = new ArrayList<>(count); + for(int i = 0; i < count; i++) { + DatafeedConfigTests.createRandomBuilder(); + results.add(DatafeedConfigTests.createRandomBuilder()); + } + return new GetDatafeedResponse(results, count); + } + + @Override + protected GetDatafeedResponse doParseInstance(XContentParser parser) throws IOException { + return GetDatafeedResponse.fromXContent(parser); + } + + @Override + protected Predicate getRandomFieldsExcludeFilter() { + return field -> !field.isEmpty(); + } + + @Override + protected boolean supportsUnknownFields() { + return true; + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/GetJobRequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/GetJobRequestTests.java index 77b2109dd7c68..36aa02dbd62b7 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/GetJobRequestTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/GetJobRequestTests.java @@ -64,6 +64,6 @@ protected GetJobRequest doParseInstance(XContentParser parser) throws IOExceptio @Override protected boolean supportsUnknownFields() { - return true; + return false; } } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/datafeed/DatafeedConfigTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/datafeed/DatafeedConfigTests.java index e4e16c45fbfdf..4cf23978c2546 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/datafeed/DatafeedConfigTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/datafeed/DatafeedConfigTests.java @@ -44,6 +44,10 @@ protected DatafeedConfig createTestInstance() { } public static DatafeedConfig createRandom() { + return createRandomBuilder().build(); + } + + public static DatafeedConfig.Builder createRandomBuilder() { long bucketSpanMillis = 3600000; DatafeedConfig.Builder builder = constructBuilder(); builder.setIndices(randomStringList(1, 10)); @@ -99,7 +103,7 @@ public static DatafeedConfig createRandom() { if (randomBoolean()) { builder.setChunkingConfig(ChunkingConfigTests.createRandomizedChunk()); } - return builder.build(); + return builder; } public static List randomStringList(int min, int max) { diff --git a/docs/java-rest/high-level/ml/get-datafeed.asciidoc b/docs/java-rest/high-level/ml/get-datafeed.asciidoc new file mode 100644 index 0000000000000..8e5f0664c6181 --- /dev/null +++ b/docs/java-rest/high-level/ml/get-datafeed.asciidoc @@ -0,0 +1,56 @@ +[[java-rest-high-x-pack-ml-get-datafeed]] +=== Get Datafeed API + +The Get Datafeed API provides the ability to get {ml} datafeeds in the cluster. +It accepts a `GetDatafeedRequest` object and responds +with a `GetDatafeedResponse` object. + +[[java-rest-high-x-pack-ml-get-datafeed-request]] +==== Get Datafeed Request + +A `GetDatafeedRequest` object gets can have any number of `datafeedId` entries. +However, they all must be non-null. An empty list is the same as requesting for all datafeeds. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-get-datafeed-request] +-------------------------------------------------- +<1> Constructing a new request referencing existing `datafeedIds`, can contain wildcards +<2> Whether to ignore if a wildcard expression matches no datafeeds. + (This includes `_all` string or when no datafeeds have been specified) + +[[java-rest-high-x-pack-ml-get-datafeed-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-datafeed-execute] +-------------------------------------------------- +<1> The count of retrieved datafeeds +<2> The retrieved datafeeds + +[[java-rest-high-x-pack-ml-get-datafeed-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-datafeed-execute-async] +-------------------------------------------------- +<1> The `GetDatafeedRequest` 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 `GetDatafeedResponse` may +look like + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-get-datafeed-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 cb297d0f712dc..60819cd3935eb 100644 --- a/docs/java-rest/high-level/supported-apis.asciidoc +++ b/docs/java-rest/high-level/supported-apis.asciidoc @@ -221,6 +221,7 @@ The Java High Level REST Client supports the following Machine Learning APIs: * <> * <> * <> +* <> * <> * <> * <> @@ -239,6 +240,7 @@ include::ml/close-job.asciidoc[] include::ml/update-job.asciidoc[] include::ml/flush-job.asciidoc[] include::ml/put-datafeed.asciidoc[] +include::ml/get-datafeed.asciidoc[] include::ml/delete-datafeed.asciidoc[] include::ml/get-job-stats.asciidoc[] include::ml/forecast-job.asciidoc[]