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 aa998591159f6..62c1740ab8250 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
@@ -61,6 +61,7 @@
import org.elasticsearch.client.ml.UpdateDatafeedRequest;
import org.elasticsearch.client.ml.UpdateFilterRequest;
import org.elasticsearch.client.ml.UpdateJobRequest;
+import org.elasticsearch.client.ml.UpdateModelSnapshotRequest;
import org.elasticsearch.client.ml.job.util.PageParams;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
@@ -391,6 +392,21 @@ static Request getModelSnapshots(GetModelSnapshotsRequest getModelSnapshotsReque
return request;
}
+ static Request updateModelSnapshot(UpdateModelSnapshotRequest updateModelSnapshotRequest) throws IOException {
+ String endpoint = new EndpointBuilder()
+ .addPathPartAsIs("_xpack")
+ .addPathPartAsIs("ml")
+ .addPathPartAsIs("anomaly_detectors")
+ .addPathPart(updateModelSnapshotRequest.getJobId())
+ .addPathPartAsIs("model_snapshots")
+ .addPathPart(updateModelSnapshotRequest.getSnapshotId())
+ .addPathPartAsIs("_update")
+ .build();
+ Request request = new Request(HttpPost.METHOD_NAME, endpoint);
+ request.setEntity(createEntity(updateModelSnapshotRequest, REQUEST_BODY_CONTENT_TYPE));
+ return request;
+ }
+
static Request getOverallBuckets(GetOverallBucketsRequest getOverallBucketsRequest) throws IOException {
String endpoint = new EndpointBuilder()
.addPathPartAsIs("_xpack")
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/MachineLearningClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/MachineLearningClient.java
index a35bbb042e7a2..c34385bc7599e 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
@@ -79,6 +79,8 @@
import org.elasticsearch.client.ml.UpdateDatafeedRequest;
import org.elasticsearch.client.ml.UpdateFilterRequest;
import org.elasticsearch.client.ml.UpdateJobRequest;
+import org.elasticsearch.client.ml.UpdateModelSnapshotRequest;
+import org.elasticsearch.client.ml.UpdateModelSnapshotResponse;
import org.elasticsearch.client.ml.job.stats.JobStats;
import java.io.IOException;
@@ -984,6 +986,47 @@ public void getModelSnapshotsAsync(GetModelSnapshotsRequest request, RequestOpti
Collections.emptySet());
}
+ /**
+ * Updates a snapshot for a Machine Learning Job.
+ *
+ * For additional info
+ * see
+ * ML UPDATE model snapshots documentation
+ *
+ * @param request The request
+ * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @throws IOException when there is a serialization issue sending the request or receiving the response
+ */
+ public UpdateModelSnapshotResponse updateModelSnapshot(UpdateModelSnapshotRequest request,
+ RequestOptions options) throws IOException {
+ return restHighLevelClient.performRequestAndParseEntity(request,
+ MLRequestConverters::updateModelSnapshot,
+ options,
+ UpdateModelSnapshotResponse::fromXContent,
+ Collections.emptySet());
+ }
+
+ /**
+ * Updates a snapshot for a Machine Learning Job, notifies listener once the requested snapshots are retrieved.
+ *
+ * For additional info
+ * see
+ * ML UPDATE model snapshots documentation
+ *
+ * @param request The request
+ * @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 updateModelSnapshotAsync(UpdateModelSnapshotRequest request, RequestOptions options,
+ ActionListener listener) {
+ restHighLevelClient.performRequestAsyncAndParseEntity(request,
+ MLRequestConverters::updateModelSnapshot,
+ options,
+ UpdateModelSnapshotResponse::fromXContent,
+ listener,
+ Collections.emptySet());
+ }
+
/**
* Gets overall buckets for a set of Machine Learning Jobs.
*
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/UpdateModelSnapshotRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/UpdateModelSnapshotRequest.java
new file mode 100644
index 0000000000000..b2b6417ab2edb
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/UpdateModelSnapshotRequest.java
@@ -0,0 +1,135 @@
+/*
+ * 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.client.ml.job.process.ModelSnapshot;
+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.Objects;
+
+/**
+ * A request to update information about an existing model snapshot for a given job
+ */
+public class UpdateModelSnapshotRequest extends ActionRequest implements ToXContentObject {
+
+
+ public static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(
+ "update_model_snapshot_request", a -> new UpdateModelSnapshotRequest((String) a[0], (String) a[1]));
+
+
+ static {
+ PARSER.declareString(ConstructingObjectParser.constructorArg(), Job.ID);
+ PARSER.declareString(ConstructingObjectParser.constructorArg(), ModelSnapshot.SNAPSHOT_ID);
+ PARSER.declareStringOrNull(UpdateModelSnapshotRequest::setDescription, ModelSnapshot.DESCRIPTION);
+ PARSER.declareBoolean(UpdateModelSnapshotRequest::setRetain, ModelSnapshot.RETAIN);
+ }
+
+ private final String jobId;
+ private String snapshotId;
+ private String description;
+ private Boolean retain;
+
+ /**
+ * Constructs a request to update information for a snapshot of given job
+ * @param jobId id of the job from which to retrieve results
+ * @param snapshotId id of the snapshot from which to retrieve results
+ */
+ public UpdateModelSnapshotRequest(String jobId, String snapshotId) {
+ this.jobId = Objects.requireNonNull(jobId, "[" + Job.ID + "] must not be null");
+ this.snapshotId = Objects.requireNonNull(snapshotId, "[" + ModelSnapshot.SNAPSHOT_ID + "] must not be null");
+ }
+
+ public String getJobId() {
+ return jobId;
+ }
+
+ public String getSnapshotId() {
+ return snapshotId;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * The new description of the snapshot.
+ * @param description the updated snapshot description
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public Boolean getRetain() {
+ return retain;
+ }
+
+ /**
+ * The new value of the "retain" property of the snapshot
+ * @param retain the updated retain property
+ */
+ public void setRetain(boolean retain) {
+ this.retain = retain;
+ }
+
+ @Override
+ public ActionRequestValidationException validate() {
+ return null;
+ }
+
+ @Override
+ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+ builder.startObject();
+ builder.field(Job.ID.getPreferredName(), jobId);
+ builder.field(ModelSnapshot.SNAPSHOT_ID.getPreferredName(), snapshotId);
+ if (description != null) {
+ builder.field(ModelSnapshot.DESCRIPTION.getPreferredName(), description);
+ }
+ if (retain != null) {
+ builder.field(ModelSnapshot.RETAIN.getPreferredName(), retain);
+ }
+ builder.endObject();
+ return builder;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ UpdateModelSnapshotRequest request = (UpdateModelSnapshotRequest) obj;
+ return Objects.equals(jobId, request.jobId)
+ && Objects.equals(snapshotId, request.snapshotId)
+ && Objects.equals(description, request.description)
+ && Objects.equals(retain, request.retain);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(jobId, snapshotId, description, retain);
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/UpdateModelSnapshotResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/UpdateModelSnapshotResponse.java
new file mode 100644
index 0000000000000..049a24c02d10a
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/UpdateModelSnapshotResponse.java
@@ -0,0 +1,109 @@
+/*
+ * 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.client.ml.job.process.ModelSnapshot;
+import org.elasticsearch.common.ParseField;
+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 org.elasticsearch.common.xcontent.XContentParser;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * A response acknowledging the update of information for an existing model snapshot for a given job
+ */
+public class UpdateModelSnapshotResponse extends ActionResponse implements ToXContentObject {
+
+ private static final ParseField ACKNOWLEDGED = new ParseField("acknowledged");
+ private static final ParseField MODEL = new ParseField("model");
+
+ public UpdateModelSnapshotResponse(boolean acknowledged, ModelSnapshot.Builder modelSnapshot) {
+ this.acknowledged = acknowledged;
+ this.model = modelSnapshot.build();
+ }
+
+ public static final ConstructingObjectParser PARSER =
+ new ConstructingObjectParser<>("update_model_snapshot_response", true,
+ a -> new UpdateModelSnapshotResponse((Boolean) a[0], ((ModelSnapshot.Builder) a[1])));
+
+ static {
+ PARSER.declareBoolean(ConstructingObjectParser.constructorArg(), ACKNOWLEDGED);
+ PARSER.declareObject(ConstructingObjectParser.constructorArg(), ModelSnapshot.PARSER, MODEL);
+ }
+
+ public static UpdateModelSnapshotResponse fromXContent(XContentParser parser) throws IOException {
+ return PARSER.parse(parser, null);
+ }
+
+ private final Boolean acknowledged;
+ private final ModelSnapshot model;
+
+ /**
+ * Get the action acknowledgement
+ * @return a {@code boolean} that indicates whether the model snapshot was updated successfully.
+ */
+ public Boolean getAcknowledged() {
+ return acknowledged;
+ }
+
+ /**
+ * Get the updated snapshot of the model
+ * @return the updated model snapshot.
+ */
+ public ModelSnapshot getModel() {
+ return model;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(acknowledged, model);
+ }
+
+ @Override
+ public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
+ builder.startObject();
+ if (acknowledged != null) {
+ builder.field(ACKNOWLEDGED.getPreferredName(), acknowledged);
+ }
+ if (model != null) {
+ builder.field(MODEL.getPreferredName(), model);
+ }
+ builder.endObject();
+ return builder;
+ }
+
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ UpdateModelSnapshotResponse request = (UpdateModelSnapshotResponse) obj;
+ return Objects.equals(acknowledged, request.acknowledged)
+ && Objects.equals(model, request.model);
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/job/process/ModelSnapshot.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/job/process/ModelSnapshot.java
index 603bff0d90653..5d95e091d40b1 100644
--- a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/job/process/ModelSnapshot.java
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/job/process/ModelSnapshot.java
@@ -176,6 +176,10 @@ public Quantiles getQuantiles() {
return quantiles;
}
+ public boolean getRetain() {
+ return retain;
+ }
+
public Date getLatestRecordTimeStamp() {
return latestRecordTimeStamp;
}
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 a38584b0d020e..b47ee4d4bbb12 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
@@ -57,6 +57,7 @@
import org.elasticsearch.client.ml.StopDatafeedRequest;
import org.elasticsearch.client.ml.UpdateFilterRequest;
import org.elasticsearch.client.ml.UpdateJobRequest;
+import org.elasticsearch.client.ml.UpdateModelSnapshotRequest;
import org.elasticsearch.client.ml.calendars.Calendar;
import org.elasticsearch.client.ml.calendars.CalendarTests;
import org.elasticsearch.client.ml.datafeed.DatafeedConfig;
@@ -422,6 +423,22 @@ public void testGetModelSnapshots() throws IOException {
}
}
+ public void testUpdateModelSnapshot() throws IOException {
+ String jobId = randomAlphaOfLength(10);
+ String snapshotId = randomAlphaOfLength(10);
+ UpdateModelSnapshotRequest updateModelSnapshotRequest = new UpdateModelSnapshotRequest(jobId, snapshotId);
+ updateModelSnapshotRequest.setDescription("My First Snapshot");
+ updateModelSnapshotRequest.setRetain(true);
+
+ Request request = MLRequestConverters.updateModelSnapshot(updateModelSnapshotRequest);
+ assertEquals(HttpPost.METHOD_NAME, request.getMethod());
+ assertEquals("/_xpack/ml/anomaly_detectors/" + jobId + "/model_snapshots/" + snapshotId + "/_update", request.getEndpoint());
+ try (XContentParser parser = createParser(JsonXContent.jsonXContent, request.getEntity().getContent())) {
+ UpdateModelSnapshotRequest parsedRequest = UpdateModelSnapshotRequest.PARSER.apply(parser, null);
+ assertThat(parsedRequest, equalTo(updateModelSnapshotRequest));
+ }
+ }
+
public void testGetOverallBuckets() throws IOException {
String jobId = randomAlphaOfLength(10);
GetOverallBucketsRequest getOverallBucketsRequest = new GetOverallBucketsRequest(jobId);
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 bffdc1aa1a07b..4b52c8d8d5419 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
@@ -52,6 +52,8 @@
import org.elasticsearch.client.ml.GetJobResponse;
import org.elasticsearch.client.ml.GetJobStatsRequest;
import org.elasticsearch.client.ml.GetJobStatsResponse;
+import org.elasticsearch.client.ml.GetModelSnapshotsRequest;
+import org.elasticsearch.client.ml.GetModelSnapshotsResponse;
import org.elasticsearch.client.ml.OpenJobRequest;
import org.elasticsearch.client.ml.OpenJobResponse;
import org.elasticsearch.client.ml.PostDataRequest;
@@ -74,6 +76,8 @@
import org.elasticsearch.client.ml.UpdateDatafeedRequest;
import org.elasticsearch.client.ml.UpdateFilterRequest;
import org.elasticsearch.client.ml.UpdateJobRequest;
+import org.elasticsearch.client.ml.UpdateModelSnapshotRequest;
+import org.elasticsearch.client.ml.UpdateModelSnapshotResponse;
import org.elasticsearch.client.ml.calendars.Calendar;
import org.elasticsearch.client.ml.calendars.CalendarTests;
import org.elasticsearch.client.ml.datafeed.DatafeedConfig;
@@ -1047,10 +1051,11 @@ private String createAndPutDatafeed(String jobId, String indexName) throws IOExc
}
public void createModelSnapshot(String jobId, String snapshotId) throws IOException {
+ String documentId = jobId + "_model_snapshot_" + snapshotId;
Job job = MachineLearningIT.buildJob(jobId);
highLevelClient().machineLearning().putJob(new PutJobRequest(job), RequestOptions.DEFAULT);
- IndexRequest indexRequest = new IndexRequest(".ml-anomalies-shared", "doc");
+ IndexRequest indexRequest = new IndexRequest(".ml-anomalies-shared", "doc", documentId);
indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
indexRequest.source("{\"job_id\":\"" + jobId + "\", \"timestamp\":1541587919000, " +
"\"description\":\"State persisted due to job close at 2018-11-07T10:51:59+0000\", " +
@@ -1079,4 +1084,40 @@ public void testDeleteModelSnapshot() throws IOException {
assertTrue(response.isAcknowledged());
}
+
+ public void testUpdateModelSnapshot() throws Exception {
+ String jobId = "test-update-model-snapshot";
+
+ String snapshotId = "1541587919";
+ createModelSnapshot(jobId, snapshotId);
+
+ MachineLearningClient machineLearningClient = highLevelClient().machineLearning();
+
+ GetModelSnapshotsRequest getModelSnapshotsRequest = new GetModelSnapshotsRequest(jobId);
+
+ GetModelSnapshotsResponse getModelSnapshotsResponse1 = execute(getModelSnapshotsRequest, machineLearningClient::getModelSnapshots,
+ machineLearningClient::getModelSnapshotsAsync);
+
+ assertEquals(getModelSnapshotsResponse1.count(), 1L);
+ assertEquals("State persisted due to job close at 2018-11-07T10:51:59+0000",
+ getModelSnapshotsResponse1.snapshots().get(0).getDescription());
+
+ UpdateModelSnapshotRequest request = new UpdateModelSnapshotRequest(jobId, snapshotId);
+ request.setDescription("Updated description");
+ request.setRetain(true);
+
+ UpdateModelSnapshotResponse response = execute(request, machineLearningClient::updateModelSnapshot,
+ machineLearningClient::updateModelSnapshotAsync);
+
+ assertTrue(response.getAcknowledged());
+ assertEquals("Updated description", response.getModel().getDescription());
+ assertTrue(response.getModel().getRetain());
+
+ GetModelSnapshotsResponse getModelSnapshotsResponse2 = execute(getModelSnapshotsRequest, machineLearningClient::getModelSnapshots,
+ machineLearningClient::getModelSnapshotsAsync);
+
+ assertEquals(getModelSnapshotsResponse2.count(), 1L);
+ assertEquals("Updated description",
+ getModelSnapshotsResponse2.snapshots().get(0).getDescription());
+ }
}
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 a2f29fae60a0d..38203a38d8144 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
@@ -92,6 +92,8 @@
import org.elasticsearch.client.ml.UpdateDatafeedRequest;
import org.elasticsearch.client.ml.UpdateFilterRequest;
import org.elasticsearch.client.ml.UpdateJobRequest;
+import org.elasticsearch.client.ml.UpdateModelSnapshotRequest;
+import org.elasticsearch.client.ml.UpdateModelSnapshotResponse;
import org.elasticsearch.client.ml.calendars.Calendar;
import org.elasticsearch.client.ml.datafeed.ChunkingConfig;
import org.elasticsearch.client.ml.datafeed.DatafeedConfig;
@@ -2042,6 +2044,82 @@ public void onFailure(Exception e) {
}
}
+ public void testUpdateModelSnapshot() throws IOException, InterruptedException {
+ RestHighLevelClient client = highLevelClient();
+
+ String jobId = "test-update-model-snapshot";
+ String snapshotId = "1541587919";
+ String documentId = jobId + "_model_snapshot_" + snapshotId;
+ Job job = MachineLearningIT.buildJob(jobId);
+ client.machineLearning().putJob(new PutJobRequest(job), RequestOptions.DEFAULT);
+
+ // Let us index a snapshot
+ IndexRequest indexRequest = new IndexRequest(".ml-anomalies-shared", "doc", documentId);
+ indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
+ indexRequest.source("{\"job_id\":\"test-update-model-snapshot\", \"timestamp\":1541587919000, " +
+ "\"description\":\"State persisted due to job close at 2018-11-07T10:51:59+0000\", " +
+ "\"snapshot_id\":\"1541587919\", \"snapshot_doc_count\":1, \"model_size_stats\":{" +
+ "\"job_id\":\"test-update-model-snapshot\", \"result_type\":\"model_size_stats\",\"model_bytes\":51722, " +
+ "\"total_by_field_count\":3, \"total_over_field_count\":0, \"total_partition_field_count\":2," +
+ "\"bucket_allocation_failures_count\":0, \"memory_status\":\"ok\", \"log_time\":1541587919000, " +
+ "\"timestamp\":1519930800000}, \"latest_record_time_stamp\":1519931700000," +
+ "\"latest_result_time_stamp\":1519930800000, \"retain\":false}", XContentType.JSON);
+ client.index(indexRequest, RequestOptions.DEFAULT);
+
+ {
+ // tag::update-model-snapshot-request
+ UpdateModelSnapshotRequest request = new UpdateModelSnapshotRequest(jobId, snapshotId); // <1>
+ // end::update-model-snapshot-request
+
+ // tag::update-model-snapshot-description
+ request.setDescription("My Snapshot"); // <1>
+ // end::update-model-snapshot-description
+
+ // tag::update-model-snapshot-retain
+ request.setRetain(true); // <1>
+ // end::update-model-snapshot-retain
+
+ // tag::update-model-snapshot-execute
+ UpdateModelSnapshotResponse response = client.machineLearning().updateModelSnapshot(request, RequestOptions.DEFAULT);
+ // end::update-model-snapshot-execute
+
+ // tag::update-model-snapshot-response
+ boolean acknowledged = response.getAcknowledged(); // <1>
+ ModelSnapshot modelSnapshot = response.getModel(); // <2>
+ // end::update-model-snapshot-response
+
+ assertTrue(acknowledged);
+ assertEquals("My Snapshot", modelSnapshot.getDescription()); }
+ {
+ UpdateModelSnapshotRequest request = new UpdateModelSnapshotRequest(jobId, snapshotId);
+
+ // tag::update-model-snapshot-execute-listener
+ ActionListener listener =
+ new ActionListener() {
+ @Override
+ public void onResponse(UpdateModelSnapshotResponse updateModelSnapshotResponse) {
+ // <1>
+ }
+
+ @Override
+ public void onFailure(Exception e) {
+ // <2>
+ }
+ };
+ // end::update-model-snapshot-execute-listener
+
+ // Replace the empty listener by a blocking listener in test
+ final CountDownLatch latch = new CountDownLatch(1);
+ listener = new LatchedActionListener<>(listener, latch);
+
+ // tag::update-model-snapshot-execute-async
+ client.machineLearning().updateModelSnapshotAsync(request, RequestOptions.DEFAULT, listener); // <1>
+ // end::update-model-snapshot-execute-async
+
+ assertTrue(latch.await(30L, TimeUnit.SECONDS));
+ }
+ }
+
public void testPutCalendar() throws IOException, InterruptedException {
RestHighLevelClient client = highLevelClient();
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/UpdateModelSnapshotRequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/UpdateModelSnapshotRequestTests.java
new file mode 100644
index 0000000000000..659265fcfeac4
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/UpdateModelSnapshotRequestTests.java
@@ -0,0 +1,53 @@
+/*
+ * 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 UpdateModelSnapshotRequestTests extends AbstractXContentTestCase {
+
+ @Override
+ protected UpdateModelSnapshotRequest createTestInstance() {
+ String jobId = randomAlphaOfLengthBetween(1, 20);
+ String snapshotId = randomAlphaOfLengthBetween(1, 20);
+ UpdateModelSnapshotRequest request = new UpdateModelSnapshotRequest(jobId, snapshotId);
+ if (randomBoolean()) {
+ request.setDescription(String.valueOf(randomNonNegativeLong()));
+ }
+ if (randomBoolean()) {
+ request.setRetain(randomBoolean());
+ }
+
+ return request;
+ }
+
+ @Override
+ protected UpdateModelSnapshotRequest doParseInstance(XContentParser parser) throws IOException {
+ return UpdateModelSnapshotRequest.PARSER.apply(parser, null);
+ }
+
+ @Override
+ protected boolean supportsUnknownFields() {
+ return false;
+ }
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/UpdateModelSnapshotResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/UpdateModelSnapshotResponseTests.java
new file mode 100644
index 0000000000000..b03c07d880435
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/UpdateModelSnapshotResponseTests.java
@@ -0,0 +1,47 @@
+/*
+ * 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.job.process.ModelSnapshot;
+import org.elasticsearch.client.ml.job.process.ModelSnapshotTests;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.test.AbstractXContentTestCase;
+
+import java.io.IOException;
+
+
+public class UpdateModelSnapshotResponseTests extends AbstractXContentTestCase {
+
+ @Override
+ protected UpdateModelSnapshotResponse createTestInstance() {
+ Boolean acknowledged = randomBoolean();
+ ModelSnapshot.Builder modelBuilder = ModelSnapshotTests.createRandomizedBuilder();
+ return new UpdateModelSnapshotResponse(acknowledged, modelBuilder);
+ }
+
+ @Override
+ protected UpdateModelSnapshotResponse doParseInstance(XContentParser parser) throws IOException {
+ return UpdateModelSnapshotResponse.fromXContent(parser);
+ }
+
+ @Override
+ protected boolean supportsUnknownFields() {
+ return true;
+ }
+}
diff --git a/docs/java-rest/high-level/ml/update-model-snapshot.asciidoc b/docs/java-rest/high-level/ml/update-model-snapshot.asciidoc
new file mode 100644
index 0000000000000..b38539b062224
--- /dev/null
+++ b/docs/java-rest/high-level/ml/update-model-snapshot.asciidoc
@@ -0,0 +1,53 @@
+--
+:api: update-model-snapshot
+:request: UpdateModelSnapshotRequest
+:response: UpdateModelSnapshotResponse
+--
+[id="{upid}-{api}"]
+=== Update Model Snapshot API
+
+The Update Model Snapshot API provides the ability to update a {ml} model snapshot.
+It accepts a +{request}+ object and responds
+with a +{response}+ object.
+
+[id="{upid}-{api}-request"]
+==== Update Model Snapshot Request
+
+A +{request}+ requires the following arguments:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-request]
+--------------------------------------------------
+<1> Constructing a new request referencing existing `jobId` and `snapshotId` values.
+
+==== Optional Arguments
+
+The following arguments are optional:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-description]
+--------------------------------------------------
+<1> The updated description of the {ml} model snapshot
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-retain]
+--------------------------------------------------
+<1> The updated `retain` property of the {ml} model snapshot
+
+
+include::../execution.asciidoc[]
+
+[id="{upid}-{api}-response"]
+==== Update Job Response
+
+A +{response}+ contains an acknowledgement of the update request and the full representation of the updated `ModelSnapshot` object
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-response]
+--------------------------------------------------
+<1> An acknowledgement of the request
+<2> The updated `ModelSnapshot`
diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc
index cabd20d52ff07..76f05570174b6 100644
--- a/docs/java-rest/high-level/supported-apis.asciidoc
+++ b/docs/java-rest/high-level/supported-apis.asciidoc
@@ -274,6 +274,7 @@ The Java High Level REST Client supports the following Machine Learning APIs:
* <<{upid}-update-filter>>
* <<{upid}-delete-filter>>
* <<{upid}-get-model-snapshots>>
+* <<{upid}-update-model-snapshot>>
include::ml/put-job.asciidoc[]
include::ml/get-job.asciidoc[]
@@ -309,6 +310,7 @@ include::ml/get-filters.asciidoc[]
include::ml/delete-model-snapshot.asciidoc[]
include::ml/update-filter.asciidoc[]
include::ml/delete-filter.asciidoc[]
+include::ml/update-model-snapshot.asciidoc[]
== Migration APIs