Skip to content

Commit 0ce36fc

Browse files
committed
HLRC: adding machine learning open job (#32860)
* HLRC: adding machine learning open job HLRC: adding ML open job API call * Addressing @droberts195 comments and fixing minor style issue
1 parent 11c635d commit 0ce36fc

File tree

13 files changed

+495
-4
lines changed

13 files changed

+495
-4
lines changed

client/rest-high-level/src/main/java/org/elasticsearch/client/MachineLearningClient.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
package org.elasticsearch.client;
2020

2121
import org.elasticsearch.action.ActionListener;
22+
import org.elasticsearch.protocol.xpack.ml.OpenJobRequest;
23+
import org.elasticsearch.protocol.xpack.ml.OpenJobResponse;
2224
import org.elasticsearch.protocol.xpack.ml.PutJobRequest;
2325
import org.elasticsearch.protocol.xpack.ml.PutJobResponse;
2426

@@ -77,4 +79,51 @@ public void putJobAsync(PutJobRequest request, RequestOptions options, ActionLis
7779
listener,
7880
Collections.emptySet());
7981
}
82+
83+
/**
84+
* Opens a Machine Learning Job.
85+
* When you open a new job, it starts with an empty model.
86+
*
87+
* When you open an existing job, the most recent model state is automatically loaded.
88+
* The job is ready to resume its analysis from where it left off, once new data is received.
89+
*
90+
* <p>
91+
* For additional info
92+
* see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-open-job.html"></a>
93+
* </p>
94+
* @param request request containing job_id and additional optional options
95+
* @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
96+
* @return response containing if the job was successfully opened or not.
97+
* @throws IOException when there is a serialization issue sending the request or receiving the response
98+
*/
99+
public OpenJobResponse openJob(OpenJobRequest request, RequestOptions options) throws IOException {
100+
return restHighLevelClient.performRequestAndParseEntity(request,
101+
RequestConverters::machineLearningOpenJob,
102+
options,
103+
OpenJobResponse::fromXContent,
104+
Collections.emptySet());
105+
}
106+
107+
/**
108+
* Opens a Machine Learning Job asynchronously, notifies listener on completion.
109+
* When you open a new job, it starts with an empty model.
110+
*
111+
* When you open an existing job, the most recent model state is automatically loaded.
112+
* The job is ready to resume its analysis from where it left off, once new data is received.
113+
* <p>
114+
* For additional info
115+
* see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-open-job.html"></a>
116+
* </p>
117+
* @param request request containing job_id and additional optional options
118+
* @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
119+
* @param listener Listener to be notified upon request completion
120+
*/
121+
public void openJobAsync(OpenJobRequest request, RequestOptions options, ActionListener<OpenJobResponse> listener) {
122+
restHighLevelClient.performRequestAsyncAndParseEntity(request,
123+
RequestConverters::machineLearningOpenJob,
124+
options,
125+
OpenJobResponse::fromXContent,
126+
listener,
127+
Collections.emptySet());
128+
}
80129
}

client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@
112112
import org.elasticsearch.protocol.xpack.license.GetLicenseRequest;
113113
import org.elasticsearch.protocol.xpack.license.PutLicenseRequest;
114114
import org.elasticsearch.protocol.xpack.migration.IndexUpgradeInfoRequest;
115+
import org.elasticsearch.protocol.xpack.ml.OpenJobRequest;
115116
import org.elasticsearch.protocol.xpack.ml.PutJobRequest;
116117
import org.elasticsearch.protocol.xpack.watcher.DeleteWatchRequest;
117118
import org.elasticsearch.protocol.xpack.watcher.PutWatchRequest;
@@ -1221,6 +1222,19 @@ static Request putMachineLearningJob(PutJobRequest putJobRequest) throws IOExcep
12211222
return request;
12221223
}
12231224

1225+
static Request machineLearningOpenJob(OpenJobRequest openJobRequest) throws IOException {
1226+
String endpoint = new EndpointBuilder()
1227+
.addPathPartAsIs("_xpack")
1228+
.addPathPartAsIs("ml")
1229+
.addPathPartAsIs("anomaly_detectors")
1230+
.addPathPart(openJobRequest.getJobId())
1231+
.addPathPartAsIs("_open")
1232+
.build();
1233+
Request request = new Request(HttpPost.METHOD_NAME, endpoint);
1234+
request.setJsonEntity(openJobRequest.toString());
1235+
return request;
1236+
}
1237+
12241238
static Request getMigrationAssistance(IndexUpgradeInfoRequest indexUpgradeInfoRequest) {
12251239
EndpointBuilder endpointBuilder = new EndpointBuilder()
12261240
.addPathPartAsIs("_xpack/migration/assistance")

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
import com.carrotsearch.randomizedtesting.generators.CodepointSetGenerator;
2222
import org.elasticsearch.common.unit.TimeValue;
23+
import org.elasticsearch.protocol.xpack.ml.OpenJobRequest;
24+
import org.elasticsearch.protocol.xpack.ml.OpenJobResponse;
2325
import org.elasticsearch.protocol.xpack.ml.PutJobRequest;
2426
import org.elasticsearch.protocol.xpack.ml.PutJobResponse;
2527
import org.elasticsearch.protocol.xpack.ml.job.config.AnalysisConfig;
@@ -46,12 +48,24 @@ public void testPutJob() throws Exception {
4648
assertThat(createdJob.getJobType(), is(Job.ANOMALY_DETECTOR_JOB_TYPE));
4749
}
4850

51+
public void testOpenJob() throws Exception {
52+
String jobId = randomValidJobId();
53+
Job job = buildJob(jobId);
54+
MachineLearningClient machineLearningClient = highLevelClient().machineLearning();
55+
56+
machineLearningClient.putJob(new PutJobRequest(job), RequestOptions.DEFAULT);
57+
58+
OpenJobResponse response = execute(new OpenJobRequest(jobId), machineLearningClient::openJob, machineLearningClient::openJobAsync);
59+
60+
assertTrue(response.isOpened());
61+
}
62+
4963
public static String randomValidJobId() {
5064
CodepointSetGenerator generator = new CodepointSetGenerator("abcdefghijklmnopqrstuvwxyz0123456789".toCharArray());
5165
return generator.ofCodePointsLength(random(), 10, 10);
5266
}
5367

54-
private static Job buildJob(String jobId) {
68+
public static Job buildJob(String jobId) {
5569
Job.Builder builder = new Job.Builder(jobId);
5670
builder.setDescription(randomAlphaOfLength(10));
5771

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@
128128
import org.elasticsearch.index.rankeval.RestRankEvalAction;
129129
import org.elasticsearch.protocol.xpack.XPackInfoRequest;
130130
import org.elasticsearch.protocol.xpack.migration.IndexUpgradeInfoRequest;
131+
import org.elasticsearch.protocol.xpack.ml.OpenJobRequest;
131132
import org.elasticsearch.protocol.xpack.watcher.DeleteWatchRequest;
132133
import org.elasticsearch.protocol.xpack.watcher.PutWatchRequest;
133134
import org.elasticsearch.repositories.fs.FsRepository;
@@ -2644,6 +2645,19 @@ public void testXPackDeleteWatch() {
26442645
assertThat(request.getEntity(), nullValue());
26452646
}
26462647

2648+
public void testPostMachineLearningOpenJob() throws Exception {
2649+
String jobId = "some-job-id";
2650+
OpenJobRequest openJobRequest = new OpenJobRequest(jobId);
2651+
openJobRequest.setTimeout(TimeValue.timeValueMinutes(10));
2652+
2653+
Request request = RequestConverters.machineLearningOpenJob(openJobRequest);
2654+
assertEquals(HttpPost.METHOD_NAME, request.getMethod());
2655+
assertEquals("/_xpack/ml/anomaly_detectors/" + jobId + "/_open", request.getEndpoint());
2656+
ByteArrayOutputStream bos = new ByteArrayOutputStream();
2657+
request.getEntity().writeTo(bos);
2658+
assertEquals(bos.toString("UTF-8"), "{\"job_id\":\""+ jobId +"\",\"timeout\":\"10m\"}");
2659+
}
2660+
26472661
/**
26482662
* Randomize the {@link FetchSourceContext} request parameters.
26492663
*/

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

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,12 @@
2121
import org.elasticsearch.action.ActionListener;
2222
import org.elasticsearch.action.LatchedActionListener;
2323
import org.elasticsearch.client.ESRestHighLevelClientTestCase;
24+
import org.elasticsearch.client.MachineLearningIT;
2425
import org.elasticsearch.client.RequestOptions;
2526
import org.elasticsearch.client.RestHighLevelClient;
2627
import org.elasticsearch.common.unit.TimeValue;
28+
import org.elasticsearch.protocol.xpack.ml.OpenJobRequest;
29+
import org.elasticsearch.protocol.xpack.ml.OpenJobResponse;
2730
import org.elasticsearch.protocol.xpack.ml.PutJobRequest;
2831
import org.elasticsearch.protocol.xpack.ml.PutJobResponse;
2932
import org.elasticsearch.protocol.xpack.ml.job.config.AnalysisConfig;
@@ -118,4 +121,54 @@ public void onFailure(Exception e) {
118121
assertTrue(latch.await(30L, TimeUnit.SECONDS));
119122
}
120123
}
124+
125+
public void testOpenJob() throws Exception {
126+
RestHighLevelClient client = highLevelClient();
127+
128+
Job job = MachineLearningIT.buildJob("opening-my-first-machine-learning-job");
129+
client.machineLearning().putJob(new PutJobRequest(job), RequestOptions.DEFAULT);
130+
131+
Job secondJob = MachineLearningIT.buildJob("opening-my-second-machine-learning-job");
132+
client.machineLearning().putJob(new PutJobRequest(secondJob), RequestOptions.DEFAULT);
133+
134+
{
135+
//tag::x-pack-ml-open-job-request
136+
OpenJobRequest openJobRequest = new OpenJobRequest("opening-my-first-machine-learning-job"); //<1>
137+
openJobRequest.setTimeout(TimeValue.timeValueMinutes(10)); //<2>
138+
//end::x-pack-ml-open-job-request
139+
140+
//tag::x-pack-ml-open-job-execute
141+
OpenJobResponse openJobResponse = client.machineLearning().openJob(openJobRequest, RequestOptions.DEFAULT);
142+
boolean isOpened = openJobResponse.isOpened(); //<1>
143+
//end::x-pack-ml-open-job-execute
144+
145+
}
146+
147+
{
148+
//tag::x-pack-ml-open-job-listener
149+
ActionListener<OpenJobResponse> listener = new ActionListener<OpenJobResponse>() {
150+
@Override
151+
public void onResponse(OpenJobResponse openJobResponse) {
152+
//<1>
153+
}
154+
155+
@Override
156+
public void onFailure(Exception e) {
157+
//<2>
158+
}
159+
};
160+
//end::x-pack-ml-open-job-listener
161+
OpenJobRequest openJobRequest = new OpenJobRequest("opening-my-second-machine-learning-job");
162+
// Replace the empty listener by a blocking listener in test
163+
final CountDownLatch latch = new CountDownLatch(1);
164+
listener = new LatchedActionListener<>(listener, latch);
165+
166+
// tag::x-pack-ml-open-job-execute-async
167+
client.machineLearning().openJobAsync(openJobRequest, RequestOptions.DEFAULT, listener); //<1>
168+
// end::x-pack-ml-open-job-execute-async
169+
170+
assertTrue(latch.await(30L, TimeUnit.SECONDS));
171+
}
172+
173+
}
121174
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
[[java-rest-high-x-pack-ml-open-job]]
2+
=== Open Job API
3+
4+
The Open Job API provides the ability to open {ml} jobs in the cluster.
5+
It accepts a `OpenJobRequest` object and responds
6+
with a `OpenJobResponse` object.
7+
8+
[[java-rest-high-x-pack-ml-open-job-request]]
9+
==== Open Job Request
10+
11+
An `OpenJobRequest` object gets created with an existing non-null `jobId`.
12+
13+
["source","java",subs="attributes,callouts,macros"]
14+
--------------------------------------------------
15+
include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-open-job-request]
16+
--------------------------------------------------
17+
<1> Constructing a new request referencing an existing `jobId`
18+
<2> Optionally setting the `timeout` value for how long the
19+
execution should wait for the job to be opened.
20+
21+
[[java-rest-high-x-pack-ml-open-job-execution]]
22+
==== Execution
23+
24+
The request can be executed through the `MachineLearningClient` contained
25+
in the `RestHighLevelClient` object, accessed via the `machineLearningClient()` method.
26+
27+
["source","java",subs="attributes,callouts,macros"]
28+
--------------------------------------------------
29+
include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-open-job-execute]
30+
--------------------------------------------------
31+
<1> `isOpened()` from the `OpenJobResponse` indicates if the job was successfully
32+
opened or not.
33+
34+
[[java-rest-high-x-pack-ml-open-job-execution-async]]
35+
==== Asynchronous Execution
36+
37+
The request can also be executed asynchronously:
38+
39+
["source","java",subs="attributes,callouts,macros"]
40+
--------------------------------------------------
41+
include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-open-job-execute-async]
42+
--------------------------------------------------
43+
<1> The `OpenJobRequest` to execute and the `ActionListener` to use when
44+
the execution completes
45+
46+
The method does not block and returns immediately. The passed `ActionListener` is used
47+
to notify the caller of completion. A typical `ActionListner` for `OpenJobResponse` may
48+
look like
49+
50+
["source","java",subs="attributes,callouts,macros"]
51+
--------------------------------------------------
52+
include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-open-job-listener]
53+
--------------------------------------------------
54+
<1> `onResponse` is called back when the action is completed successfully
55+
<2> `onFailure` is called back when some unexpected error occurs
File renamed without changes.

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,10 @@ include::licensing/delete-license.asciidoc[]
205205
The Java High Level REST Client supports the following Machine Learning APIs:
206206

207207
* <<java-rest-high-x-pack-ml-put-job>>
208+
* <<java-rest-high-x-pack-ml-open-job>>
208209

209-
include::ml/put_job.asciidoc[]
210+
include::ml/put-job.asciidoc[]
211+
include::ml/open-job.asciidoc[]
210212

211213
== Migration APIs
212214

0 commit comments

Comments
 (0)