Skip to content

Commit 32ca849

Browse files
[ML][HLRC] Adds support for reset job api
Adds HLRC support for the newly added reset anomaly detection job API.
1 parent 20ed4fe commit 32ca849

File tree

16 files changed

+635
-11
lines changed

16 files changed

+635
-11
lines changed

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
import org.elasticsearch.client.ml.PutJobRequest;
6666
import org.elasticsearch.client.ml.PutTrainedModelAliasRequest;
6767
import org.elasticsearch.client.ml.PutTrainedModelRequest;
68+
import org.elasticsearch.client.ml.ResetJobRequest;
6869
import org.elasticsearch.client.ml.RevertModelSnapshotRequest;
6970
import org.elasticsearch.client.ml.SetUpgradeModeRequest;
7071
import org.elasticsearch.client.ml.StartDataFrameAnalyticsRequest;
@@ -191,6 +192,23 @@ static Request deleteJob(DeleteJobRequest deleteJobRequest) {
191192
return request;
192193
}
193194

195+
static Request resetJob(ResetJobRequest resetJobRequest) {
196+
String endpoint = new EndpointBuilder()
197+
.addPathPartAsIs("_ml")
198+
.addPathPartAsIs("anomaly_detectors")
199+
.addPathPart(resetJobRequest.getJobId())
200+
.addPathPartAsIs("_reset")
201+
.build();
202+
Request request = new Request(HttpPost.METHOD_NAME, endpoint);
203+
204+
RequestConverters.Params params = new RequestConverters.Params();
205+
if (resetJobRequest.getWaitForCompletion() != null) {
206+
params.putParam("wait_for_completion", Boolean.toString(resetJobRequest.getWaitForCompletion()));
207+
}
208+
request.addParameters(params.asMap());
209+
return request;
210+
}
211+
194212
static Request flushJob(FlushJobRequest flushJobRequest) throws IOException {
195213
String endpoint = new EndpointBuilder()
196214
.addPathPartAsIs("_ml")

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

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,6 @@
1111
import org.elasticsearch.action.support.master.AcknowledgedResponse;
1212
import org.elasticsearch.client.ml.CloseJobRequest;
1313
import org.elasticsearch.client.ml.CloseJobResponse;
14-
import org.elasticsearch.client.ml.DeleteTrainedModelAliasRequest;
15-
import org.elasticsearch.client.ml.DeleteTrainedModelRequest;
16-
import org.elasticsearch.client.ml.EstimateModelMemoryRequest;
17-
import org.elasticsearch.client.ml.EstimateModelMemoryResponse;
18-
import org.elasticsearch.client.ml.ExplainDataFrameAnalyticsRequest;
19-
import org.elasticsearch.client.ml.ExplainDataFrameAnalyticsResponse;
2014
import org.elasticsearch.client.ml.DeleteCalendarEventRequest;
2115
import org.elasticsearch.client.ml.DeleteCalendarJobRequest;
2216
import org.elasticsearch.client.ml.DeleteCalendarRequest;
@@ -29,8 +23,14 @@
2923
import org.elasticsearch.client.ml.DeleteJobRequest;
3024
import org.elasticsearch.client.ml.DeleteJobResponse;
3125
import org.elasticsearch.client.ml.DeleteModelSnapshotRequest;
26+
import org.elasticsearch.client.ml.DeleteTrainedModelAliasRequest;
27+
import org.elasticsearch.client.ml.DeleteTrainedModelRequest;
28+
import org.elasticsearch.client.ml.EstimateModelMemoryRequest;
29+
import org.elasticsearch.client.ml.EstimateModelMemoryResponse;
3230
import org.elasticsearch.client.ml.EvaluateDataFrameRequest;
3331
import org.elasticsearch.client.ml.EvaluateDataFrameResponse;
32+
import org.elasticsearch.client.ml.ExplainDataFrameAnalyticsRequest;
33+
import org.elasticsearch.client.ml.ExplainDataFrameAnalyticsResponse;
3434
import org.elasticsearch.client.ml.FlushJobRequest;
3535
import org.elasticsearch.client.ml.FlushJobResponse;
3636
import org.elasticsearch.client.ml.ForecastJobRequest;
@@ -93,6 +93,8 @@
9393
import org.elasticsearch.client.ml.PutTrainedModelAliasRequest;
9494
import org.elasticsearch.client.ml.PutTrainedModelRequest;
9595
import org.elasticsearch.client.ml.PutTrainedModelResponse;
96+
import org.elasticsearch.client.ml.ResetJobRequest;
97+
import org.elasticsearch.client.ml.ResetJobResponse;
9698
import org.elasticsearch.client.ml.RevertModelSnapshotRequest;
9799
import org.elasticsearch.client.ml.RevertModelSnapshotResponse;
98100
import org.elasticsearch.client.ml.SetUpgradeModeRequest;
@@ -611,6 +613,46 @@ public RevertModelSnapshotResponse revertModelSnapshot(RevertModelSnapshotReques
611613
Collections.emptySet());
612614
}
613615

616+
/**
617+
* Resets the given Machine Learning Job
618+
* <p>
619+
* For additional info
620+
* see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-reset-job.html">ML Reset job documentation</a>
621+
*
622+
* @param request The request to reset the job
623+
* @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
624+
* @return The action response which contains the acknowledgement or the task id depending on whether the action was set to wait for
625+
* completion
626+
* @throws IOException when there is a serialization issue sending the request or receiving the response
627+
*/
628+
public ResetJobResponse resetJob(ResetJobRequest request, RequestOptions options) throws IOException {
629+
return restHighLevelClient.performRequestAndParseEntity(request,
630+
MLRequestConverters::resetJob,
631+
options,
632+
ResetJobResponse::fromXContent,
633+
Collections.emptySet());
634+
}
635+
636+
/**
637+
* Resets the given Machine Learning Job asynchronously and notifies the listener on completion
638+
* <p>
639+
* For additional info
640+
* see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-reset-job.html">ML Reset Job documentation</a>
641+
*
642+
* @param request The request to reset the job
643+
* @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
644+
* @param listener Listener to be notified upon request completion
645+
* @return cancellable that may be used to cancel the request
646+
*/
647+
public Cancellable resetJobAsync(ResetJobRequest request, RequestOptions options, ActionListener<ResetJobResponse> listener) {
648+
return restHighLevelClient.performRequestAsyncAndParseEntity(request,
649+
MLRequestConverters::resetJob,
650+
options,
651+
ResetJobResponse::fromXContent,
652+
listener,
653+
Collections.emptySet());
654+
}
655+
614656
/**
615657
* Reverts to a particular Machine Learning Model Snapshot asynchronously and notifies the listener on completion
616658
* <p>
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
package org.elasticsearch.client.ml;
9+
10+
import org.elasticsearch.action.ActionRequest;
11+
import org.elasticsearch.action.ActionRequestValidationException;
12+
13+
import java.util.Objects;
14+
15+
/**
16+
* Request to delete a Machine Learning Job via its ID
17+
*/
18+
public class ResetJobRequest extends ActionRequest {
19+
20+
private String jobId;
21+
private Boolean waitForCompletion;
22+
23+
public ResetJobRequest(String jobId) {
24+
this.jobId = Objects.requireNonNull(jobId, "[job_id] must not be null");
25+
}
26+
27+
public String getJobId() {
28+
return jobId;
29+
}
30+
31+
/**
32+
* The jobId which to reset
33+
* @param jobId unique jobId to reset, must not be null
34+
*/
35+
public void setJobId(String jobId) {
36+
this.jobId = Objects.requireNonNull(jobId, "[job_id] must not be null");
37+
}
38+
39+
public Boolean getWaitForCompletion() {
40+
return waitForCompletion;
41+
}
42+
43+
/**
44+
* Set whether this request should wait until the operation has completed before returning
45+
* @param waitForCompletion When {@code true} the call will wait for the job reset to complete.
46+
* Otherwise, the reset will be executed asynchronously and the response
47+
* will contain the task id.
48+
*/
49+
public void setWaitForCompletion(Boolean waitForCompletion) {
50+
this.waitForCompletion = waitForCompletion;
51+
}
52+
53+
@Override
54+
public ActionRequestValidationException validate() {
55+
return null;
56+
}
57+
58+
@Override
59+
public int hashCode() {
60+
return Objects.hash(jobId, waitForCompletion);
61+
}
62+
63+
@Override
64+
public boolean equals(Object obj) {
65+
if (this == obj) {
66+
return true;
67+
}
68+
69+
if (obj == null || obj.getClass() != getClass()) {
70+
return false;
71+
}
72+
73+
ResetJobRequest other = (ResetJobRequest) obj;
74+
return Objects.equals(jobId, other.jobId) && Objects.equals(waitForCompletion, other.waitForCompletion);
75+
}
76+
77+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
package org.elasticsearch.client.ml;
9+
10+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
11+
import org.elasticsearch.common.xcontent.ObjectParser;
12+
import org.elasticsearch.common.xcontent.ParseField;
13+
import org.elasticsearch.common.xcontent.ToXContentObject;
14+
import org.elasticsearch.common.xcontent.XContentBuilder;
15+
import org.elasticsearch.common.xcontent.XContentParser;
16+
import org.elasticsearch.core.Nullable;
17+
import org.elasticsearch.tasks.TaskId;
18+
19+
import java.io.IOException;
20+
import java.util.Objects;
21+
22+
/**
23+
* Response object that contains the acknowledgement or the task id
24+
* depending on whether the reset job action was requested to wait for completion.
25+
*/
26+
public class ResetJobResponse implements ToXContentObject {
27+
28+
private static final ParseField ACKNOWLEDGED = new ParseField("acknowledged");
29+
private static final ParseField TASK = new ParseField("task");
30+
31+
public static final ConstructingObjectParser<ResetJobResponse, Void> PARSER = new ConstructingObjectParser<>("reset_job_response",
32+
true, a-> new ResetJobResponse((Boolean) a[0], (TaskId) a[1]));
33+
34+
static {
35+
PARSER.declareBoolean(ConstructingObjectParser.optionalConstructorArg(), ACKNOWLEDGED);
36+
PARSER.declareField(ConstructingObjectParser.optionalConstructorArg(), TaskId.parser(), TASK, ObjectParser.ValueType.STRING);
37+
}
38+
39+
public static ResetJobResponse fromXContent(XContentParser parser) throws IOException {
40+
return PARSER.parse(parser, null);
41+
}
42+
43+
private final Boolean acknowledged;
44+
private final TaskId task;
45+
46+
ResetJobResponse(@Nullable Boolean acknowledged, @Nullable TaskId task) {
47+
assert acknowledged != null || task != null;
48+
this.acknowledged = acknowledged;
49+
this.task = task;
50+
}
51+
52+
/**
53+
* Get the action acknowledgement
54+
* @return {@code null} when the request had {@link ResetJobRequest#getWaitForCompletion()} set to {@code false} or
55+
* otherwise a {@code boolean} that indicates whether the job was reset successfully.
56+
*/
57+
public Boolean getAcknowledged() {
58+
return acknowledged;
59+
}
60+
61+
/**
62+
* Get the task id
63+
* @return {@code null} when the request had {@link ResetJobRequest#getWaitForCompletion()} set to {@code true} or
64+
* otherwise the id of the job reset task.
65+
*/
66+
public TaskId getTask() {
67+
return task;
68+
}
69+
70+
@Override
71+
public int hashCode() {
72+
return Objects.hash(acknowledged, task);
73+
}
74+
75+
@Override
76+
public boolean equals(Object other) {
77+
if (this == other) {
78+
return true;
79+
}
80+
81+
if (other == null || getClass() != other.getClass()) {
82+
return false;
83+
}
84+
85+
ResetJobResponse that = (ResetJobResponse) other;
86+
return Objects.equals(acknowledged, that.acknowledged) && Objects.equals(task, that.task);
87+
}
88+
89+
@Override
90+
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
91+
builder.startObject();
92+
if (acknowledged != null) {
93+
builder.field(ACKNOWLEDGED.getPreferredName(), acknowledged);
94+
}
95+
if (task != null) {
96+
builder.field(TASK.getPreferredName(), task.toString());
97+
}
98+
builder.endObject();
99+
return builder;
100+
}
101+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.client.ml.job.config;
10+
11+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
12+
import org.elasticsearch.common.xcontent.ParseField;
13+
import org.elasticsearch.common.xcontent.ToXContentObject;
14+
import org.elasticsearch.common.xcontent.XContentBuilder;
15+
import org.elasticsearch.core.Nullable;
16+
import org.elasticsearch.tasks.TaskId;
17+
18+
import java.io.IOException;
19+
import java.util.Locale;
20+
import java.util.Objects;
21+
22+
public class Blocked implements ToXContentObject {
23+
24+
public enum Reason {
25+
NONE, DELETE, RESET, REVERT;
26+
27+
public static Reason fromString(String value) {
28+
return Reason.valueOf(value.toUpperCase(Locale.ROOT));
29+
}
30+
31+
@Override
32+
public String toString() {
33+
return name().toLowerCase(Locale.ROOT);
34+
}
35+
}
36+
37+
public static final ParseField REASON = new ParseField("reason");
38+
public static final ParseField TASK_ID = new ParseField("task_id");
39+
40+
public static final ConstructingObjectParser<Blocked, Void> PARSER = new ConstructingObjectParser<>("blocked", true,
41+
a -> new Blocked((Reason) a[0], (TaskId) a[1]));
42+
43+
static {
44+
PARSER.declareString(ConstructingObjectParser.constructorArg(), Reason::fromString, REASON);
45+
PARSER.declareString(ConstructingObjectParser.optionalConstructorArg(), TaskId::new, TASK_ID);
46+
}
47+
48+
private final Reason reason;
49+
50+
@Nullable
51+
private final TaskId taskId;
52+
53+
public Blocked(Reason reason, @Nullable TaskId taskId) {
54+
this.reason = Objects.requireNonNull(reason);
55+
this.taskId = taskId;
56+
}
57+
58+
public Reason getReason() {
59+
return reason;
60+
}
61+
62+
@Nullable
63+
public TaskId getTaskId() {
64+
return taskId;
65+
}
66+
67+
@Override
68+
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
69+
builder.startObject();
70+
builder.field(REASON.getPreferredName(), reason);
71+
if (taskId != null) {
72+
builder.field(TASK_ID.getPreferredName(), taskId.toString());
73+
}
74+
builder.endObject();
75+
return builder;
76+
}
77+
78+
@Override
79+
public int hashCode() {
80+
return Objects.hash(reason, taskId);
81+
}
82+
83+
@Override
84+
public boolean equals(Object o) {
85+
if (this == o) return true;
86+
if (o == null || getClass() != o.getClass()) return false;
87+
88+
Blocked that = (Blocked) o;
89+
return Objects.equals(reason, that.reason) && Objects.equals(taskId, that.taskId);
90+
}
91+
}

0 commit comments

Comments
 (0)