Skip to content

Commit

Permalink
[HLRC][ML] Add ML get datafeed API to HLRC (#33715)
Browse files Browse the repository at this point in the history
Relates #29827
  • Loading branch information
dimitris-athanasiou committed Sep 16, 2018
1 parent 2ae3b44 commit b824ed9
Show file tree
Hide file tree
Showing 19 changed files with 736 additions and 97 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.elasticsearch.client.ml.ForecastJobRequest;
import org.elasticsearch.client.ml.GetBucketsRequest;
import org.elasticsearch.client.ml.GetCategoriesRequest;
import org.elasticsearch.client.ml.GetDatafeedRequest;
import org.elasticsearch.client.ml.GetInfluencersRequest;
import org.elasticsearch.client.ml.GetJobRequest;
import org.elasticsearch.client.ml.GetJobStatsRequest;
Expand Down Expand Up @@ -196,6 +197,24 @@ static Request putDatafeed(PutDatafeedRequest putDatafeedRequest) throws IOExcep
return request;
}

static Request getDatafeed(GetDatafeedRequest getDatafeedRequest) {
String endpoint = new EndpointBuilder()
.addPathPartAsIs("_xpack")
.addPathPartAsIs("ml")
.addPathPartAsIs("datafeeds")
.addPathPart(Strings.collectionToCommaDelimitedString(getDatafeedRequest.getDatafeedIds()))
.build();
Request request = new Request(HttpGet.METHOD_NAME, endpoint);

RequestConverters.Params params = new RequestConverters.Params(request);
if (getDatafeedRequest.isAllowNoDatafeeds() != null) {
params.putParam(GetDatafeedRequest.ALLOW_NO_DATAFEEDS.getPreferredName(),
Boolean.toString(getDatafeedRequest.isAllowNoDatafeeds()));
}

return request;
}

static Request deleteDatafeed(DeleteDatafeedRequest deleteDatafeedRequest) {
String endpoint = new EndpointBuilder()
.addPathPartAsIs("_xpack")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
import org.elasticsearch.client.ml.GetBucketsResponse;
import org.elasticsearch.client.ml.GetCategoriesRequest;
import org.elasticsearch.client.ml.GetCategoriesResponse;
import org.elasticsearch.client.ml.GetDatafeedRequest;
import org.elasticsearch.client.ml.GetDatafeedResponse;
import org.elasticsearch.client.ml.GetInfluencersRequest;
import org.elasticsearch.client.ml.GetInfluencersResponse;
import org.elasticsearch.client.ml.GetJobRequest;
Expand Down Expand Up @@ -479,8 +481,8 @@ public PutDatafeedResponse putDatafeed(PutDatafeedRequest request, RequestOption
* For additional info
* see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-put-datafeed.html">ML PUT datafeed documentation</a>
*
* @param request The request containing the {@link org.elasticsearch.client.ml.datafeed.DatafeedConfig} settings
* @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @param request The request containing the {@link org.elasticsearch.client.ml.datafeed.DatafeedConfig} settings
* @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 putDatafeedAsync(PutDatafeedRequest request, RequestOptions options, ActionListener<PutDatafeedResponse> listener) {
Expand All @@ -492,6 +494,47 @@ public void putDatafeedAsync(PutDatafeedRequest request, RequestOptions options,
Collections.emptySet());
}

/**
* Gets one or more Machine Learning datafeed configuration info.
*
* <p>
* For additional info
* see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-datafeed.html">ML GET datafeed documentation</a>
*
* @param request {@link GetDatafeedRequest} Request containing a list of datafeedId(s) and additional options
* @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @return {@link GetDatafeedResponse} response object containing
* the {@link org.elasticsearch.client.ml.datafeed.DatafeedConfig} objects and the number of jobs found
* @throws IOException when there is a serialization issue sending the request or receiving the response
*/
public GetDatafeedResponse getDatafeed(GetDatafeedRequest request, RequestOptions options) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(request,
MLRequestConverters::getDatafeed,
options,
GetDatafeedResponse::fromXContent,
Collections.emptySet());
}

/**
* Gets one or more Machine Learning datafeed configuration info, asynchronously.
*
* <p>
* For additional info
* see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-datafeed.html">ML GET datafeed documentation</a>
*
* @param request {@link GetDatafeedRequest} Request containing a list of datafeedId(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 GetDatafeedResponse} upon request completion
*/
public void getDatafeedAsync(GetDatafeedRequest request, RequestOptions options, ActionListener<GetDatafeedResponse> listener) {
restHighLevelClient.performRequestAsyncAndParseEntity(request,
MLRequestConverters::getDatafeed,
options,
GetDatafeedResponse::fromXContent,
listener,
Collections.emptySet());
}

/**
* Deletes the given Machine Learning Datafeed
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@ public Boolean isAllowNoJobs() {
/**
* Whether to ignore if a wildcard expression matches no jobs.
*
* This includes `_all` string or when no jobs have been specified
* This includes {@code _all} string or when no jobs have been specified
*
* @param allowNoJobs When {@code true} ignore if wildcard or `_all` matches no jobs. Defaults to {@code true}
* @param allowNoJobs When {@code true} ignore if wildcard or {@code _all} matches no jobs. Defaults to {@code true}
*/
public void setAllowNoJobs(boolean allowNoJobs) {
this.allowNoJobs = allowNoJobs;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public Boolean isAllowNoForecasts() {
}

/**
* Sets the `allow_no_forecasts` field.
* Sets the value of "allow_no_forecasts".
*
* @param allowNoForecasts when {@code true} no error is thrown when {@link DeleteForecastRequest#ALL} does not find any forecasts
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* 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.datafeed.DatafeedConfig;
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.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
* Request object to get {@link DatafeedConfig} objects with the matching {@code datafeedId}s.
*
* {@code _all} explicitly gets all the datafeeds in the cluster
* An empty request (no {@code datafeedId}s) implicitly gets all the datafeeds in the cluster
*/
public class GetDatafeedRequest extends ActionRequest implements ToXContentObject {

public static final ParseField DATAFEED_IDS = new ParseField("datafeed_ids");
public static final ParseField ALLOW_NO_DATAFEEDS = new ParseField("allow_no_datafeeds");

private static final String ALL_DATAFEEDS = "_all";
private final List<String> datafeedIds;
private Boolean allowNoDatafeeds;

@SuppressWarnings("unchecked")
public static final ConstructingObjectParser<GetDatafeedRequest, Void> PARSER = new ConstructingObjectParser<>(
"get_datafeed_request",
true, a -> new GetDatafeedRequest(a[0] == null ? new ArrayList<>() : (List<String>) a[0]));

static {
PARSER.declareStringArray(ConstructingObjectParser.optionalConstructorArg(), DATAFEED_IDS);
PARSER.declareBoolean(GetDatafeedRequest::setAllowNoDatafeeds, ALLOW_NO_DATAFEEDS);
}

/**
* Helper method to create a query that will get ALL datafeeds
* @return new {@link GetDatafeedRequest} object searching for the datafeedId "_all"
*/
public static GetDatafeedRequest getAllDatafeedsRequest() {
return new GetDatafeedRequest(ALL_DATAFEEDS);
}

/**
* Get the specified {@link DatafeedConfig} configurations via their unique datafeedIds
* @param datafeedIds must not contain any null values
*/
public GetDatafeedRequest(String... datafeedIds) {
this(Arrays.asList(datafeedIds));
}

GetDatafeedRequest(List<String> datafeedIds) {
if (datafeedIds.stream().anyMatch(Objects::isNull)) {
throw new NullPointerException("datafeedIds must not contain null values");
}
this.datafeedIds = new ArrayList<>(datafeedIds);
}

/**
* All the datafeedIds for which to get configuration information
*/
public List<String> getDatafeedIds() {
return datafeedIds;
}

/**
* Whether to ignore if a wildcard expression matches no datafeeds.
*
* @param allowNoDatafeeds If this is {@code false}, then an error is returned when a wildcard (or {@code _all})
* does not match any datafeeds
*/
public void setAllowNoDatafeeds(boolean allowNoDatafeeds) {
this.allowNoDatafeeds = allowNoDatafeeds;
}

public Boolean isAllowNoDatafeeds() {
return allowNoDatafeeds;
}

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

@Override
public int hashCode() {
return Objects.hash(datafeedIds, allowNoDatafeeds);
}

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

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

GetDatafeedRequest that = (GetDatafeedRequest) other;
return Objects.equals(datafeedIds, that.datafeedIds) &&
Objects.equals(allowNoDatafeeds, that.allowNoDatafeeds);
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();

if (datafeedIds.isEmpty() == false) {
builder.field(DATAFEED_IDS.getPreferredName(), datafeedIds);
}

if (allowNoDatafeeds != null) {
builder.field(ALLOW_NO_DATAFEEDS.getPreferredName(), allowNoDatafeeds);
}

builder.endObject();
return builder;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* 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.datafeed.DatafeedConfig;
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 java.util.stream.Collectors;

import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;

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

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

@SuppressWarnings("unchecked")
public static final ConstructingObjectParser<GetDatafeedResponse, Void> PARSER =
new ConstructingObjectParser<>("get_datafeed_response", true,
a -> new GetDatafeedResponse((List<DatafeedConfig.Builder>) a[0], (long) a[1]));

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

GetDatafeedResponse(List<DatafeedConfig.Builder> datafeedBuilders, long count) {
super(RESULTS_FIELD, datafeedBuilders.stream().map(DatafeedConfig.Builder::build).collect(Collectors.toList()), count);
}

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

public static GetDatafeedResponse 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;
}

GetDatafeedResponse other = (GetDatafeedResponse) 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 @@ -33,11 +33,11 @@
import java.util.Objects;

/**
* Request object to get {@link Job} objects with the matching `jobId`s or
* `groupName`s.
* Request object to get {@link Job} objects with the matching {@code jobId}s or
* {@code groupName}s.
*
* `_all` explicitly gets all the jobs in the cluster
* An empty request (no `jobId`s) implicitly gets all the jobs in the cluster
* {@code _all} explicitly gets all the jobs in the cluster
* An empty request (no {@code jobId}s) implicitly gets all the jobs in the cluster
*/
public class GetJobRequest extends ActionRequest implements ToXContentObject {

Expand Down Expand Up @@ -91,7 +91,7 @@ public List<String> getJobIds() {
/**
* Whether to ignore if a wildcard expression matches no jobs.
*
* @param allowNoJobs If this is {@code false}, then an error is returned when a wildcard (or `_all`) does not match any jobs
* @param allowNoJobs If this is {@code false}, then an error is returned when a wildcard (or {@code _all}) does not match any jobs
*/
public void setAllowNoJobs(boolean allowNoJobs) {
this.allowNoJobs = allowNoJobs;
Expand Down
Loading

0 comments on commit b824ed9

Please sign in to comment.