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 28e52a8d6271e..6d7fefe907fc6 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 @@ -43,6 +43,7 @@ import org.elasticsearch.client.ml.GetInfluencersRequest; import org.elasticsearch.client.ml.GetJobRequest; import org.elasticsearch.client.ml.GetJobStatsRequest; +import org.elasticsearch.client.ml.GetModelSnapshotsRequest; import org.elasticsearch.client.ml.GetOverallBucketsRequest; import org.elasticsearch.client.ml.GetRecordsRequest; import org.elasticsearch.client.ml.OpenJobRequest; @@ -361,6 +362,19 @@ static Request getCategories(GetCategoriesRequest getCategoriesRequest) throws I return request; } + static Request getModelSnapshots(GetModelSnapshotsRequest getModelSnapshotsRequest) throws IOException { + String endpoint = new EndpointBuilder() + .addPathPartAsIs("_xpack") + .addPathPartAsIs("ml") + .addPathPartAsIs("anomaly_detectors") + .addPathPart(getModelSnapshotsRequest.getJobId()) + .addPathPartAsIs("model_snapshots") + .build(); + Request request = new Request(HttpGet.METHOD_NAME, endpoint); + request.setEntity(createEntity(getModelSnapshotsRequest, 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 4b62712c571e9..e327f9b2a5812 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 @@ -49,6 +49,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.GetOverallBucketsRequest; import org.elasticsearch.client.ml.GetOverallBucketsResponse; import org.elasticsearch.client.ml.GetRecordsRequest; @@ -897,6 +899,46 @@ public void getCategoriesAsync(GetCategoriesRequest request, RequestOptions opti Collections.emptySet()); } + /** + * Gets the snapshots for a Machine Learning Job. + *

+ * For additional info + * see + * ML GET 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 GetModelSnapshotsResponse getModelSnapshots(GetModelSnapshotsRequest request, RequestOptions options) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(request, + MLRequestConverters::getModelSnapshots, + options, + GetModelSnapshotsResponse::fromXContent, + Collections.emptySet()); + } + + /** + * Gets the snapshots for a Machine Learning Job, notifies listener once the requested snapshots are retrieved. + *

+ * For additional info + * see + * ML GET 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 getModelSnapshotsAsync(GetModelSnapshotsRequest request, RequestOptions options, + ActionListener listener) { + restHighLevelClient.performRequestAsyncAndParseEntity(request, + MLRequestConverters::getModelSnapshots, + options, + GetModelSnapshotsResponse::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/GetModelSnapshotsRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetModelSnapshotsRequest.java new file mode 100644 index 0000000000000..8743f3043e589 --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetModelSnapshotsRequest.java @@ -0,0 +1,208 @@ +/* + * 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.util.PageParams; +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.Objects; + +/** + * A request to retrieve information about model snapshots for a given job + */ +public class GetModelSnapshotsRequest extends ActionRequest implements ToXContentObject { + + + public static final ParseField SNAPSHOT_ID = new ParseField("snapshot_id"); + public static final ParseField SORT = new ParseField("sort"); + public static final ParseField START = new ParseField("start"); + public static final ParseField END = new ParseField("end"); + public static final ParseField DESC = new ParseField("desc"); + + public static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( + "get_model_snapshots_request", a -> new GetModelSnapshotsRequest((String) a[0])); + + + static { + PARSER.declareString(ConstructingObjectParser.constructorArg(), Job.ID); + PARSER.declareString(GetModelSnapshotsRequest::setSnapshotId, SNAPSHOT_ID); + PARSER.declareString(GetModelSnapshotsRequest::setSort, SORT); + PARSER.declareStringOrNull(GetModelSnapshotsRequest::setStart, START); + PARSER.declareStringOrNull(GetModelSnapshotsRequest::setEnd, END); + PARSER.declareBoolean(GetModelSnapshotsRequest::setDesc, DESC); + PARSER.declareObject(GetModelSnapshotsRequest::setPageParams, PageParams.PARSER, PageParams.PAGE); + } + + private final String jobId; + private String snapshotId; + private String sort; + private String start; + private String end; + private Boolean desc; + private PageParams pageParams; + + /** + * Constructs a request to retrieve snapshot information from a given job + * @param jobId id of the job from which to retrieve results + */ + public GetModelSnapshotsRequest(String jobId) { + this.jobId = Objects.requireNonNull(jobId); + } + + public String getJobId() { + return jobId; + } + + public String getSnapshotId() { + return snapshotId; + } + + /** + * Sets the id of the snapshot to retrieve. + * @param snapshotId the snapshot id + */ + public void setSnapshotId(String snapshotId) { + this.snapshotId = snapshotId; + } + + public String getSort() { + return sort; + } + + /** + * Sets the value of "sort". + * Specifies the snapshot field to sort on. + * @param sort value of "sort". + */ + public void setSort(String sort) { + this.sort = sort; + } + + public PageParams getPageParams() { + return pageParams; + } + + /** + * Sets the paging parameters + * @param pageParams the paging parameters + */ + public void setPageParams(PageParams pageParams) { + this.pageParams = pageParams; + } + + public String getStart() { + return start; + } + + /** + * Sets the value of "start" which is a timestamp. + * Only snapshots whose timestamp is on or after the "start" value will be returned. + * @param start String representation of a timestamp; may be an epoch seconds, epoch millis or an ISO string + */ + public void setStart(String start) { + this.start = start; + } + + + public String getEnd() { + return end; + } + + /** + * Sets the value of "end" which is a timestamp. + * Only snapshots whose timestamp is before the "end" value will be returned. + * @param end String representation of a timestamp; may be an epoch seconds, epoch millis or an ISO string + */ + public void setEnd(String end) { + this.end = end; + } + + public Boolean getDesc() { + return desc; + } + + /** + * Sets the value of "desc". + * Specifies the sorting order. + * @param desc value of "desc" + */ + public void setDesc(boolean desc) { + this.desc = desc; + } + + @Override + public ActionRequestValidationException validate() { + return null; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.field(Job.ID.getPreferredName(), jobId); + if (snapshotId != null) { + builder.field(SNAPSHOT_ID.getPreferredName(), snapshotId); + } + if (sort != null) { + builder.field(SORT.getPreferredName(), sort); + } + if (start != null) { + builder.field(START.getPreferredName(), start); + } + if (end != null) { + builder.field(END.getPreferredName(), end); + } + if (desc != null) { + builder.field(DESC.getPreferredName(), desc); + } + if (pageParams != null) { + builder.field(PageParams.PAGE.getPreferredName(), pageParams); + } builder.endObject(); + return builder; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + GetModelSnapshotsRequest request = (GetModelSnapshotsRequest) obj; + return Objects.equals(jobId, request.jobId) + && Objects.equals(snapshotId, request.snapshotId) + && Objects.equals(sort, request.sort) + && Objects.equals(start, request.start) + && Objects.equals(end, request.end) + && Objects.equals(desc, request.desc) + && Objects.equals(pageParams, request.pageParams); + } + + @Override + public int hashCode() { + return Objects.hash(jobId, snapshotId, pageParams, start, end, sort, desc); + } +} diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetModelSnapshotsResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetModelSnapshotsResponse.java new file mode 100644 index 0000000000000..d4932d27a89f5 --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/GetModelSnapshotsResponse.java @@ -0,0 +1,80 @@ +/* + * 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.common.ParseField; +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; + +/** + * A response containing the requested snapshots + */ +public class GetModelSnapshotsResponse extends AbstractResultResponse { + + public static final ParseField SNAPSHOTS = new ParseField("model_snapshots"); + + @SuppressWarnings("unchecked") + public static final ConstructingObjectParser PARSER = + new ConstructingObjectParser<>("get_model_snapshots_response", true, + a -> new GetModelSnapshotsResponse((List) a[0], (long) a[1])); + + static { + PARSER.declareObjectArray(ConstructingObjectParser.constructorArg(), ModelSnapshot.PARSER, SNAPSHOTS); + PARSER.declareLong(ConstructingObjectParser.constructorArg(), COUNT); + } + + public static GetModelSnapshotsResponse fromXContent(XContentParser parser) throws IOException { + return PARSER.parse(parser, null); + } + + GetModelSnapshotsResponse(List snapshotBuilders, long count) { + super(SNAPSHOTS, snapshotBuilders.stream().map(ModelSnapshot.Builder::build).collect(Collectors.toList()), count); + } + + /** + * The retrieved snapshots + * @return the retrieved snapshots + */ + public List snapshots() { + return results; + } + + @Override + public int hashCode() { + return Objects.hash(count, results); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + GetModelSnapshotsResponse other = (GetModelSnapshotsResponse) obj; + return count == other.count && Objects.equals(results, other.results); + } +} 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 eea2531bda16a..bb4822990722e 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 @@ -39,6 +39,7 @@ import org.elasticsearch.client.ml.GetInfluencersRequest; import org.elasticsearch.client.ml.GetJobRequest; import org.elasticsearch.client.ml.GetJobStatsRequest; +import org.elasticsearch.client.ml.GetModelSnapshotsRequest; import org.elasticsearch.client.ml.GetOverallBucketsRequest; import org.elasticsearch.client.ml.GetRecordsRequest; import org.elasticsearch.client.ml.OpenJobRequest; @@ -391,6 +392,21 @@ public void testGetCategories() throws IOException { } } + public void testGetModelSnapshots() throws IOException { + String jobId = randomAlphaOfLength(10); + GetModelSnapshotsRequest getModelSnapshotsRequest = new GetModelSnapshotsRequest(jobId); + getModelSnapshotsRequest.setPageParams(new PageParams(100, 300)); + + + Request request = MLRequestConverters.getModelSnapshots(getModelSnapshotsRequest); + assertEquals(HttpGet.METHOD_NAME, request.getMethod()); + assertEquals("/_xpack/ml/anomaly_detectors/" + jobId + "/model_snapshots", request.getEndpoint()); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, request.getEntity().getContent())) { + GetModelSnapshotsRequest parsedRequest = GetModelSnapshotsRequest.PARSER.apply(parser, null); + assertThat(parsedRequest, equalTo(getModelSnapshotsRequest)); + } + } + 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/MachineLearningGetResultsIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningGetResultsIT.java index 751f4cfdf0efe..2ee09b496fc85 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningGetResultsIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningGetResultsIT.java @@ -25,6 +25,8 @@ import org.elasticsearch.client.ml.GetBucketsResponse; import org.elasticsearch.client.ml.GetCategoriesRequest; import org.elasticsearch.client.ml.GetCategoriesResponse; +import org.elasticsearch.client.ml.GetModelSnapshotsRequest; +import org.elasticsearch.client.ml.GetModelSnapshotsResponse; import org.elasticsearch.client.ml.GetInfluencersRequest; import org.elasticsearch.client.ml.GetInfluencersResponse; import org.elasticsearch.client.ml.GetOverallBucketsRequest; @@ -36,6 +38,7 @@ import org.elasticsearch.client.ml.job.config.DataDescription; import org.elasticsearch.client.ml.job.config.Detector; import org.elasticsearch.client.ml.job.config.Job; +import org.elasticsearch.client.ml.job.process.ModelSizeStats; import org.elasticsearch.client.ml.job.results.AnomalyRecord; import org.elasticsearch.client.ml.job.results.Bucket; import org.elasticsearch.client.ml.job.results.Influencer; @@ -48,6 +51,7 @@ import java.io.IOException; import java.util.Arrays; +import java.util.Date; import java.util.List; import static org.hamcrest.Matchers.closeTo; @@ -145,11 +149,384 @@ private void addCategoriesIndexRequests(BulkRequest bulkRequest) { } } + private void addModelSnapshotIndexRequests(BulkRequest bulkRequest) { + { + IndexRequest indexRequest = new IndexRequest(RESULTS_INDEX, DOC); + indexRequest.source("{\"job_id\":\"" + JOB_ID + "\", \"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\":\"" + JOB_ID + "\", \"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); + bulkRequest.add(indexRequest); + } + { + IndexRequest indexRequest = new IndexRequest(RESULTS_INDEX, DOC); + indexRequest.source("{\"job_id\":\"" + JOB_ID + "\", \"timestamp\":1541588919000, " + + "\"description\":\"State persisted due to job close at 2018-11-07T11:08:39+0000\", \"snapshot_id\":\"1541588919\"," + + "\"snapshot_doc_count\":1, \"model_size_stats\":{\"job_id\":\"" + JOB_ID + "\", \"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\":1541588919000," + + "\"timestamp\":1519930800000},\"latest_record_time_stamp\":1519931700000, \"latest_result_time_stamp\":1519930800000, " + + "\"retain\":false }", XContentType.JSON); + bulkRequest.add(indexRequest); + } + { + IndexRequest indexRequest = new IndexRequest(RESULTS_INDEX, DOC); + indexRequest.source("{\"job_id\":\"" + JOB_ID + "\", \"timestamp\":1541589919000, " + + "\"description\":\"State persisted due to job close at 2018-11-07T11:25:19+0000\", \"snapshot_id\":\"1541589919\"," + + "\"snapshot_doc_count\":1, \"model_size_stats\":{\"job_id\":\"" + JOB_ID + "\", \"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\":1541589919000," + + "\"timestamp\":1519930800000},\"latest_record_time_stamp\":1519931700000, \"latest_result_time_stamp\":1519930800000," + + "\"retain\":false }", XContentType.JSON); + bulkRequest.add(indexRequest); + } + } + @After public void deleteJob() throws IOException { new MlTestStateCleaner(logger, highLevelClient().machineLearning()).clearMlMetadata(); } + public void testGetModelSnapshots() throws IOException { + + // index some model_snapshot results + BulkRequest bulkRequest = new BulkRequest(); + bulkRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE); + + addModelSnapshotIndexRequests(bulkRequest); + + highLevelClient().bulk(bulkRequest, RequestOptions.DEFAULT); + + MachineLearningClient machineLearningClient = highLevelClient().machineLearning(); + + { + GetModelSnapshotsRequest request = new GetModelSnapshotsRequest(JOB_ID); + request.setSort("timestamp"); + request.setDesc(false); + request.setPageParams(new PageParams(0, 10000)); + + GetModelSnapshotsResponse response = execute(request, machineLearningClient::getModelSnapshots, + machineLearningClient::getModelSnapshotsAsync); + + assertThat(response.count(), equalTo(3L)); + assertThat(response.snapshots().size(), equalTo(3)); + assertThat(response.snapshots().get(0).getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(0).getSnapshotId(), equalTo("1541587919")); + assertThat(response.snapshots().get(0).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(0).getDescription(), equalTo("State persisted due to job close at" + + " 2018-11-07T10:51:59+0000")); + assertThat(response.snapshots().get(0).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(0).getTimestamp(), equalTo(new Date(1541587919000L))); + assertThat(response.snapshots().get(0).getLatestRecordTimeStamp(), equalTo(new Date(1519931700000L))); + assertThat(response.snapshots().get(0).getLatestResultTimeStamp(), equalTo(new Date(1519930800000L))); + assertThat(response.snapshots().get(0).getModelSizeStats().getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(0).getModelSizeStats().getModelBytes(), equalTo(51722L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalByFieldCount(), equalTo(3L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalOverFieldCount(), equalTo(0L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalPartitionFieldCount(), equalTo(2L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getBucketAllocationFailuresCount(), equalTo(0L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getMemoryStatus(), + equalTo(ModelSizeStats.MemoryStatus.fromString("ok"))); + + assertThat(response.snapshots().get(1).getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(1).getSnapshotId(), equalTo("1541588919")); + assertThat(response.snapshots().get(1).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(1).getDescription(), equalTo("State persisted due to job close at" + + " 2018-11-07T11:08:39+0000")); + assertThat(response.snapshots().get(1).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(1).getTimestamp(), equalTo(new Date(1541588919000L))); + assertThat(response.snapshots().get(1).getLatestRecordTimeStamp(), equalTo(new Date(1519931700000L))); + assertThat(response.snapshots().get(1).getLatestResultTimeStamp(), equalTo(new Date(1519930800000L))); + assertThat(response.snapshots().get(1).getModelSizeStats().getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(1).getModelSizeStats().getModelBytes(), equalTo(51722L)); + assertThat(response.snapshots().get(1).getModelSizeStats().getTotalByFieldCount(), equalTo(3L)); + assertThat(response.snapshots().get(1).getModelSizeStats().getTotalOverFieldCount(), equalTo(0L)); + assertThat(response.snapshots().get(1).getModelSizeStats().getTotalPartitionFieldCount(), equalTo(2L)); + assertThat(response.snapshots().get(1).getModelSizeStats().getBucketAllocationFailuresCount(), equalTo(0L)); + assertThat(response.snapshots().get(1).getModelSizeStats().getMemoryStatus(), + equalTo(ModelSizeStats.MemoryStatus.fromString("ok"))); + + assertThat(response.snapshots().get(2).getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(2).getSnapshotId(), equalTo("1541589919")); + assertThat(response.snapshots().get(2).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(2).getDescription(), equalTo("State persisted due to job close at" + + " 2018-11-07T11:25:19+0000")); + assertThat(response.snapshots().get(2).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(2).getTimestamp(), equalTo(new Date(1541589919000L))); + assertThat(response.snapshots().get(2).getLatestRecordTimeStamp(), equalTo(new Date(1519931700000L))); + assertThat(response.snapshots().get(2).getLatestResultTimeStamp(), equalTo(new Date(1519930800000L))); + assertThat(response.snapshots().get(2).getModelSizeStats().getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(2).getModelSizeStats().getModelBytes(), equalTo(51722L)); + assertThat(response.snapshots().get(2).getModelSizeStats().getTotalByFieldCount(), equalTo(3L)); + assertThat(response.snapshots().get(2).getModelSizeStats().getTotalOverFieldCount(), equalTo(0L)); + assertThat(response.snapshots().get(2).getModelSizeStats().getTotalPartitionFieldCount(), equalTo(2L)); + assertThat(response.snapshots().get(2).getModelSizeStats().getBucketAllocationFailuresCount(), equalTo(0L)); + assertThat(response.snapshots().get(2).getModelSizeStats().getMemoryStatus(), + equalTo(ModelSizeStats.MemoryStatus.fromString("ok"))); + } + { + GetModelSnapshotsRequest request = new GetModelSnapshotsRequest(JOB_ID); + request.setSort("timestamp"); + request.setDesc(true); + request.setPageParams(new PageParams(0, 10000)); + + GetModelSnapshotsResponse response = execute(request, machineLearningClient::getModelSnapshots, + machineLearningClient::getModelSnapshotsAsync); + + assertThat(response.count(), equalTo(3L)); + assertThat(response.snapshots().size(), equalTo(3)); + assertThat(response.snapshots().get(2).getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(2).getSnapshotId(), equalTo("1541587919")); + assertThat(response.snapshots().get(2).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(2).getDescription(), equalTo("State persisted due to job close at" + + " 2018-11-07T10:51:59+0000")); + assertThat(response.snapshots().get(2).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(2).getTimestamp(), equalTo(new Date(1541587919000L))); + assertThat(response.snapshots().get(2).getLatestRecordTimeStamp(), equalTo(new Date(1519931700000L))); + assertThat(response.snapshots().get(2).getLatestResultTimeStamp(), equalTo(new Date(1519930800000L))); + assertThat(response.snapshots().get(2).getModelSizeStats().getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(2).getModelSizeStats().getModelBytes(), equalTo(51722L)); + assertThat(response.snapshots().get(2).getModelSizeStats().getTotalByFieldCount(), equalTo(3L)); + assertThat(response.snapshots().get(2).getModelSizeStats().getTotalOverFieldCount(), equalTo(0L)); + assertThat(response.snapshots().get(2).getModelSizeStats().getTotalPartitionFieldCount(), equalTo(2L)); + assertThat(response.snapshots().get(2).getModelSizeStats().getBucketAllocationFailuresCount(), equalTo(0L)); + assertThat(response.snapshots().get(2).getModelSizeStats().getMemoryStatus(), + equalTo(ModelSizeStats.MemoryStatus.fromString("ok"))); + + assertThat(response.snapshots().get(1).getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(1).getSnapshotId(), equalTo("1541588919")); + assertThat(response.snapshots().get(1).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(1).getDescription(), equalTo("State persisted due to job close at" + + " 2018-11-07T11:08:39+0000")); + assertThat(response.snapshots().get(1).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(1).getTimestamp(), equalTo(new Date(1541588919000L))); + assertThat(response.snapshots().get(1).getLatestRecordTimeStamp(), equalTo(new Date(1519931700000L))); + assertThat(response.snapshots().get(1).getLatestResultTimeStamp(), equalTo(new Date(1519930800000L))); + assertThat(response.snapshots().get(1).getModelSizeStats().getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(1).getModelSizeStats().getModelBytes(), equalTo(51722L)); + assertThat(response.snapshots().get(1).getModelSizeStats().getTotalByFieldCount(), equalTo(3L)); + assertThat(response.snapshots().get(1).getModelSizeStats().getTotalOverFieldCount(), equalTo(0L)); + assertThat(response.snapshots().get(1).getModelSizeStats().getTotalPartitionFieldCount(), equalTo(2L)); + assertThat(response.snapshots().get(1).getModelSizeStats().getBucketAllocationFailuresCount(), equalTo(0L)); + assertThat(response.snapshots().get(1).getModelSizeStats().getMemoryStatus(), + equalTo(ModelSizeStats.MemoryStatus.fromString("ok"))); + + assertThat(response.snapshots().get(0).getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(0).getSnapshotId(), equalTo("1541589919")); + assertThat(response.snapshots().get(0).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(0).getDescription(), equalTo("State persisted due to job close at" + + " 2018-11-07T11:25:19+0000")); + assertThat(response.snapshots().get(0).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(0).getTimestamp(), equalTo(new Date(1541589919000L))); + assertThat(response.snapshots().get(0).getLatestRecordTimeStamp(), equalTo(new Date(1519931700000L))); + assertThat(response.snapshots().get(0).getLatestResultTimeStamp(), equalTo(new Date(1519930800000L))); + assertThat(response.snapshots().get(0).getModelSizeStats().getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(0).getModelSizeStats().getModelBytes(), equalTo(51722L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalByFieldCount(), equalTo(3L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalOverFieldCount(), equalTo(0L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalPartitionFieldCount(), equalTo(2L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getBucketAllocationFailuresCount(), equalTo(0L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getMemoryStatus(), + equalTo(ModelSizeStats.MemoryStatus.fromString("ok"))); + } + { + GetModelSnapshotsRequest request = new GetModelSnapshotsRequest(JOB_ID); + request.setSort("timestamp"); + request.setDesc(false); + request.setPageParams(new PageParams(0, 1)); + + GetModelSnapshotsResponse response = execute(request, machineLearningClient::getModelSnapshots, + machineLearningClient::getModelSnapshotsAsync); + + assertThat(response.count(), equalTo(3L)); + assertThat(response.snapshots().size(), equalTo(1)); + assertThat(response.snapshots().get(0).getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(0).getSnapshotId(), equalTo("1541587919")); + assertThat(response.snapshots().get(0).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(0).getDescription(), equalTo("State persisted due to job close at" + + " 2018-11-07T10:51:59+0000")); + assertThat(response.snapshots().get(0).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(0).getTimestamp(), equalTo(new Date(1541587919000L))); + assertThat(response.snapshots().get(0).getLatestRecordTimeStamp(), equalTo(new Date(1519931700000L))); + assertThat(response.snapshots().get(0).getLatestResultTimeStamp(), equalTo(new Date(1519930800000L))); + assertThat(response.snapshots().get(0).getModelSizeStats().getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(0).getModelSizeStats().getModelBytes(), equalTo(51722L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalByFieldCount(), equalTo(3L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalOverFieldCount(), equalTo(0L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalPartitionFieldCount(), equalTo(2L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getBucketAllocationFailuresCount(), equalTo(0L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getMemoryStatus(), + equalTo(ModelSizeStats.MemoryStatus.fromString("ok"))); + } + { + GetModelSnapshotsRequest request = new GetModelSnapshotsRequest(JOB_ID); + request.setSort("timestamp"); + request.setDesc(false); + request.setPageParams(new PageParams(1, 2)); + + GetModelSnapshotsResponse response = execute(request, machineLearningClient::getModelSnapshots, + machineLearningClient::getModelSnapshotsAsync); + + assertThat(response.count(), equalTo(3L)); + assertThat(response.snapshots().size(), equalTo(2)); + + assertThat(response.snapshots().get(0).getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(0).getSnapshotId(), equalTo("1541588919")); + assertThat(response.snapshots().get(0).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(0).getDescription(), equalTo("State persisted due to job close at" + + " 2018-11-07T11:08:39+0000")); + assertThat(response.snapshots().get(0).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(0).getTimestamp(), equalTo(new Date(1541588919000L))); + assertThat(response.snapshots().get(0).getLatestRecordTimeStamp(), equalTo(new Date(1519931700000L))); + assertThat(response.snapshots().get(0).getLatestResultTimeStamp(), equalTo(new Date(1519930800000L))); + assertThat(response.snapshots().get(0).getModelSizeStats().getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(0).getModelSizeStats().getModelBytes(), equalTo(51722L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalByFieldCount(), equalTo(3L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalOverFieldCount(), equalTo(0L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalPartitionFieldCount(), equalTo(2L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getBucketAllocationFailuresCount(), equalTo(0L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getMemoryStatus(), + equalTo(ModelSizeStats.MemoryStatus.fromString("ok"))); + + + assertThat(response.snapshots().get(1).getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(1).getSnapshotId(), equalTo("1541589919")); + assertThat(response.snapshots().get(1).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(1).getDescription(), equalTo("State persisted due to job close at" + + " 2018-11-07T11:25:19+0000")); + assertThat(response.snapshots().get(1).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(1).getTimestamp(), equalTo(new Date(1541589919000L))); + assertThat(response.snapshots().get(1).getLatestRecordTimeStamp(), equalTo(new Date(1519931700000L))); + assertThat(response.snapshots().get(1).getLatestResultTimeStamp(), equalTo(new Date(1519930800000L))); + assertThat(response.snapshots().get(1).getModelSizeStats().getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(1).getModelSizeStats().getModelBytes(), equalTo(51722L)); + assertThat(response.snapshots().get(1).getModelSizeStats().getTotalByFieldCount(), equalTo(3L)); + assertThat(response.snapshots().get(1).getModelSizeStats().getTotalOverFieldCount(), equalTo(0L)); + assertThat(response.snapshots().get(1).getModelSizeStats().getTotalPartitionFieldCount(), equalTo(2L)); + assertThat(response.snapshots().get(1).getModelSizeStats().getBucketAllocationFailuresCount(), equalTo(0L)); + assertThat(response.snapshots().get(1).getModelSizeStats().getMemoryStatus(), + equalTo(ModelSizeStats.MemoryStatus.fromString("ok"))); + } + { + GetModelSnapshotsRequest request = new GetModelSnapshotsRequest(JOB_ID); + request.setSnapshotId("1541588919"); + + GetModelSnapshotsResponse response = execute(request, machineLearningClient::getModelSnapshots, + machineLearningClient::getModelSnapshotsAsync); + + assertThat(response.count(), equalTo(1L)); + assertThat(response.snapshots().size(), equalTo(1)); + + assertThat(response.snapshots().get(0).getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(0).getSnapshotId(), equalTo("1541588919")); + assertThat(response.snapshots().get(0).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(0).getDescription(), equalTo("State persisted due to job close at" + + " 2018-11-07T11:08:39+0000")); + assertThat(response.snapshots().get(0).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(0).getTimestamp(), equalTo(new Date(1541588919000L))); + assertThat(response.snapshots().get(0).getLatestRecordTimeStamp(), equalTo(new Date(1519931700000L))); + assertThat(response.snapshots().get(0).getLatestResultTimeStamp(), equalTo(new Date(1519930800000L))); + assertThat(response.snapshots().get(0).getModelSizeStats().getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(0).getModelSizeStats().getModelBytes(), equalTo(51722L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalByFieldCount(), equalTo(3L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalOverFieldCount(), equalTo(0L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalPartitionFieldCount(), equalTo(2L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getBucketAllocationFailuresCount(), equalTo(0L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getMemoryStatus(), + equalTo(ModelSizeStats.MemoryStatus.fromString("ok"))); + } + { + GetModelSnapshotsRequest request = new GetModelSnapshotsRequest(JOB_ID); + request.setSnapshotId("1541586919"); // request a non-existent snapshotId + + GetModelSnapshotsResponse response = execute(request, machineLearningClient::getModelSnapshots, + machineLearningClient::getModelSnapshotsAsync); + + assertThat(response.count(), equalTo(0L)); + assertThat(response.snapshots().size(), equalTo(0)); + } + { + GetModelSnapshotsRequest request = new GetModelSnapshotsRequest(JOB_ID); + request.setSort("timestamp"); + request.setDesc(false); + request.setStart("1541586919000"); + request.setEnd("1541589019000"); + + GetModelSnapshotsResponse response = execute(request, machineLearningClient::getModelSnapshots, + machineLearningClient::getModelSnapshotsAsync); + + assertThat(response.count(), equalTo(2L)); + assertThat(response.snapshots().size(), equalTo(2)); + assertThat(response.snapshots().get(0).getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(0).getSnapshotId(), equalTo("1541587919")); + assertThat(response.snapshots().get(0).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(0).getDescription(), equalTo("State persisted due to job close at" + + " 2018-11-07T10:51:59+0000")); + assertThat(response.snapshots().get(0).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(0).getTimestamp(), equalTo(new Date(1541587919000L))); + assertThat(response.snapshots().get(0).getLatestRecordTimeStamp(), equalTo(new Date(1519931700000L))); + assertThat(response.snapshots().get(0).getLatestResultTimeStamp(), equalTo(new Date(1519930800000L))); + assertThat(response.snapshots().get(0).getModelSizeStats().getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(0).getModelSizeStats().getModelBytes(), equalTo(51722L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalByFieldCount(), equalTo(3L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalOverFieldCount(), equalTo(0L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalPartitionFieldCount(), equalTo(2L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getBucketAllocationFailuresCount(), equalTo(0L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getMemoryStatus(), + equalTo(ModelSizeStats.MemoryStatus.fromString("ok"))); + + assertThat(response.snapshots().get(1).getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(1).getSnapshotId(), equalTo("1541588919")); + assertThat(response.snapshots().get(1).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(1).getDescription(), equalTo("State persisted due to job close at" + + " 2018-11-07T11:08:39+0000")); + assertThat(response.snapshots().get(1).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(1).getTimestamp(), equalTo(new Date(1541588919000L))); + assertThat(response.snapshots().get(1).getLatestRecordTimeStamp(), equalTo(new Date(1519931700000L))); + assertThat(response.snapshots().get(1).getLatestResultTimeStamp(), equalTo(new Date(1519930800000L))); + assertThat(response.snapshots().get(1).getModelSizeStats().getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(1).getModelSizeStats().getModelBytes(), equalTo(51722L)); + assertThat(response.snapshots().get(1).getModelSizeStats().getTotalByFieldCount(), equalTo(3L)); + assertThat(response.snapshots().get(1).getModelSizeStats().getTotalOverFieldCount(), equalTo(0L)); + assertThat(response.snapshots().get(1).getModelSizeStats().getTotalPartitionFieldCount(), equalTo(2L)); + assertThat(response.snapshots().get(1).getModelSizeStats().getBucketAllocationFailuresCount(), equalTo(0L)); + assertThat(response.snapshots().get(1).getModelSizeStats().getMemoryStatus(), + equalTo(ModelSizeStats.MemoryStatus.fromString("ok"))); + } + { + GetModelSnapshotsRequest request = new GetModelSnapshotsRequest(JOB_ID); + request.setSort("timestamp"); + request.setDesc(false); + request.setStart("1541589019000"); + + GetModelSnapshotsResponse response = execute(request, machineLearningClient::getModelSnapshots, + machineLearningClient::getModelSnapshotsAsync); + + assertThat(response.count(), equalTo(1L)); + assertThat(response.snapshots().size(), equalTo(1)); + assertThat(response.snapshots().get(0).getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(0).getSnapshotId(), equalTo("1541589919")); + assertThat(response.snapshots().get(0).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(0).getDescription(), equalTo("State persisted due to job close at" + + " 2018-11-07T11:25:19+0000")); + assertThat(response.snapshots().get(0).getSnapshotDocCount(), equalTo(1)); + assertThat(response.snapshots().get(0).getTimestamp(), equalTo(new Date(1541589919000L))); + assertThat(response.snapshots().get(0).getLatestRecordTimeStamp(), equalTo(new Date(1519931700000L))); + assertThat(response.snapshots().get(0).getLatestResultTimeStamp(), equalTo(new Date(1519930800000L))); + assertThat(response.snapshots().get(0).getModelSizeStats().getJobId(), equalTo(JOB_ID)); + assertThat(response.snapshots().get(0).getModelSizeStats().getModelBytes(), equalTo(51722L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalByFieldCount(), equalTo(3L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalOverFieldCount(), equalTo(0L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getTotalPartitionFieldCount(), equalTo(2L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getBucketAllocationFailuresCount(), equalTo(0L)); + assertThat(response.snapshots().get(0).getModelSizeStats().getMemoryStatus(), + equalTo(ModelSizeStats.MemoryStatus.fromString("ok"))); + } + } + public void testGetCategories() throws IOException { // index some category results 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 47498e7ac8382..e6a8976a3c75c 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 @@ -50,6 +50,8 @@ import org.elasticsearch.client.ml.GetCalendarsResponse; import org.elasticsearch.client.ml.GetCategoriesRequest; import org.elasticsearch.client.ml.GetCategoriesResponse; +import org.elasticsearch.client.ml.GetModelSnapshotsRequest; +import org.elasticsearch.client.ml.GetModelSnapshotsResponse; import org.elasticsearch.client.ml.GetDatafeedRequest; import org.elasticsearch.client.ml.GetDatafeedResponse; import org.elasticsearch.client.ml.GetDatafeedStatsRequest; @@ -103,6 +105,7 @@ import org.elasticsearch.client.ml.job.config.Operator; import org.elasticsearch.client.ml.job.config.RuleCondition; import org.elasticsearch.client.ml.job.process.DataCounts; +import org.elasticsearch.client.ml.job.process.ModelSnapshot; import org.elasticsearch.client.ml.job.results.AnomalyRecord; import org.elasticsearch.client.ml.job.results.Bucket; import org.elasticsearch.client.ml.job.results.CategoryDefinition; @@ -1863,6 +1866,102 @@ public void onFailure(Exception e) { } } + public void testGetModelSnapshots() throws IOException, InterruptedException { + RestHighLevelClient client = highLevelClient(); + + String jobId = "test-get-model-snapshots"; + 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"); + indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE); + indexRequest.source("{\"job_id\":\"test-get-model-snapshots\", \"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-get-model-snapshots\", \"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::get-model-snapshots-request + GetModelSnapshotsRequest request = new GetModelSnapshotsRequest(jobId); // <1> + // end::get-model-snapshots-request + + // tag::get-model-snapshots-snapshot-id + request.setSnapshotId("1541587919"); // <1> + // end::get-model-snapshots-snapshot-id + + // Set snapshot id to null as it is incompatible with other args + request.setSnapshotId(null); + + // tag::get-model-snapshots-desc + request.setDesc(true); // <1> + // end::get-model-snapshots-desc + + // tag::get-model-snapshots-end + request.setEnd("2018-11-07T21:00:00Z"); // <1> + // end::get-model-snapshots-end + + // tag::get-model-snapshots-page + request.setPageParams(new PageParams(100, 200)); // <1> + // end::get-model-snapshots-page + + // Set page params back to null so the response contains the snapshot we indexed + request.setPageParams(null); + + // tag::get-model-snapshots-sort + request.setSort("latest_result_time_stamp"); // <1> + // end::get-model-snapshots-sort + + // tag::get-model-snapshots-start + request.setStart("2018-11-07T00:00:00Z"); // <1> + // end::get-model-snapshots-start + + // tag::get-model-snapshots-execute + GetModelSnapshotsResponse response = client.machineLearning().getModelSnapshots(request, RequestOptions.DEFAULT); + // end::get-model-snapshots-execute + + // tag::get-model-snapshots-response + long count = response.count(); // <1> + List modelSnapshots = response.snapshots(); // <2> + // end::get-model-snapshots-response + + assertEquals(1, modelSnapshots.size()); + } + { + GetModelSnapshotsRequest request = new GetModelSnapshotsRequest(jobId); + + // tag::get-model-snapshots-execute-listener + ActionListener listener = + new ActionListener() { + @Override + public void onResponse(GetModelSnapshotsResponse getModelSnapshotsResponse) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }; + // end::get-model-snapshots-execute-listener + + // Replace the empty listener by a blocking listener in test + final CountDownLatch latch = new CountDownLatch(1); + listener = new LatchedActionListener<>(listener, latch); + + // tag::get-model-snapshots-execute-async + client.machineLearning().getModelSnapshotsAsync(request, RequestOptions.DEFAULT, listener); // <1> + // end::get-model-snapshots-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/GetModelSnapshotsRequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/GetModelSnapshotsRequestTests.java new file mode 100644 index 0000000000000..80a08f8c765ac --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/GetModelSnapshotsRequestTests.java @@ -0,0 +1,67 @@ +/* + * 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.util.PageParams; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.test.AbstractXContentTestCase; + +import java.io.IOException; + + +public class GetModelSnapshotsRequestTests extends AbstractXContentTestCase { + + @Override + protected GetModelSnapshotsRequest createTestInstance() { + GetModelSnapshotsRequest request = new GetModelSnapshotsRequest(randomAlphaOfLengthBetween(1, 20)); + if (randomBoolean()) { + request.setSnapshotId(String.valueOf(randomNonNegativeLong())); + } + else { + if (randomBoolean()) { + request.setStart(String.valueOf(randomLong())); + } + if (randomBoolean()) { + request.setEnd(String.valueOf(randomLong())); + } + if (randomBoolean()) { + int from = randomInt(10000); + int size = randomInt(10000); + request.setPageParams(new PageParams(from, size)); + } + if (randomBoolean()) { + request.setSort("description"); + } + if (randomBoolean()) { + request.setDesc(randomBoolean()); + } + } + return request; + } + + @Override + protected GetModelSnapshotsRequest doParseInstance(XContentParser parser) throws IOException { + return GetModelSnapshotsRequest.PARSER.apply(parser, null); + } + + @Override + protected boolean supportsUnknownFields() { + return false; + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/GetModelSnapshotsResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/GetModelSnapshotsResponseTests.java new file mode 100644 index 0000000000000..60288233e7286 --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/GetModelSnapshotsResponseTests.java @@ -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.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; +import java.util.ArrayList; +import java.util.List; + +public class GetModelSnapshotsResponseTests extends AbstractXContentTestCase { + + @Override + protected GetModelSnapshotsResponse createTestInstance() { + int listSize = randomInt(10); + List modelSnapshots = new ArrayList<>(listSize); + for (int j = 0; j < listSize; j++) { + modelSnapshots.add(ModelSnapshotTests.createRandomizedBuilder()); + } + return new GetModelSnapshotsResponse(modelSnapshots, listSize); + } + + @Override + protected GetModelSnapshotsResponse doParseInstance(XContentParser parser) throws IOException { + return GetModelSnapshotsResponse.fromXContent(parser); + } + + @Override + protected boolean supportsUnknownFields() { + return true; + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/job/process/ModelSnapshotTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/job/process/ModelSnapshotTests.java index 9669f9bfa4f4e..15565c28391af 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/job/process/ModelSnapshotTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/job/process/ModelSnapshotTests.java @@ -158,6 +158,10 @@ protected ModelSnapshot createTestInstance() { } public static ModelSnapshot createRandomized() { + return createRandomizedBuilder().build(); + } + + public static ModelSnapshot.Builder createRandomizedBuilder() { ModelSnapshot.Builder modelSnapshot = new ModelSnapshot.Builder(randomAlphaOfLengthBetween(1, 20)); modelSnapshot.setMinVersion(Version.CURRENT); modelSnapshot.setTimestamp(new Date(TimeValue.parseTimeValue(randomTimeValue(), "test").millis())); @@ -171,7 +175,7 @@ public static ModelSnapshot createRandomized() { new Date(TimeValue.parseTimeValue(randomTimeValue(), "test").millis())); modelSnapshot.setQuantiles(QuantilesTests.createRandomized()); modelSnapshot.setRetain(randomBoolean()); - return modelSnapshot.build(); + return modelSnapshot; } @Override diff --git a/docs/java-rest/high-level/ml/get-model-snapshots.asciidoc b/docs/java-rest/high-level/ml/get-model-snapshots.asciidoc new file mode 100644 index 0000000000000..c23cdcabdf4aa --- /dev/null +++ b/docs/java-rest/high-level/ml/get-model-snapshots.asciidoc @@ -0,0 +1,76 @@ +-- +:api: get-model-snapshots +:request: GetModelSnapshotsRequest +:response: GetModelSnapshotsResponse +-- +[id="{upid}-{api}"] +=== Get Model Snapshots API + +The Get Model Snapshots API retrieves one or more model snapshot results. +It accepts a +{request}+ object and responds +with a +{response}+ object. + +[id="{upid}-{api}-request"] +==== Get Model Snapshots Request + +A +{request}+ object gets created with an existing non-null `jobId`. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests-file}[{api}-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-file}[{api}-snapshot-id] +-------------------------------------------------- +<1> The id of the snapshot to get. Otherwise it will return all snapshots. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests-file}[{api}-desc] +-------------------------------------------------- +<1> If `true`, the snapshots are sorted in descending order. Defaults to `false`. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests-file}[{api}-end] +-------------------------------------------------- +<1> Snapshots with timestamps earlier than this time will be returned. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests-file}[{api}-sort] +-------------------------------------------------- +<1> The field to sort snapshots on. Defaults to `timestamp`. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests-file}[{api}-start] +-------------------------------------------------- +<1> Snapshots with timestamps on or after this time will be returned. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests-file}[{api}-page] +-------------------------------------------------- +<1> The page parameters `from` and `size`. `from` specifies the number of snapshots to skip. +`size` specifies the maximum number of snapshots to retrieve. Defaults to `0` and `100` respectively. + +include::../execution.asciidoc[] + +[id="{upid}-{api}-response"] +==== Get Model Snapshots Response + +The returned +{response}+ contains the requested snapshots: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests-file}[{api}-response] +-------------------------------------------------- +<1> The count of snapshots that were matched +<2> The snapshots retrieved \ No newline at end of file diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc index 7deb214d29628..33810aeabe50c 100644 --- a/docs/java-rest/high-level/supported-apis.asciidoc +++ b/docs/java-rest/high-level/supported-apis.asciidoc @@ -265,6 +265,7 @@ The Java High Level REST Client supports the following Machine Learning APIs: * <<{upid}-put-calendar>> * <<{upid}-delete-calendar>> * <<{upid}-put-filter>> +* <<{upid}-get-model-snapshots>> * <<{upid}-get-filters>> include::ml/put-job.asciidoc[] @@ -295,6 +296,7 @@ include::ml/get-calendars.asciidoc[] include::ml/put-calendar.asciidoc[] include::ml/delete-calendar.asciidoc[] include::ml/put-filter.asciidoc[] +include::ml/get-model-snapshots.asciidoc[] include::ml/get-filters.asciidoc[] == Migration APIs