From b04faa059b50bfd8c55a5704c5bca432439ec85d Mon Sep 17 00:00:00 2001 From: David Kyle Date: Fri, 14 Sep 2018 15:00:18 +0100 Subject: [PATCH] HLRC: ML PUT Calendar (#33362) --- .../client/MLRequestConverters.java | 13 + .../client/MachineLearningClient.java | 461 +++++++++--------- .../client/ml/PutCalendarRequest.java | 73 +++ .../client/ml/PutCalendarResponse.java | 76 +++ .../client/ml/calendars/Calendar.java | 115 +++++ .../client/ml/calendars/ScheduledEvent.java | 125 +++++ .../client/MLRequestConvertersTests.java | 14 + .../client/MachineLearningIT.java | 14 + .../MlClientDocumentationIT.java | 71 ++- .../client/ml/PutCalendarRequestTests.java | 44 ++ .../client/ml/PutCalendarResponseTests.java | 43 ++ .../client/ml/calendars/CalendarTests.java | 61 +++ .../ml/calendars/ScheduledEventTests.java | 51 ++ .../high-level/ml/get-buckets.asciidoc | 2 +- .../high-level/ml/get-categories.asciidoc | 2 +- .../high-level/ml/get-influencers.asciidoc | 2 +- .../ml/get-overall-buckets.asciidoc | 2 +- .../high-level/ml/get-records.asciidoc | 2 +- .../high-level/ml/put-calendar.asciidoc | 65 +++ .../high-level/supported-apis.asciidoc | 2 + 20 files changed, 999 insertions(+), 239 deletions(-) create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PutCalendarRequest.java create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PutCalendarResponse.java create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/ml/calendars/Calendar.java create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/ml/calendars/ScheduledEvent.java create mode 100644 client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PutCalendarRequestTests.java create mode 100644 client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PutCalendarResponseTests.java create mode 100644 client/rest-high-level/src/test/java/org/elasticsearch/client/ml/calendars/CalendarTests.java create mode 100644 client/rest-high-level/src/test/java/org/elasticsearch/client/ml/calendars/ScheduledEventTests.java create mode 100644 docs/java-rest/high-level/ml/put-calendar.asciidoc 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 81b1f6b570969..731a4d4137877 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 @@ -42,6 +42,7 @@ import org.elasticsearch.client.ml.GetRecordsRequest; import org.elasticsearch.client.ml.OpenJobRequest; import org.elasticsearch.client.ml.PostDataRequest; +import org.elasticsearch.client.ml.PutCalendarRequest; import org.elasticsearch.client.ml.PutDatafeedRequest; import org.elasticsearch.client.ml.PutJobRequest; import org.elasticsearch.client.ml.UpdateJobRequest; @@ -327,4 +328,16 @@ static Request getInfluencers(GetInfluencersRequest getInfluencersRequest) throw request.setEntity(createEntity(getInfluencersRequest, REQUEST_BODY_CONTENT_TYPE)); return request; } + + static Request putCalendar(PutCalendarRequest putCalendarRequest) throws IOException { + String endpoint = new EndpointBuilder() + .addPathPartAsIs("_xpack") + .addPathPartAsIs("ml") + .addPathPartAsIs("calendars") + .addPathPart(putCalendarRequest.getCalendar().getId()) + .build(); + Request request = new Request(HttpPut.METHOD_NAME, endpoint); + request.setEntity(createEntity(putCalendarRequest, REQUEST_BODY_CONTENT_TYPE)); + return request; + } } 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 4d2167ce063d8..0fd397bba8997 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 @@ -47,6 +47,8 @@ import org.elasticsearch.client.ml.OpenJobResponse; import org.elasticsearch.client.ml.PostDataRequest; import org.elasticsearch.client.ml.PostDataResponse; +import org.elasticsearch.client.ml.PutCalendarRequest; +import org.elasticsearch.client.ml.PutCalendarResponse; import org.elasticsearch.client.ml.PutDatafeedRequest; import org.elasticsearch.client.ml.PutDatafeedResponse; import org.elasticsearch.client.ml.PutJobRequest; @@ -60,7 +62,6 @@ /** * Machine Learning API client wrapper for the {@link RestHighLevelClient} - * *

* See the * X-Pack Machine Learning APIs for additional information. @@ -86,10 +87,10 @@ public final class MachineLearningClient { */ public PutJobResponse putJob(PutJobRequest request, RequestOptions options) throws IOException { return restHighLevelClient.performRequestAndParseEntity(request, - MLRequestConverters::putJob, - options, - PutJobResponse::fromXContent, - Collections.emptySet()); + MLRequestConverters::putJob, + options, + PutJobResponse::fromXContent, + Collections.emptySet()); } /** @@ -104,63 +105,60 @@ public PutJobResponse putJob(PutJobRequest request, RequestOptions options) thro */ public void putJobAsync(PutJobRequest request, RequestOptions options, ActionListener listener) { restHighLevelClient.performRequestAsyncAndParseEntity(request, - MLRequestConverters::putJob, - options, - PutJobResponse::fromXContent, - listener, - Collections.emptySet()); + MLRequestConverters::putJob, + options, + PutJobResponse::fromXContent, + listener, + Collections.emptySet()); } /** * Gets one or more Machine Learning job configuration info. - * *

- * For additional info - * see - *

+ * For additional info + * see ML GET job documentation + * * @param request {@link GetJobRequest} Request containing a list of jobId(s) and additional options - * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @return {@link GetJobResponse} response object containing * the {@link org.elasticsearch.client.ml.job.config.Job} objects and the number of jobs found * @throws IOException when there is a serialization issue sending the request or receiving the response */ public GetJobResponse getJob(GetJobRequest request, RequestOptions options) throws IOException { return restHighLevelClient.performRequestAndParseEntity(request, - MLRequestConverters::getJob, - options, - GetJobResponse::fromXContent, - Collections.emptySet()); + MLRequestConverters::getJob, + options, + GetJobResponse::fromXContent, + Collections.emptySet()); } - /** + /** * Gets one or more Machine Learning job configuration info, asynchronously. - * *

- * For additional info - * see - *

- * @param request {@link GetJobRequest} Request containing a list of jobId(s) and additional options + * For additional info + * see ML GET job documentation + * + * @param request {@link GetJobRequest} Request containing a list of jobId(s) and additional options * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @param listener Listener to be notified with {@link GetJobResponse} upon request completion */ public void getJobAsync(GetJobRequest request, RequestOptions options, ActionListener listener) { restHighLevelClient.performRequestAsyncAndParseEntity(request, - MLRequestConverters::getJob, - options, - GetJobResponse::fromXContent, - listener, - Collections.emptySet()); + MLRequestConverters::getJob, + options, + GetJobResponse::fromXContent, + listener, + Collections.emptySet()); } /** * Gets usage statistics for one or more Machine Learning jobs - * *

- * For additional info - * see Get Job stats docs - *

+ * For additional info + * see Get job stats docs + * * @param request {@link GetJobStatsRequest} Request containing a list of jobId(s) and additional options - * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @return {@link GetJobStatsResponse} response object containing * the {@link JobStats} objects and the number of jobs found * @throws IOException when there is a serialization issue sending the request or receiving the response @@ -175,12 +173,11 @@ public GetJobStatsResponse getJobStats(GetJobStatsRequest request, RequestOption /** * Gets one or more Machine Learning job configuration info, asynchronously. - * *

- * For additional info - * see Get Job stats docs - *

- * @param request {@link GetJobStatsRequest} Request containing a list of jobId(s) and additional options + * For additional info + * see Get job stats docs + * + * @param request {@link GetJobStatsRequest} Request containing a list of jobId(s) and additional options * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @param listener Listener to be notified with {@link GetJobStatsResponse} upon request completion */ @@ -196,11 +193,11 @@ public void getJobStatsAsync(GetJobStatsRequest request, RequestOptions options, /** * Deletes the given Machine Learning Job *

- * For additional info - * see ML Delete Job documentation - *

+ * For additional info + * see ML Delete job documentation + * * @param request The request to delete the job - * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @return action acknowledgement * @throws IOException when there is a serialization issue sending the request or receiving the response */ @@ -215,10 +212,10 @@ public AcknowledgedResponse deleteJob(DeleteJobRequest request, RequestOptions o /** * Deletes the given Machine Learning Job asynchronously and notifies the listener on completion *

- * For additional info - * see ML Delete Job documentation - *

- * @param request The request to delete the job + * For additional info + * see ML Delete Job documentation + * + * @param request The request to delete the job * @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 */ @@ -234,103 +231,101 @@ public void deleteJobAsync(DeleteJobRequest request, RequestOptions options, Act /** * Opens a Machine Learning Job. * When you open a new job, it starts with an empty model. - * * When you open an existing job, the most recent model state is automatically loaded. * The job is ready to resume its analysis from where it left off, once new data is received. - * *

- * For additional info - * see - *

+ * For additional info + * see ML Open Job documentation + * * @param request Request containing job_id and additional optional options - * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @return response containing if the job was successfully opened or not. * @throws IOException when there is a serialization issue sending the request or receiving the response */ public OpenJobResponse openJob(OpenJobRequest request, RequestOptions options) throws IOException { return restHighLevelClient.performRequestAndParseEntity(request, - MLRequestConverters::openJob, - options, - OpenJobResponse::fromXContent, - Collections.emptySet()); + MLRequestConverters::openJob, + options, + OpenJobResponse::fromXContent, + Collections.emptySet()); } /** * Opens a Machine Learning Job asynchronously, notifies listener on completion. * When you open a new job, it starts with an empty model. - * * When you open an existing job, the most recent model state is automatically loaded. * The job is ready to resume its analysis from where it left off, once new data is received. *

- * For additional info - * see - *

- * @param request Request containing job_id and additional optional options + * For additional info + * see ML Open Job documentation + * + * @param request Request containing job_id and additional optional options * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @param listener Listener to be notified upon request completion */ public void openJobAsync(OpenJobRequest request, RequestOptions options, ActionListener listener) { restHighLevelClient.performRequestAsyncAndParseEntity(request, - MLRequestConverters::openJob, - options, - OpenJobResponse::fromXContent, - listener, - Collections.emptySet()); + MLRequestConverters::openJob, + options, + OpenJobResponse::fromXContent, + listener, + Collections.emptySet()); } /** * Closes one or more Machine Learning Jobs. A job can be opened and closed multiple times throughout its lifecycle. - * * A closed job cannot receive data or perform analysis operations, but you can still explore and navigate results. + *

+ * For additional info + * see ML Close Job documentation * * @param request Request containing job_ids and additional options. See {@link CloseJobRequest} - * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @return response containing if the job was successfully closed or not. * @throws IOException when there is a serialization issue sending the request or receiving the response */ public CloseJobResponse closeJob(CloseJobRequest request, RequestOptions options) throws IOException { return restHighLevelClient.performRequestAndParseEntity(request, - MLRequestConverters::closeJob, - options, - CloseJobResponse::fromXContent, - Collections.emptySet()); + MLRequestConverters::closeJob, + options, + CloseJobResponse::fromXContent, + Collections.emptySet()); } /** * Closes one or more Machine Learning Jobs asynchronously, notifies listener on completion - * * A closed job cannot receive data or perform analysis operations, but you can still explore and navigate results. + *

+ * For additional info + * see ML Close Job documentation * - * @param request Request containing job_ids and additional options. See {@link CloseJobRequest} + * @param request Request containing job_ids and additional options. See {@link CloseJobRequest} * @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 closeJobAsync(CloseJobRequest request, RequestOptions options, ActionListener listener) { restHighLevelClient.performRequestAsyncAndParseEntity(request, - MLRequestConverters::closeJob, - options, - CloseJobResponse::fromXContent, - listener, - Collections.emptySet()); + MLRequestConverters::closeJob, + options, + CloseJobResponse::fromXContent, + listener, + Collections.emptySet()); } /** * Flushes internally buffered data for the given Machine Learning Job ensuring all data sent to the has been processed. * This may cause new results to be calculated depending on the contents of the buffer - * * Both flush and close operations are similar, * however the flush is more efficient if you are expecting to send more data for analysis. - * * When flushing, the job remains open and is available to continue analyzing data. * A close operation additionally prunes and persists the model state to disk and the * job must be opened again before analyzing further data. - * *

* For additional info * see Flush ML job documentation * - * @param request The {@link FlushJobRequest} object enclosing the `jobId` and additional request options - * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param request The {@link FlushJobRequest} object enclosing the `jobId` and additional request options + * @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 FlushJobResponse flushJob(FlushJobRequest request, RequestOptions options) throws IOException { @@ -344,14 +339,11 @@ public FlushJobResponse flushJob(FlushJobRequest request, RequestOptions options /** * Flushes internally buffered data for the given Machine Learning Job asynchronously ensuring all data sent to the has been processed. * This may cause new results to be calculated depending on the contents of the buffer - * * Both flush and close operations are similar, * however the flush is more efficient if you are expecting to send more data for analysis. - * * When flushing, the job remains open and is available to continue analyzing data. * A close operation additionally prunes and persists the model state to disk and the * job must be opened again before analyzing further data. - * *

* For additional info * see Flush ML job documentation @@ -371,87 +363,82 @@ public void flushJobAsync(FlushJobRequest request, RequestOptions options, Actio /** * Creates a forecast of an existing, opened Machine Learning Job - * * This predicts the future behavior of a time series by using its historical behavior. - * *

- * For additional info - * see Forecast ML Job Documentation - *

+ * For additional info + * see Forecast ML Job Documentation + * * @param request ForecastJobRequest with forecasting options - * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @return response containing forecast acknowledgement and new forecast's ID * @throws IOException when there is a serialization issue sending the request or receiving the response */ public ForecastJobResponse forecastJob(ForecastJobRequest request, RequestOptions options) throws IOException { return restHighLevelClient.performRequestAndParseEntity(request, - MLRequestConverters::forecastJob, - options, - ForecastJobResponse::fromXContent, - Collections.emptySet()); - } - - /** - * Updates a Machine Learning {@link org.elasticsearch.client.ml.job.config.Job} - * - *

- * For additional info - * see - *

- * - * @param request the {@link UpdateJobRequest} object enclosing the desired updates - * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized - * @return a PutJobResponse object containing the updated job object - * @throws IOException when there is a serialization issue sending the request or receiving the response - */ - public PutJobResponse updateJob(UpdateJobRequest request, RequestOptions options) throws IOException { - return restHighLevelClient.performRequestAndParseEntity(request, - MLRequestConverters::updateJob, - options, - PutJobResponse::fromXContent, - Collections.emptySet()); + MLRequestConverters::forecastJob, + options, + ForecastJobResponse::fromXContent, + Collections.emptySet()); } /** * Creates a forecast of an existing, opened Machine Learning Job asynchronously - * * This predicts the future behavior of a time series by using its historical behavior. - * *

- * For additional info - * see Forecast ML Job Documentation - *

- * @param request ForecastJobRequest with forecasting options + * For additional info + * see Forecast ML Job Documentation + * + * @param request ForecastJobRequest with forecasting options * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @param listener Listener to be notified upon request completion */ public void forecastJobAsync(ForecastJobRequest request, RequestOptions options, ActionListener listener) { restHighLevelClient.performRequestAsyncAndParseEntity(request, - MLRequestConverters::forecastJob, - options, - ForecastJobResponse::fromXContent, - listener, - Collections.emptySet()); + MLRequestConverters::forecastJob, + options, + ForecastJobResponse::fromXContent, + listener, + Collections.emptySet()); } /** - * Updates a Machine Learning {@link org.elasticsearch.client.ml.job.config.Job} asynchronously + * Deletes Machine Learning Job Forecasts + *

+ * For additional info + * see Delete Job Forecast + * Documentation * + * @param request the {@link DeleteForecastRequest} object enclosing the desired jobId, forecastIDs, and other options + * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @return a AcknowledgedResponse object indicating request success + * @throws IOException when there is a serialization issue sending the request or receiving the response + */ + public AcknowledgedResponse deleteForecast(DeleteForecastRequest request, RequestOptions options) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(request, + MLRequestConverters::deleteForecast, + options, + AcknowledgedResponse::fromXContent, + Collections.emptySet()); + } + + /** + * Deletes Machine Learning Job Forecasts asynchronously *

- * For additional info - * see - *

- * @param request the {@link UpdateJobRequest} object enclosing the desired updates + * For additional info + * see Delete Job Forecast + * Documentation + * + * @param request the {@link DeleteForecastRequest} object enclosing the desired jobId, forecastIDs, and other options * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @param listener Listener to be notified upon request completion */ - public void updateJobAsync(UpdateJobRequest request, RequestOptions options, ActionListener listener) { + public void deleteForecastAsync(DeleteForecastRequest request, RequestOptions options, ActionListener listener) { restHighLevelClient.performRequestAsyncAndParseEntity(request, - MLRequestConverters::updateJob, - options, - PutJobResponse::fromXContent, - listener, - Collections.emptySet()); + MLRequestConverters::deleteForecast, + options, + AcknowledgedResponse::fromXContent, + listener, + Collections.emptySet()); } /** @@ -495,10 +482,10 @@ public void putDatafeedAsync(PutDatafeedRequest request, RequestOptions options, /** * Deletes the given Machine Learning Datafeed *

- * For additional info - * see - * ML Delete Datafeed documentation - *

+ * For additional info + * see + * ML Delete Datafeed documentation + * * @param request The request to delete the datafeed * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @return action acknowledgement @@ -515,10 +502,10 @@ public AcknowledgedResponse deleteDatafeed(DeleteDatafeedRequest request, Reques /** * Deletes the given Machine Learning Datafeed asynchronously and notifies the listener on completion *

- * For additional info - * see + * For additional info + * see * ML Delete Datafeed documentation - *

+ * * @param request The request to delete the datafeed * @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 @@ -533,45 +520,41 @@ public void deleteDatafeedAsync(DeleteDatafeedRequest request, RequestOptions op } /** - * Deletes Machine Learning Job Forecasts - * + * Updates a Machine Learning {@link org.elasticsearch.client.ml.job.config.Job} *

- * For additional info - * see - *

+ * For additional info + * see ML Update Job Documentation * - * @param request the {@link DeleteForecastRequest} object enclosing the desired jobId, forecastIDs, and other options - * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized - * @return a AcknowledgedResponse object indicating request success + * @param request the {@link UpdateJobRequest} object enclosing the desired updates + * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @return a PutJobResponse object containing the updated job object * @throws IOException when there is a serialization issue sending the request or receiving the response */ - public AcknowledgedResponse deleteForecast(DeleteForecastRequest request, RequestOptions options) throws IOException { + public PutJobResponse updateJob(UpdateJobRequest request, RequestOptions options) throws IOException { return restHighLevelClient.performRequestAndParseEntity(request, - MLRequestConverters::deleteForecast, - options, - AcknowledgedResponse::fromXContent, - Collections.emptySet()); + MLRequestConverters::updateJob, + options, + PutJobResponse::fromXContent, + Collections.emptySet()); } /** - * Deletes Machine Learning Job Forecasts asynchronously - * + * Updates a Machine Learning {@link org.elasticsearch.client.ml.job.config.Job} asynchronously *

- * For additional info - * see - *

+ * For additional info + * see ML Update Job Documentation * - * @param request the {@link DeleteForecastRequest} object enclosing the desired jobId, forecastIDs, and other options + * @param request the {@link UpdateJobRequest} object enclosing the desired updates * @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 deleteForecastAsync(DeleteForecastRequest request, RequestOptions options, ActionListener listener) { + public void updateJobAsync(UpdateJobRequest request, RequestOptions options, ActionListener listener) { restHighLevelClient.performRequestAsyncAndParseEntity(request, - MLRequestConverters::deleteForecast, - options, - AcknowledgedResponse::fromXContent, - listener, - Collections.emptySet()); + MLRequestConverters::updateJob, + options, + PutJobResponse::fromXContent, + listener, + Collections.emptySet()); } /** @@ -580,8 +563,8 @@ public void deleteForecastAsync(DeleteForecastRequest request, RequestOptions op * For additional info * see ML GET buckets documentation * - * @param request The request - * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param request The request + * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized */ public GetBucketsResponse getBuckets(GetBucketsRequest request, RequestOptions options) throws IOException { return restHighLevelClient.performRequestAndParseEntity(request, @@ -608,25 +591,25 @@ public void getBucketsAsync(GetBucketsRequest request, RequestOptions options, A GetBucketsResponse::fromXContent, listener, Collections.emptySet()); - } + } /** * Gets the categories for a Machine Learning Job. *

* For additional info * see - * ML GET categories documentation + * ML GET categories documentation * - * @param request The request - * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @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 GetCategoriesResponse getCategories(GetCategoriesRequest request, RequestOptions options) throws IOException { return restHighLevelClient.performRequestAndParseEntity(request, - MLRequestConverters::getCategories, - options, - GetCategoriesResponse::fromXContent, - Collections.emptySet()); + MLRequestConverters::getCategories, + options, + GetCategoriesResponse::fromXContent, + Collections.emptySet()); } /** @@ -634,7 +617,7 @@ public GetCategoriesResponse getCategories(GetCategoriesRequest request, Request *

* For additional info * see - * ML GET categories documentation + * ML GET categories documentation * * @param request The request * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized @@ -642,11 +625,11 @@ public GetCategoriesResponse getCategories(GetCategoriesRequest request, Request */ public void getCategoriesAsync(GetCategoriesRequest request, RequestOptions options, ActionListener listener) { restHighLevelClient.performRequestAsyncAndParseEntity(request, - MLRequestConverters::getCategories, - options, - GetCategoriesResponse::fromXContent, - listener, - Collections.emptySet()); + MLRequestConverters::getCategories, + options, + GetCategoriesResponse::fromXContent, + listener, + Collections.emptySet()); } /** @@ -654,10 +637,10 @@ public void getCategoriesAsync(GetCategoriesRequest request, RequestOptions opti *

* For additional info * see - * ML GET overall buckets documentation + * ML GET overall buckets documentation * - * @param request The request - * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param request The request + * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized */ public GetOverallBucketsResponse getOverallBuckets(GetOverallBucketsRequest request, RequestOptions options) throws IOException { return restHighLevelClient.performRequestAndParseEntity(request, @@ -672,7 +655,7 @@ public GetOverallBucketsResponse getOverallBuckets(GetOverallBucketsRequest requ *

* For additional info * see - * ML GET overall buckets documentation + * ML GET overall buckets documentation * * @param request The request * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized @@ -694,8 +677,8 @@ public void getOverallBucketsAsync(GetOverallBucketsRequest request, RequestOpti * For additional info * see ML GET records documentation * - * @param request the request - * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param request the request + * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized */ public GetRecordsResponse getRecords(GetRecordsRequest request, RequestOptions options) throws IOException { return restHighLevelClient.performRequestAndParseEntity(request, @@ -726,48 +709,44 @@ public void getRecordsAsync(GetRecordsRequest request, RequestOptions options, A /** * Sends data to an anomaly detection job for analysis. - * + *

* NOTE: The job must have a state of open to receive and process the data. - * *

- * For additional info - * see ML POST Data documentation - *

+ * For additional info + * see ML POST Data documentation * * @param request PostDataRequest containing the data to post and some additional options - * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @return response containing operational progress about the job * @throws IOException when there is a serialization issue sending the request or receiving the response */ public PostDataResponse postData(PostDataRequest request, RequestOptions options) throws IOException { return restHighLevelClient.performRequestAndParseEntity(request, - MLRequestConverters::postData, - options, - PostDataResponse::fromXContent, - Collections.emptySet()); + MLRequestConverters::postData, + options, + PostDataResponse::fromXContent, + Collections.emptySet()); } /** * Sends data to an anomaly detection job for analysis, asynchronously - * + *

* NOTE: The job must have a state of open to receive and process the data. - * *

- * For additional info - * see ML POST Data documentation - *

+ * For additional info + * see ML POST Data documentation * - * @param request PostDataRequest containing the data to post and some additional options + * @param request PostDataRequest containing the data to post and some additional options * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @param listener Listener to be notified upon request completion */ public void postDataAsync(PostDataRequest request, RequestOptions options, ActionListener listener) { restHighLevelClient.performRequestAsyncAndParseEntity(request, - MLRequestConverters::postData, - options, - PostDataResponse::fromXContent, - listener, - Collections.emptySet()); + MLRequestConverters::postData, + options, + PostDataResponse::fromXContent, + listener, + Collections.emptySet()); } /** @@ -775,10 +754,10 @@ public void postDataAsync(PostDataRequest request, RequestOptions options, Actio *

* For additional info * see - * ML GET influencers documentation + * ML GET influencers documentation * - * @param request the request - * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param request the request + * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized */ public GetInfluencersResponse getInfluencers(GetInfluencersRequest request, RequestOptions options) throws IOException { return restHighLevelClient.performRequestAndParseEntity(request, @@ -793,7 +772,7 @@ public GetInfluencersResponse getInfluencers(GetInfluencersRequest request, Requ *

* For additional info * * see - * ML GET influencers documentation + * ML GET influencers documentation * * @param request the request * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized @@ -808,4 +787,44 @@ public void getInfluencersAsync(GetInfluencersRequest request, RequestOptions op listener, Collections.emptySet()); } + + /** + * Create a new machine learning calendar + *

+ * For additional info + * see + * ML create calendar documentation + * + * @param request The request + * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @return The {@link PutCalendarResponse} containing the calendar + * @throws IOException when there is a serialization issue sending the request or receiving the response + */ + public PutCalendarResponse putCalendar(PutCalendarRequest request, RequestOptions options) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(request, + MLRequestConverters::putCalendar, + options, + PutCalendarResponse::fromXContent, + Collections.emptySet()); + } + + /** + * Create a new machine learning calendar, notifies listener with the created calendar + *

+ * For additional info + * see + * ML create calendar 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 putCalendarAsync(PutCalendarRequest request, RequestOptions options, ActionListener listener) { + restHighLevelClient.performRequestAsyncAndParseEntity(request, + MLRequestConverters::putCalendar, + options, + PutCalendarResponse::fromXContent, + listener, + Collections.emptySet()); + } } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PutCalendarRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PutCalendarRequest.java new file mode 100644 index 0000000000000..56d6b2b545b5b --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PutCalendarRequest.java @@ -0,0 +1,73 @@ +/* + * 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.calendars.Calendar; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; + +import java.io.IOException; +import java.util.Objects; + +/** + * Request to create a new Machine Learning calendar + */ +public class PutCalendarRequest extends ActionRequest implements ToXContentObject { + + private final Calendar calendar; + + public PutCalendarRequest(Calendar calendar) { + this.calendar = calendar; + } + + public Calendar getCalendar() { + return calendar; + } + + @Override + public ActionRequestValidationException validate() { + return null; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + calendar.toXContent(builder, params); + return builder; + } + + @Override + public int hashCode() { + return Objects.hash(calendar); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + PutCalendarRequest other = (PutCalendarRequest) obj; + return Objects.equals(calendar, other.calendar); + } +} diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PutCalendarResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PutCalendarResponse.java new file mode 100644 index 0000000000000..31c056add9860 --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PutCalendarResponse.java @@ -0,0 +1,76 @@ +/* + * 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.calendars.Calendar; +import org.elasticsearch.common.Strings; +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; + +public class PutCalendarResponse implements ToXContentObject { + + public static PutCalendarResponse fromXContent(XContentParser parser) throws IOException { + return new PutCalendarResponse(Calendar.PARSER.parse(parser, null)); + } + + private final Calendar calendar; + + PutCalendarResponse(Calendar calendar) { + this.calendar = calendar; + } + + public Calendar getCalendar() { + return calendar; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + calendar.toXContent(builder, params); + return builder; + } + + @Override + public int hashCode() { + return Objects.hash(calendar); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + PutCalendarResponse other = (PutCalendarResponse) obj; + return Objects.equals(calendar, other.calendar); + } + + @Override + public final String toString() { + return Strings.toString(this); + } +} diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/calendars/Calendar.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/calendars/Calendar.java new file mode 100644 index 0000000000000..2116ce8de7de2 --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/calendars/Calendar.java @@ -0,0 +1,115 @@ +/* + * 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.calendars; + +import org.elasticsearch.common.Nullable; +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.Collections; +import java.util.List; +import java.util.Objects; + +/** + * A simple calendar object for scheduled (special) events. + * The calendar consists of a name an a list of job Ids or job groups + * the events are stored separately and reference the calendar. + */ +public class Calendar implements ToXContentObject { + + public static final String CALENDAR_TYPE = "calendar"; + + public static final ParseField JOB_IDS = new ParseField("job_ids"); + public static final ParseField ID = new ParseField("calendar_id"); + public static final ParseField DESCRIPTION = new ParseField("description"); + + @SuppressWarnings("unchecked") + public static final ConstructingObjectParser PARSER = + new ConstructingObjectParser<>(CALENDAR_TYPE, true, a -> + new Calendar((String) a[0], (List) a[1], (String) a[2])); + + static { + PARSER.declareString(ConstructingObjectParser.constructorArg(), ID); + PARSER.declareStringArray(ConstructingObjectParser.constructorArg(), JOB_IDS); + PARSER.declareString(ConstructingObjectParser.optionalConstructorArg(), DESCRIPTION); + } + + private final String id; + private final List jobIds; + private final String description; + + /** + * {@code jobIds} can be a mix of job groups and job Ids + * @param id The calendar Id + * @param jobIds List of job Ids or job groups + * @param description An optional description + */ + public Calendar(String id, List jobIds, @Nullable String description) { + this.id = Objects.requireNonNull(id, ID.getPreferredName() + " must not be null"); + this.jobIds = Collections.unmodifiableList(Objects.requireNonNull(jobIds, JOB_IDS.getPreferredName() + " must not be null")); + this.description = description; + } + + public String getId() { + return id; + } + + public List getJobIds() { + return jobIds; + } + + @Nullable + public String getDescription() { + return description; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.field(ID.getPreferredName(), id); + builder.field(JOB_IDS.getPreferredName(), jobIds); + if (description != null) { + builder.field(DESCRIPTION.getPreferredName(), description); + } + builder.endObject(); + return builder; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + Calendar other = (Calendar) obj; + return id.equals(other.id) && jobIds.equals(other.jobIds) && Objects.equals(description, other.description); + } + + @Override + public int hashCode() { + return Objects.hash(id, jobIds, description); + } +} diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/calendars/ScheduledEvent.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/calendars/ScheduledEvent.java new file mode 100644 index 0000000000000..decaff728c6c7 --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/calendars/ScheduledEvent.java @@ -0,0 +1,125 @@ +/* + * 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.calendars; + +import org.elasticsearch.client.ml.job.util.TimeUtil; +import org.elasticsearch.common.Nullable; +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.ObjectParser; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; + + +import java.io.IOException; +import java.util.Date; +import java.util.Objects; + +public class ScheduledEvent implements ToXContentObject { + + public static final ParseField DESCRIPTION = new ParseField("description"); + public static final ParseField START_TIME = new ParseField("start_time"); + public static final ParseField END_TIME = new ParseField("end_time"); + public static final ParseField EVENT_ID = new ParseField("event_id"); + public static final String SCHEDULED_EVENT_TYPE = "scheduled_event"; + + public static final ConstructingObjectParser PARSER = + new ConstructingObjectParser<>(SCHEDULED_EVENT_TYPE, true, a -> + new ScheduledEvent((String) a[0], (Date) a[1], (Date) a[2], (String) a[3], (String) a[4])); + + static { + PARSER.declareString(ConstructingObjectParser.constructorArg(), DESCRIPTION); + PARSER.declareField(ConstructingObjectParser.constructorArg(),(p) -> TimeUtil.parseTimeField(p, START_TIME.getPreferredName()), + START_TIME, ObjectParser.ValueType.VALUE); + PARSER.declareField(ConstructingObjectParser.constructorArg(),(p) -> TimeUtil.parseTimeField(p, END_TIME.getPreferredName()), + END_TIME, ObjectParser.ValueType.VALUE); + PARSER.declareString(ConstructingObjectParser.constructorArg(), Calendar.ID); + PARSER.declareString(ConstructingObjectParser.optionalConstructorArg(), EVENT_ID); + } + + private final String description; + private final Date startTime; + private final Date endTime; + private final String calendarId; + private final String eventId; + + ScheduledEvent(String description, Date startTime, Date endTime, String calendarId, @Nullable String eventId) { + this.description = Objects.requireNonNull(description); + this.startTime = Objects.requireNonNull(startTime); + this.endTime = Objects.requireNonNull(endTime); + this.calendarId = Objects.requireNonNull(calendarId); + this.eventId = eventId; + } + + public String getDescription() { + return description; + } + + public Date getStartTime() { + return startTime; + } + + public Date getEndTime() { + return endTime; + } + + public String getCalendarId() { + return calendarId; + } + + public String getEventId() { + return eventId; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.field(DESCRIPTION.getPreferredName(), description); + builder.timeField(START_TIME.getPreferredName(), START_TIME.getPreferredName() + "_string", startTime.getTime()); + builder.timeField(END_TIME.getPreferredName(), END_TIME.getPreferredName() + "_string", endTime.getTime()); + builder.field(Calendar.ID.getPreferredName(), calendarId); + if (eventId != null) { + builder.field(EVENT_ID.getPreferredName(), eventId); + } + builder.endObject(); + return builder; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + ScheduledEvent other = (ScheduledEvent) obj; + return Objects.equals(this.description, other.description) + && Objects.equals(this.startTime, other.startTime) + && Objects.equals(this.endTime, other.endTime) + && Objects.equals(this.calendarId, other.calendarId); + } + + @Override + public int hashCode() { + return Objects.hash(description, startTime, endTime, calendarId); + } +} 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 547bc2e9a934f..e0a9640ef40fa 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 @@ -38,9 +38,12 @@ import org.elasticsearch.client.ml.GetRecordsRequest; import org.elasticsearch.client.ml.OpenJobRequest; import org.elasticsearch.client.ml.PostDataRequest; +import org.elasticsearch.client.ml.PutCalendarRequest; import org.elasticsearch.client.ml.PutDatafeedRequest; import org.elasticsearch.client.ml.PutJobRequest; import org.elasticsearch.client.ml.UpdateJobRequest; +import org.elasticsearch.client.ml.calendars.Calendar; +import org.elasticsearch.client.ml.calendars.CalendarTests; import org.elasticsearch.client.ml.datafeed.DatafeedConfig; import org.elasticsearch.client.ml.datafeed.DatafeedConfigTests; import org.elasticsearch.client.ml.job.config.AnalysisConfig; @@ -383,6 +386,17 @@ public void testGetInfluencers() throws IOException { } } + public void testPutCalendar() throws IOException { + PutCalendarRequest putCalendarRequest = new PutCalendarRequest(CalendarTests.testInstance()); + Request request = MLRequestConverters.putCalendar(putCalendarRequest); + assertEquals(HttpPut.METHOD_NAME, request.getMethod()); + assertEquals("/_xpack/ml/calendars/" + putCalendarRequest.getCalendar().getId(), request.getEndpoint()); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, request.getEntity().getContent())) { + Calendar parsedCalendar = Calendar.PARSER.apply(parser, null); + assertThat(parsedCalendar, equalTo(putCalendarRequest.getCalendar())); + } + } + private static Job createValidJob(String jobId) { AnalysisConfig.Builder analysisConfig = AnalysisConfig.builder(Collections.singletonList( Detector.builder().setFunction("count").build())); 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 a07b441484386..598f29eec9208 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 @@ -40,11 +40,15 @@ import org.elasticsearch.client.ml.OpenJobResponse; import org.elasticsearch.client.ml.PostDataRequest; import org.elasticsearch.client.ml.PostDataResponse; +import org.elasticsearch.client.ml.PutCalendarRequest; +import org.elasticsearch.client.ml.PutCalendarResponse; import org.elasticsearch.client.ml.PutDatafeedRequest; import org.elasticsearch.client.ml.PutDatafeedResponse; import org.elasticsearch.client.ml.PutJobRequest; import org.elasticsearch.client.ml.PutJobResponse; import org.elasticsearch.client.ml.UpdateJobRequest; +import org.elasticsearch.client.ml.calendars.Calendar; +import org.elasticsearch.client.ml.calendars.CalendarTests; import org.elasticsearch.client.ml.datafeed.DatafeedConfig; import org.elasticsearch.client.ml.job.config.AnalysisConfig; import org.elasticsearch.client.ml.job.config.DataDescription; @@ -397,6 +401,16 @@ private boolean forecastExists(String jobId, String forecastId) throws Exception return getResponse.isExists(); } + public void testPutCalendar() throws IOException { + + Calendar calendar = CalendarTests.testInstance(); + MachineLearningClient machineLearningClient = highLevelClient().machineLearning(); + PutCalendarResponse putCalendarResponse = execute(new PutCalendarRequest(calendar), machineLearningClient::putCalendar, + machineLearningClient::putCalendarAsync); + + assertThat(putCalendarResponse.getCalendar(), equalTo(calendar)); + } + public static String randomValidJobId() { CodepointSetGenerator generator = new CodepointSetGenerator("abcdefghijklmnopqrstuvwxyz0123456789".toCharArray()); return generator.ofCodePointsLength(random(), 10, 10); 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 09d32710eb176..66a38ca781c4d 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 @@ -59,11 +59,14 @@ import org.elasticsearch.client.ml.OpenJobResponse; import org.elasticsearch.client.ml.PostDataRequest; import org.elasticsearch.client.ml.PostDataResponse; +import org.elasticsearch.client.ml.PutCalendarRequest; +import org.elasticsearch.client.ml.PutCalendarResponse; import org.elasticsearch.client.ml.PutDatafeedRequest; import org.elasticsearch.client.ml.PutDatafeedResponse; import org.elasticsearch.client.ml.PutJobRequest; import org.elasticsearch.client.ml.PutJobResponse; import org.elasticsearch.client.ml.UpdateJobRequest; +import org.elasticsearch.client.ml.calendars.Calendar; import org.elasticsearch.client.ml.datafeed.ChunkingConfig; import org.elasticsearch.client.ml.datafeed.DatafeedConfig; import org.elasticsearch.client.ml.job.config.AnalysisConfig; @@ -1368,7 +1371,7 @@ public void testGetCategories() throws IOException, InterruptedException { IndexRequest indexRequest = new IndexRequest(".ml-anomalies-shared", "doc"); indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE); indexRequest.source("{\"job_id\": \"test-get-categories\", \"category_id\": 1, \"terms\": \"AAL\"," + - " \"regex\": \".*?AAL.*\", \"max_matching_length\": 3, \"examples\": [\"AAL\"]}", XContentType.JSON); + " \"regex\": \".*?AAL.*\", \"max_matching_length\": 3, \"examples\": [\"AAL\"]}", XContentType.JSON); client.index(indexRequest, RequestOptions.DEFAULT); { @@ -1402,17 +1405,17 @@ public void testGetCategories() throws IOException, InterruptedException { // tag::x-pack-ml-get-categories-listener ActionListener listener = - new ActionListener() { - @Override - public void onResponse(GetCategoriesResponse getcategoriesResponse) { - // <1> - } - - @Override - public void onFailure(Exception e) { - // <2> - } - }; + new ActionListener() { + @Override + public void onResponse(GetCategoriesResponse getcategoriesResponse) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }; // end::x-pack-ml-get-categories-listener // Replace the empty listener by a blocking listener in test @@ -1424,6 +1427,48 @@ public void onFailure(Exception e) { // end::x-pack-ml-get-categories-execute-async assertTrue(latch.await(30L, TimeUnit.SECONDS)); - } + } + } + + public void testPutCalendar() throws IOException, InterruptedException { + RestHighLevelClient client = highLevelClient(); + + //tag::x-pack-ml-put-calendar-request + Calendar calendar = new Calendar("public_holidays", Collections.singletonList("job_1"), "A calendar for public holidays"); + PutCalendarRequest request = new PutCalendarRequest(calendar); // <1> + //end::x-pack-ml-put-calendar-request + + //tag::x-pack-ml-put-calendar-execution + PutCalendarResponse response = client.machineLearning().putCalendar(request, RequestOptions.DEFAULT); + //end::x-pack-ml-put-calendar-execution + + //tag::x-pack-ml-put-calendar-response + Calendar newCalendar = response.getCalendar(); // <1> + //end::x-pack-ml-put-calendar-response + assertThat(newCalendar.getId(), equalTo("public_holidays")); + + // tag::x-pack-ml-put-calendar-listener + ActionListener listener = new ActionListener() { + @Override + public void onResponse(PutCalendarResponse response) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }; + // end::x-pack-ml-put-calendar-listener + + // Replace the empty listener by a blocking listener in test + final CountDownLatch latch = new CountDownLatch(1); + listener = new LatchedActionListener<>(listener, latch); + + // tag::x-pack-ml-put-calendar-execute-async + client.machineLearning().putCalendarAsync(request, RequestOptions.DEFAULT, listener); // <1> + // end::x-pack-ml-put-calendar-execute-async + + assertTrue(latch.await(30L, TimeUnit.SECONDS)); } } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PutCalendarRequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PutCalendarRequestTests.java new file mode 100644 index 0000000000000..3b5b6b8658b6d --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PutCalendarRequestTests.java @@ -0,0 +1,44 @@ +/* + * 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.calendars.Calendar; +import org.elasticsearch.client.ml.calendars.CalendarTests; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.test.AbstractXContentTestCase; + +import java.io.IOException; + +public class PutCalendarRequestTests extends AbstractXContentTestCase { + @Override + protected PutCalendarRequest createTestInstance() { + return new PutCalendarRequest(CalendarTests.testInstance()); + } + + @Override + protected PutCalendarRequest doParseInstance(XContentParser parser) throws IOException { + return new PutCalendarRequest(Calendar.PARSER.apply(parser, null)); + } + + @Override + protected boolean supportsUnknownFields() { + return true; + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PutCalendarResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PutCalendarResponseTests.java new file mode 100644 index 0000000000000..1756e1ceb7fca --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PutCalendarResponseTests.java @@ -0,0 +1,43 @@ +/* + * 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.calendars.CalendarTests; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.test.AbstractXContentTestCase; + +import java.io.IOException; + +public class PutCalendarResponseTests extends AbstractXContentTestCase { + @Override + protected PutCalendarResponse createTestInstance() { + return new PutCalendarResponse(CalendarTests.testInstance()); + } + + @Override + protected PutCalendarResponse doParseInstance(XContentParser parser) throws IOException { + return PutCalendarResponse.fromXContent(parser); + } + + @Override + protected boolean supportsUnknownFields() { + return true; + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/calendars/CalendarTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/calendars/CalendarTests.java new file mode 100644 index 0000000000000..ddb5c7be0b9a2 --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/calendars/CalendarTests.java @@ -0,0 +1,61 @@ +/* + * 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.calendars; + +import com.carrotsearch.randomizedtesting.generators.CodepointSetGenerator; +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 CalendarTests extends AbstractXContentTestCase { + + public static Calendar testInstance() { + int size = randomInt(10); + List items = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + items.add(randomAlphaOfLengthBetween(1, 20)); + } + String description = null; + if (randomBoolean()) { + description = randomAlphaOfLength(20); + } + + CodepointSetGenerator generator = new CodepointSetGenerator("abcdefghijklmnopqrstuvwxyz".toCharArray()); + return new Calendar(generator.ofCodePointsLength(random(), 10, 10), items, description); + } + + @Override + protected Calendar createTestInstance() { + return testInstance(); + } + + @Override + protected Calendar doParseInstance(XContentParser parser) throws IOException { + return Calendar.PARSER.apply(parser, null); + } + + @Override + protected boolean supportsUnknownFields() { + return true; + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/calendars/ScheduledEventTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/calendars/ScheduledEventTests.java new file mode 100644 index 0000000000000..0b7a293340245 --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/calendars/ScheduledEventTests.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.calendars; + +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.test.AbstractXContentTestCase; + +import java.util.Date; + +public class ScheduledEventTests extends AbstractXContentTestCase { + + public static ScheduledEvent testInstance() { + Date start = new Date(randomNonNegativeLong()); + Date end = new Date(start.getTime() + randomIntBetween(1, 10000) * 1000); + + return new ScheduledEvent(randomAlphaOfLength(10), start, end, randomAlphaOfLengthBetween(1, 20), + randomBoolean() ? null : randomAlphaOfLength(7)); + } + + @Override + protected ScheduledEvent createTestInstance() { + return testInstance(); + } + + @Override + protected ScheduledEvent doParseInstance(XContentParser parser) { + return ScheduledEvent.PARSER.apply(parser, null); + } + + @Override + protected boolean supportsUnknownFields() { + return true; + } +} diff --git a/docs/java-rest/high-level/ml/get-buckets.asciidoc b/docs/java-rest/high-level/ml/get-buckets.asciidoc index 33a3059166c3f..f77b368a49536 100644 --- a/docs/java-rest/high-level/ml/get-buckets.asciidoc +++ b/docs/java-rest/high-level/ml/get-buckets.asciidoc @@ -112,7 +112,7 @@ include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-get-buckets-l <1> `onResponse` is called back when the action is completed successfully <2> `onFailure` is called back when some unexpected error occurs -[[java-rest-high-snapshot-ml-get-buckets-response]] +[[java-rest-high-x-pack-ml-get-buckets-response]] ==== Get Buckets Response The returned `GetBucketsResponse` contains the requested buckets: diff --git a/docs/java-rest/high-level/ml/get-categories.asciidoc b/docs/java-rest/high-level/ml/get-categories.asciidoc index 0e86a2b7f33a6..2a5988a5cc6fb 100644 --- a/docs/java-rest/high-level/ml/get-categories.asciidoc +++ b/docs/java-rest/high-level/ml/get-categories.asciidoc @@ -70,7 +70,7 @@ include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-get-categorie <1> `onResponse` is called back when the action is completed successfully <2> `onFailure` is called back when some unexpected error occurs -[[java-rest-high-snapshot-ml-get-categories-response]] +[[java-rest-high-x-pack-ml-get-categories-response]] ==== Get Categories Response The returned `GetCategoriesResponse` contains the requested categories: diff --git a/docs/java-rest/high-level/ml/get-influencers.asciidoc b/docs/java-rest/high-level/ml/get-influencers.asciidoc index e53e92ff1df07..8b1ba061bcb10 100644 --- a/docs/java-rest/high-level/ml/get-influencers.asciidoc +++ b/docs/java-rest/high-level/ml/get-influencers.asciidoc @@ -99,7 +99,7 @@ include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-get-influence <1> `onResponse` is called back when the action is completed successfully <2> `onFailure` is called back when some unexpected error occurs -[[java-rest-high-snapshot-ml-get-influencers-response]] +[[java-rest-high-x-pack-ml-get-influencers-response]] ==== Get Influencers Response The returned `GetInfluencersResponse` contains the requested influencers: diff --git a/docs/java-rest/high-level/ml/get-overall-buckets.asciidoc b/docs/java-rest/high-level/ml/get-overall-buckets.asciidoc index 832eb8f251481..1e299dc27216c 100644 --- a/docs/java-rest/high-level/ml/get-overall-buckets.asciidoc +++ b/docs/java-rest/high-level/ml/get-overall-buckets.asciidoc @@ -94,7 +94,7 @@ include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-get-overall-b <1> `onResponse` is called back when the action is completed successfully <2> `onFailure` is called back when some unexpected error occurs -[[java-rest-high-snapshot-ml-get-overall-buckets-response]] +[[java-rest-high-x-pack-ml-get-overall-buckets-response]] ==== Get Overall Buckets Response The returned `GetOverallBucketsResponse` contains the requested buckets: diff --git a/docs/java-rest/high-level/ml/get-records.asciidoc b/docs/java-rest/high-level/ml/get-records.asciidoc index f8a88f34d3379..7b8e6b1313106 100644 --- a/docs/java-rest/high-level/ml/get-records.asciidoc +++ b/docs/java-rest/high-level/ml/get-records.asciidoc @@ -100,7 +100,7 @@ include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-get-records-l <1> `onResponse` is called back when the action is completed successfully <2> `onFailure` is called back when some unexpected error occurs -[[java-rest-high-snapshot-ml-get-records-response]] +[[java-rest-high-x-pack-ml-get-records-response]] ==== Get Records Response The returned `GetRecordsResponse` contains the requested records: diff --git a/docs/java-rest/high-level/ml/put-calendar.asciidoc b/docs/java-rest/high-level/ml/put-calendar.asciidoc new file mode 100644 index 0000000000000..e6814c76fad5f --- /dev/null +++ b/docs/java-rest/high-level/ml/put-calendar.asciidoc @@ -0,0 +1,65 @@ +[[java-rest-high-x-pack-ml-put-calendar]] +=== Put Calendar API +Creates a new {ml} calendar. +The API accepts a `PutCalendarRequest` and responds +with a `PutCalendarResponse` object. + +[[java-rest-high-x-pack-ml-get-calendars-request]] +==== Put Calendar Request + +A `PutCalendarRequest` is constructed with a Calendar object + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-put-calendar-request] +-------------------------------------------------- +<1> Create a request with the given Calendar + + +[[java-rest-high-x-pack-ml-put-calendar-response]] +==== Put Calendar Response + +The returned `PutCalendarResponse` contains the created Calendar: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-put-calendar-response] +-------------------------------------------------- +<1> The created Calendar + +[[java-rest-high-x-pack-ml-put-calendar-execution]] +==== Execution +The request can be executed through the `MachineLearningClient` contained +in the `RestHighLevelClient` object, accessed via the `machineLearningClient()` method. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-put-calendar-execute] +-------------------------------------------------- + +[[java-rest-high-x-pack-ml-put-calendar-execution-async]] +==== Asynchronous Execution + +The request can also be executed asynchronously: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-put-calendar-execute-async] +-------------------------------------------------- +<1> The `PutCalendarResquest` to execute and the `ActionListener` to use when +the execution completes + +The asynchronous method does not block and returns immediately. Once it is +completed the `ActionListener` is called back with the `onResponse` method +if the execution is successful or the `onFailure` method if the execution +failed. + +A typical listener for `PutCalendarResponse` looks like: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-put-calendar-listener] +-------------------------------------------------- +<1> `onResponse` is called back when the action is completed successfully +<2> `onFailure` is called back when some unexpected error occurs + diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc index cb297d0f712dc..089fe26cede52 100644 --- a/docs/java-rest/high-level/supported-apis.asciidoc +++ b/docs/java-rest/high-level/supported-apis.asciidoc @@ -230,6 +230,7 @@ The Java High Level REST Client supports the following Machine Learning APIs: * <> * <> * <> +* <> include::ml/put-job.asciidoc[] include::ml/get-job.asciidoc[] @@ -249,6 +250,7 @@ include::ml/get-records.asciidoc[] include::ml/post-data.asciidoc[] include::ml/get-influencers.asciidoc[] include::ml/get-categories.asciidoc[] +include::ml/put-calendar.asciidoc[] == Migration APIs