diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/MLRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/MLRequestConverters.java index 4c3090680664d..7d916d89c8494 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/MLRequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/MLRequestConverters.java @@ -30,6 +30,7 @@ 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 @@ static Request updateFilter(UpdateFilterRequest updateFilterRequest) throws IOEx 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; + } } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/MachineLearningClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/MachineLearningClient.java index 7afc5a462ed21..7455bf4274c73 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/MachineLearningClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/MachineLearningClient.java @@ -24,6 +24,7 @@ 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 void updateFilterAsync(UpdateFilterRequest request, RequestOptions option listener, Collections.emptySet()); } + + /** + * Deletes the given Machine Learning filter + *

+ * For additional info + * see + * ML Delete Filter documentation + * + * @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 + *

+ * For additional info + * see + * ML Delete Filter documentation + * + * @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 listener) { + restHighLevelClient.performRequestAsyncAndParseEntity(request, + MLRequestConverters::deleteFilter, + options, + AcknowledgedResponse::fromXContent, + listener, + Collections.emptySet()); + } } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/DeleteFilterRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/DeleteFilterRequest.java new file mode 100644 index 0000000000000..4f1b4136a3a0d --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/DeleteFilterRequest.java @@ -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); + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/MLRequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/MLRequestConvertersTests.java index c683941187751..0381fe88bb49a 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/MLRequestConvertersTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/MLRequestConvertersTests.java @@ -26,6 +26,7 @@ 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 void testUpdateFilter() throws IOException { } } + 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())); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java index 5a9c7890fdc47..8fac48854e511 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java @@ -31,6 +31,7 @@ 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 void testUpdateFilter() throws Exception { 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); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java index 556e25a2b0ef5..343acc16810f6 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java @@ -37,6 +37,7 @@ 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 void testGetFilters() throws IOException, InterruptedException { // tag::get-filters-execute-listener ActionListener listener = new ActionListener() { - @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 void onFailure(Exception e) { 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 listener = new ActionListener() { + @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(); + } } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/DeleteFilterRequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/DeleteFilterRequestTests.java new file mode 100644 index 0000000000000..64a364d7ab62b --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/DeleteFilterRequestTests.java @@ -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); + } +} diff --git a/docs/java-rest/high-level/ml/delete-filter.asciidoc b/docs/java-rest/high-level/ml/delete-filter.asciidoc new file mode 100644 index 0000000000000..abdcdcb53920a --- /dev/null +++ b/docs/java-rest/high-level/ml/delete-filter.asciidoc @@ -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[] diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc index 5fa05135cc035..a666469ad0370 100644 --- a/docs/java-rest/high-level/supported-apis.asciidoc +++ b/docs/java-rest/high-level/supported-apis.asciidoc @@ -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