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 69b1c4a91e087..be513b0985c55 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
@@ -49,6 +49,7 @@
import org.elasticsearch.client.ml.PreviewDatafeedRequest;
import org.elasticsearch.client.ml.PutCalendarRequest;
import org.elasticsearch.client.ml.PutDatafeedRequest;
+import org.elasticsearch.client.ml.PutFilterRequest;
import org.elasticsearch.client.ml.PutJobRequest;
import org.elasticsearch.client.ml.StartDatafeedRequest;
import org.elasticsearch.client.ml.StopDatafeedRequest;
@@ -463,4 +464,16 @@ static Request deleteCalendar(DeleteCalendarRequest deleteCalendarRequest) {
Request request = new Request(HttpDelete.METHOD_NAME, endpoint);
return request;
}
+
+ static Request putFilter(PutFilterRequest putFilterRequest) throws IOException {
+ String endpoint = new EndpointBuilder()
+ .addPathPartAsIs("_xpack")
+ .addPathPartAsIs("ml")
+ .addPathPartAsIs("filters")
+ .addPathPart(putFilterRequest.getMlFilter().getId())
+ .build();
+ Request request = new Request(HttpPut.METHOD_NAME, endpoint);
+ request.setEntity(createEntity(putFilterRequest, REQUEST_BODY_CONTENT_TYPE));
+ 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 0b7647b7d579f..3f7a938f9ce1a 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
@@ -61,6 +61,8 @@
import org.elasticsearch.client.ml.PutCalendarResponse;
import org.elasticsearch.client.ml.PutDatafeedRequest;
import org.elasticsearch.client.ml.PutDatafeedResponse;
+import org.elasticsearch.client.ml.PutFilterRequest;
+import org.elasticsearch.client.ml.PutFilterResponse;
import org.elasticsearch.client.ml.PutJobRequest;
import org.elasticsearch.client.ml.PutJobResponse;
import org.elasticsearch.client.ml.StartDatafeedRequest;
@@ -1166,4 +1168,43 @@ public void deleteCalendarAsync(DeleteCalendarRequest request, RequestOptions op
listener,
Collections.emptySet());
}
+
+ /**
+ * Creates a new Machine Learning Filter
+ *
+ * For additional info
+ * see ML PUT Filter documentation
+ *
+ * @param request The PutFilterRequest containing the {@link org.elasticsearch.client.ml.job.config.MlFilter} settings
+ * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @return PutFilterResponse with enclosed {@link org.elasticsearch.client.ml.job.config.MlFilter} object
+ * @throws IOException when there is a serialization issue sending the request or receiving the response
+ */
+ public PutFilterResponse putFilter(PutFilterRequest request, RequestOptions options) throws IOException {
+ return restHighLevelClient.performRequestAndParseEntity(request,
+ MLRequestConverters::putFilter,
+ options,
+ PutFilterResponse::fromXContent,
+ Collections.emptySet());
+ }
+
+ /**
+ * Creates a new Machine Learning Filter asynchronously and notifies listener on completion
+ *
+ * For additional info
+ * see ML PUT Filter documentation
+ *
+ * @param request The request containing the {@link org.elasticsearch.client.ml.job.config.MlFilter} 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 putFilterAsync(PutFilterRequest request, RequestOptions options, ActionListener listener) {
+ restHighLevelClient.performRequestAsyncAndParseEntity(request,
+ MLRequestConverters::putFilter,
+ options,
+ PutFilterResponse::fromXContent,
+ listener,
+ Collections.emptySet());
+ }
+
}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PutFilterRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PutFilterRequest.java
new file mode 100644
index 0000000000000..5414c86258111
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PutFilterRequest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.job.config.MlFilter;
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.xcontent.ToXContentObject;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * Request to create a new Machine Learning MlFilter given a {@link MlFilter} configuration
+ */
+public class PutFilterRequest extends ActionRequest implements ToXContentObject {
+
+ private final MlFilter filter;
+
+ /**
+ * Construct a new PutMlFilterRequest
+ *
+ * @param filter a {@link MlFilter} configuration to create
+ */
+ public PutFilterRequest(MlFilter filter) {
+ this.filter = filter;
+ }
+
+ public MlFilter getMlFilter() {
+ return filter;
+ }
+
+ @Override
+ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+ return filter.toXContent(builder, params);
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+
+ if (object == null || getClass() != object.getClass()) {
+ return false;
+ }
+
+ PutFilterRequest request = (PutFilterRequest) object;
+ return Objects.equals(filter, request.filter);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(filter);
+ }
+
+ @Override
+ public final String toString() {
+ return Strings.toString(this);
+ }
+
+ @Override
+ public ActionRequestValidationException validate() {
+ return null;
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PutFilterResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PutFilterResponse.java
new file mode 100644
index 0000000000000..56164bd5be08e
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/PutFilterResponse.java
@@ -0,0 +1,70 @@
+/*
+ * 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.job.config.MlFilter;
+import org.elasticsearch.common.xcontent.ToXContentObject;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.common.xcontent.XContentParser;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * Response containing the newly created {@link MlFilter}
+ */
+public class PutFilterResponse implements ToXContentObject {
+
+ private MlFilter filter;
+
+ public static PutFilterResponse fromXContent(XContentParser parser) throws IOException {
+ return new PutFilterResponse(MlFilter.PARSER.parse(parser, null).build());
+ }
+
+ PutFilterResponse(MlFilter filter) {
+ this.filter = filter;
+ }
+
+ public MlFilter getResponse() {
+ return filter;
+ }
+
+ @Override
+ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+ filter.toXContent(builder, params);
+ return builder;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (object == null || getClass() != object.getClass()) {
+ return false;
+ }
+ PutFilterResponse response = (PutFilterResponse) object;
+ return Objects.equals(filter, response.filter);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(filter);
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/job/config/MlFilter.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/job/config/MlFilter.java
index e0d1bd0849b3b..1b67fc4459b50 100644
--- a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/job/config/MlFilter.java
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/job/config/MlFilter.java
@@ -32,6 +32,14 @@
import java.util.SortedSet;
import java.util.TreeSet;
+/**
+ * An MlFilter Object
+ *
+ * A filter contains a list of strings.
+ * It can be used by one or more jobs.
+ *
+ * Specifically, filters are referenced in the custom_rules property of detector configuration objects.
+ */
public class MlFilter implements ToXContentObject {
public static final ParseField TYPE = new ParseField("type");
@@ -105,6 +113,10 @@ public int hashCode() {
return Objects.hash(id, description, items);
}
+ /**
+ * Creates a new Builder object for creating an MlFilter object
+ * @param filterId The ID of the filter to create
+ */
public static Builder builder(String filterId) {
return new Builder().setId(filterId);
}
@@ -118,6 +130,10 @@ public static class Builder {
private Builder() {
}
+ /**
+ * Set the ID of the filter
+ * @param id The id desired
+ */
public Builder setId(String id) {
this.id = Objects.requireNonNull(id);
return this;
@@ -128,6 +144,10 @@ public String getId() {
return id;
}
+ /**
+ * Set the description of the filter
+ * @param description The description desired
+ */
public Builder setDescription(String description) {
this.description = description;
return this;
@@ -143,6 +163,13 @@ public Builder setItems(List items) {
return this;
}
+ /**
+ * The items of the filter.
+ *
+ * A wildcard * can be used at the beginning or the end of an item. Up to 10000 items are allowed in each filter.
+ *
+ * @param items String list of items to be applied in the filter
+ */
public Builder setItems(String... items) {
setItems(Arrays.asList(items));
return this;
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 d4fdfb2c995df..bb0dbf6680127 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
@@ -45,6 +45,7 @@
import org.elasticsearch.client.ml.PreviewDatafeedRequest;
import org.elasticsearch.client.ml.PutCalendarRequest;
import org.elasticsearch.client.ml.PutDatafeedRequest;
+import org.elasticsearch.client.ml.PutFilterRequest;
import org.elasticsearch.client.ml.PutJobRequest;
import org.elasticsearch.client.ml.StartDatafeedRequest;
import org.elasticsearch.client.ml.StartDatafeedRequestTests;
@@ -59,6 +60,8 @@
import org.elasticsearch.client.ml.job.config.Job;
import org.elasticsearch.client.ml.job.config.JobUpdate;
import org.elasticsearch.client.ml.job.config.JobUpdateTests;
+import org.elasticsearch.client.ml.job.config.MlFilter;
+import org.elasticsearch.client.ml.job.config.MlFilterTests;
import org.elasticsearch.client.ml.job.util.PageParams;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.unit.TimeValue;
@@ -511,6 +514,20 @@ public void testDeleteCalendar() {
assertEquals("/_xpack/ml/calendars/" + deleteCalendarRequest.getCalendarId(), request.getEndpoint());
}
+ public void testPutFilter() throws IOException {
+ MlFilter filter = MlFilterTests.createRandom("foo");
+ PutFilterRequest putFilterRequest = new PutFilterRequest(filter);
+
+ Request request = MLRequestConverters.putFilter(putFilterRequest);
+
+ assertEquals(HttpPut.METHOD_NAME, request.getMethod());
+ assertThat(request.getEndpoint(), equalTo("/_xpack/ml/filters/foo"));
+ try (XContentParser parser = createParser(JsonXContent.jsonXContent, request.getEntity().getContent())) {
+ MlFilter parsedFilter = MlFilter.PARSER.apply(parser, null).build();
+ assertThat(parsedFilter, equalTo(filter));
+ }
+ }
+
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 951e6209d6b8c..ff3218795e435 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
@@ -58,6 +58,8 @@
import org.elasticsearch.client.ml.PutCalendarResponse;
import org.elasticsearch.client.ml.PutDatafeedRequest;
import org.elasticsearch.client.ml.PutDatafeedResponse;
+import org.elasticsearch.client.ml.PutFilterRequest;
+import org.elasticsearch.client.ml.PutFilterResponse;
import org.elasticsearch.client.ml.PutJobRequest;
import org.elasticsearch.client.ml.PutJobResponse;
import org.elasticsearch.client.ml.StartDatafeedRequest;
@@ -78,6 +80,7 @@
import org.elasticsearch.client.ml.job.config.Job;
import org.elasticsearch.client.ml.job.config.JobState;
import org.elasticsearch.client.ml.job.config.JobUpdate;
+import org.elasticsearch.client.ml.job.config.MlFilter;
import org.elasticsearch.client.ml.job.stats.JobStats;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
@@ -859,6 +862,22 @@ public void testDeleteCalendar() throws IOException {
assertThat(exception.status().getStatus(), equalTo(404));
}
+ public void testFilterJob() throws Exception {
+ String filterId = "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));
+ }
+
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 cf6a9622c0c72..90337ebf6053e 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
@@ -74,6 +74,8 @@
import org.elasticsearch.client.ml.PutCalendarResponse;
import org.elasticsearch.client.ml.PutDatafeedRequest;
import org.elasticsearch.client.ml.PutDatafeedResponse;
+import org.elasticsearch.client.ml.PutFilterRequest;
+import org.elasticsearch.client.ml.PutFilterResponse;
import org.elasticsearch.client.ml.PutJobRequest;
import org.elasticsearch.client.ml.PutJobResponse;
import org.elasticsearch.client.ml.StartDatafeedRequest;
@@ -94,6 +96,7 @@
import org.elasticsearch.client.ml.job.config.Detector;
import org.elasticsearch.client.ml.job.config.Job;
import org.elasticsearch.client.ml.job.config.JobUpdate;
+import org.elasticsearch.client.ml.job.config.MlFilter;
import org.elasticsearch.client.ml.job.config.ModelPlotConfig;
import org.elasticsearch.client.ml.job.config.Operator;
import org.elasticsearch.client.ml.job.config.RuleCondition;
@@ -2007,4 +2010,58 @@ public void onFailure(Exception e) {
assertTrue(latch.await(30L, TimeUnit.SECONDS));
}
+
+ public void testCreateFilter() throws Exception {
+ RestHighLevelClient client = highLevelClient();
+ {
+ // tag::put-filter-config
+ MlFilter.Builder filterBuilder = MlFilter.builder("my_safe_domains") // <1>
+ .setDescription("A list of safe domains") // <2>
+ .setItems("*.google.com", "wikipedia.org"); // <3>
+ // end::put-filter-config
+
+ // tag::put-filter-request
+ PutFilterRequest request = new PutFilterRequest(filterBuilder.build()); // <1>
+ // end::put-filter-request
+
+ // tag::put-filter-execute
+ PutFilterResponse response = client.machineLearning().putFilter(request, RequestOptions.DEFAULT);
+ // end::put-filter-execute
+
+ // tag::put-filter-response
+ MlFilter createdFilter = response.getResponse(); // <1>
+ // end::put-filter-response
+ assertThat(createdFilter.getId(), equalTo("my_safe_domains"));
+ }
+ {
+ MlFilter.Builder filterBuilder = MlFilter.builder("safe_domains_async")
+ .setDescription("A list of safe domains")
+ .setItems("*.google.com", "wikipedia.org");
+
+ PutFilterRequest request = new PutFilterRequest(filterBuilder.build());
+ // tag::put-filter-execute-listener
+ ActionListener listener = new ActionListener() {
+ @Override
+ public void onResponse(PutFilterResponse response) {
+ // <1>
+ }
+
+ @Override
+ public void onFailure(Exception e) {
+ // <2>
+ }
+ };
+ // end::put-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::put-filter-execute-async
+ client.machineLearning().putFilterAsync(request, RequestOptions.DEFAULT, listener); // <1>
+ // end::put-filter-execute-async
+
+ assertTrue(latch.await(30L, TimeUnit.SECONDS));
+ }
+ }
}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PutFilterRequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PutFilterRequestTests.java
new file mode 100644
index 0000000000000..6b39d81f171ca
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PutFilterRequestTests.java
@@ -0,0 +1,43 @@
+/*
+ * 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.job.config.MlFilter;
+import org.elasticsearch.client.ml.job.config.MlFilterTests;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.test.AbstractXContentTestCase;
+
+
+public class PutFilterRequestTests extends AbstractXContentTestCase {
+
+ @Override
+ protected PutFilterRequest createTestInstance() {
+ return new PutFilterRequest(MlFilterTests.createRandom());
+ }
+
+ @Override
+ protected PutFilterRequest doParseInstance(XContentParser parser) {
+ return new PutFilterRequest(MlFilter.PARSER.apply(parser, null).build());
+ }
+
+ @Override
+ protected boolean supportsUnknownFields() {
+ return false;
+ }
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PutFilterResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PutFilterResponseTests.java
new file mode 100644
index 0000000000000..29eda47598b2f
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/PutFilterResponseTests.java
@@ -0,0 +1,43 @@
+/*
+ * 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.job.config.MlFilterTests;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.test.AbstractXContentTestCase;
+
+import java.io.IOException;
+
+public class PutFilterResponseTests extends AbstractXContentTestCase {
+
+ @Override
+ protected PutFilterResponse createTestInstance() {
+ return new PutFilterResponse(MlFilterTests.createRandom());
+ }
+
+ @Override
+ protected PutFilterResponse doParseInstance(XContentParser parser) throws IOException {
+ return PutFilterResponse.fromXContent(parser);
+ }
+
+ @Override
+ protected boolean supportsUnknownFields() {
+ return false;
+ }
+}
diff --git a/docs/java-rest/high-level/ml/put-filter.asciidoc b/docs/java-rest/high-level/ml/put-filter.asciidoc
new file mode 100644
index 0000000000000..2582e7715ab59
--- /dev/null
+++ b/docs/java-rest/high-level/ml/put-filter.asciidoc
@@ -0,0 +1,53 @@
+--
+:api: put-filter
+:request: PutFilterRequest
+:response: PutFilterResponse
+--
+[id="{upid}-{api}"]
+=== Put Filter API
+
+The Put Filter API can be used to create a new {ml} filter
+in the cluster. The API accepts a +{request}+ object
+as a request and returns a +{response}+.
+
+[id="{upid}-{api}-request"]
+==== Put Filter Request
+
+A +{request}+ requires the following argument:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-request]
+--------------------------------------------------
+<1> The configuration of the {ml} filter to create as a `MlFilter`
+
+[id="{upid}-{api}-config"]
+==== Filter Configuration
+
+The `MlFilter` object contains all the details about the {ml} filter
+configuration.
+
+A `MlFilter` contains the following arguments:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-config]
+--------------------------------------------------
+<1> Required, the filter ID
+<2> Optional, the filter description
+<3> Optional, the items of the filter. A wildcard * can be used at the beginning or the end of an item.
+Up to 10000 items are allowed in each filter.
+
+include::../execution.asciidoc[]
+
+[id="{upid}-{api}-response"]
+==== Response
+
+The returned +{response}+ returns the full representation of
+the new {ml} filter if it has been successfully created.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-response]
+--------------------------------------------------
+<1> The newly created `MlFilter`
diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc
index 4411a6b375f91..8a8b601e02923 100644
--- a/docs/java-rest/high-level/supported-apis.asciidoc
+++ b/docs/java-rest/high-level/supported-apis.asciidoc
@@ -258,6 +258,7 @@ The Java High Level REST Client supports the following Machine Learning APIs:
* <<{upid}-get-calendars>>
* <<{upid}-put-calendar>>
* <<{upid}-delete-calendar>>
+* <<{upid}-put-filter>>
include::ml/put-job.asciidoc[]
include::ml/get-job.asciidoc[]
@@ -286,6 +287,7 @@ include::ml/get-categories.asciidoc[]
include::ml/get-calendars.asciidoc[]
include::ml/put-calendar.asciidoc[]
include::ml/delete-calendar.asciidoc[]
+include::ml/put-filter.asciidoc[]
== Migration APIs