HLRC: Add ML delete filter action (#35382)

* HLRC: Add ML delete filter action

It adds delete ML filter action to the high level rest client.

Relates #29827
This commit is contained in:
Ignacio Vera 2018-11-19 11:25:35 +01:00 committed by GitHub
parent 2ee25c858d
commit ae6a33237f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 289 additions and 10 deletions

View File

@ -30,6 +30,7 @@ import org.elasticsearch.client.RequestConverters.EndpointBuilder;
import org.elasticsearch.client.ml.CloseJobRequest;
import org.elasticsearch.client.ml.DeleteCalendarRequest;
import org.elasticsearch.client.ml.DeleteDatafeedRequest;
import org.elasticsearch.client.ml.DeleteFilterRequest;
import org.elasticsearch.client.ml.DeleteForecastRequest;
import org.elasticsearch.client.ml.DeleteJobRequest;
import org.elasticsearch.client.ml.DeleteModelSnapshotRequest;
@ -537,4 +538,13 @@ final class MLRequestConverters {
request.setEntity(createEntity(updateFilterRequest, REQUEST_BODY_CONTENT_TYPE));
return request;
}
static Request deleteFilter(DeleteFilterRequest deleteFilterRequest) {
String endpoint = new EndpointBuilder()
.addPathPartAsIs("_xpack", "ml", "filters")
.addPathPart(deleteFilterRequest.getId())
.build();
Request request = new Request(HttpDelete.METHOD_NAME, endpoint);
return request;
}
}

View File

@ -24,6 +24,7 @@ import org.elasticsearch.client.ml.CloseJobRequest;
import org.elasticsearch.client.ml.CloseJobResponse;
import org.elasticsearch.client.ml.DeleteCalendarRequest;
import org.elasticsearch.client.ml.DeleteDatafeedRequest;
import org.elasticsearch.client.ml.DeleteFilterRequest;
import org.elasticsearch.client.ml.DeleteForecastRequest;
import org.elasticsearch.client.ml.DeleteJobRequest;
import org.elasticsearch.client.ml.DeleteJobResponse;
@ -1371,4 +1372,44 @@ public final class MachineLearningClient {
listener,
Collections.emptySet());
}
/**
* Deletes the given Machine Learning filter
* <p>
* For additional info
* see <a href="http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-filter.html">
* ML Delete Filter documentation</a>
*
* @param request The request to delete the filter
* @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
*/
public AcknowledgedResponse deleteFilter(DeleteFilterRequest request, RequestOptions options) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(request,
MLRequestConverters::deleteFilter,
options,
AcknowledgedResponse::fromXContent,
Collections.emptySet());
}
/**
* Deletes the given Machine Learning filter asynchronously and notifies the listener on completion
* <p>
* For additional info
* see <a href="http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-filter.html">
* ML Delete Filter documentation</a>
*
* @param request The request to delete the filter
* @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 deleteFilterAsync(DeleteFilterRequest request, RequestOptions options, ActionListener<AcknowledgedResponse> listener) {
restHighLevelClient.performRequestAsyncAndParseEntity(request,
MLRequestConverters::deleteFilter,
options,
AcknowledgedResponse::fromXContent,
listener,
Collections.emptySet());
}
}

View File

@ -0,0 +1,60 @@
/*
* 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.Validatable;
import java.util.Objects;
/**
* A request to delete a machine learning filter
*/
public class DeleteFilterRequest implements Validatable {
private final String filterId;
public DeleteFilterRequest(String filterId) {
this.filterId = Objects.requireNonNull(filterId, "[filter_id] is required");
}
public String getId() {
return filterId;
}
@Override
public int hashCode() {
return Objects.hash(filterId);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final DeleteFilterRequest other = (DeleteFilterRequest) obj;
return Objects.equals(filterId, other.filterId);
}
}

View File

@ -26,6 +26,7 @@ import org.apache.http.client.methods.HttpPut;
import org.elasticsearch.client.ml.CloseJobRequest;
import org.elasticsearch.client.ml.DeleteCalendarRequest;
import org.elasticsearch.client.ml.DeleteDatafeedRequest;
import org.elasticsearch.client.ml.DeleteFilterRequest;
import org.elasticsearch.client.ml.DeleteForecastRequest;
import org.elasticsearch.client.ml.DeleteJobRequest;
import org.elasticsearch.client.ml.DeleteModelSnapshotRequest;
@ -596,6 +597,17 @@ public class MLRequestConvertersTests extends ESTestCase {
}
}
public void testDeleteFilter() {
MlFilter filter = MlFilterTests.createRandomBuilder("foo").build();
DeleteFilterRequest deleteFilterRequest = new DeleteFilterRequest(filter.getId());
Request request = MLRequestConverters.deleteFilter(deleteFilterRequest);
assertEquals(HttpDelete.METHOD_NAME, request.getMethod());
assertThat(request.getEndpoint(), equalTo("/_xpack/ml/filters/foo"));
assertNull(request.getEntity());
}
private static Job createValidJob(String jobId) {
AnalysisConfig.Builder analysisConfig = AnalysisConfig.builder(Collections.singletonList(
Detector.builder().setFunction("count").build()));

View File

@ -31,6 +31,7 @@ import org.elasticsearch.client.ml.CloseJobRequest;
import org.elasticsearch.client.ml.CloseJobResponse;
import org.elasticsearch.client.ml.DeleteCalendarRequest;
import org.elasticsearch.client.ml.DeleteDatafeedRequest;
import org.elasticsearch.client.ml.DeleteFilterRequest;
import org.elasticsearch.client.ml.DeleteForecastRequest;
import org.elasticsearch.client.ml.DeleteJobRequest;
import org.elasticsearch.client.ml.DeleteJobResponse;
@ -952,6 +953,32 @@ public class MachineLearningIT extends ESRestHighLevelClientTestCase {
assertThat(filter.getItems(), contains("newItem1", "newItem2", "olditem2"));
}
public void testDeleteFilter() throws Exception {
String filterId = "delete-filter-job-test";
MlFilter mlFilter = MlFilter.builder(filterId)
.setDescription(randomAlphaOfLength(10))
.setItems(generateRandomStringArray(10, 10, false, false))
.build();
MachineLearningClient machineLearningClient = highLevelClient().machineLearning();
PutFilterResponse putFilterResponse = execute(new PutFilterRequest(mlFilter),
machineLearningClient::putFilter,
machineLearningClient::putFilterAsync);
MlFilter createdFilter = putFilterResponse.getResponse();
assertThat(createdFilter, equalTo(mlFilter));
DeleteFilterRequest deleteFilterRequest = new DeleteFilterRequest(filterId);
AcknowledgedResponse response = execute(deleteFilterRequest, machineLearningClient::deleteFilter,
machineLearningClient::deleteFilterAsync);
assertTrue(response.isAcknowledged());
ElasticsearchStatusException exception = expectThrows(ElasticsearchStatusException.class,
() -> execute(deleteFilterRequest, machineLearningClient::deleteFilter,
machineLearningClient::deleteFilterAsync));
assertThat(exception.status().getStatus(), equalTo(404));
}
public static String randomValidJobId() {
CodepointSetGenerator generator = new CodepointSetGenerator("abcdefghijklmnopqrstuvwxyz0123456789".toCharArray());
return generator.ofCodePointsLength(random(), 10, 10);

View File

@ -37,6 +37,7 @@ import org.elasticsearch.client.ml.CloseJobRequest;
import org.elasticsearch.client.ml.CloseJobResponse;
import org.elasticsearch.client.ml.DeleteCalendarRequest;
import org.elasticsearch.client.ml.DeleteDatafeedRequest;
import org.elasticsearch.client.ml.DeleteFilterRequest;
import org.elasticsearch.client.ml.DeleteForecastRequest;
import org.elasticsearch.client.ml.DeleteJobRequest;
import org.elasticsearch.client.ml.DeleteJobResponse;
@ -2284,16 +2285,16 @@ public class MlClientDocumentationIT extends ESRestHighLevelClientTestCase {
// tag::get-filters-execute-listener
ActionListener<GetFiltersResponse> listener = new ActionListener<GetFiltersResponse>() {
@Override
public void onResponse(GetFiltersResponse getfiltersResponse) {
// <1>
}
@Override
public void onResponse(GetFiltersResponse getfiltersResponse) {
// <1>
}
@Override
public void onFailure(Exception e) {
// <2>
}
};
@Override
public void onFailure(Exception e) {
// <2>
}
};
// end::get-filters-execute-listener
// Replace the empty listener by a blocking listener in test
@ -2369,4 +2370,62 @@ public class MlClientDocumentationIT extends ESRestHighLevelClientTestCase {
assertTrue(latch.await(30L, TimeUnit.SECONDS));
}
}
public void testDeleteFilter() throws Exception {
RestHighLevelClient client = highLevelClient();
String filterId = createFilter(client);
{
// tag::delete-filter-request
DeleteFilterRequest request = new DeleteFilterRequest(filterId); // <1>
// end::delete-filter-request
// tag::delete-filter-execute
AcknowledgedResponse response = client.machineLearning().deleteFilter(request, RequestOptions.DEFAULT);
// end::delete-filter-execute
// tag::delete-filter-response
boolean isAcknowledged = response.isAcknowledged(); // <1>
// end::delete-filter-response
assertTrue(isAcknowledged);
}
filterId = createFilter(client);
{
DeleteFilterRequest request = new DeleteFilterRequest(filterId);
// tag::delete-filter-execute-listener
ActionListener<AcknowledgedResponse> listener = new ActionListener<AcknowledgedResponse>() {
@Override
public void onResponse(AcknowledgedResponse response) {
// <1>
}
@Override
public void onFailure(Exception e) {
// <2>
}
};
// end::delete-filter-execute-listener
// Replace the empty listener by a blocking listener in test
final CountDownLatch latch = new CountDownLatch(1);
listener = new LatchedActionListener<>(listener, latch);
// tag::delete-filter-execute-async
client.machineLearning().deleteFilterAsync(request, RequestOptions.DEFAULT, listener); //<1>
// end::delete-filter-execute-async
assertTrue(latch.await(30L, TimeUnit.SECONDS));
}
}
private String createFilter(RestHighLevelClient client) throws IOException {
MlFilter.Builder filterBuilder = MlFilter.builder("my_safe_domains")
.setDescription("A list of safe domains")
.setItems("*.google.com", "wikipedia.org");
PutFilterRequest putFilterRequest = new PutFilterRequest(filterBuilder.build());
PutFilterResponse putFilterResponse = client.machineLearning().putFilter(putFilterRequest, RequestOptions.DEFAULT);
MlFilter createdFilter = putFilterResponse.getResponse();
assertThat(createdFilter.getId(), equalTo("my_safe_domains"));
return createdFilter.getId();
}
}

View File

@ -0,0 +1,35 @@
/*
* 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.test.ESTestCase;
public class DeleteFilterRequestTests extends ESTestCase {
public void test_WithNullFilter() {
NullPointerException ex = expectThrows(NullPointerException.class, () -> new DeleteFilterRequest(null));
assertEquals("[filter_id] is required", ex.getMessage());
}
public void test_instance() {
String filterId = randomAlphaOfLengthBetween(2, 10);
DeleteFilterRequest deleteFilterRequest = new DeleteFilterRequest(filterId);
assertEquals(deleteFilterRequest.getId(), filterId);
}
}

View File

@ -0,0 +1,33 @@
--
:api: delete-filter
:request: DeleteFilterRequest
:response: AcknowledgedResponse
--
[id="{upid}-{api}"]
=== Delete Filter API
Delete a {ml} filter.
The API accepts a +{request}+ and responds
with a +{response}+ object.
[id="{upid}-{api}-request"]
==== Delete Filter Request
A +{request}+ object requires a non-null `filterId`.
["source","java",subs="attributes,callouts,macros"]
---------------------------------------------------
include-tagged::{doc-tests-file}[{api}-request]
---------------------------------------------------
<1> Constructing a new request referencing an existing filter
[id="{upid}-{api}-response"]
==== Delete Filter Response
The returned +{response}+ object indicates the acknowledgement of the request:
["source","java",subs="attributes,callouts,macros"]
---------------------------------------------------
include-tagged::{doc-tests-file}[{api}-response]
---------------------------------------------------
<1> `isAcknowledged` was the deletion request acknowledged or not
include::../execution.asciidoc[]

View File

@ -265,10 +265,11 @@ The Java High Level REST Client supports the following Machine Learning APIs:
* <<{upid}-put-calendar>>
* <<{upid}-delete-calendar>>
* <<{upid}-put-filter>>
* <<{upid}-get-model-snapshots>>
* <<{upid}-get-filters>>
* <<{upid}-delete-model-snapshot>>
* <<{upid}-update-filter>>
* <<{upid}-delete-filter>>
* <<{upid}-get-model-snapshots>>
include::ml/put-job.asciidoc[]
include::ml/get-job.asciidoc[]
@ -302,6 +303,7 @@ include::ml/get-model-snapshots.asciidoc[]
include::ml/get-filters.asciidoc[]
include::ml/delete-model-snapshot.asciidoc[]
include::ml/update-filter.asciidoc[]
include::ml/delete-filter.asciidoc[]
== Migration APIs