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 a3e5ba72b773f..2e7914e64abdb 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
@@ -19,6 +19,8 @@
package org.elasticsearch.client;
import org.elasticsearch.action.ActionListener;
+import org.elasticsearch.protocol.xpack.ml.DeleteJobRequest;
+import org.elasticsearch.protocol.xpack.ml.DeleteJobResponse;
import org.elasticsearch.protocol.xpack.ml.OpenJobRequest;
import org.elasticsearch.protocol.xpack.ml.OpenJobResponse;
import org.elasticsearch.protocol.xpack.ml.PutJobRequest;
@@ -80,6 +82,44 @@ public void putJobAsync(PutJobRequest request, RequestOptions options, ActionLis
Collections.emptySet());
}
+ /**
+ * Deletes the given Machine Learning Job
+ *
+ * For additional info
+ * see ML Delete Job documentation
+ *
+ * @param request the request to delete the job
+ * @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 DeleteJobResponse deleteJob(DeleteJobRequest request, RequestOptions options) throws IOException {
+ return restHighLevelClient.performRequestAndParseEntity(request,
+ RequestConverters::deleteMachineLearningJob,
+ options,
+ DeleteJobResponse::fromXContent,
+ Collections.emptySet());
+ }
+
+ /**
+ * Deletes the given Machine Learning Job asynchronously and notifies the listener on completion
+ *
+ * For additional info
+ * see ML Delete Job documentation
+ *
+ * @param request the request to delete the job
+ * @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 deleteJobAsync(DeleteJobRequest request, RequestOptions options, ActionListener listener) {
+ restHighLevelClient.performRequestAsyncAndParseEntity(request,
+ RequestConverters::deleteMachineLearningJob,
+ options,
+ DeleteJobResponse::fromXContent,
+ listener,
+ Collections.emptySet());
+ }
+
/**
* Opens a Machine Learning Job.
* When you open a new job, it starts with an empty model.
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java
index 973c0ce126d37..c40b4893e0146 100644
--- a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java
@@ -112,6 +112,7 @@
import org.elasticsearch.protocol.xpack.license.GetLicenseRequest;
import org.elasticsearch.protocol.xpack.license.PutLicenseRequest;
import org.elasticsearch.protocol.xpack.migration.IndexUpgradeInfoRequest;
+import org.elasticsearch.protocol.xpack.ml.DeleteJobRequest;
import org.elasticsearch.protocol.xpack.ml.OpenJobRequest;
import org.elasticsearch.protocol.xpack.ml.PutJobRequest;
import org.elasticsearch.protocol.xpack.watcher.DeleteWatchRequest;
@@ -1211,6 +1212,21 @@ static Request putMachineLearningJob(PutJobRequest putJobRequest) throws IOExcep
return request;
}
+ static Request deleteMachineLearningJob(DeleteJobRequest deleteJobRequest) {
+ String endpoint = new EndpointBuilder()
+ .addPathPartAsIs("_xpack")
+ .addPathPartAsIs("ml")
+ .addPathPartAsIs("anomaly_detectors")
+ .addPathPart(deleteJobRequest.getJobId())
+ .build();
+ Request request = new Request(HttpDelete.METHOD_NAME, endpoint);
+
+ Params params = new Params(request);
+ params.putParam("force", Boolean.toString(deleteJobRequest.isForce()));
+
+ return request;
+ }
+
static Request machineLearningOpenJob(OpenJobRequest openJobRequest) throws IOException {
String endpoint = new EndpointBuilder()
.addPathPartAsIs("_xpack")
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 94e73a14c188c..0037460150f1a 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
@@ -20,6 +20,8 @@
import com.carrotsearch.randomizedtesting.generators.CodepointSetGenerator;
import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.protocol.xpack.ml.DeleteJobRequest;
+import org.elasticsearch.protocol.xpack.ml.DeleteJobResponse;
import org.elasticsearch.protocol.xpack.ml.OpenJobRequest;
import org.elasticsearch.protocol.xpack.ml.OpenJobResponse;
import org.elasticsearch.protocol.xpack.ml.PutJobRequest;
@@ -48,6 +50,19 @@ public void testPutJob() throws Exception {
assertThat(createdJob.getJobType(), is(Job.ANOMALY_DETECTOR_JOB_TYPE));
}
+ public void testDeleteJob() throws Exception {
+ String jobId = randomValidJobId();
+ Job job = buildJob(jobId);
+ MachineLearningClient machineLearningClient = highLevelClient().machineLearning();
+ machineLearningClient.putJob(new PutJobRequest(job), RequestOptions.DEFAULT);
+
+ DeleteJobResponse response = execute(new DeleteJobRequest(jobId),
+ machineLearningClient::deleteJob,
+ machineLearningClient::deleteJobAsync);
+
+ assertTrue(response.isAcknowledged());
+ }
+
public void testOpenJob() throws Exception {
String jobId = randomValidJobId();
Job job = buildJob(jobId);
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java
index 1c9707e0e27fa..786cb94f8926d 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java
@@ -127,6 +127,7 @@
import org.elasticsearch.index.rankeval.RestRankEvalAction;
import org.elasticsearch.protocol.xpack.XPackInfoRequest;
import org.elasticsearch.protocol.xpack.migration.IndexUpgradeInfoRequest;
+import org.elasticsearch.protocol.xpack.ml.DeleteJobRequest;
import org.elasticsearch.protocol.xpack.ml.OpenJobRequest;
import org.elasticsearch.protocol.xpack.watcher.DeleteWatchRequest;
import org.elasticsearch.protocol.xpack.watcher.PutWatchRequest;
@@ -2611,6 +2612,20 @@ public void testXPackDeleteWatch() {
assertThat(request.getEntity(), nullValue());
}
+ public void testDeleteMachineLearningJob() {
+ String jobId = randomAlphaOfLength(10);
+ DeleteJobRequest deleteJobRequest = new DeleteJobRequest(jobId);
+
+ Request request = RequestConverters.deleteMachineLearningJob(deleteJobRequest);
+ assertEquals(HttpDelete.METHOD_NAME, request.getMethod());
+ assertEquals("/_xpack/ml/anomaly_detectors/" + jobId, request.getEndpoint());
+ assertEquals(Boolean.toString(false), request.getParameters().get("force"));
+
+ deleteJobRequest.setForce(true);
+ request = RequestConverters.deleteMachineLearningJob(deleteJobRequest);
+ assertEquals(Boolean.toString(true), request.getParameters().get("force"));
+ }
+
public void testPostMachineLearningOpenJob() throws Exception {
String jobId = "some-job-id";
OpenJobRequest openJobRequest = new OpenJobRequest(jobId);
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 50cd244c0fa07..a77d8b43e5737 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
@@ -25,6 +25,8 @@
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.protocol.xpack.ml.DeleteJobRequest;
+import org.elasticsearch.protocol.xpack.ml.DeleteJobResponse;
import org.elasticsearch.protocol.xpack.ml.OpenJobRequest;
import org.elasticsearch.protocol.xpack.ml.OpenJobResponse;
import org.elasticsearch.protocol.xpack.ml.PutJobRequest;
@@ -122,6 +124,56 @@ public void onFailure(Exception e) {
}
}
+ public void testDeleteJob() throws Exception {
+ RestHighLevelClient client = highLevelClient();
+
+ String jobId = "my-first-machine-learning-job";
+
+ Job job = MachineLearningIT.buildJob(jobId);
+ client.machineLearning().putJob(new PutJobRequest(job), RequestOptions.DEFAULT);
+
+ Job secondJob = MachineLearningIT.buildJob("my-second-machine-learning-job");
+ client.machineLearning().putJob(new PutJobRequest(secondJob), RequestOptions.DEFAULT);
+
+ {
+ //tag::x-pack-delete-ml-job-request
+ DeleteJobRequest deleteJobRequest = new DeleteJobRequest("my-first-machine-learning-job");
+ deleteJobRequest.setForce(false); //<1>
+ DeleteJobResponse deleteJobResponse = client.machineLearning().deleteJob(deleteJobRequest, RequestOptions.DEFAULT);
+ //end::x-pack-delete-ml-job-request
+
+ //tag::x-pack-delete-ml-job-response
+ boolean isAcknowledged = deleteJobResponse.isAcknowledged(); //<1>
+ //end::x-pack-delete-ml-job-response
+ }
+ {
+ //tag::x-pack-delete-ml-job-request-listener
+ ActionListener listener = new ActionListener() {
+ @Override
+ public void onResponse(DeleteJobResponse deleteJobResponse) {
+ // <1>
+ }
+
+ @Override
+ public void onFailure(Exception e) {
+ // <2>
+ }
+ };
+ //end::x-pack-delete-ml-job-request-listener
+
+ // Replace the empty listener by a blocking listener in test
+ final CountDownLatch latch = new CountDownLatch(1);
+ listener = new LatchedActionListener<>(listener, latch);
+
+ //tag::x-pack-delete-ml-job-request-async
+ DeleteJobRequest deleteJobRequest = new DeleteJobRequest("my-second-machine-learning-job");
+ client.machineLearning().deleteJobAsync(deleteJobRequest, RequestOptions.DEFAULT, listener); // <1>
+ //end::x-pack-delete-ml-job-request-async
+
+ assertTrue(latch.await(30L, TimeUnit.SECONDS));
+ }
+ }
+
public void testOpenJob() throws Exception {
RestHighLevelClient client = highLevelClient();
@@ -143,7 +195,6 @@ public void testOpenJob() throws Exception {
//end::x-pack-ml-open-job-execute
}
-
{
//tag::x-pack-ml-open-job-listener
ActionListener listener = new ActionListener() {
@@ -154,7 +205,7 @@ public void onResponse(OpenJobResponse openJobResponse) {
@Override
public void onFailure(Exception e) {
- //<2>
+ // <2>
}
};
//end::x-pack-ml-open-job-listener
@@ -169,6 +220,5 @@ public void onFailure(Exception e) {
assertTrue(latch.await(30L, TimeUnit.SECONDS));
}
-
}
}
diff --git a/docs/java-rest/high-level/ml/delete-job.asciidoc b/docs/java-rest/high-level/ml/delete-job.asciidoc
new file mode 100644
index 0000000000000..44a6a47940955
--- /dev/null
+++ b/docs/java-rest/high-level/ml/delete-job.asciidoc
@@ -0,0 +1,49 @@
+[[java-rest-high-x-pack-ml-delete-job]]
+=== Delete Job API
+
+[[java-rest-high-x-pack-machine-learning-delete-job-request]]
+==== Delete Job Request
+
+A `DeleteJobRequest` object requires a non-null `jobId` and can optionally set `force`.
+Can be executed as follows:
+
+["source","java",subs="attributes,callouts,macros"]
+---------------------------------------------------
+include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-delete-ml-job-request]
+---------------------------------------------------
+<1> Use to forcefully delete an opened job;
+this method is quicker than closing and deleting the job.
+Defaults to `false`
+
+[[java-rest-high-x-pack-machine-learning-delete-job-response]]
+==== Delete Job Response
+
+The returned `DeleteJobResponse` object indicates the acknowledgement of the request:
+["source","java",subs="attributes,callouts,macros"]
+---------------------------------------------------
+include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-delete-ml-job-response]
+---------------------------------------------------
+<1> `isAcknowledged` was the deletion request acknowledged or not
+
+[[java-rest-high-x-pack-machine-learning-delete-job-async]]
+==== Delete Job Asynchronously
+
+This request can also be made asynchronously.
+["source","java",subs="attributes,callouts,macros"]
+---------------------------------------------------
+include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-delete-ml-job-request-async]
+---------------------------------------------------
+<1> The `DeleteJobRequest` to execute and the `ActionListener` to alert on completion or error.
+
+The deletion request returns immediately. Once the request is completed, the `ActionListener` is
+called back using the `onResponse` or `onFailure`. The latter indicates some failure occurred when
+making the request.
+
+A typical listener for a `DeleteJobRequest` could be defined as follows:
+
+["source","java",subs="attributes,callouts,macros"]
+---------------------------------------------------
+include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-delete-ml-job-request-listener]
+---------------------------------------------------
+<1> The action to be taken when it is completed
+<2> What to do when a failure occurs
diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc
index a2db3436317c3..6bcb736243a7c 100644
--- a/docs/java-rest/high-level/supported-apis.asciidoc
+++ b/docs/java-rest/high-level/supported-apis.asciidoc
@@ -205,9 +205,11 @@ include::licensing/delete-license.asciidoc[]
The Java High Level REST Client supports the following Machine Learning APIs:
* <>
+* <>
* <>
include::ml/put-job.asciidoc[]
+include::ml/delete-job.asciidoc[]
include::ml/open-job.asciidoc[]
== Migration APIs
diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/DeleteJobRequest.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/DeleteJobRequest.java
new file mode 100644
index 0000000000000..1b7450de0929c
--- /dev/null
+++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/DeleteJobRequest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.protocol.xpack.ml;
+
+import org.elasticsearch.action.ActionRequest;
+import org.elasticsearch.action.ActionRequestValidationException;
+
+import java.util.Objects;
+
+public class DeleteJobRequest extends ActionRequest {
+
+ private String jobId;
+ private boolean force;
+
+ public DeleteJobRequest(String jobId) {
+ this.jobId = Objects.requireNonNull(jobId, "[job_id] must not be null");
+ }
+
+ public String getJobId() {
+ return jobId;
+ }
+
+ public void setJobId(String jobId) {
+ this.jobId = Objects.requireNonNull(jobId, "[job_id] must not be null");
+ }
+
+ public boolean isForce() {
+ return force;
+ }
+
+ public void setForce(boolean force) {
+ this.force = force;
+ }
+
+ @Override
+ public ActionRequestValidationException validate() {
+ return null;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(jobId, force);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj == null || obj.getClass() != getClass()) {
+ return false;
+ }
+
+ DeleteJobRequest other = (DeleteJobRequest) obj;
+ return Objects.equals(jobId, other.jobId) && Objects.equals(force, other.force);
+ }
+
+}
diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/DeleteJobResponse.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/DeleteJobResponse.java
new file mode 100644
index 0000000000000..0b4faa38f545f
--- /dev/null
+++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/ml/DeleteJobResponse.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.protocol.xpack.ml;
+
+import org.elasticsearch.action.support.master.AcknowledgedResponse;
+import org.elasticsearch.common.xcontent.XContentParser;
+
+import java.io.IOException;
+import java.util.Objects;
+
+public class DeleteJobResponse extends AcknowledgedResponse {
+
+ public DeleteJobResponse(boolean acknowledged) {
+ super(acknowledged);
+ }
+
+ public DeleteJobResponse() {
+ }
+
+ public static DeleteJobResponse fromXContent(XContentParser parser) throws IOException {
+ AcknowledgedResponse response = AcknowledgedResponse.fromXContent(parser);
+ return new DeleteJobResponse(response.isAcknowledged());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+
+ if (other == null || getClass() != other.getClass()) {
+ return false;
+ }
+
+ DeleteJobResponse that = (DeleteJobResponse) other;
+ return isAcknowledged() == that.isAcknowledged();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(isAcknowledged());
+ }
+
+}
diff --git a/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/DeleteJobRequestTests.java b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/DeleteJobRequestTests.java
new file mode 100644
index 0000000000000..fb8a38fa0c68e
--- /dev/null
+++ b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/DeleteJobRequestTests.java
@@ -0,0 +1,45 @@
+/*
+ * 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.protocol.xpack.ml;
+
+import org.elasticsearch.protocol.xpack.ml.job.config.JobTests;
+import org.elasticsearch.test.ESTestCase;
+
+public class DeleteJobRequestTests extends ESTestCase {
+
+ private DeleteJobRequest createTestInstance() {
+ return new DeleteJobRequest(JobTests.randomValidJobId());
+ }
+
+ public void test_WithNullJobId() {
+ NullPointerException ex = expectThrows(NullPointerException.class, () -> new DeleteJobRequest(null));
+ assertEquals("[job_id] must not be null", ex.getMessage());
+
+ ex = expectThrows(NullPointerException.class, () -> createTestInstance().setJobId(null));
+ assertEquals("[job_id] must not be null", ex.getMessage());
+ }
+
+ public void test_WithForce() {
+ DeleteJobRequest deleteJobRequest = createTestInstance();
+ assertFalse(deleteJobRequest.isForce());
+
+ deleteJobRequest.setForce(true);
+ assertTrue(deleteJobRequest.isForce());
+ }
+}
diff --git a/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/DeleteJobResponseTests.java b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/DeleteJobResponseTests.java
new file mode 100644
index 0000000000000..a73179a08983d
--- /dev/null
+++ b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/ml/DeleteJobResponseTests.java
@@ -0,0 +1,42 @@
+/*
+ * 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.protocol.xpack.ml;
+
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.test.AbstractXContentTestCase;
+
+import java.io.IOException;
+
+public class DeleteJobResponseTests extends AbstractXContentTestCase {
+
+ @Override
+ protected DeleteJobResponse createTestInstance() {
+ return new DeleteJobResponse();
+ }
+
+ @Override
+ protected DeleteJobResponse doParseInstance(XContentParser parser) throws IOException {
+ return DeleteJobResponse.fromXContent(parser);
+ }
+
+ @Override
+ protected boolean supportsUnknownFields() {
+ return false;
+ }
+}