Skip to content

Commit 026488b

Browse files
authored
HLRC: ML Adding get datafeed stats API (#34271)
* HLRC: ML Adding get datafeed stats API * addressing PR comments * fixing field exclusion filter * removing unnecessary whitespace
1 parent a6c5b68 commit 026488b

File tree

14 files changed

+919
-1
lines changed

14 files changed

+919
-1
lines changed

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.elasticsearch.client.ml.GetCalendarsRequest;
3939
import org.elasticsearch.client.ml.GetCategoriesRequest;
4040
import org.elasticsearch.client.ml.GetDatafeedRequest;
41+
import org.elasticsearch.client.ml.GetDatafeedStatsRequest;
4142
import org.elasticsearch.client.ml.GetInfluencersRequest;
4243
import org.elasticsearch.client.ml.GetJobRequest;
4344
import org.elasticsearch.client.ml.GetJobStatsRequest;
@@ -260,6 +261,23 @@ static Request stopDatafeed(StopDatafeedRequest stopDatafeedRequest) throws IOEx
260261
return request;
261262
}
262263

264+
static Request getDatafeedStats(GetDatafeedStatsRequest getDatafeedStatsRequest) {
265+
String endpoint = new EndpointBuilder()
266+
.addPathPartAsIs("_xpack")
267+
.addPathPartAsIs("ml")
268+
.addPathPartAsIs("datafeeds")
269+
.addPathPart(Strings.collectionToCommaDelimitedString(getDatafeedStatsRequest.getDatafeedIds()))
270+
.addPathPartAsIs("_stats")
271+
.build();
272+
Request request = new Request(HttpGet.METHOD_NAME, endpoint);
273+
274+
RequestConverters.Params params = new RequestConverters.Params(request);
275+
if (getDatafeedStatsRequest.isAllowNoDatafeeds() != null) {
276+
params.putParam("allow_no_datafeeds", Boolean.toString(getDatafeedStatsRequest.isAllowNoDatafeeds()));
277+
}
278+
return request;
279+
}
280+
263281
static Request previewDatafeed(PreviewDatafeedRequest previewDatafeedRequest) {
264282
String endpoint = new EndpointBuilder()
265283
.addPathPartAsIs("_xpack")

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

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
import org.elasticsearch.client.ml.GetCategoriesResponse;
3939
import org.elasticsearch.client.ml.GetDatafeedRequest;
4040
import org.elasticsearch.client.ml.GetDatafeedResponse;
41+
import org.elasticsearch.client.ml.GetDatafeedStatsRequest;
42+
import org.elasticsearch.client.ml.GetDatafeedStatsResponse;
4143
import org.elasticsearch.client.ml.GetInfluencersRequest;
4244
import org.elasticsearch.client.ml.GetInfluencersResponse;
4345
import org.elasticsearch.client.ml.GetJobRequest;
@@ -183,7 +185,7 @@ public GetJobStatsResponse getJobStats(GetJobStatsRequest request, RequestOption
183185
}
184186

185187
/**
186-
* Gets one or more Machine Learning job configuration info, asynchronously.
188+
* Gets usage statistics for one or more Machine Learning jobs, asynchronously.
187189
* <p>
188190
* For additional info
189191
* see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-job-stats.html">Get job stats docs</a>
@@ -651,6 +653,26 @@ public void stopDatafeedAsync(StopDatafeedRequest request, RequestOptions option
651653
Collections.emptySet());
652654
}
653655

656+
/**
657+
* Gets statistics for one or more Machine Learning datafeeds
658+
* <p>
659+
* For additional info
660+
* see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-datafeed-stats.html">Get datafeed stats docs</a>
661+
*
662+
* @param request {@link GetDatafeedStatsRequest} Request containing a list of datafeedId(s) and additional options
663+
* @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
664+
* @return {@link GetDatafeedStatsResponse} response object containing
665+
* the {@link org.elasticsearch.client.ml.datafeed.DatafeedStats} objects and the number of datafeeds found
666+
* @throws IOException when there is a serialization issue sending the request or receiving the response
667+
*/
668+
public GetDatafeedStatsResponse getDatafeedStats(GetDatafeedStatsRequest request, RequestOptions options) throws IOException {
669+
return restHighLevelClient.performRequestAndParseEntity(request,
670+
MLRequestConverters::getDatafeedStats,
671+
options,
672+
GetDatafeedStatsResponse::fromXContent,
673+
Collections.emptySet());
674+
}
675+
654676
/**
655677
* Previews the given Machine Learning Datafeed
656678
* <p>
@@ -672,6 +694,27 @@ public PreviewDatafeedResponse previewDatafeed(PreviewDatafeedRequest request, R
672694
Collections.emptySet());
673695
}
674696

697+
/**
698+
* Gets statistics for one or more Machine Learning datafeeds, asynchronously.
699+
* <p>
700+
* For additional info
701+
* see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-datafeed-stats.html">Get datafeed stats docs</a>
702+
*
703+
* @param request {@link GetDatafeedStatsRequest} Request containing a list of datafeedId(s) and additional options
704+
* @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
705+
* @param listener Listener to be notified with {@link GetDatafeedStatsResponse} upon request completion
706+
*/
707+
public void getDatafeedStatsAsync(GetDatafeedStatsRequest request,
708+
RequestOptions options,
709+
ActionListener<GetDatafeedStatsResponse> listener) {
710+
restHighLevelClient.performRequestAsyncAndParseEntity(request,
711+
MLRequestConverters::getDatafeedStats,
712+
options,
713+
GetDatafeedStatsResponse::fromXContent,
714+
listener,
715+
Collections.emptySet());
716+
}
717+
675718
/**
676719
* Previews the given Machine Learning Datafeed asynchronously and notifies the listener on completion
677720
* <p>
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
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+
package org.elasticsearch.client.ml;
20+
21+
import org.elasticsearch.action.ActionRequest;
22+
import org.elasticsearch.action.ActionRequestValidationException;
23+
import org.elasticsearch.client.ml.datafeed.DatafeedConfig;
24+
import org.elasticsearch.common.ParseField;
25+
import org.elasticsearch.common.Strings;
26+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
27+
import org.elasticsearch.common.xcontent.ObjectParser;
28+
import org.elasticsearch.common.xcontent.ToXContent;
29+
import org.elasticsearch.common.xcontent.ToXContentObject;
30+
import org.elasticsearch.common.xcontent.XContentBuilder;
31+
32+
import java.io.IOException;
33+
import java.util.ArrayList;
34+
import java.util.Arrays;
35+
import java.util.List;
36+
import java.util.Objects;
37+
38+
/**
39+
* Request object to get {@link org.elasticsearch.client.ml.datafeed.DatafeedStats} by their respective datafeedIds
40+
*
41+
* {@code _all} explicitly gets all the datafeeds' statistics in the cluster
42+
* An empty request (no {@code datafeedId}s) implicitly gets all the datafeeds' statistics in the cluster
43+
*/
44+
public class GetDatafeedStatsRequest extends ActionRequest implements ToXContentObject {
45+
46+
public static final ParseField ALLOW_NO_DATAFEEDS = new ParseField("allow_no_datafeeds");
47+
48+
@SuppressWarnings("unchecked")
49+
public static final ConstructingObjectParser<GetDatafeedStatsRequest, Void> PARSER = new ConstructingObjectParser<>(
50+
"get_datafeed_stats_request", a -> new GetDatafeedStatsRequest((List<String>) a[0]));
51+
52+
static {
53+
PARSER.declareField(ConstructingObjectParser.constructorArg(),
54+
p -> Arrays.asList(Strings.commaDelimitedListToStringArray(p.text())),
55+
DatafeedConfig.ID, ObjectParser.ValueType.STRING_ARRAY);
56+
PARSER.declareBoolean(GetDatafeedStatsRequest::setAllowNoDatafeeds, ALLOW_NO_DATAFEEDS);
57+
}
58+
59+
private static final String ALL_DATAFEEDS = "_all";
60+
61+
private final List<String> datafeedIds;
62+
private Boolean allowNoDatafeeds;
63+
64+
/**
65+
* Explicitly gets all datafeeds statistics
66+
*
67+
* @return a {@link GetDatafeedStatsRequest} for all existing datafeeds
68+
*/
69+
public static GetDatafeedStatsRequest getAllDatafeedStatsRequest(){
70+
return new GetDatafeedStatsRequest(ALL_DATAFEEDS);
71+
}
72+
73+
GetDatafeedStatsRequest(List<String> datafeedIds) {
74+
if (datafeedIds.stream().anyMatch(Objects::isNull)) {
75+
throw new NullPointerException("datafeedIds must not contain null values");
76+
}
77+
this.datafeedIds = new ArrayList<>(datafeedIds);
78+
}
79+
80+
/**
81+
* Get the specified Datafeed's statistics via their unique datafeedIds
82+
*
83+
* @param datafeedIds must be non-null and each datafeedId must be non-null
84+
*/
85+
public GetDatafeedStatsRequest(String... datafeedIds) {
86+
this(Arrays.asList(datafeedIds));
87+
}
88+
89+
/**
90+
* All the datafeedIds for which to get statistics
91+
*/
92+
public List<String> getDatafeedIds() {
93+
return datafeedIds;
94+
}
95+
96+
public Boolean isAllowNoDatafeeds() {
97+
return this.allowNoDatafeeds;
98+
}
99+
100+
/**
101+
* Whether to ignore if a wildcard expression matches no datafeeds.
102+
*
103+
* This includes {@code _all} string or when no datafeeds have been specified
104+
*
105+
* @param allowNoDatafeeds When {@code true} ignore if wildcard or {@code _all} matches no datafeeds. Defaults to {@code true}
106+
*/
107+
public void setAllowNoDatafeeds(boolean allowNoDatafeeds) {
108+
this.allowNoDatafeeds = allowNoDatafeeds;
109+
}
110+
111+
@Override
112+
public int hashCode() {
113+
return Objects.hash(datafeedIds, allowNoDatafeeds);
114+
}
115+
116+
@Override
117+
public boolean equals(Object other) {
118+
if (this == other) {
119+
return true;
120+
}
121+
122+
if (other == null || getClass() != other.getClass()) {
123+
return false;
124+
}
125+
126+
GetDatafeedStatsRequest that = (GetDatafeedStatsRequest) other;
127+
return Objects.equals(datafeedIds, that.datafeedIds) &&
128+
Objects.equals(allowNoDatafeeds, that.allowNoDatafeeds);
129+
}
130+
131+
@Override
132+
public ActionRequestValidationException validate() {
133+
return null;
134+
}
135+
136+
@Override
137+
public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
138+
builder.startObject();
139+
builder.field(DatafeedConfig.ID.getPreferredName(), Strings.collectionToCommaDelimitedString(datafeedIds));
140+
if (allowNoDatafeeds != null) {
141+
builder.field(ALLOW_NO_DATAFEEDS.getPreferredName(), allowNoDatafeeds);
142+
}
143+
builder.endObject();
144+
return builder;
145+
}
146+
147+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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+
package org.elasticsearch.client.ml;
20+
21+
import org.elasticsearch.client.ml.datafeed.DatafeedStats;
22+
import org.elasticsearch.common.ParseField;
23+
import org.elasticsearch.common.Strings;
24+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
25+
import org.elasticsearch.common.xcontent.XContentParser;
26+
27+
import java.io.IOException;
28+
import java.util.List;
29+
import java.util.Objects;
30+
31+
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
32+
33+
/**
34+
* Contains a {@link List} of the found {@link DatafeedStats} objects and the total count found
35+
*/
36+
public class GetDatafeedStatsResponse extends AbstractResultResponse<DatafeedStats> {
37+
38+
public static final ParseField RESULTS_FIELD = new ParseField("datafeeds");
39+
40+
@SuppressWarnings("unchecked")
41+
public static final ConstructingObjectParser<GetDatafeedStatsResponse, Void> PARSER =
42+
new ConstructingObjectParser<>("get_datafeed_stats_response",
43+
true,
44+
a -> new GetDatafeedStatsResponse((List<DatafeedStats>) a[0], (long) a[1]));
45+
46+
static {
47+
PARSER.declareObjectArray(constructorArg(), DatafeedStats.PARSER, RESULTS_FIELD);
48+
PARSER.declareLong(constructorArg(), COUNT);
49+
}
50+
51+
GetDatafeedStatsResponse(List<DatafeedStats> results, long count) {
52+
super(RESULTS_FIELD, results, count);
53+
}
54+
55+
/**
56+
* The collection of {@link DatafeedStats} objects found in the query
57+
*/
58+
public List<DatafeedStats> datafeedStats() {
59+
return results;
60+
}
61+
62+
public static GetDatafeedStatsResponse fromXContent(XContentParser parser) throws IOException {
63+
return PARSER.parse(parser, null);
64+
}
65+
66+
@Override
67+
public int hashCode() {
68+
return Objects.hash(results, count);
69+
}
70+
71+
@Override
72+
public boolean equals(Object obj) {
73+
if (this == obj) {
74+
return true;
75+
}
76+
77+
if (obj == null || getClass() != obj.getClass()) {
78+
return false;
79+
}
80+
81+
GetDatafeedStatsResponse other = (GetDatafeedStatsResponse) obj;
82+
return Objects.equals(results, other.results) && count == other.count;
83+
}
84+
85+
@Override
86+
public final String toString() {
87+
return Strings.toString(this);
88+
}
89+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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+
package org.elasticsearch.client.ml.datafeed;
20+
21+
import org.elasticsearch.common.ParseField;
22+
23+
import java.util.Locale;
24+
25+
/**
26+
* Datafeed State POJO
27+
*/
28+
public enum DatafeedState {
29+
30+
STARTED, STOPPED, STARTING, STOPPING;
31+
32+
public static final ParseField STATE = new ParseField("state");
33+
34+
public static DatafeedState fromString(String name) {
35+
return valueOf(name.trim().toUpperCase(Locale.ROOT));
36+
}
37+
38+
@Override
39+
public String toString() {
40+
return name().toLowerCase(Locale.ROOT);
41+
}
42+
}

0 commit comments

Comments
 (0)