Skip to content

Commit 42d5811

Browse files
committed
HLRC: Get ML calendars (#33760)
1 parent ba2465c commit 42d5811

18 files changed

+563
-66
lines changed

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

+15-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.elasticsearch.client.ml.FlushJobRequest;
3535
import org.elasticsearch.client.ml.ForecastJobRequest;
3636
import org.elasticsearch.client.ml.GetBucketsRequest;
37+
import org.elasticsearch.client.ml.GetCalendarsRequest;
3738
import org.elasticsearch.client.ml.GetCategoriesRequest;
3839
import org.elasticsearch.client.ml.GetDatafeedRequest;
3940
import org.elasticsearch.client.ml.GetInfluencersRequest;
@@ -229,7 +230,7 @@ static Request deleteDatafeed(DeleteDatafeedRequest deleteDatafeedRequest) {
229230
return request;
230231
}
231232

232-
static Request deleteForecast(DeleteForecastRequest deleteForecastRequest) throws IOException {
233+
static Request deleteForecast(DeleteForecastRequest deleteForecastRequest) {
233234
String endpoint = new EndpointBuilder()
234235
.addPathPartAsIs("_xpack")
235236
.addPathPartAsIs("ml")
@@ -305,7 +306,7 @@ static Request getRecords(GetRecordsRequest getRecordsRequest) throws IOExceptio
305306
return request;
306307
}
307308

308-
static Request postData(PostDataRequest postDataRequest) throws IOException {
309+
static Request postData(PostDataRequest postDataRequest) {
309310
String endpoint = new EndpointBuilder()
310311
.addPathPartAsIs("_xpack")
311312
.addPathPartAsIs("ml")
@@ -359,4 +360,16 @@ static Request putCalendar(PutCalendarRequest putCalendarRequest) throws IOExcep
359360
request.setEntity(createEntity(putCalendarRequest, REQUEST_BODY_CONTENT_TYPE));
360361
return request;
361362
}
363+
364+
static Request getCalendars(GetCalendarsRequest getCalendarsRequest) throws IOException {
365+
String endpoint = new EndpointBuilder()
366+
.addPathPartAsIs("_xpack")
367+
.addPathPartAsIs("ml")
368+
.addPathPartAsIs("calendars")
369+
.addPathPart(getCalendarsRequest.getCalendarId())
370+
.build();
371+
Request request = new Request(HttpGet.METHOD_NAME, endpoint);
372+
request.setEntity(createEntity(getCalendarsRequest, REQUEST_BODY_CONTENT_TYPE));
373+
return request;
374+
}
362375
}

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

+40
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
import org.elasticsearch.client.ml.ForecastJobResponse;
3232
import org.elasticsearch.client.ml.GetBucketsRequest;
3333
import org.elasticsearch.client.ml.GetBucketsResponse;
34+
import org.elasticsearch.client.ml.GetCalendarsRequest;
35+
import org.elasticsearch.client.ml.GetCalendarsResponse;
3436
import org.elasticsearch.client.ml.GetCategoriesRequest;
3537
import org.elasticsearch.client.ml.GetCategoriesResponse;
3638
import org.elasticsearch.client.ml.GetDatafeedRequest;
@@ -792,6 +794,44 @@ public void postDataAsync(PostDataRequest request, RequestOptions options, Actio
792794
Collections.emptySet());
793795
}
794796

797+
/**
798+
* Gets a single or multiple calendars.
799+
* <p>
800+
* For additional info
801+
* see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-calendar.html">ML GET calendars documentation</a>
802+
*
803+
* @param request The calendars request
804+
* @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
805+
* @return {@link GetCalendarsResponse} response object containing the {@link org.elasticsearch.client.ml.calendars.Calendar}
806+
* objects and the number of calendars found
807+
*/
808+
public GetCalendarsResponse getCalendars(GetCalendarsRequest request, RequestOptions options) throws IOException {
809+
return restHighLevelClient.performRequestAndParseEntity(request,
810+
MLRequestConverters::getCalendars,
811+
options,
812+
GetCalendarsResponse::fromXContent,
813+
Collections.emptySet());
814+
}
815+
816+
/**
817+
* Gets a single or multiple calendars, notifies listener once the requested records are retrieved.
818+
* <p>
819+
* For additional info
820+
* see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-calendar.html">ML GET calendars documentation</a>
821+
*
822+
* @param request The calendars request
823+
* @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
824+
* @param listener Listener to be notified upon request completion
825+
*/
826+
public void getCalendarsAsync(GetCalendarsRequest request, RequestOptions options, ActionListener<GetCalendarsResponse> listener) {
827+
restHighLevelClient.performRequestAsyncAndParseEntity(request,
828+
MLRequestConverters::getCalendars,
829+
options,
830+
GetCalendarsResponse::fromXContent,
831+
listener,
832+
Collections.emptySet());
833+
}
834+
795835
/**
796836
* Gets the influencers for a Machine Learning Job.
797837
* <p>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.client.ml;
21+
22+
import org.elasticsearch.action.ActionRequest;
23+
import org.elasticsearch.action.ActionRequestValidationException;
24+
import org.elasticsearch.client.ml.calendars.Calendar;
25+
import org.elasticsearch.common.xcontent.ObjectParser;
26+
import org.elasticsearch.common.xcontent.ToXContentObject;
27+
import org.elasticsearch.common.xcontent.XContentBuilder;
28+
29+
import org.elasticsearch.client.ml.job.util.PageParams;
30+
31+
import java.io.IOException;
32+
import java.util.Objects;
33+
34+
public class GetCalendarsRequest extends ActionRequest implements ToXContentObject {
35+
36+
public static final ObjectParser<GetCalendarsRequest, Void> PARSER =
37+
new ObjectParser<>("get_calendars_request", GetCalendarsRequest::new);
38+
39+
static {
40+
PARSER.declareString(GetCalendarsRequest::setCalendarId, Calendar.ID);
41+
PARSER.declareObject(GetCalendarsRequest::setPageParams, PageParams.PARSER, PageParams.PAGE);
42+
}
43+
44+
private String calendarId;
45+
private PageParams pageParams;
46+
47+
public GetCalendarsRequest() {
48+
}
49+
50+
public GetCalendarsRequest(String calendarId) {
51+
this.calendarId = calendarId;
52+
}
53+
54+
public String getCalendarId() {
55+
return calendarId;
56+
}
57+
58+
public void setCalendarId(String calendarId) {
59+
this.calendarId = calendarId;
60+
}
61+
62+
public PageParams getPageParams() {
63+
return pageParams;
64+
}
65+
66+
public void setPageParams(PageParams pageParams) {
67+
this.pageParams = pageParams;
68+
}
69+
70+
@Override
71+
public ActionRequestValidationException validate() {
72+
return null;
73+
}
74+
75+
@Override
76+
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
77+
builder.startObject();
78+
if (calendarId != null) {
79+
builder.field(Calendar.ID.getPreferredName(), calendarId);
80+
}
81+
if (pageParams != null) {
82+
builder.field(PageParams.PAGE.getPreferredName(), pageParams);
83+
}
84+
builder.endObject();
85+
return builder;
86+
}
87+
88+
@Override
89+
public int hashCode() {
90+
return Objects.hash(calendarId, pageParams);
91+
}
92+
93+
@Override
94+
public boolean equals(Object obj) {
95+
if (obj == null) {
96+
return false;
97+
}
98+
if (getClass() != obj.getClass()) {
99+
return false;
100+
}
101+
GetCalendarsRequest other = (GetCalendarsRequest) obj;
102+
return Objects.equals(calendarId, other.calendarId) && Objects.equals(pageParams, other.pageParams);
103+
}
104+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.client.ml;
21+
22+
import org.elasticsearch.client.ml.calendars.Calendar;
23+
import org.elasticsearch.common.ParseField;
24+
import org.elasticsearch.common.Strings;
25+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
26+
import org.elasticsearch.common.xcontent.XContentParser;
27+
28+
import java.io.IOException;
29+
import java.util.List;
30+
import java.util.Objects;
31+
32+
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
33+
34+
public class GetCalendarsResponse extends AbstractResultResponse<Calendar> {
35+
36+
public static final ParseField RESULTS_FIELD = new ParseField("calendars");
37+
38+
@SuppressWarnings("unchecked")
39+
public static final ConstructingObjectParser<GetCalendarsResponse, Void> PARSER =
40+
new ConstructingObjectParser<>("calendars_response", true,
41+
a -> new GetCalendarsResponse((List<Calendar>) a[0], (long) a[1]));
42+
43+
static {
44+
PARSER.declareObjectArray(constructorArg(), Calendar.PARSER, RESULTS_FIELD);
45+
PARSER.declareLong(constructorArg(), AbstractResultResponse.COUNT);
46+
}
47+
48+
public static GetCalendarsResponse fromXContent(XContentParser parser) throws IOException {
49+
return PARSER.parse(parser, null);
50+
}
51+
52+
GetCalendarsResponse(List<Calendar> calendars, long count) {
53+
super(RESULTS_FIELD, calendars, count);
54+
}
55+
56+
/**
57+
* The collection of {@link Calendar} objects found in the query
58+
*/
59+
public List<Calendar> calendars() {
60+
return results;
61+
}
62+
63+
@Override
64+
public int hashCode() {
65+
return Objects.hash(results, count);
66+
}
67+
68+
@Override
69+
public boolean equals(Object obj) {
70+
if (this == obj) {
71+
return true;
72+
}
73+
74+
if (obj == null || getClass() != obj.getClass()) {
75+
return false;
76+
}
77+
78+
GetCalendarsResponse other = (GetCalendarsResponse) obj;
79+
return Objects.equals(results, other.results) && count == other.count;
80+
}
81+
82+
@Override
83+
public final String toString() {
84+
return Strings.toString(this);
85+
}
86+
}

client/rest-high-level/src/main/java/org/elasticsearch/client/ml/job/results/AnomalyRecord.java

+4-12
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,14 @@
1919
package org.elasticsearch.client.ml.job.results;
2020

2121
import org.elasticsearch.client.ml.job.config.Job;
22+
import org.elasticsearch.client.ml.job.util.TimeUtil;
2223
import org.elasticsearch.common.ParseField;
23-
import org.elasticsearch.common.time.DateFormatters;
2424
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
2525
import org.elasticsearch.common.xcontent.ObjectParser.ValueType;
2626
import org.elasticsearch.common.xcontent.ToXContentObject;
2727
import org.elasticsearch.common.xcontent.XContentBuilder;
28-
import org.elasticsearch.common.xcontent.XContentParser.Token;
2928

3029
import java.io.IOException;
31-
import java.time.format.DateTimeFormatter;
3230
import java.util.Collections;
3331
import java.util.Date;
3432
import java.util.List;
@@ -90,15 +88,9 @@ public class AnomalyRecord implements ToXContentObject {
9088

9189
static {
9290
PARSER.declareString(ConstructingObjectParser.constructorArg(), Job.ID);
93-
PARSER.declareField(ConstructingObjectParser.constructorArg(), p -> {
94-
if (p.currentToken() == Token.VALUE_NUMBER) {
95-
return new Date(p.longValue());
96-
} else if (p.currentToken() == Token.VALUE_STRING) {
97-
return new Date(DateFormatters.toZonedDateTime(DateTimeFormatter.ISO_INSTANT.parse(p.text())).toInstant().toEpochMilli());
98-
}
99-
throw new IllegalArgumentException("unexpected token [" + p.currentToken() + "] for ["
100-
+ Result.TIMESTAMP.getPreferredName() + "]");
101-
}, Result.TIMESTAMP, ValueType.VALUE);
91+
PARSER.declareField(ConstructingObjectParser.constructorArg(),
92+
(p) -> TimeUtil.parseTimeField(p, Result.TIMESTAMP.getPreferredName()),
93+
Result.TIMESTAMP, ValueType.VALUE);
10294
PARSER.declareLong(ConstructingObjectParser.constructorArg(), BUCKET_SPAN);
10395
PARSER.declareString((anomalyRecord, s) -> {}, Result.RESULT_TYPE);
10496
PARSER.declareDouble(AnomalyRecord::setProbability, PROBABILITY);

client/rest-high-level/src/main/java/org/elasticsearch/client/ml/job/results/Bucket.java

+3-12
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,14 @@
1919
package org.elasticsearch.client.ml.job.results;
2020

2121
import org.elasticsearch.client.ml.job.config.Job;
22+
import org.elasticsearch.client.ml.job.util.TimeUtil;
2223
import org.elasticsearch.common.ParseField;
23-
import org.elasticsearch.common.time.DateFormatters;
2424
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
2525
import org.elasticsearch.common.xcontent.ObjectParser.ValueType;
2626
import org.elasticsearch.common.xcontent.ToXContentObject;
2727
import org.elasticsearch.common.xcontent.XContentBuilder;
28-
import org.elasticsearch.common.xcontent.XContentParser.Token;
2928

3029
import java.io.IOException;
31-
import java.time.format.DateTimeFormatter;
3230
import java.util.ArrayList;
3331
import java.util.Collections;
3432
import java.util.Date;
@@ -63,15 +61,8 @@ public class Bucket implements ToXContentObject {
6361

6462
static {
6563
PARSER.declareString(ConstructingObjectParser.constructorArg(), Job.ID);
66-
PARSER.declareField(ConstructingObjectParser.constructorArg(), p -> {
67-
if (p.currentToken() == Token.VALUE_NUMBER) {
68-
return new Date(p.longValue());
69-
} else if (p.currentToken() == Token.VALUE_STRING) {
70-
return new Date(DateFormatters.toZonedDateTime(DateTimeFormatter.ISO_INSTANT.parse(p.text())).toInstant().toEpochMilli());
71-
}
72-
throw new IllegalArgumentException("unexpected token [" + p.currentToken() + "] for ["
73-
+ Result.TIMESTAMP.getPreferredName() + "]");
74-
}, Result.TIMESTAMP, ValueType.VALUE);
64+
PARSER.declareField(ConstructingObjectParser.constructorArg(),
65+
(p) -> TimeUtil.parseTimeField(p, Result.TIMESTAMP.getPreferredName()), Result.TIMESTAMP, ValueType.VALUE);
7566
PARSER.declareLong(ConstructingObjectParser.constructorArg(), BUCKET_SPAN);
7667
PARSER.declareDouble(Bucket::setAnomalyScore, ANOMALY_SCORE);
7768
PARSER.declareDouble(Bucket::setInitialAnomalyScore, INITIAL_ANOMALY_SCORE);

client/rest-high-level/src/main/java/org/elasticsearch/client/ml/job/results/BucketInfluencer.java

+4-12
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,14 @@
1919
package org.elasticsearch.client.ml.job.results;
2020

2121
import org.elasticsearch.client.ml.job.config.Job;
22+
import org.elasticsearch.client.ml.job.util.TimeUtil;
2223
import org.elasticsearch.common.ParseField;
23-
import org.elasticsearch.common.time.DateFormatters;
2424
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
2525
import org.elasticsearch.common.xcontent.ObjectParser.ValueType;
2626
import org.elasticsearch.common.xcontent.ToXContentObject;
2727
import org.elasticsearch.common.xcontent.XContentBuilder;
28-
import org.elasticsearch.common.xcontent.XContentParser.Token;
2928

3029
import java.io.IOException;
31-
import java.time.format.DateTimeFormatter;
3230
import java.util.Date;
3331
import java.util.Objects;
3432

@@ -56,15 +54,9 @@ public class BucketInfluencer implements ToXContentObject {
5654

5755
static {
5856
PARSER.declareString(ConstructingObjectParser.constructorArg(), Job.ID);
59-
PARSER.declareField(ConstructingObjectParser.constructorArg(), p -> {
60-
if (p.currentToken() == Token.VALUE_NUMBER) {
61-
return new Date(p.longValue());
62-
} else if (p.currentToken() == Token.VALUE_STRING) {
63-
return new Date(DateFormatters.toZonedDateTime(DateTimeFormatter.ISO_INSTANT.parse(p.text())).toInstant().toEpochMilli());
64-
}
65-
throw new IllegalArgumentException("unexpected token [" + p.currentToken() + "] for ["
66-
+ Result.TIMESTAMP.getPreferredName() + "]");
67-
}, Result.TIMESTAMP, ValueType.VALUE);
57+
PARSER.declareField(ConstructingObjectParser.constructorArg(),
58+
(p) -> TimeUtil.parseTimeField(p, Result.TIMESTAMP.getPreferredName()),
59+
Result.TIMESTAMP, ValueType.VALUE);
6860
PARSER.declareLong(ConstructingObjectParser.constructorArg(), BUCKET_SPAN);
6961
PARSER.declareString((bucketInfluencer, s) -> {}, Result.RESULT_TYPE);
7062
PARSER.declareString(BucketInfluencer::setInfluencerFieldName, INFLUENCER_FIELD_NAME);

0 commit comments

Comments
 (0)