HLRC: ML Forecast Job (#33506)

* HLRC: ML Forecast job
This commit is contained in:
Benjamin Trent 2018-09-07 11:16:58 -05:00 committed by GitHub
parent 42469a9930
commit 4d233107f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 585 additions and 0 deletions

View File

@ -30,6 +30,7 @@ import org.elasticsearch.client.RequestConverters.EndpointBuilder;
import org.elasticsearch.client.ml.CloseJobRequest; import org.elasticsearch.client.ml.CloseJobRequest;
import org.elasticsearch.client.ml.DeleteJobRequest; import org.elasticsearch.client.ml.DeleteJobRequest;
import org.elasticsearch.client.ml.FlushJobRequest; import org.elasticsearch.client.ml.FlushJobRequest;
import org.elasticsearch.client.ml.ForecastJobRequest;
import org.elasticsearch.client.ml.GetBucketsRequest; import org.elasticsearch.client.ml.GetBucketsRequest;
import org.elasticsearch.client.ml.GetInfluencersRequest; import org.elasticsearch.client.ml.GetInfluencersRequest;
import org.elasticsearch.client.ml.GetJobRequest; import org.elasticsearch.client.ml.GetJobRequest;
@ -153,6 +154,19 @@ final class MLRequestConverters {
return request; return request;
} }
static Request forecastJob(ForecastJobRequest forecastJobRequest) throws IOException {
String endpoint = new EndpointBuilder()
.addPathPartAsIs("_xpack")
.addPathPartAsIs("ml")
.addPathPartAsIs("anomaly_detectors")
.addPathPart(forecastJobRequest.getJobId())
.addPathPartAsIs("_forecast")
.build();
Request request = new Request(HttpPost.METHOD_NAME, endpoint);
request.setEntity(createEntity(forecastJobRequest, REQUEST_BODY_CONTENT_TYPE));
return request;
}
static Request updateJob(UpdateJobRequest updateJobRequest) throws IOException { static Request updateJob(UpdateJobRequest updateJobRequest) throws IOException {
String endpoint = new EndpointBuilder() String endpoint = new EndpointBuilder()
.addPathPartAsIs("_xpack") .addPathPartAsIs("_xpack")

View File

@ -19,6 +19,8 @@
package org.elasticsearch.client; package org.elasticsearch.client;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
import org.elasticsearch.client.ml.ForecastJobRequest;
import org.elasticsearch.client.ml.ForecastJobResponse;
import org.elasticsearch.client.ml.PostDataRequest; import org.elasticsearch.client.ml.PostDataRequest;
import org.elasticsearch.client.ml.PostDataResponse; import org.elasticsearch.client.ml.PostDataResponse;
import org.elasticsearch.client.ml.UpdateJobRequest; import org.elasticsearch.client.ml.UpdateJobRequest;
@ -360,6 +362,28 @@ public final class MachineLearningClient {
Collections.emptySet()); Collections.emptySet());
} }
/**
* Creates a forecast of an existing, opened Machine Learning Job
*
* This predicts the future behavior of a time series by using its historical behavior.
*
* <p>
* For additional info
* see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/master/ml-forecast.html">Forecast ML Job Documentation</a>
* </p>
* @param request ForecastJobRequest with forecasting options
* @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @return response containing forecast acknowledgement and new forecast's ID
* @throws IOException when there is a serialization issue sending the request or receiving the response
*/
public ForecastJobResponse forecastJob(ForecastJobRequest request, RequestOptions options) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(request,
MLRequestConverters::forecastJob,
options,
ForecastJobResponse::fromXContent,
Collections.emptySet());
}
/** /**
* Updates a Machine Learning {@link org.elasticsearch.client.ml.job.config.Job} * Updates a Machine Learning {@link org.elasticsearch.client.ml.job.config.Job}
* *
@ -376,6 +400,28 @@ public final class MachineLearningClient {
Collections.emptySet()); Collections.emptySet());
} }
/**
* Creates a forecast of an existing, opened Machine Learning Job asynchronously
*
* This predicts the future behavior of a time series by using its historical behavior.
*
* <p>
* For additional info
* see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/master/ml-forecast.html">Forecast ML Job Documentation</a>
* </p>
* @param request ForecastJobRequest with forecasting 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 upon request completion
*/
public void forecastJobAsync(ForecastJobRequest request, RequestOptions options, ActionListener<ForecastJobResponse> listener) {
restHighLevelClient.performRequestAsyncAndParseEntity(request,
MLRequestConverters::forecastJob,
options,
ForecastJobResponse::fromXContent,
listener,
Collections.emptySet());
}
/** /**
* Updates a Machine Learning {@link org.elasticsearch.client.ml.job.config.Job} asynchronously * Updates a Machine Learning {@link org.elasticsearch.client.ml.job.config.Job} asynchronously
* *

View File

@ -0,0 +1,140 @@
/*
* 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.job.config.Job;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException;
import java.util.Objects;
/**
* Pojo for forecasting an existing and open Machine Learning Job
*/
public class ForecastJobRequest extends ActionRequest implements ToXContentObject {
public static final ParseField DURATION = new ParseField("duration");
public static final ParseField EXPIRES_IN = new ParseField("expires_in");
public static final ConstructingObjectParser<ForecastJobRequest, Void> PARSER =
new ConstructingObjectParser<>("forecast_job_request", (a) -> new ForecastJobRequest((String)a[0]));
static {
PARSER.declareString(ConstructingObjectParser.constructorArg(), Job.ID);
PARSER.declareString(
(request, val) -> request.setDuration(TimeValue.parseTimeValue(val, DURATION.getPreferredName())), DURATION);
PARSER.declareString(
(request, val) -> request.setExpiresIn(TimeValue.parseTimeValue(val, EXPIRES_IN.getPreferredName())), EXPIRES_IN);
}
private final String jobId;
private TimeValue duration;
private TimeValue expiresIn;
/**
* A new forecast request
*
* @param jobId the non-null, existing, and opened jobId to forecast
*/
public ForecastJobRequest(String jobId) {
this.jobId = jobId;
}
public String getJobId() {
return jobId;
}
public TimeValue getDuration() {
return duration;
}
/**
* Set the forecast duration
*
* A period of time that indicates how far into the future to forecast.
* The default value is 1 day. The forecast starts at the last record that was processed.
*
* @param duration TimeValue for the duration of the forecast
*/
public void setDuration(TimeValue duration) {
this.duration = duration;
}
public TimeValue getExpiresIn() {
return expiresIn;
}
/**
* Set the forecast expiration
*
* The period of time that forecast results are retained.
* After a forecast expires, the results are deleted. The default value is 14 days.
* If set to a value of 0, the forecast is never automatically deleted.
*
* @param expiresIn TimeValue for the forecast expiration
*/
public void setExpiresIn(TimeValue expiresIn) {
this.expiresIn = expiresIn;
}
@Override
public int hashCode() {
return Objects.hash(jobId, duration, expiresIn);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
ForecastJobRequest other = (ForecastJobRequest) obj;
return Objects.equals(jobId, other.jobId)
&& Objects.equals(duration, other.duration)
&& Objects.equals(expiresIn, other.expiresIn);
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
builder.startObject();
builder.field(Job.ID.getPreferredName(), jobId);
if (duration != null) {
builder.field(DURATION.getPreferredName(), duration.getStringRep());
}
if (expiresIn != null) {
builder.field(EXPIRES_IN.getPreferredName(), expiresIn.getStringRep());
}
builder.endObject();
return builder;
}
@Override
public ActionRequestValidationException validate() {
return null;
}
}

View File

@ -0,0 +1,102 @@
/*
* 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.ActionResponse;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException;
import java.util.Objects;
/**
* Forecast response object
*/
public class ForecastJobResponse extends ActionResponse implements ToXContentObject {
public static final ParseField ACKNOWLEDGED = new ParseField("acknowledged");
public static final ParseField FORECAST_ID = new ParseField("forecast_id");
public static final ConstructingObjectParser<ForecastJobResponse, Void> PARSER =
new ConstructingObjectParser<>("forecast_job_response",
true,
(a) -> new ForecastJobResponse((Boolean)a[0], (String)a[1]));
static {
PARSER.declareBoolean(ConstructingObjectParser.constructorArg(), ACKNOWLEDGED);
PARSER.declareString(ConstructingObjectParser.constructorArg(), FORECAST_ID);
}
public static ForecastJobResponse fromXContent(XContentParser parser) throws IOException {
return PARSER.parse(parser, null);
}
private final boolean acknowledged;
private final String forecastId;
public ForecastJobResponse(boolean acknowledged, String forecastId) {
this.acknowledged = acknowledged;
this.forecastId = forecastId;
}
/**
* Forecast creating acknowledgement
* @return {@code true} indicates success, {@code false} otherwise
*/
public boolean isAcknowledged() {
return acknowledged;
}
/**
* The created forecast ID
*/
public String getForecastId() {
return forecastId;
}
@Override
public int hashCode() {
return Objects.hash(acknowledged, forecastId);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
ForecastJobResponse other = (ForecastJobResponse) obj;
return Objects.equals(acknowledged, other.acknowledged)
&& Objects.equals(forecastId, other.forecastId);
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(ACKNOWLEDGED.getPreferredName(), acknowledged);
builder.field(FORECAST_ID.getPreferredName(), forecastId);
builder.endObject();
return builder;
}
}

View File

@ -26,6 +26,7 @@ import org.apache.http.client.methods.HttpPut;
import org.elasticsearch.client.ml.CloseJobRequest; import org.elasticsearch.client.ml.CloseJobRequest;
import org.elasticsearch.client.ml.DeleteJobRequest; import org.elasticsearch.client.ml.DeleteJobRequest;
import org.elasticsearch.client.ml.FlushJobRequest; import org.elasticsearch.client.ml.FlushJobRequest;
import org.elasticsearch.client.ml.ForecastJobRequest;
import org.elasticsearch.client.ml.GetBucketsRequest; import org.elasticsearch.client.ml.GetBucketsRequest;
import org.elasticsearch.client.ml.GetInfluencersRequest; import org.elasticsearch.client.ml.GetInfluencersRequest;
import org.elasticsearch.client.ml.GetJobRequest; import org.elasticsearch.client.ml.GetJobRequest;
@ -173,6 +174,21 @@ public class MLRequestConvertersTests extends ESTestCase {
requestEntityToString(request)); requestEntityToString(request));
} }
public void testForecastJob() throws Exception {
String jobId = randomAlphaOfLength(10);
ForecastJobRequest forecastJobRequest = new ForecastJobRequest(jobId);
forecastJobRequest.setDuration(TimeValue.timeValueHours(10));
forecastJobRequest.setExpiresIn(TimeValue.timeValueHours(12));
Request request = MLRequestConverters.forecastJob(forecastJobRequest);
assertEquals(HttpPost.METHOD_NAME, request.getMethod());
assertEquals("/_xpack/ml/anomaly_detectors/" + jobId + "/_forecast", request.getEndpoint());
try (XContentParser parser = createParser(JsonXContent.jsonXContent, request.getEntity().getContent())) {
ForecastJobRequest parsedRequest = ForecastJobRequest.PARSER.apply(parser, null);
assertThat(parsedRequest, equalTo(forecastJobRequest));
}
}
public void testUpdateJob() throws Exception { public void testUpdateJob() throws Exception {
String jobId = randomAlphaOfLength(10); String jobId = randomAlphaOfLength(10);
JobUpdate updates = JobUpdateTests.createRandom(jobId); JobUpdate updates = JobUpdateTests.createRandom(jobId);

View File

@ -20,6 +20,8 @@ package org.elasticsearch.client;
import com.carrotsearch.randomizedtesting.generators.CodepointSetGenerator; import com.carrotsearch.randomizedtesting.generators.CodepointSetGenerator;
import org.elasticsearch.ElasticsearchStatusException; import org.elasticsearch.ElasticsearchStatusException;
import org.elasticsearch.client.ml.ForecastJobRequest;
import org.elasticsearch.client.ml.ForecastJobResponse;
import org.elasticsearch.client.ml.PostDataRequest; import org.elasticsearch.client.ml.PostDataRequest;
import org.elasticsearch.client.ml.PostDataResponse; import org.elasticsearch.client.ml.PostDataResponse;
import org.elasticsearch.client.ml.UpdateJobRequest; import org.elasticsearch.client.ml.UpdateJobRequest;
@ -223,6 +225,31 @@ public class MachineLearningIT extends ESRestHighLevelClientTestCase {
assertThat(exception.status().getStatus(), equalTo(404)); assertThat(exception.status().getStatus(), equalTo(404));
} }
public void testForecastJob() throws Exception {
String jobId = "ml-forecast-job-test";
Job job = buildJob(jobId);
MachineLearningClient machineLearningClient = highLevelClient().machineLearning();
machineLearningClient.putJob(new PutJobRequest(job), RequestOptions.DEFAULT);
machineLearningClient.openJob(new OpenJobRequest(jobId), RequestOptions.DEFAULT);
PostDataRequest.JsonBuilder builder = new PostDataRequest.JsonBuilder();
for(int i = 0; i < 30; i++) {
Map<String, Object> hashMap = new HashMap<>();
hashMap.put("total", randomInt(1000));
hashMap.put("timestamp", (i+1)*1000);
builder.addDoc(hashMap);
}
PostDataRequest postDataRequest = new PostDataRequest(jobId, builder);
machineLearningClient.postData(postDataRequest, RequestOptions.DEFAULT);
machineLearningClient.flushJob(new FlushJobRequest(jobId), RequestOptions.DEFAULT);
ForecastJobRequest request = new ForecastJobRequest(jobId);
ForecastJobResponse response = execute(request, machineLearningClient::forecastJob, machineLearningClient::forecastJobAsync);
assertTrue(response.isAcknowledged());
assertNotNull(response.getForecastId());
}
public void testPostData() throws Exception { public void testPostData() throws Exception {
String jobId = randomValidJobId(); String jobId = randomValidJobId();
Job job = buildJob(jobId); Job job = buildJob(jobId);

View File

@ -35,6 +35,8 @@ import org.elasticsearch.client.ml.DeleteJobRequest;
import org.elasticsearch.client.ml.DeleteJobResponse; import org.elasticsearch.client.ml.DeleteJobResponse;
import org.elasticsearch.client.ml.FlushJobRequest; import org.elasticsearch.client.ml.FlushJobRequest;
import org.elasticsearch.client.ml.FlushJobResponse; import org.elasticsearch.client.ml.FlushJobResponse;
import org.elasticsearch.client.ml.ForecastJobRequest;
import org.elasticsearch.client.ml.ForecastJobResponse;
import org.elasticsearch.client.ml.GetBucketsRequest; import org.elasticsearch.client.ml.GetBucketsRequest;
import org.elasticsearch.client.ml.GetBucketsResponse; import org.elasticsearch.client.ml.GetBucketsResponse;
import org.elasticsearch.client.ml.GetInfluencersRequest; import org.elasticsearch.client.ml.GetInfluencersRequest;
@ -694,6 +696,73 @@ public class MlClientDocumentationIT extends ESRestHighLevelClientTestCase {
} }
} }
public void testForecastJob() throws Exception {
RestHighLevelClient client = highLevelClient();
Job job = MachineLearningIT.buildJob("forecasting-my-first-machine-learning-job");
client.machineLearning().putJob(new PutJobRequest(job), RequestOptions.DEFAULT);
client.machineLearning().openJob(new OpenJobRequest(job.getId()), RequestOptions.DEFAULT);
PostDataRequest.JsonBuilder builder = new PostDataRequest.JsonBuilder();
for(int i = 0; i < 30; i++) {
Map<String, Object> hashMap = new HashMap<>();
hashMap.put("total", randomInt(1000));
hashMap.put("timestamp", (i+1)*1000);
builder.addDoc(hashMap);
}
PostDataRequest postDataRequest = new PostDataRequest(job.getId(), builder);
client.machineLearning().postData(postDataRequest, RequestOptions.DEFAULT);
client.machineLearning().flushJob(new FlushJobRequest(job.getId()), RequestOptions.DEFAULT);
{
//tag::x-pack-ml-forecast-job-request
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>
//end::x-pack-ml-forecast-job-request-options
//tag::x-pack-ml-forecast-job-execute
ForecastJobResponse forecastJobResponse = client.machineLearning().forecastJob(forecastJobRequest, RequestOptions.DEFAULT);
//end::x-pack-ml-forecast-job-execute
//tag::x-pack-ml-forecast-job-response
boolean isAcknowledged = forecastJobResponse.isAcknowledged(); //<1>
String forecastId = forecastJobResponse.getForecastId(); //<2>
//end::x-pack-ml-forecast-job-response
assertTrue(isAcknowledged);
assertNotNull(forecastId);
}
{
//tag::x-pack-ml-forecast-job-listener
ActionListener<ForecastJobResponse> listener = new ActionListener<ForecastJobResponse>() {
@Override
public void onResponse(ForecastJobResponse forecastJobResponse) {
//<1>
}
@Override
public void onFailure(Exception e) {
// <2>
}
};
//end::x-pack-ml-forecast-job-listener
ForecastJobRequest forecastJobRequest = new ForecastJobRequest("forecasting-my-first-machine-learning-job");
// 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-forecast-job-execute-async
client.machineLearning().forecastJobAsync(forecastJobRequest, RequestOptions.DEFAULT, listener); //<1>
// end::x-pack-ml-forecast-job-execute-async
assertTrue(latch.await(30L, TimeUnit.SECONDS));
}
}
public void testGetOverallBuckets() throws IOException, InterruptedException { public void testGetOverallBuckets() throws IOException, InterruptedException {
RestHighLevelClient client = highLevelClient(); RestHighLevelClient client = highLevelClient();

View File

@ -0,0 +1,51 @@
/*
* 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.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.test.AbstractXContentTestCase;
import java.io.IOException;
public class ForecastJobRequestTests extends AbstractXContentTestCase<ForecastJobRequest> {
@Override
protected ForecastJobRequest createTestInstance() {
ForecastJobRequest request = new ForecastJobRequest(randomAlphaOfLengthBetween(1, 20));
if (randomBoolean()) {
request.setExpiresIn(TimeValue.timeValueHours(randomInt(10)));
}
if (randomBoolean()) {
request.setDuration(TimeValue.timeValueHours(randomIntBetween(24, 72)));
}
return request;
}
@Override
protected ForecastJobRequest doParseInstance(XContentParser parser) throws IOException {
return ForecastJobRequest.PARSER.apply(parser, null);
}
@Override
protected boolean supportsUnknownFields() {
return false;
}
}

View File

@ -0,0 +1,42 @@
/*
* 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.common.xcontent.XContentParser;
import org.elasticsearch.test.AbstractXContentTestCase;
import java.io.IOException;
public class ForecastJobResponseTests extends AbstractXContentTestCase<ForecastJobResponse> {
@Override
protected ForecastJobResponse createTestInstance() {
return new ForecastJobResponse(randomBoolean(),randomAlphaOfLength(10));
}
@Override
protected ForecastJobResponse doParseInstance(XContentParser parser) throws IOException {
return ForecastJobResponse.PARSER.apply(parser, null);
}
@Override
protected boolean supportsUnknownFields() {
return true;
}
}

View File

@ -0,0 +1,76 @@
[[java-rest-high-x-pack-ml-forecast-job]]
=== Forecast Job API
The Forecast Job API provides the ability to forecast a {ml} job's behavior based
on historical data.
It accepts a `ForecastJobRequest` object and responds
with a `ForecastJobResponse` object.
[[java-rest-high-x-pack-ml-forecast-job-request]]
==== Forecast Job Request
A `ForecastJobRequest` object gets created with an existing non-null `jobId`.
All other fields are optional for the request.
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-forecast-job-request]
--------------------------------------------------
<1> Constructing a new request referencing an existing `jobId`
==== Optional Arguments
The following arguments are optional.
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-forecast-job-request-options]
--------------------------------------------------
<1> Set when the forecast for the job should expire
<2> Set how far into the future should the forecast predict
[[java-rest-high-x-pack-ml-forecast-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-forecast-job-execute]
--------------------------------------------------
[[java-rest-high-x-pack-ml-forecast-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-forecast-job-execute-async]
--------------------------------------------------
<1> The `ForecastJobRequest` 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 `ForecastJobResponse` may
look like
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-forecast-job-listener]
--------------------------------------------------
<1> `onResponse` is called back when the action is completed successfully
<2> `onFailure` is called back when some unexpected error occurs
[[java-rest-high-x-pack-ml-forecast-job-response]]
==== Forecast Job Response
A `ForecastJobResponse` contains an acknowledgement and the forecast ID
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-forecast-job-response]
--------------------------------------------------
<1> `isAcknowledged()` indicates if the forecast was successful
<2> `getForecastId()` provides the ID of the forecast that was created

View File

@ -218,6 +218,7 @@ The Java High Level REST Client supports the following Machine Learning APIs:
* <<java-rest-high-x-pack-ml-flush-job>> * <<java-rest-high-x-pack-ml-flush-job>>
* <<java-rest-high-x-pack-ml-update-job>> * <<java-rest-high-x-pack-ml-update-job>>
* <<java-rest-high-x-pack-ml-get-job-stats>> * <<java-rest-high-x-pack-ml-get-job-stats>>
* <<java-rest-high-x-pack-ml-forecast-job>>
* <<java-rest-high-x-pack-ml-get-buckets>> * <<java-rest-high-x-pack-ml-get-buckets>>
* <<java-rest-high-x-pack-ml-get-overall-buckets>> * <<java-rest-high-x-pack-ml-get-overall-buckets>>
* <<java-rest-high-x-pack-ml-get-records>> * <<java-rest-high-x-pack-ml-get-records>>
@ -232,6 +233,7 @@ include::ml/close-job.asciidoc[]
include::ml/update-job.asciidoc[] include::ml/update-job.asciidoc[]
include::ml/flush-job.asciidoc[] include::ml/flush-job.asciidoc[]
include::ml/get-job-stats.asciidoc[] include::ml/get-job-stats.asciidoc[]
include::ml/forecast-job.asciidoc[]
include::ml/get-buckets.asciidoc[] include::ml/get-buckets.asciidoc[]
include::ml/get-overall-buckets.asciidoc[] include::ml/get-overall-buckets.asciidoc[]
include::ml/get-records.asciidoc[] include::ml/get-records.asciidoc[]