Skip to content

Commit

Permalink
HLRC: ML Get Calendar Events (#35747)
Browse files Browse the repository at this point in the history
* HLRC: ML Get Calendar Events

* Addressing PR comments
  • Loading branch information
benwtrent committed Nov 20, 2018
1 parent c4e1220 commit a21169f
Show file tree
Hide file tree
Showing 11 changed files with 628 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.elasticsearch.client.ml.FlushJobRequest;
import org.elasticsearch.client.ml.ForecastJobRequest;
import org.elasticsearch.client.ml.GetBucketsRequest;
import org.elasticsearch.client.ml.GetCalendarEventsRequest;
import org.elasticsearch.client.ml.GetCalendarsRequest;
import org.elasticsearch.client.ml.GetCategoriesRequest;
import org.elasticsearch.client.ml.GetDatafeedRequest;
Expand Down Expand Up @@ -539,6 +540,19 @@ static Request deleteCalendar(DeleteCalendarRequest deleteCalendarRequest) {
return request;
}

static Request getCalendarEvents(GetCalendarEventsRequest getCalendarEventsRequest) throws IOException {
String endpoint = new EndpointBuilder()
.addPathPartAsIs("_xpack")
.addPathPartAsIs("ml")
.addPathPartAsIs("calendars")
.addPathPart(getCalendarEventsRequest.getCalendarId())
.addPathPartAsIs("events")
.build();
Request request = new Request(HttpGet.METHOD_NAME, endpoint);
request.setEntity(createEntity(getCalendarEventsRequest, REQUEST_BODY_CONTENT_TYPE));
return request;
}

static Request postCalendarEvents(PostCalendarEventRequest postCalendarEventRequest) throws IOException {
String endpoint = new EndpointBuilder()
.addPathPartAsIs("_xpack")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
import org.elasticsearch.client.ml.ForecastJobResponse;
import org.elasticsearch.client.ml.GetBucketsRequest;
import org.elasticsearch.client.ml.GetBucketsResponse;
import org.elasticsearch.client.ml.GetCalendarEventsRequest;
import org.elasticsearch.client.ml.GetCalendarEventsResponse;
import org.elasticsearch.client.ml.GetCalendarsRequest;
import org.elasticsearch.client.ml.GetCalendarsResponse;
import org.elasticsearch.client.ml.GetCategoriesRequest;
Expand Down Expand Up @@ -1386,6 +1388,47 @@ public void deleteCalendarAsync(DeleteCalendarRequest request, RequestOptions op
Collections.emptySet());
}

/**
* Gets the events for a machine learning calendar
* <p>
* For additional info
* see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-calendar-event.html">
* GET Calendar Events API</a>
*
* @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 PostCalendarEventRequest} containing the scheduled events
* @throws IOException when there is a serialization issue sending the request or receiving the response
*/
public GetCalendarEventsResponse getCalendarEvents(GetCalendarEventsRequest request, RequestOptions options) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(request,
MLRequestConverters::getCalendarEvents,
options,
GetCalendarEventsResponse::fromXContent,
Collections.emptySet());
}

/**
* Gets the events for a a machine learning calendar asynchronously, notifies the listener on completion
* <p>
* For additional info
* see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-calendar-event.html">
* GET Calendar Events API</a>
*
* @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 getCalendarEventsAsync(GetCalendarEventsRequest request, RequestOptions options,
ActionListener<GetCalendarEventsResponse> listener) {
restHighLevelClient.performRequestAsyncAndParseEntity(request,
MLRequestConverters::getCalendarEvents,
options,
GetCalendarEventsResponse::fromXContent,
listener,
Collections.emptySet());
}

/**
* Creates new events for a a machine learning calendar
* <p>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/*
* 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.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;

/**
* Get the Scheduled Events for a Calendar
*/
public class GetCalendarEventsRequest extends ActionRequest implements ToXContentObject {

public static final ParseField START = new ParseField("start");
public static final ParseField END = new ParseField("end");

public static final ConstructingObjectParser<GetCalendarEventsRequest, Void> PARSER =
new ConstructingObjectParser<>("get_calendar_events_request", a -> new GetCalendarEventsRequest((String)a[0]));

static {
PARSER.declareString(ConstructingObjectParser.constructorArg(), Calendar.ID);
PARSER.declareString(GetCalendarEventsRequest::setStart, START);
PARSER.declareString(GetCalendarEventsRequest::setEnd, END);
PARSER.declareString(GetCalendarEventsRequest::setJobId, Job.ID);
PARSER.declareObject(GetCalendarEventsRequest::setPageParams, PageParams.PARSER, PageParams.PAGE);
}

private final String calendarId;
private String start;
private String end;
private String jobId;
private PageParams pageParams;

/**
* Create a new request to get the ScheduledEvents for the given calendarId.
*
* @param calendarId The ID of the calendar.
* Can be `_all` to get ALL ScheduledEvents for all calendars.
*/
public GetCalendarEventsRequest(String calendarId) {
this.calendarId = Objects.requireNonNull(calendarId, "[calendar_id] must not be null.");
}

public String getCalendarId() {
return calendarId;
}

public PageParams getPageParams() {
return pageParams;
}

/**
* The paging parameters for the gathered ScheduledEvents
* @param pageParams The desired paging params
*/
public void setPageParams(PageParams pageParams) {
this.pageParams = pageParams;
}

public String getStart() {
return start;
}

/**
* Specifies to get events with timestamps after this time.
*
* @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;
}

/**
* Specifies to get events with timestamps earlier than this time.
*
* @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 String getJobId() {
return jobId;
}

/**
* The jobId for which to get the ScheduledEvents. When this option is used calendarId must be `_all`
* @param jobId The job for which to get the events.
*/
public void setJobId(String jobId) {
this.jobId = jobId;
}

@Override
public ActionRequestValidationException validate() {
return null;
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(Calendar.ID.getPreferredName(), calendarId);
if (start != null) {
builder.field(START.getPreferredName(), start);
}
if (end != null) {
builder.field(END.getPreferredName(), end);
}
if (jobId != null) {
builder.field(Job.ID.getPreferredName(), jobId);
}
if (pageParams != null) {
builder.field(PageParams.PAGE.getPreferredName(), pageParams);
}
builder.endObject();
return builder;
}

@Override
public int hashCode() {
return Objects.hash(calendarId, start, end, jobId, pageParams);
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
GetCalendarEventsRequest other = (GetCalendarEventsRequest) obj;
return Objects.equals(calendarId, other.calendarId)
&& Objects.equals(pageParams, other.pageParams)
&& Objects.equals(start, other.start)
&& Objects.equals(end, other.end)
&& Objects.equals(jobId, other.jobId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* 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.ScheduledEvent;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.Strings;
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 static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;

/**
* Contains a {@link List} of the found {@link ScheduledEvent} objects and the total count found
*/
public class GetCalendarEventsResponse extends AbstractResultResponse<ScheduledEvent> {

public static final ParseField RESULTS_FIELD = new ParseField("events");

@SuppressWarnings("unchecked")
public static final ConstructingObjectParser<GetCalendarEventsResponse, Void> PARSER =
new ConstructingObjectParser<>("calendar_events_response", true,
a -> new GetCalendarEventsResponse((List<ScheduledEvent>) a[0], (long) a[1]));

static {
PARSER.declareObjectArray(constructorArg(), ScheduledEvent.PARSER, RESULTS_FIELD);
PARSER.declareLong(constructorArg(), COUNT);
}

GetCalendarEventsResponse(List<ScheduledEvent> events, long count) {
super(RESULTS_FIELD, events, count);
}

/**
* The collection of {@link ScheduledEvent} objects found in the query
*/
public List<ScheduledEvent> events() {
return results;
}

public static GetCalendarEventsResponse fromXContent(XContentParser parser) throws IOException {
return PARSER.parse(parser, null);
}

@Override
public int hashCode() {
return Objects.hash(results, count);
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}

if (obj == null || getClass() != obj.getClass()) {
return false;
}

GetCalendarEventsResponse other = (GetCalendarEventsResponse) obj;
return Objects.equals(results, other.results) && count == other.count;
}

@Override
public final String toString() {
return Strings.toString(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.elasticsearch.client.ml.FlushJobRequest;
import org.elasticsearch.client.ml.ForecastJobRequest;
import org.elasticsearch.client.ml.GetBucketsRequest;
import org.elasticsearch.client.ml.GetCalendarEventsRequest;
import org.elasticsearch.client.ml.GetCalendarsRequest;
import org.elasticsearch.client.ml.GetCategoriesRequest;
import org.elasticsearch.client.ml.GetDatafeedRequest;
Expand Down Expand Up @@ -591,6 +592,23 @@ public void testDeleteCalendar() {
assertEquals("/_xpack/ml/calendars/" + deleteCalendarRequest.getCalendarId(), request.getEndpoint());
}

public void testGetCalendarEvents() throws IOException {
String calendarId = randomAlphaOfLength(10);
GetCalendarEventsRequest getCalendarEventsRequest = new GetCalendarEventsRequest(calendarId);
getCalendarEventsRequest.setStart("2018-08-08T00:00:00Z");
getCalendarEventsRequest.setEnd("2018-09-08T00:00:00Z");
getCalendarEventsRequest.setPageParams(new PageParams(100, 300));
getCalendarEventsRequest.setJobId(randomAlphaOfLength(10));

Request request = MLRequestConverters.getCalendarEvents(getCalendarEventsRequest);
assertEquals(HttpGet.METHOD_NAME, request.getMethod());
assertEquals("/_xpack/ml/calendars/" + calendarId + "/events", request.getEndpoint());
try (XContentParser parser = createParser(JsonXContent.jsonXContent, request.getEntity().getContent())) {
GetCalendarEventsRequest parsedRequest = GetCalendarEventsRequest.PARSER.apply(parser, null);
assertThat(parsedRequest, equalTo(getCalendarEventsRequest));
}
}

public void testPostCalendarEvent() throws Exception {
String calendarId = randomAlphaOfLength(10);
List<ScheduledEvent> events = Arrays.asList(ScheduledEventTests.testInstance(),
Expand Down
Loading

0 comments on commit a21169f

Please sign in to comment.