diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/EnrichClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/EnrichClient.java
new file mode 100644
index 00000000000..420f11b23d8
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/EnrichClient.java
@@ -0,0 +1,274 @@
+/*
+ * 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;
+
+import org.elasticsearch.action.ActionListener;
+import org.elasticsearch.client.core.AcknowledgedResponse;
+import org.elasticsearch.client.enrich.DeletePolicyRequest;
+import org.elasticsearch.client.enrich.ExecutePolicyRequest;
+import org.elasticsearch.client.enrich.ExecutePolicyResponse;
+import org.elasticsearch.client.enrich.GetPolicyRequest;
+import org.elasticsearch.client.enrich.GetPolicyResponse;
+import org.elasticsearch.client.enrich.PutPolicyRequest;
+import org.elasticsearch.client.enrich.StatsRequest;
+import org.elasticsearch.client.enrich.StatsResponse;
+
+import java.io.IOException;
+import java.util.Collections;
+
+/**
+ * A wrapper for the {@link RestHighLevelClient} that provides methods for
+ * accessing the Elastic enrich related methods
+ *
+ * See the
+ * X-Pack Enrich Policy APIs on elastic.co for more information.
+ */
+public final class EnrichClient {
+
+ private final RestHighLevelClient restHighLevelClient;
+
+ EnrichClient(RestHighLevelClient restHighLevelClient) {
+ this.restHighLevelClient = restHighLevelClient;
+ }
+
+ /**
+ * Executes the put policy api, which stores an enrich policy.
+ *
+ * See
+ * the docs for more.
+ *
+ * @param request the {@link PutPolicyRequest}
+ * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @return the response
+ * @throws IOException in case there is a problem sending the request or parsing back the response
+ */
+ public AcknowledgedResponse putPolicy(PutPolicyRequest request, RequestOptions options) throws IOException {
+ return restHighLevelClient.performRequestAndParseEntity(
+ request,
+ EnrichRequestConverters::putPolicy,
+ options,
+ AcknowledgedResponse::fromXContent,
+ Collections.emptySet()
+ );
+ }
+
+ /**
+ * Asynchronously executes the put policy api, which stores an enrich policy.
+ *
+ * See
+ * the docs for more.
+ *
+ * @param request the {@link PutPolicyRequest}
+ * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @param listener the listener to be notified upon request completion
+ * @return cancellable that may be used to cancel the request
+ */
+ public Cancellable putPolicyAsync(PutPolicyRequest request,
+ RequestOptions options,
+ ActionListener listener) {
+ return restHighLevelClient.performRequestAsyncAndParseEntity(
+ request,
+ EnrichRequestConverters::putPolicy,
+ options,
+ AcknowledgedResponse::fromXContent,
+ listener,
+ Collections.emptySet()
+ );
+ }
+
+ /**
+ * Executes the delete policy api, which deletes an enrich policy.
+ *
+ * See
+ * the docs for more.
+ *
+ * @param request the {@link DeletePolicyRequest}
+ * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @return the response
+ * @throws IOException in case there is a problem sending the request or parsing back the response
+ */
+ public AcknowledgedResponse deletePolicy(DeletePolicyRequest request, RequestOptions options) throws IOException {
+ return restHighLevelClient.performRequestAndParseEntity(
+ request,
+ EnrichRequestConverters::deletePolicy,
+ options,
+ AcknowledgedResponse::fromXContent,
+ Collections.emptySet()
+ );
+ }
+
+ /**
+ * Asynchronously executes the delete policy api, which deletes an enrich policy.
+ *
+ * See
+ * the docs for more.
+ *
+ * @param request the {@link DeletePolicyRequest}
+ * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @param listener the listener to be notified upon request completion
+ * @return cancellable that may be used to cancel the request
+ */
+ public Cancellable deletePolicyAsync(DeletePolicyRequest request,
+ RequestOptions options,
+ ActionListener listener) {
+ return restHighLevelClient.performRequestAsyncAndParseEntity(
+ request,
+ EnrichRequestConverters::deletePolicy,
+ options,
+ AcknowledgedResponse::fromXContent,
+ listener,
+ Collections.emptySet()
+ );
+ }
+
+ /**
+ * Executes the get policy api, which retrieves an enrich policy.
+ *
+ * See
+ * the docs for more.
+ *
+ * @param request the {@link PutPolicyRequest}
+ * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @return the response
+ * @throws IOException in case there is a problem sending the request or parsing back the response
+ */
+ public GetPolicyResponse getPolicy(GetPolicyRequest request, RequestOptions options) throws IOException {
+ return restHighLevelClient.performRequestAndParseEntity(
+ request,
+ EnrichRequestConverters::getPolicy,
+ options,
+ GetPolicyResponse::fromXContent,
+ Collections.emptySet()
+ );
+ }
+
+ /**
+ * Asynchronously executes the get policy api, which retrieves an enrich policy.
+ *
+ * See
+ * the docs for more.
+ *
+ * @param request the {@link PutPolicyRequest}
+ * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @param listener the listener to be notified upon request completion
+ * @return cancellable that may be used to cancel the request
+ */
+ public Cancellable getPolicyAsync(GetPolicyRequest request,
+ RequestOptions options,
+ ActionListener listener) {
+ return restHighLevelClient.performRequestAsyncAndParseEntity(
+ request,
+ EnrichRequestConverters::getPolicy,
+ options,
+ GetPolicyResponse::fromXContent,
+ listener,
+ Collections.emptySet()
+ );
+ }
+
+ /**
+ * Executes the enrich stats api, which retrieves enrich related stats.
+ *
+ * See
+ * the docs for more.
+ *
+ * @param request the {@link StatsRequest}
+ * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @return the response
+ * @throws IOException in case there is a problem sending the request or parsing back the response
+ */
+ public StatsResponse stats(StatsRequest request, RequestOptions options) throws IOException {
+ return restHighLevelClient.performRequestAndParseEntity(
+ request,
+ EnrichRequestConverters::stats,
+ options,
+ StatsResponse::fromXContent,
+ Collections.emptySet()
+ );
+ }
+
+ /**
+ * Asynchronously executes the enrich stats api, which retrieves enrich related stats.
+ *
+ * See
+ * the docs for more.
+ *
+ * @param request the {@link StatsRequest}
+ * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @param listener the listener to be notified upon request completion
+ * @return cancellable that may be used to cancel the request
+ */
+ public Cancellable statsAsync(StatsRequest request,
+ RequestOptions options,
+ ActionListener listener) {
+ return restHighLevelClient.performRequestAsyncAndParseEntity(
+ request,
+ EnrichRequestConverters::stats,
+ options,
+ StatsResponse::fromXContent,
+ listener,
+ Collections.emptySet()
+ );
+ }
+
+ /**
+ * Executes the execute policy api, which executes an enrich policy.
+ *
+ * See
+ * the docs for more.
+ *
+ * @param request the {@link ExecutePolicyRequest}
+ * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @return the response
+ * @throws IOException in case there is a problem sending the request or parsing back the response
+ */
+ public ExecutePolicyResponse executePolicy(ExecutePolicyRequest request, RequestOptions options) throws IOException {
+ return restHighLevelClient.performRequestAndParseEntity(
+ request,
+ EnrichRequestConverters::executePolicy,
+ options,
+ ExecutePolicyResponse::fromXContent,
+ Collections.emptySet()
+ );
+ }
+
+ /**
+ * Asynchronously executes the execute policy api, which executes an enrich policy.
+ *
+ * See
+ * the docs for more.
+ *
+ * @param request the {@link ExecutePolicyRequest}
+ * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @param listener the listener to be notified upon request completion
+ * @return cancellable that may be used to cancel the request
+ */
+ public Cancellable executePolicyAsync(ExecutePolicyRequest request,
+ RequestOptions options,
+ ActionListener listener) {
+ return restHighLevelClient.performRequestAsyncAndParseEntity(
+ request,
+ EnrichRequestConverters::executePolicy,
+ options,
+ ExecutePolicyResponse::fromXContent,
+ listener,
+ Collections.emptySet()
+ );
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/EnrichRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/EnrichRequestConverters.java
new file mode 100644
index 00000000000..9e9e74fb005
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/EnrichRequestConverters.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;
+
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.elasticsearch.client.enrich.DeletePolicyRequest;
+import org.elasticsearch.client.enrich.ExecutePolicyRequest;
+import org.elasticsearch.client.enrich.GetPolicyRequest;
+import org.elasticsearch.client.enrich.PutPolicyRequest;
+import org.elasticsearch.client.enrich.StatsRequest;
+
+import java.io.IOException;
+
+import static org.elasticsearch.client.RequestConverters.REQUEST_BODY_CONTENT_TYPE;
+import static org.elasticsearch.client.RequestConverters.createEntity;
+
+final class EnrichRequestConverters {
+
+ static Request putPolicy(PutPolicyRequest putPolicyRequest) throws IOException {
+ String endpoint = new RequestConverters.EndpointBuilder()
+ .addPathPartAsIs("_enrich", "policy")
+ .addPathPart(putPolicyRequest.getName())
+ .build();
+ Request request = new Request(HttpPut.METHOD_NAME, endpoint);
+ request.setEntity(createEntity(putPolicyRequest, REQUEST_BODY_CONTENT_TYPE));
+ return request;
+ }
+
+ static Request deletePolicy(DeletePolicyRequest deletePolicyRequest) {
+ String endpoint = new RequestConverters.EndpointBuilder()
+ .addPathPartAsIs("_enrich", "policy")
+ .addPathPart(deletePolicyRequest.getName())
+ .build();
+ return new Request(HttpDelete.METHOD_NAME, endpoint);
+ }
+
+ static Request getPolicy(GetPolicyRequest getPolicyRequest) {
+ String endpoint = new RequestConverters.EndpointBuilder()
+ .addPathPartAsIs("_enrich", "policy")
+ .addCommaSeparatedPathParts(getPolicyRequest.getNames())
+ .build();
+ return new Request(HttpGet.METHOD_NAME, endpoint);
+ }
+
+ static Request stats(StatsRequest statsRequest) {
+ String endpoint = new RequestConverters.EndpointBuilder()
+ .addPathPartAsIs("_enrich", "_stats")
+ .build();
+ return new Request(HttpGet.METHOD_NAME, endpoint);
+ }
+
+ static Request executePolicy(ExecutePolicyRequest executePolicyRequest) {
+ String endpoint = new RequestConverters.EndpointBuilder()
+ .addPathPartAsIs("_enrich", "policy")
+ .addPathPart(executePolicyRequest.getName())
+ .addPathPartAsIs("_execute")
+ .build();
+ Request request = new Request(HttpPost.METHOD_NAME, endpoint);
+ if (executePolicyRequest.getWaitForCompletion() != null) {
+ request.addParameter("wait_for_completion", executePolicyRequest.getWaitForCompletion().toString());
+ }
+ return request;
+ }
+
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java
index 171dfb174dc..3986d4e8f13 100644
--- a/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java
@@ -257,6 +257,7 @@ public class RestHighLevelClient implements Closeable {
private final RollupClient rollupClient = new RollupClient(this);
private final CcrClient ccrClient = new CcrClient(this);
private final TransformClient transformClient = new TransformClient(this);
+ private final EnrichClient enrichClient = new EnrichClient(this);
/**
* Creates a {@link RestHighLevelClient} given the low level {@link RestClientBuilder} that allows to build the
@@ -481,6 +482,10 @@ public class RestHighLevelClient implements Closeable {
return transformClient;
}
+ public EnrichClient enrich() {
+ return enrichClient;
+ }
+
/**
* Executes a bulk request using the Bulk API.
* See Bulk API on elastic.co
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/DeletePolicyRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/DeletePolicyRequest.java
new file mode 100644
index 00000000000..745aeb30914
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/DeletePolicyRequest.java
@@ -0,0 +1,38 @@
+/*
+ * 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.enrich;
+
+import org.elasticsearch.client.Validatable;
+import org.elasticsearch.common.Strings;
+
+public final class DeletePolicyRequest implements Validatable {
+
+ private final String name;
+
+ public DeletePolicyRequest(String name) {
+ if (Strings.hasLength(name) == false) {
+ throw new IllegalArgumentException("name must be a non-null and non-empty string");
+ }
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/ExecutePolicyRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/ExecutePolicyRequest.java
new file mode 100644
index 00000000000..f5f4151d2e6
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/ExecutePolicyRequest.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.enrich;
+
+import org.elasticsearch.client.Validatable;
+
+public final class ExecutePolicyRequest implements Validatable {
+
+ private final String name;
+ private Boolean waitForCompletion;
+
+ public ExecutePolicyRequest(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Boolean getWaitForCompletion() {
+ return waitForCompletion;
+ }
+
+ public void setWaitForCompletion(boolean waitForCompletion) {
+ this.waitForCompletion = waitForCompletion;
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/ExecutePolicyResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/ExecutePolicyResponse.java
new file mode 100644
index 00000000000..099a8c4c329
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/ExecutePolicyResponse.java
@@ -0,0 +1,85 @@
+/*
+ * 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.enrich;
+
+import org.elasticsearch.common.ParseField;
+import org.elasticsearch.common.xcontent.ConstructingObjectParser;
+import org.elasticsearch.common.xcontent.XContentParser;
+
+public final class ExecutePolicyResponse {
+
+ private static final ParseField TASK_FIELD = new ParseField("task");
+ private static final ParseField STATUS_FIELD = new ParseField("status");
+
+ private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(
+ "execute_policy_response",
+ true,
+ args -> new ExecutePolicyResponse((String) args[0], (ExecutionStatus) args[1])
+ );
+
+ static {
+ PARSER.declareString(ConstructingObjectParser.optionalConstructorArg(), TASK_FIELD);
+ PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), ExecutionStatus.PARSER, STATUS_FIELD);
+ }
+
+ public static ExecutePolicyResponse fromXContent(XContentParser parser) {
+ return PARSER.apply(parser, null);
+ }
+
+ private final String taskId;
+ private final ExecutionStatus executionStatus;
+
+ ExecutePolicyResponse(String taskId, ExecutionStatus executionStatus) {
+ this.taskId = taskId;
+ this.executionStatus = executionStatus;
+ }
+
+ public String getTaskId() {
+ return taskId;
+ }
+
+ public ExecutionStatus getExecutionStatus() {
+ return executionStatus;
+ }
+
+ public static final class ExecutionStatus {
+
+ private static final ParseField PHASE_FIELD = new ParseField("phase");
+
+ private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(
+ "execution_status",
+ true,
+ args -> new ExecutionStatus((String) args[0])
+ );
+
+ static {
+ PARSER.declareString(ConstructingObjectParser.constructorArg(), PHASE_FIELD);
+ }
+
+ private final String phase;
+
+ ExecutionStatus(String phase) {
+ this.phase = phase;
+ }
+
+ public String getPhase() {
+ return phase;
+ }
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/GetPolicyRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/GetPolicyRequest.java
new file mode 100644
index 00000000000..cada904b31e
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/GetPolicyRequest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.enrich;
+
+import org.elasticsearch.client.Validatable;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public final class GetPolicyRequest implements Validatable {
+
+ private final List names;
+
+ public GetPolicyRequest() {
+ this(Collections.emptyList());
+ }
+
+ public GetPolicyRequest(String... names) {
+ this(Arrays.asList(names));
+ }
+
+ public GetPolicyRequest(List names) {
+ this.names = names;
+ }
+
+ public List getNames() {
+ return names;
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/GetPolicyResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/GetPolicyResponse.java
new file mode 100644
index 00000000000..e09d4657828
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/GetPolicyResponse.java
@@ -0,0 +1,64 @@
+/*
+ * 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.enrich;
+
+import org.elasticsearch.common.ParseField;
+import org.elasticsearch.common.xcontent.ConstructingObjectParser;
+import org.elasticsearch.common.xcontent.XContentParser;
+
+import java.io.IOException;
+import java.util.List;
+
+public final class GetPolicyResponse {
+
+ @SuppressWarnings("unchecked")
+ private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(
+ "get_policy_response",
+ true,
+ args -> new GetPolicyResponse((List) args[0])
+ );
+
+ @SuppressWarnings("unchecked")
+ private static final ConstructingObjectParser CONFIG_PARSER = new ConstructingObjectParser<>(
+ "config",
+ true,
+ args -> (NamedPolicy) args[0]
+ );
+
+ static {
+ PARSER.declareObjectArray(ConstructingObjectParser.constructorArg(),
+ CONFIG_PARSER::apply, new ParseField("policies"));
+ CONFIG_PARSER.declareObject(ConstructingObjectParser.constructorArg(),
+ (p, c) -> NamedPolicy.fromXContent(p), new ParseField("config"));
+ }
+
+ private final List policies;
+
+ public static GetPolicyResponse fromXContent(XContentParser parser) throws IOException {
+ return PARSER.apply(parser, null);
+ }
+
+ public GetPolicyResponse(List policies) {
+ this.policies = policies;
+ }
+
+ public List getPolicies() {
+ return policies;
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/NamedPolicy.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/NamedPolicy.java
new file mode 100644
index 00000000000..ea0ea52e892
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/NamedPolicy.java
@@ -0,0 +1,130 @@
+/*
+ * 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.enrich;
+
+import org.elasticsearch.common.ParseField;
+import org.elasticsearch.common.ParsingException;
+import org.elasticsearch.common.bytes.BytesArray;
+import org.elasticsearch.common.bytes.BytesReference;
+import org.elasticsearch.common.xcontent.ConstructingObjectParser;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.common.xcontent.XContentParser;
+
+import java.io.IOException;
+import java.util.List;
+
+public final class NamedPolicy {
+
+ static final ParseField NAME_FIELD = new ParseField("name");
+ static final ParseField QUERY_FIELD = new ParseField("query");
+ static final ParseField INDICES_FIELD = new ParseField("indices");
+ static final ParseField MATCH_FIELD_FIELD = new ParseField("match_field");
+ static final ParseField ENRICH_FIELDS_FIELD = new ParseField("enrich_fields");
+
+ @SuppressWarnings("unchecked")
+ private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(
+ "policy",
+ true,
+ (args, policyType) -> new NamedPolicy(
+ policyType,
+ (String) args[0],
+ (BytesReference) args[1],
+ (List) args[2],
+ (String) args[3],
+ (List) args[4]
+ )
+ );
+
+ static {
+ declareParserOptions(PARSER);
+ }
+
+ private static void declareParserOptions(ConstructingObjectParser, ?> parser) {
+ parser.declareString(ConstructingObjectParser.constructorArg(), NAME_FIELD);
+ parser.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> {
+ XContentBuilder builder = XContentBuilder.builder(p.contentType().xContent());
+ builder.copyCurrentStructure(p);
+ return BytesArray.bytes(builder);
+ }, QUERY_FIELD);
+ parser.declareStringArray(ConstructingObjectParser.constructorArg(), INDICES_FIELD);
+ parser.declareString(ConstructingObjectParser.constructorArg(), MATCH_FIELD_FIELD);
+ parser.declareStringArray(ConstructingObjectParser.constructorArg(), ENRICH_FIELDS_FIELD);
+ }
+
+ public static NamedPolicy fromXContent(XContentParser parser) throws IOException {
+ XContentParser.Token token = parser.currentToken();
+ if (token != XContentParser.Token.START_OBJECT) {
+ token = parser.nextToken();
+ }
+ if (token != XContentParser.Token.START_OBJECT) {
+ throw new ParsingException(parser.getTokenLocation(), "unexpected token");
+ }
+ token = parser.nextToken();
+ if (token != XContentParser.Token.FIELD_NAME) {
+ throw new ParsingException(parser.getTokenLocation(), "unexpected token");
+ }
+ String policyType = parser.currentName();
+ NamedPolicy policy = PARSER.parse(parser, policyType);
+ token = parser.nextToken();
+ if (token != XContentParser.Token.END_OBJECT) {
+ throw new ParsingException(parser.getTokenLocation(), "unexpected token");
+ }
+ return policy;
+ }
+
+ private final String type;
+ private final String name;
+ private final BytesReference query;
+ private final List indices;
+ private final String matchField;
+ private final List enrichFields;
+
+ NamedPolicy(String type, String name, BytesReference query, List indices, String matchField, List enrichFields) {
+ this.type = type;
+ this.name = name;
+ this.query = query;
+ this.indices = indices;
+ this.matchField = matchField;
+ this.enrichFields = enrichFields;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public BytesReference getQuery() {
+ return query;
+ }
+
+ public List getIndices() {
+ return indices;
+ }
+
+ public String getMatchField() {
+ return matchField;
+ }
+
+ public List getEnrichFields() {
+ return enrichFields;
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/PutPolicyRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/PutPolicyRequest.java
new file mode 100644
index 00000000000..0eb902dfe46
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/PutPolicyRequest.java
@@ -0,0 +1,148 @@
+/*
+ * 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.enrich;
+
+import org.elasticsearch.client.Validatable;
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.bytes.BytesReference;
+import org.elasticsearch.common.xcontent.ToXContentObject;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.common.xcontent.XContentHelper;
+import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.common.xcontent.json.JsonXContent;
+import org.elasticsearch.index.query.QueryBuilder;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+public final class PutPolicyRequest implements Validatable, ToXContentObject {
+
+ private final String name;
+ private final String type;
+ private BytesReference query;
+ private final List indices;
+ private final String matchField;
+ private final List enrichFields;
+
+ public PutPolicyRequest(String name, String type, List indices, String matchField, List enrichFields) {
+ if (Strings.hasLength(name) == false) {
+ throw new IllegalArgumentException("name must be a non-null and non-empty string");
+ }
+ if (Strings.hasLength(type) == false) {
+ throw new IllegalArgumentException("type must be a non-null and non-empty string");
+ }
+ if (indices == null || indices.isEmpty()) {
+ throw new IllegalArgumentException("indices must be specified");
+ }
+ if (Strings.hasLength(matchField) == false) {
+ throw new IllegalArgumentException("matchField must be a non-null and non-empty string");
+ }
+ if (enrichFields == null || enrichFields.isEmpty()) {
+ throw new IllegalArgumentException("enrichFields must be specified");
+ }
+
+ this.name = name;
+ this.type = type;
+ this.indices = indices;
+ this.matchField = matchField;
+ this.enrichFields = enrichFields;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public BytesReference getQuery() {
+ return query;
+ }
+
+ public void setQuery(BytesReference query) {
+ this.query = query;
+ }
+
+ public void setQuery(QueryBuilder query) throws IOException {
+ setQuery(xContentToBytes(query));
+ }
+
+ public List getIndices() {
+ return indices;
+ }
+
+ public String getMatchField() {
+ return matchField;
+ }
+
+ public List getEnrichFields() {
+ return enrichFields;
+ }
+
+ @Override
+ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+ builder.startObject();
+ {
+ builder.startObject(type);
+ {
+ builder.field(NamedPolicy.INDICES_FIELD.getPreferredName(), indices);
+ if (query != null) {
+ builder.field(NamedPolicy.QUERY_FIELD.getPreferredName(), asMap(query, builder.contentType()));
+ }
+ builder.field(NamedPolicy.MATCH_FIELD_FIELD.getPreferredName(), matchField);
+ builder.field(NamedPolicy.ENRICH_FIELDS_FIELD.getPreferredName(), enrichFields);
+ }
+ builder.endObject();
+ }
+ builder.endObject();
+ return builder;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ PutPolicyRequest that = (PutPolicyRequest) o;
+ return Objects.equals(name, that.name) &&
+ Objects.equals(type, that.type) &&
+ Objects.equals(query, that.query) &&
+ Objects.equals(indices, that.indices) &&
+ Objects.equals(matchField, that.matchField) &&
+ Objects.equals(enrichFields, that.enrichFields);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, type, query, indices, matchField, enrichFields);
+ }
+
+ private static BytesReference xContentToBytes(ToXContentObject object) throws IOException {
+ try (XContentBuilder builder = JsonXContent.contentBuilder()) {
+ object.toXContent(builder, ToXContentObject.EMPTY_PARAMS);
+ return BytesReference.bytes(builder);
+ }
+ }
+
+ static Map asMap(BytesReference bytesReference, XContentType xContentType) {
+ return bytesReference == null ? null : XContentHelper.convertToMap(bytesReference, true, xContentType).v2();
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/StatsRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/StatsRequest.java
new file mode 100644
index 00000000000..c9a8223d5a1
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/StatsRequest.java
@@ -0,0 +1,24 @@
+/*
+ * 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.enrich;
+
+import org.elasticsearch.client.Validatable;
+
+public final class StatsRequest implements Validatable {
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/StatsResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/StatsResponse.java
new file mode 100644
index 00000000000..af6e03655f0
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/enrich/StatsResponse.java
@@ -0,0 +1,191 @@
+/*
+ * 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.enrich;
+
+import org.elasticsearch.common.ParseField;
+import org.elasticsearch.common.xcontent.ConstructingObjectParser;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.tasks.TaskInfo;
+
+import java.util.List;
+import java.util.Objects;
+
+public final class StatsResponse {
+
+ private static ParseField EXECUTING_POLICIES_FIELD = new ParseField("executing_policies");
+ private static ParseField COORDINATOR_STATS_FIELD = new ParseField("coordinator_stats");
+
+ @SuppressWarnings("unchecked")
+ private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(
+ "stats_response",
+ true,
+ args -> new StatsResponse((List) args[0], (List) args[1])
+ );
+
+ static {
+ PARSER.declareObjectArray(ConstructingObjectParser.constructorArg(), ExecutingPolicy.PARSER::apply, EXECUTING_POLICIES_FIELD);
+ PARSER.declareObjectArray(ConstructingObjectParser.constructorArg(), CoordinatorStats.PARSER::apply, COORDINATOR_STATS_FIELD);
+ }
+
+ public static StatsResponse fromXContent(XContentParser parser) {
+ return PARSER.apply(parser, null);
+ }
+
+ private final List executingPolicies;
+ private final List coordinatorStats;
+
+ public StatsResponse(List executingPolicies, List coordinatorStats) {
+ this.executingPolicies = executingPolicies;
+ this.coordinatorStats = coordinatorStats;
+ }
+
+ public List getExecutingPolicies() {
+ return executingPolicies;
+ }
+
+ public List getCoordinatorStats() {
+ return coordinatorStats;
+ }
+
+ public static final class CoordinatorStats {
+
+ static ParseField NODE_ID_FIELD = new ParseField("node_id");
+ static ParseField QUEUE_SIZE_FIELD = new ParseField("queue_size");
+ static ParseField REMOTE_REQUESTS_CONCURRENT_FIELD = new ParseField("remote_requests_current");
+ static ParseField REMOTE_REQUESTS_TOTAL_FIELD = new ParseField("remote_requests_total");
+ static ParseField EXECUTED_SEARCHES_FIELD = new ParseField("executed_searches_total");
+
+ private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(
+ "coordinator_stats_item",
+ true,
+ args -> new CoordinatorStats((String) args[0], (int) args[1], (int) args[2], (long) args[3], (long) args[4])
+ );
+
+ static {
+ PARSER.declareString(ConstructingObjectParser.constructorArg(), NODE_ID_FIELD);
+ PARSER.declareInt(ConstructingObjectParser.constructorArg(), QUEUE_SIZE_FIELD);
+ PARSER.declareInt(ConstructingObjectParser.constructorArg(), REMOTE_REQUESTS_CONCURRENT_FIELD);
+ PARSER.declareLong(ConstructingObjectParser.constructorArg(), REMOTE_REQUESTS_TOTAL_FIELD);
+ PARSER.declareLong(ConstructingObjectParser.constructorArg(), EXECUTED_SEARCHES_FIELD);
+ }
+
+ private final String nodeId;
+ private final int queueSize;
+ private final int remoteRequestsCurrent;
+ private final long remoteRequestsTotal;
+ private final long executedSearchesTotal;
+
+ public CoordinatorStats(String nodeId,
+ int queueSize,
+ int remoteRequestsCurrent,
+ long remoteRequestsTotal,
+ long executedSearchesTotal) {
+ this.nodeId = nodeId;
+ this.queueSize = queueSize;
+ this.remoteRequestsCurrent = remoteRequestsCurrent;
+ this.remoteRequestsTotal = remoteRequestsTotal;
+ this.executedSearchesTotal = executedSearchesTotal;
+ }
+
+ public String getNodeId() {
+ return nodeId;
+ }
+
+ public int getQueueSize() {
+ return queueSize;
+ }
+
+ public int getRemoteRequestsCurrent() {
+ return remoteRequestsCurrent;
+ }
+
+ public long getRemoteRequestsTotal() {
+ return remoteRequestsTotal;
+ }
+
+ public long getExecutedSearchesTotal() {
+ return executedSearchesTotal;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ CoordinatorStats stats = (CoordinatorStats) o;
+ return Objects.equals(nodeId, stats.nodeId) &&
+ queueSize == stats.queueSize &&
+ remoteRequestsCurrent == stats.remoteRequestsCurrent &&
+ remoteRequestsTotal == stats.remoteRequestsTotal &&
+ executedSearchesTotal == stats.executedSearchesTotal;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(nodeId, queueSize, remoteRequestsCurrent, remoteRequestsTotal, executedSearchesTotal);
+ }
+ }
+
+ public static class ExecutingPolicy {
+
+ static ParseField NAME_FIELD = new ParseField("name");
+ static ParseField TASK_FIELD = new ParseField("task");
+
+ private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(
+ "executing_policy_item",
+ true,
+ args -> new ExecutingPolicy((String) args[0], (TaskInfo) args[1])
+ );
+
+ static {
+ PARSER.declareString(ConstructingObjectParser.constructorArg(), NAME_FIELD);
+ PARSER.declareObject(ConstructingObjectParser.constructorArg(), (p, c) -> TaskInfo.fromXContent(p), TASK_FIELD);
+ }
+
+ private final String name;
+ private final TaskInfo taskInfo;
+
+ public ExecutingPolicy(String name, TaskInfo taskInfo) {
+ this.name = name;
+ this.taskInfo = taskInfo;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public TaskInfo getTaskInfo() {
+ return taskInfo;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ExecutingPolicy that = (ExecutingPolicy) o;
+ return name.equals(that.name) &&
+ taskInfo.equals(that.taskInfo);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, taskInfo);
+ }
+ }
+
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/Role.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/Role.java
index ba98dc6c6eb..3ef0d6dd332 100644
--- a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/Role.java
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/Role.java
@@ -322,10 +322,12 @@ public final class Role {
public static final String READ_CCR = "read_ccr";
public static final String MANAGE_ILM = "manage_ilm";
public static final String READ_ILM = "read_ilm";
+ public static final String MANAGE_ENRICH = "manage_enrich";
public static final String[] ALL_ARRAY = new String[] { NONE, ALL, MONITOR, MONITOR_TRANSFORM_DEPRECATED, MONITOR_TRANSFORM,
MONITOR_ML, MONITOR_WATCHER, MONITOR_ROLLUP, MANAGE, MANAGE_TRANSFORM_DEPRECATED, MANAGE_TRANSFORM,
MANAGE_ML, MANAGE_WATCHER, MANAGE_ROLLUP, MANAGE_INDEX_TEMPLATES, MANAGE_INGEST_PIPELINES, TRANSPORT_CLIENT,
- MANAGE_SECURITY, MANAGE_SAML, MANAGE_OIDC, MANAGE_TOKEN, MANAGE_PIPELINE, MANAGE_CCR, READ_CCR, MANAGE_ILM, READ_ILM};
+ MANAGE_SECURITY, MANAGE_SAML, MANAGE_OIDC, MANAGE_TOKEN, MANAGE_PIPELINE, MANAGE_CCR, READ_CCR, MANAGE_ILM, READ_ILM,
+ MANAGE_ENRICH };
}
/**
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/EnrichIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/EnrichIT.java
new file mode 100644
index 00000000000..fc9add73829
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/EnrichIT.java
@@ -0,0 +1,86 @@
+/*
+ * 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;
+
+import org.elasticsearch.client.core.AcknowledgedResponse;
+import org.elasticsearch.client.enrich.DeletePolicyRequest;
+import org.elasticsearch.client.enrich.ExecutePolicyRequest;
+import org.elasticsearch.client.enrich.ExecutePolicyResponse;
+import org.elasticsearch.client.enrich.GetPolicyRequest;
+import org.elasticsearch.client.enrich.GetPolicyResponse;
+import org.elasticsearch.client.enrich.PutPolicyRequest;
+import org.elasticsearch.client.enrich.StatsRequest;
+import org.elasticsearch.client.enrich.StatsResponse;
+import org.elasticsearch.client.indices.CreateIndexRequest;
+
+import java.util.Collections;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+
+public class EnrichIT extends ESRestHighLevelClientTestCase {
+
+ public void testCRUD() throws Exception {
+ CreateIndexRequest createIndexRequest = new CreateIndexRequest("my-index")
+ .mapping(Collections.singletonMap("properties", Collections.singletonMap("enrich_key",
+ Collections.singletonMap("type", "keyword"))));
+ highLevelClient().indices().create(createIndexRequest, RequestOptions.DEFAULT);
+
+ final EnrichClient enrichClient = highLevelClient().enrich();
+ PutPolicyRequest putPolicyRequest = new PutPolicyRequest("my-policy", "match",
+ Collections.singletonList("my-index"), "enrich_key", Collections.singletonList("enrich_value"));
+ AcknowledgedResponse putPolicyResponse = execute(putPolicyRequest, enrichClient::putPolicy, enrichClient::putPolicyAsync);
+ assertThat(putPolicyResponse.isAcknowledged(), is(true));
+
+ GetPolicyRequest getPolicyRequest = randomBoolean() ? new GetPolicyRequest("my-policy") : new GetPolicyRequest();
+ GetPolicyResponse getPolicyResponse = execute(getPolicyRequest, enrichClient::getPolicy, enrichClient::getPolicyAsync);
+ assertThat(getPolicyResponse.getPolicies().size(), equalTo(1));
+ assertThat(getPolicyResponse.getPolicies().get(0).getType(), equalTo(putPolicyRequest.getType()));
+ assertThat(getPolicyResponse.getPolicies().get(0).getIndices(), equalTo(putPolicyRequest.getIndices()));
+ assertThat(getPolicyResponse.getPolicies().get(0).getMatchField(), equalTo(putPolicyRequest.getMatchField()));
+ assertThat(getPolicyResponse.getPolicies().get(0).getEnrichFields(), equalTo(putPolicyRequest.getEnrichFields()));
+
+ StatsRequest statsRequest = new StatsRequest();
+ StatsResponse statsResponse = execute(statsRequest, enrichClient::stats, enrichClient::statsAsync);
+ assertThat(statsResponse.getExecutingPolicies().size(), equalTo(0));
+ assertThat(statsResponse.getCoordinatorStats().size(), equalTo(1));
+ assertThat(statsResponse.getCoordinatorStats().get(0).getNodeId(), notNullValue());
+ assertThat(statsResponse.getCoordinatorStats().get(0).getQueueSize(), greaterThanOrEqualTo(0));
+ assertThat(statsResponse.getCoordinatorStats().get(0).getRemoteRequestsCurrent(), greaterThanOrEqualTo(0));
+ assertThat(statsResponse.getCoordinatorStats().get(0).getRemoteRequestsTotal(), greaterThanOrEqualTo(0L));
+ assertThat(statsResponse.getCoordinatorStats().get(0).getExecutedSearchesTotal(), greaterThanOrEqualTo(0L));
+
+ ExecutePolicyRequest executePolicyRequest = new ExecutePolicyRequest("my-policy");
+ ExecutePolicyResponse executePolicyResponse =
+ execute(executePolicyRequest, enrichClient::executePolicy, enrichClient::executePolicyAsync);
+ assertThat(executePolicyResponse.getExecutionStatus().getPhase(), equalTo("COMPLETE"));
+
+ DeletePolicyRequest deletePolicyRequest = new DeletePolicyRequest("my-policy");
+ AcknowledgedResponse deletePolicyResponse =
+ execute(deletePolicyRequest, enrichClient::deletePolicy, enrichClient::deletePolicyAsync);
+ assertThat(deletePolicyResponse.isAcknowledged(), is(true));
+
+ getPolicyRequest = new GetPolicyRequest();
+ getPolicyResponse = execute(getPolicyRequest, enrichClient::getPolicy, enrichClient::getPolicyAsync);
+ assertThat(getPolicyResponse.getPolicies().size(), equalTo(0));
+ }
+
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/EnrichRequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/EnrichRequestConvertersTests.java
new file mode 100644
index 00000000000..8b649a6b47c
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/EnrichRequestConvertersTests.java
@@ -0,0 +1,114 @@
+/*
+ * 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;
+
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.elasticsearch.client.enrich.DeletePolicyRequest;
+import org.elasticsearch.client.enrich.ExecutePolicyRequest;
+import org.elasticsearch.client.enrich.GetPolicyRequest;
+import org.elasticsearch.client.enrich.PutPolicyRequest;
+import org.elasticsearch.client.enrich.PutPolicyRequestTests;
+import org.elasticsearch.client.enrich.StatsRequest;
+import org.elasticsearch.test.ESTestCase;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.nullValue;
+
+public class EnrichRequestConvertersTests extends ESTestCase {
+
+ public void testPutPolicy() throws Exception {
+ PutPolicyRequest request = PutPolicyRequestTests.createTestInstance();
+ Request result = EnrichRequestConverters.putPolicy(request);
+
+ assertThat(result.getMethod(), equalTo(HttpPut.METHOD_NAME));
+ assertThat(result.getEndpoint(), equalTo("/_enrich/policy/" + request.getName()));
+ assertThat(result.getParameters().size(), equalTo(0));
+ RequestConvertersTests.assertToXContentBody(request, result.getEntity());
+ }
+
+ public void testDeletePolicy() {
+ DeletePolicyRequest request = new DeletePolicyRequest(randomAlphaOfLength(4));
+ Request result = EnrichRequestConverters.deletePolicy(request);
+
+ assertThat(result.getMethod(), equalTo(HttpDelete.METHOD_NAME));
+ assertThat(result.getEndpoint(), equalTo("/_enrich/policy/" + request.getName()));
+ assertThat(result.getParameters().size(), equalTo(0));
+ assertThat(result.getEntity(), nullValue());
+ }
+
+ public void testGetPolicy() {
+ GetPolicyRequest request = new GetPolicyRequest(randomAlphaOfLength(4));
+ Request result = EnrichRequestConverters.getPolicy(request);
+
+ assertThat(result.getMethod(), equalTo(HttpGet.METHOD_NAME));
+ assertThat(result.getEndpoint(), equalTo("/_enrich/policy/" + request.getNames().get(0)));
+ assertThat(result.getParameters().size(), equalTo(0));
+ assertThat(result.getEntity(), nullValue());
+
+ request = new GetPolicyRequest(randomAlphaOfLength(4), randomAlphaOfLength(4));
+ result = EnrichRequestConverters.getPolicy(request);
+
+ assertThat(result.getMethod(), equalTo(HttpGet.METHOD_NAME));
+ assertThat(result.getEndpoint(), equalTo("/_enrich/policy/" + request.getNames().get(0) + "," + request.getNames().get(1)));
+ assertThat(result.getParameters().size(), equalTo(0));
+ assertThat(result.getEntity(), nullValue());
+
+ request = new GetPolicyRequest();
+ result = EnrichRequestConverters.getPolicy(request);
+
+ assertThat(result.getMethod(), equalTo(HttpGet.METHOD_NAME));
+ assertThat(result.getEndpoint(), equalTo("/_enrich/policy"));
+ assertThat(result.getParameters().size(), equalTo(0));
+ assertThat(result.getEntity(), nullValue());
+ }
+
+ public void testStats() {
+ StatsRequest request = new StatsRequest();
+ Request result = EnrichRequestConverters.stats(request);
+
+ assertThat(result.getMethod(), equalTo(HttpGet.METHOD_NAME));
+ assertThat(result.getEndpoint(), equalTo("/_enrich/_stats"));
+ assertThat(result.getParameters().size(), equalTo(0));
+ assertThat(result.getEntity(), nullValue());
+ }
+
+ public void testExecutePolicy() {
+ ExecutePolicyRequest request = new ExecutePolicyRequest(randomAlphaOfLength(4));
+ Request result = EnrichRequestConverters.executePolicy(request);
+
+ assertThat(result.getMethod(), equalTo(HttpPost.METHOD_NAME));
+ assertThat(result.getEndpoint(), equalTo("/_enrich/policy/" + request.getName() + "/_execute"));
+ assertThat(result.getParameters().size(), equalTo(0));
+ assertThat(result.getEntity(), nullValue());
+
+ request = new ExecutePolicyRequest(randomAlphaOfLength(4));
+ request.setWaitForCompletion(randomBoolean());
+ result = EnrichRequestConverters.executePolicy(request);
+
+ assertThat(result.getMethod(), equalTo(HttpPost.METHOD_NAME));
+ assertThat(result.getEndpoint(), equalTo("/_enrich/policy/" + request.getName() + "/_execute"));
+ assertThat(result.getParameters().size(), equalTo(1));
+ assertThat(result.getParameters().get("wait_for_completion"), equalTo(request.getWaitForCompletion().toString()));
+ assertThat(result.getEntity(), nullValue());
+ }
+
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java
index 59df6ea93a0..2805f64adbf 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java
@@ -857,6 +857,7 @@ public class RestHighLevelClientTests extends ESTestCase {
apiName.startsWith("security.") == false &&
apiName.startsWith("index_lifecycle.") == false &&
apiName.startsWith("ccr.") == false &&
+ apiName.startsWith("enrich.") == false &&
apiName.startsWith("transform.") == false &&
apiName.endsWith("freeze") == false &&
apiName.endsWith("reload_analyzers") == false &&
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/EnrichDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/EnrichDocumentationIT.java
new file mode 100644
index 00000000000..d4c26d6c9e9
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/EnrichDocumentationIT.java
@@ -0,0 +1,314 @@
+/*
+ * 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.documentation;
+
+import org.elasticsearch.action.ActionListener;
+import org.elasticsearch.action.LatchedActionListener;
+import org.elasticsearch.client.ESRestHighLevelClientTestCase;
+import org.elasticsearch.client.RequestOptions;
+import org.elasticsearch.client.RestHighLevelClient;
+import org.elasticsearch.client.core.AcknowledgedResponse;
+import org.elasticsearch.client.enrich.DeletePolicyRequest;
+import org.elasticsearch.client.enrich.ExecutePolicyRequest;
+import org.elasticsearch.client.enrich.ExecutePolicyResponse;
+import org.elasticsearch.client.enrich.NamedPolicy;
+import org.elasticsearch.client.enrich.GetPolicyRequest;
+import org.elasticsearch.client.enrich.GetPolicyResponse;
+import org.elasticsearch.client.enrich.PutPolicyRequest;
+import org.elasticsearch.client.enrich.StatsRequest;
+import org.elasticsearch.client.enrich.StatsResponse;
+import org.elasticsearch.client.enrich.StatsResponse.CoordinatorStats;
+import org.elasticsearch.client.enrich.StatsResponse.ExecutingPolicy;
+import org.elasticsearch.client.indices.CreateIndexRequest;
+import org.junit.After;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class EnrichDocumentationIT extends ESRestHighLevelClientTestCase {
+
+ @After
+ public void cleanup() {
+ RestHighLevelClient client = highLevelClient();
+ DeletePolicyRequest deletePolicyRequest = new DeletePolicyRequest("users-policy");
+ try {
+ client.enrich().deletePolicy(deletePolicyRequest, RequestOptions.DEFAULT);
+ } catch (Exception e) {
+ // ignore... it is ok if policy has already been removed
+ }
+ }
+
+ public void testPutPolicy() throws Exception {
+ RestHighLevelClient client = highLevelClient();
+ // tag::enrich-put-policy-request
+ PutPolicyRequest putPolicyRequest = new PutPolicyRequest(
+ "users-policy", "match", Arrays.asList("users"),
+ "email", Arrays.asList("address", "zip", "city", "state"));
+ // end::enrich-put-policy-request
+
+ // tag::enrich-put-policy-execute
+ AcknowledgedResponse putPolicyResponse =
+ client.enrich().putPolicy(putPolicyRequest, RequestOptions.DEFAULT);
+ // end::enrich-put-policy-execute
+
+ // tag::enrich-put-policy-response
+ boolean isAcknowledged =
+ putPolicyResponse.isAcknowledged(); // <1>
+ // end::enrich-put-policy-response
+
+ // tag::enrich-put-policy-execute-listener
+ ActionListener listener =
+ new ActionListener() {
+ @Override
+ public void onResponse(AcknowledgedResponse response) { // <1>
+ boolean isAcknowledged = response.isAcknowledged();
+ }
+
+ @Override
+ public void onFailure(Exception e) {
+ // <2>
+ }
+ };
+ // end::enrich-put-policy-execute-listener
+
+ // Replace the empty listener by a blocking listener in test
+ final CountDownLatch latch = new CountDownLatch(1);
+ listener = new LatchedActionListener<>(listener, latch);
+
+ // tag::enrich-put-policy-execute-async
+ client.enrich().putPolicyAsync(putPolicyRequest,
+ RequestOptions.DEFAULT, listener); // <1>
+ // end::enrich-put-policy-execute-async
+
+ assertTrue(latch.await(30L, TimeUnit.SECONDS));
+ }
+
+ public void testDeletePolicy() throws Exception {
+ RestHighLevelClient client = highLevelClient();
+
+ {
+ // Add a policy, so that it can be deleted:
+ PutPolicyRequest putPolicyRequest = new PutPolicyRequest(
+ "users-policy", "match", Arrays.asList("users"),
+ "email", Arrays.asList("address", "zip", "city", "state"));
+ client.enrich().putPolicy(putPolicyRequest, RequestOptions.DEFAULT);
+ }
+
+ // tag::enrich-delete-policy-request
+ DeletePolicyRequest deletePolicyRequest =
+ new DeletePolicyRequest("users-policy");
+ // end::enrich-delete-policy-request
+
+ // tag::enrich-delete-policy-execute
+ AcknowledgedResponse deletePolicyResponse = client.enrich()
+ .deletePolicy(deletePolicyRequest, RequestOptions.DEFAULT);
+ // end::enrich-delete-policy-execute
+
+ // tag::enrich-delete-policy-response
+ boolean isAcknowledged =
+ deletePolicyResponse.isAcknowledged(); // <1>
+ // end::enrich-delete-policy-response
+
+ // tag::enrich-delete-policy-execute-listener
+ ActionListener listener =
+ new ActionListener() {
+ @Override
+ public void onResponse(AcknowledgedResponse response) { // <1>
+ boolean isAcknowledged = response.isAcknowledged();
+ }
+
+ @Override
+ public void onFailure(Exception e) {
+ // <2>
+ }
+ };
+ // end::enrich-delete-policy-execute-listener
+
+ // Replace the empty listener by a blocking listener in test
+ final CountDownLatch latch = new CountDownLatch(1);
+ listener = new LatchedActionListener<>(listener, latch);
+
+ // tag::enrich-delete-policy-execute-async
+ client.enrich().deletePolicyAsync(deletePolicyRequest,
+ RequestOptions.DEFAULT, listener); // <1>
+ // end::enrich-delete-policy-execute-async
+
+ assertTrue(latch.await(30L, TimeUnit.SECONDS));
+ }
+
+ public void testGetPolicy() throws Exception {
+ RestHighLevelClient client = highLevelClient();
+
+ PutPolicyRequest putPolicyRequest = new PutPolicyRequest(
+ "users-policy", "match", Collections.singletonList("users"),
+ "email", Arrays.asList("address", "zip", "city", "state"));
+ client.enrich().putPolicy(putPolicyRequest, RequestOptions.DEFAULT);
+
+ // tag::enrich-get-policy-request
+ GetPolicyRequest getPolicyRequest = new GetPolicyRequest("users-policy");
+ // end::enrich-get-policy-request
+
+ // tag::enrich-get-policy-execute
+ GetPolicyResponse getPolicyResponse =
+ client.enrich().getPolicy(getPolicyRequest, RequestOptions.DEFAULT);
+ // end::enrich-get-policy-execute
+
+ // tag::enrich-get-policy-response
+ List policies = getPolicyResponse.getPolicies(); // <1>
+ NamedPolicy policy = policies.get(0);
+ // end::enrich-get-policy-response
+
+ // tag::enrich-get-policy-execute-listener
+ ActionListener listener =
+ new ActionListener() {
+ @Override
+ public void onResponse(GetPolicyResponse response) { // <1>
+ List policies = response.getPolicies();
+ NamedPolicy policy = policies.get(0);
+ }
+
+ @Override
+ public void onFailure(Exception e) {
+ // <2>
+ }
+ };
+ // end::enrich-get-policy-execute-listener
+
+ // Replace the empty listener by a blocking listener in test
+ final CountDownLatch latch = new CountDownLatch(1);
+ listener = new LatchedActionListener<>(listener, latch);
+
+ // tag::enrich-get-policy-execute-async
+ client.enrich().getPolicyAsync(getPolicyRequest,
+ RequestOptions.DEFAULT, listener); // <1>
+ // end::enrich-get-policy-execute-async
+
+ assertTrue(latch.await(30L, TimeUnit.SECONDS));
+ }
+
+ public void testStats() throws Exception {
+ RestHighLevelClient client = highLevelClient();
+
+ // tag::enrich-stats-request
+ StatsRequest statsRequest = new StatsRequest();
+ // end::enrich-stats-request
+
+ // tag::enrich-stats-execute
+ StatsResponse statsResponse =
+ client.enrich().stats(statsRequest, RequestOptions.DEFAULT);
+ // end::enrich-stats-execute
+
+ // tag::enrich-stats-response
+ List executingPolicies =
+ statsResponse.getExecutingPolicies(); // <1>
+ List coordinatorStats =
+ statsResponse.getCoordinatorStats(); // <2>
+ // end::enrich-stats-response
+
+ // tag::enrich-stats-execute-listener
+ ActionListener listener =
+ new ActionListener() {
+ @Override
+ public void onResponse(StatsResponse response) { // <1>
+ List executingPolicies =
+ statsResponse.getExecutingPolicies();
+ List coordinatorStats =
+ statsResponse.getCoordinatorStats();
+ }
+
+ @Override
+ public void onFailure(Exception e) {
+ // <2>
+ }
+ };
+ // end::enrich-stats-execute-listener
+
+ // Replace the empty listener by a blocking listener in test
+ final CountDownLatch latch = new CountDownLatch(1);
+ listener = new LatchedActionListener<>(listener, latch);
+
+ // tag::enrich-stats-execute-async
+ client.enrich().statsAsync(statsRequest, RequestOptions.DEFAULT,
+ listener); // <1>
+ // end::enrich-stats-execute-async
+
+ assertTrue(latch.await(30L, TimeUnit.SECONDS));
+ }
+
+ public void testExecutePolicy() throws Exception {
+ RestHighLevelClient client = highLevelClient();
+
+ {
+ CreateIndexRequest createIndexRequest = new CreateIndexRequest("users")
+ .mapping(Collections.singletonMap("properties", Collections.singletonMap("email",
+ Collections.singletonMap("type", "keyword"))));
+ client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
+ PutPolicyRequest putPolicyRequest = new PutPolicyRequest(
+ "users-policy", "match", Collections.singletonList("users"),
+ "email", Arrays.asList("address", "zip", "city", "state"));
+ client.enrich().putPolicy(putPolicyRequest, RequestOptions.DEFAULT);
+ }
+
+ // tag::enrich-execute-policy-request
+ ExecutePolicyRequest request =
+ new ExecutePolicyRequest("users-policy");
+ // end::enrich-execute-policy-request
+
+ // tag::enrich-execute-policy-execute
+ ExecutePolicyResponse response =
+ client.enrich().executePolicy(request, RequestOptions.DEFAULT);
+ // end::enrich-execute-policy-execute
+
+ // tag::enrich-execute-policy-response
+ ExecutePolicyResponse.ExecutionStatus status =
+ response.getExecutionStatus();
+ // end::enrich-execute-policy-response
+
+ // tag::enrich-execute-policy-execute-listener
+ ActionListener listener =
+ new ActionListener() {
+ @Override
+ public void onResponse(ExecutePolicyResponse response) { // <1>
+ ExecutePolicyResponse.ExecutionStatus status =
+ response.getExecutionStatus();
+ }
+
+ @Override
+ public void onFailure(Exception e) {
+ // <2>
+ }
+ };
+ // end::enrich-execute-policy-execute-listener
+
+ // Replace the empty listener by a blocking listener in test
+ final CountDownLatch latch = new CountDownLatch(1);
+ listener = new LatchedActionListener<>(listener, latch);
+
+ // tag::enrich-execute-policy-execute-async
+ client.enrich().executePolicyAsync(request, RequestOptions.DEFAULT,
+ listener); // <1>
+ // end::enrich-execute-policy-execute-async
+
+ assertTrue(latch.await(30L, TimeUnit.SECONDS));
+ }
+
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java
index cdf7fb16a40..2093e14d7c8 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java
@@ -681,7 +681,7 @@ public class SecurityDocumentationIT extends ESRestHighLevelClientTestCase {
List roles = response.getRoles();
assertNotNull(response);
// 29 system roles plus the three we created
- assertThat(roles.size(), equalTo(32));
+ assertThat(roles.size(), equalTo(33));
}
{
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/enrich/ExecutePolicyResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/enrich/ExecutePolicyResponseTests.java
new file mode 100644
index 00000000000..cb7bdd51056
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/enrich/ExecutePolicyResponseTests.java
@@ -0,0 +1,61 @@
+/*
+ * 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.enrich;
+
+import org.elasticsearch.client.AbstractResponseTestCase;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.tasks.TaskId;
+import org.elasticsearch.xpack.core.enrich.action.ExecuteEnrichPolicyAction;
+import org.elasticsearch.xpack.core.enrich.action.ExecuteEnrichPolicyStatus;
+
+import java.io.IOException;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.nullValue;
+
+public class ExecutePolicyResponseTests extends AbstractResponseTestCase {
+
+ @Override
+ protected ExecuteEnrichPolicyAction.Response createServerTestInstance(XContentType xContentType) {
+ if (randomBoolean()) {
+ return new ExecuteEnrichPolicyAction.Response(new ExecuteEnrichPolicyStatus(randomAlphaOfLength(4)));
+ } else {
+ return new ExecuteEnrichPolicyAction.Response(new TaskId(randomAlphaOfLength(4), randomNonNegativeLong()));
+ }
+ }
+
+ @Override
+ protected ExecutePolicyResponse doParseToClientInstance(XContentParser parser) throws IOException {
+ return ExecutePolicyResponse.fromXContent(parser);
+ }
+
+ @Override
+ protected void assertInstances(ExecuteEnrichPolicyAction.Response serverTestInstance, ExecutePolicyResponse clientInstance) {
+ if (serverTestInstance.getStatus() != null) {
+ assertThat(clientInstance.getExecutionStatus().getPhase(), equalTo(serverTestInstance.getStatus().getPhase()));
+ assertThat(clientInstance.getTaskId(), nullValue());
+ } else if (serverTestInstance.getTaskId() != null) {
+ assertThat(clientInstance.getTaskId(), equalTo(clientInstance.getTaskId()));
+ assertThat(clientInstance.getExecutionStatus(), nullValue());
+ } else {
+ assert false;
+ }
+ }
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/enrich/GetPolicyResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/enrich/GetPolicyResponseTests.java
new file mode 100644
index 00000000000..fc0cfb73339
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/enrich/GetPolicyResponseTests.java
@@ -0,0 +1,95 @@
+/*
+ * 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.enrich;
+
+import org.elasticsearch.client.AbstractResponseTestCase;
+import org.elasticsearch.common.bytes.BytesArray;
+import org.elasticsearch.common.bytes.BytesReference;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.xpack.core.enrich.EnrichPolicy;
+import org.elasticsearch.xpack.core.enrich.action.GetEnrichPolicyAction;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.nullValue;
+
+public class GetPolicyResponseTests extends AbstractResponseTestCase {
+
+ @Override
+ protected GetEnrichPolicyAction.Response createServerTestInstance(XContentType xContentType) {
+ int numPolicies = randomIntBetween(0, 8);
+ Map policies = new HashMap<>(numPolicies);
+ for (int i = 0; i < numPolicies; i++) {
+ policies.put(randomAlphaOfLength(4), createRandomEnrichPolicy(xContentType));
+ }
+ return new GetEnrichPolicyAction.Response(policies);
+ }
+
+ @Override
+ protected GetPolicyResponse doParseToClientInstance(XContentParser parser) throws IOException {
+ return GetPolicyResponse.fromXContent(parser);
+ }
+
+ @Override
+ protected void assertInstances(GetEnrichPolicyAction.Response serverTestInstance, GetPolicyResponse clientInstance) {
+ assertThat(clientInstance.getPolicies().size(), equalTo(serverTestInstance.getPolicies().size()));
+ for (int i = 0; i < clientInstance.getPolicies().size(); i++) {
+ assertThat(clientInstance.getPolicies().get(i).getType(),
+ equalTo(serverTestInstance.getPolicies().get(i).getPolicy().getType()));
+ assertThat(clientInstance.getPolicies().get(i).getName(),
+ equalTo(serverTestInstance.getPolicies().get(i).getName()));
+ assertThat(clientInstance.getPolicies().get(i).getIndices(),
+ equalTo(serverTestInstance.getPolicies().get(i).getPolicy().getIndices()));
+ if (clientInstance.getPolicies().get(i).getQuery() != null) {
+ assertThat(clientInstance.getPolicies().get(i).getQuery(),
+ equalTo(serverTestInstance.getPolicies().get(i).getPolicy().getQuery().getQuery()));
+ } else {
+ assertThat(serverTestInstance.getPolicies().get(i).getPolicy().getQuery(), nullValue());
+ }
+ assertThat(clientInstance.getPolicies().get(i).getMatchField(),
+ equalTo(serverTestInstance.getPolicies().get(i).getPolicy().getMatchField()));
+ assertThat(clientInstance.getPolicies().get(i).getEnrichFields(),
+ equalTo(serverTestInstance.getPolicies().get(i).getPolicy().getEnrichFields()));
+ }
+ }
+
+ private static EnrichPolicy createRandomEnrichPolicy(XContentType xContentType){
+ try (XContentBuilder builder = XContentBuilder.builder(xContentType.xContent())) {
+ builder.startObject();
+ builder.endObject();
+ BytesReference querySource = BytesArray.bytes(builder);
+ return new EnrichPolicy(
+ randomAlphaOfLength(4),
+ randomBoolean() ? new EnrichPolicy.QuerySource(querySource, xContentType) : null,
+ Arrays.asList(generateRandomStringArray(8, 4, false, false)),
+ randomAlphaOfLength(4),
+ Arrays.asList(generateRandomStringArray(8, 4, false, false))
+ );
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/enrich/PutPolicyRequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/enrich/PutPolicyRequestTests.java
new file mode 100644
index 00000000000..a0138949490
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/enrich/PutPolicyRequestTests.java
@@ -0,0 +1,105 @@
+/*
+ * 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.enrich;
+
+import org.elasticsearch.client.AbstractRequestTestCase;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.index.query.MatchAllQueryBuilder;
+import org.elasticsearch.test.EqualsHashCodeTestUtils;
+import org.elasticsearch.xpack.core.enrich.action.PutEnrichPolicyAction;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.Arrays;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
+
+public class PutPolicyRequestTests extends AbstractRequestTestCase {
+
+ public void testValidate() {
+ PutPolicyRequest request = createClientTestInstance();
+ assertThat(request.validate().isPresent(), is(false));
+
+ Exception e = expectThrows(IllegalArgumentException.class,
+ () -> new PutPolicyRequest(request.getName(), request.getType(), request.getIndices(), null, request.getEnrichFields()));
+ assertThat(e.getMessage(), containsString("matchField must be a non-null and non-empty string"));
+ }
+
+ public void testEqualsAndHashcode() {
+ PutPolicyRequest testInstance = createTestInstance();
+ EqualsHashCodeTestUtils.checkEqualsAndHashCode(testInstance, (original) -> {
+ PutPolicyRequest copy = new PutPolicyRequest(original.getName(), original.getType(), original.getIndices(),
+ original.getMatchField(), original.getEnrichFields());
+ copy.setQuery(original.getQuery());
+ return copy;
+ });
+ }
+
+ @Override
+ protected PutPolicyRequest createClientTestInstance() {
+ return createTestInstance("name");
+ }
+
+ public static PutPolicyRequest createTestInstance() {
+ return createTestInstance(randomAlphaOfLength(4));
+ }
+
+ public static PutPolicyRequest createTestInstance(String name) {
+ PutPolicyRequest testInstance = new PutPolicyRequest(
+ name,
+ randomAlphaOfLength(4),
+ Arrays.asList(generateRandomStringArray(4, 4, false, false)),
+ randomAlphaOfLength(4),
+ Arrays.asList(generateRandomStringArray(4, 4, false, false))
+ );
+ if (randomBoolean()) {
+ try {
+ testInstance.setQuery(new MatchAllQueryBuilder());
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+ return testInstance;
+ }
+
+ @Override
+ protected PutEnrichPolicyAction.Request doParseToServerInstance(XContentParser parser) throws IOException {
+ return PutEnrichPolicyAction.fromXContent(parser, "name");
+ }
+
+ @Override
+ protected void assertInstances(PutEnrichPolicyAction.Request serverInstance, PutPolicyRequest clientTestInstance) {
+ assertThat(clientTestInstance.getName(), equalTo(serverInstance.getName()));
+ assertThat(clientTestInstance.getType(), equalTo(serverInstance.getPolicy().getType()));
+ assertThat(clientTestInstance.getIndices(), equalTo(serverInstance.getPolicy().getIndices()));
+ if (clientTestInstance.getQuery() != null) {
+ XContentType type = serverInstance.getPolicy().getQuery().getContentType();
+ assertThat(PutPolicyRequest.asMap(clientTestInstance.getQuery(), type),
+ equalTo(PutPolicyRequest.asMap(serverInstance.getPolicy().getQuery().getQuery(), type)));
+ } else {
+ assertThat(serverInstance.getPolicy().getQuery(), nullValue());
+ }
+ assertThat(clientTestInstance.getMatchField(), equalTo(serverInstance.getPolicy().getMatchField()));
+ assertThat(clientTestInstance.getEnrichFields(), equalTo(serverInstance.getPolicy().getEnrichFields()));
+ }
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/enrich/StatsResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/enrich/StatsResponseTests.java
new file mode 100644
index 00000000000..aac22348abb
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/enrich/StatsResponseTests.java
@@ -0,0 +1,98 @@
+/*
+ * 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.enrich;
+
+import org.elasticsearch.client.AbstractResponseTestCase;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.tasks.TaskId;
+import org.elasticsearch.tasks.TaskInfo;
+import org.elasticsearch.xpack.core.enrich.action.EnrichStatsAction;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static org.hamcrest.Matchers.equalTo;
+
+public class StatsResponseTests extends AbstractResponseTestCase {
+
+ @Override
+ protected EnrichStatsAction.Response createServerTestInstance(XContentType xContentType) {
+ int numExecutingPolicies = randomIntBetween(0, 16);
+ List executingPolicies = new ArrayList<>(numExecutingPolicies);
+ for (int i = 0; i < numExecutingPolicies; i++) {
+ TaskInfo taskInfo = randomTaskInfo();
+ executingPolicies.add(new EnrichStatsAction.Response.ExecutingPolicy(randomAlphaOfLength(4), taskInfo));
+ }
+ int numCoordinatingStats = randomIntBetween(0, 16);
+ List coordinatorStats = new ArrayList<>(numCoordinatingStats);
+ for (int i = 0; i < numCoordinatingStats; i++) {
+ EnrichStatsAction.Response.CoordinatorStats stats = new EnrichStatsAction.Response.CoordinatorStats(
+ randomAlphaOfLength(4), randomIntBetween(0, 8096), randomIntBetween(0, 8096), randomNonNegativeLong(),
+ randomNonNegativeLong());
+ coordinatorStats.add(stats);
+ }
+ return new EnrichStatsAction.Response(executingPolicies, coordinatorStats);
+ }
+
+ @Override
+ protected StatsResponse doParseToClientInstance(XContentParser parser) throws IOException {
+ return StatsResponse.fromXContent(parser);
+ }
+
+ @Override
+ protected void assertInstances(EnrichStatsAction.Response serverTestInstance, StatsResponse clientInstance) {
+ assertThat(clientInstance.getExecutingPolicies().size(), equalTo(serverTestInstance.getExecutingPolicies().size()));
+ for (int i = 0; i < clientInstance.getExecutingPolicies().size(); i++) {
+ StatsResponse.ExecutingPolicy actual = clientInstance.getExecutingPolicies().get(i);
+ EnrichStatsAction.Response.ExecutingPolicy expected = serverTestInstance.getExecutingPolicies().get(i);
+ assertThat(actual.getName(), equalTo(expected.getName()));
+ assertThat(actual.getTaskInfo(), equalTo(actual.getTaskInfo()));
+ }
+
+ assertThat(clientInstance.getCoordinatorStats().size(), equalTo(serverTestInstance.getCoordinatorStats().size()));
+ for (int i = 0; i < clientInstance.getCoordinatorStats().size(); i++) {
+ StatsResponse.CoordinatorStats actual = clientInstance.getCoordinatorStats().get(i);
+ EnrichStatsAction.Response.CoordinatorStats expected = serverTestInstance.getCoordinatorStats().get(i);
+ assertThat(actual.getNodeId(), equalTo(expected.getNodeId()));
+ assertThat(actual.getQueueSize(), equalTo(expected.getQueueSize()));
+ assertThat(actual.getRemoteRequestsCurrent(), equalTo(expected.getRemoteRequestsCurrent()));
+ assertThat(actual.getRemoteRequestsTotal(), equalTo(expected.getRemoteRequestsTotal()));
+ assertThat(actual.getExecutedSearchesTotal(), equalTo(expected.getExecutedSearchesTotal()));
+ }
+ }
+
+ private static TaskInfo randomTaskInfo() {
+ TaskId taskId = new TaskId(randomAlphaOfLength(5), randomLong());
+ String type = randomAlphaOfLength(5);
+ String action = randomAlphaOfLength(5);
+ String description = randomAlphaOfLength(5);
+ long startTime = randomLong();
+ long runningTimeNanos = randomLong();
+ boolean cancellable = randomBoolean();
+ TaskId parentTaskId = TaskId.EMPTY_TASK_ID;
+ Map headers = randomBoolean() ?
+ Collections.emptyMap() :
+ Collections.singletonMap(randomAlphaOfLength(5), randomAlphaOfLength(5));
+ return new TaskInfo(taskId, type, action, description, null, startTime, runningTimeNanos, cancellable, parentTaskId, headers);
+ }
+}
diff --git a/docs/java-rest/high-level/enrich/delete_policy.asciidoc b/docs/java-rest/high-level/enrich/delete_policy.asciidoc
new file mode 100644
index 00000000000..9bee686cce0
--- /dev/null
+++ b/docs/java-rest/high-level/enrich/delete_policy.asciidoc
@@ -0,0 +1,31 @@
+--
+:api: enrich-delete-policy
+:request: DeletePolicyRequest
+:response: AcknowledgedResponse
+--
+
+[id="{upid}-{api}"]
+=== Delete Policy API
+
+[id="{upid}-{api}-request"]
+==== Request
+
+The Delete Policy API deletes an enrich policy from Elasticsearch.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-request]
+--------------------------------------------------
+
+[id="{upid}-{api}-response"]
+==== Response
+
+The returned +{response}+ indicates if the delete policy request was acknowledged.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-response]
+--------------------------------------------------
+<1> Whether delete policy request was acknowledged.
+
+include::../execution.asciidoc[]
diff --git a/docs/java-rest/high-level/enrich/execute_policy.asciidoc b/docs/java-rest/high-level/enrich/execute_policy.asciidoc
new file mode 100644
index 00000000000..59594f1b741
--- /dev/null
+++ b/docs/java-rest/high-level/enrich/execute_policy.asciidoc
@@ -0,0 +1,30 @@
+--
+:api: enrich-execute-policy
+:request: ExecutePolicyRequest
+:response: ExecutePolicyResponse
+--
+
+[id="{upid}-{api}"]
+=== Execute Policy API
+
+[id="{upid}-{api}-request"]
+==== Request
+
+The Execute Policy API allows to execute an enrich policy by name.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-request]
+--------------------------------------------------
+
+[id="{upid}-{api}-response"]
+==== Response
+
+The returned +{response}+ includes either the status or task id.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-response]
+--------------------------------------------------
+
+include::../execution.asciidoc[]
diff --git a/docs/java-rest/high-level/enrich/get_policy.asciidoc b/docs/java-rest/high-level/enrich/get_policy.asciidoc
new file mode 100644
index 00000000000..401a78ccca6
--- /dev/null
+++ b/docs/java-rest/high-level/enrich/get_policy.asciidoc
@@ -0,0 +1,32 @@
+--
+:api: enrich-get-policy
+:request: GetPolicyRequest
+:response: GetPolicyResponse
+--
+
+[id="{upid}-{api}"]
+=== Get Policy API
+
+[id="{upid}-{api}-request"]
+==== Request
+
+The Get Policy API allows to retrieve enrich policies by name
+or all policies if no name is provided.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-request]
+--------------------------------------------------
+
+[id="{upid}-{api}-response"]
+==== Response
+
+The returned +{response}+ includes the requested enrich policy.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-response]
+--------------------------------------------------
+<1> The actual enrich policy.
+
+include::../execution.asciidoc[]
diff --git a/docs/java-rest/high-level/enrich/put_policy.asciidoc b/docs/java-rest/high-level/enrich/put_policy.asciidoc
new file mode 100644
index 00000000000..b8e9475bed1
--- /dev/null
+++ b/docs/java-rest/high-level/enrich/put_policy.asciidoc
@@ -0,0 +1,31 @@
+--
+:api: enrich-put-policy
+:request: PutPolicyRequest
+:response: AcknowledgedResponse
+--
+
+[id="{upid}-{api}"]
+=== Put Policy API
+
+[id="{upid}-{api}-request"]
+==== Request
+
+The Put Policy API stores an enrich policy in Elasticsearch.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-request]
+--------------------------------------------------
+
+[id="{upid}-{api}-response"]
+==== Response
+
+The returned +{response}+ indicates if the put policy request was acknowledged.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-response]
+--------------------------------------------------
+<1> Whether put policy request was acknowledged.
+
+include::../execution.asciidoc[]
diff --git a/docs/java-rest/high-level/enrich/stats.asciidoc b/docs/java-rest/high-level/enrich/stats.asciidoc
new file mode 100644
index 00000000000..1d4ae50238a
--- /dev/null
+++ b/docs/java-rest/high-level/enrich/stats.asciidoc
@@ -0,0 +1,33 @@
+--
+:api: enrich-stats
+:request: StatsRequest
+:response: StatsResponse
+--
+
+[id="{upid}-{api}"]
+=== Stats API
+
+[id="{upid}-{api}-request"]
+==== Request
+
+The stats API returns enrich related stats.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-request]
+--------------------------------------------------
+
+[id="{upid}-{api}-response"]
+==== Response
+
+The returned +{response}+ includes enrich related stats.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-response]
+--------------------------------------------------
+<1> List of policies that are currently executing with
+ additional details.
+<2> List of coordinator stats per ingest node.
+
+include::../execution.asciidoc[]
diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc
index a6975a97326..9cf1930b387 100644
--- a/docs/java-rest/high-level/supported-apis.asciidoc
+++ b/docs/java-rest/high-level/supported-apis.asciidoc
@@ -635,3 +635,22 @@ include::transform/delete_transform.asciidoc[]
include::transform/preview_transform.asciidoc[]
include::transform/start_transform.asciidoc[]
include::transform/stop_transform.asciidoc[]
+
+== Enrich APIs
+
+:upid: {mainid}-enrich
+:doc-tests-file: {doc-tests}/EnrichDocumentationIT.java
+
+The Java High Level REST Client supports the following Enrich APIs:
+
+* <<{upid}-enrich-put-policy>>
+* <<{upid}-enrich-delete-policy>>
+* <<{upid}-enrich-get-policy>>
+* <<{upid}-enrich-stats>>
+* <<{upid}-enrich-execute-policy>>
+
+include::enrich/put_policy.asciidoc[]
+include::enrich/delete_policy.asciidoc[]
+include::enrich/get_policy.asciidoc[]
+include::enrich/stats.asciidoc[]
+include::enrich/execute_policy.asciidoc[]
diff --git a/docs/reference/ingest/apis/enrich/delete-enrich-policy.asciidoc b/docs/reference/ingest/apis/enrich/delete-enrich-policy.asciidoc
new file mode 100644
index 00000000000..f0ebd40ff41
--- /dev/null
+++ b/docs/reference/ingest/apis/enrich/delete-enrich-policy.asciidoc
@@ -0,0 +1,67 @@
+[role="xpack"]
+[testenv="basic"]
+[[delete-enrich-policy-api]]
+=== Delete enrich policy API
+++++
+Delete enrich policy
+++++
+
+Deletes an existing enrich policy and its enrich index.
+
+////
+[source,console]
+----
+PUT /users
+
+PUT /_enrich/policy/my-policy
+{
+ "match": {
+ "indices": "users",
+ "match_field": "email",
+ "enrich_fields": ["first_name", "last_name", "city", "zip", "state"]
+ }
+}
+----
+// TESTSETUP
+////
+
+[source,console]
+--------------------------------------------------
+DELETE /_enrich/policy/my-policy
+--------------------------------------------------
+
+
+[[delete-enrich-policy-api-request]]
+==== {api-request-title}
+
+`DELETE /_enrich/policy/`
+
+
+[[delete-enrich-policy-api-prereqs]]
+==== {api-prereq-title}
+
+include::put-enrich-policy.asciidoc[tag=enrich-policy-api-prereqs]
+
+
+[[delete-enrich-policy-api-desc]]
+==== {api-description-title}
+
+Use the delete enrich policy API
+to delete an existing enrich policy
+and its enrich index.
+
+[IMPORTANT]
+====
+You must remove an enrich policy
+from any in-use ingest pipelines
+before deletion.
+You cannot remove in-use enrich policies.
+====
+
+
+[[delete-enrich-policy-api-path-params]]
+==== {api-path-parms-title}
+
+``::
+(Required, string)
+Enrich policy to delete.
diff --git a/docs/reference/ingest/apis/enrich/enrich-stats.asciidoc b/docs/reference/ingest/apis/enrich/enrich-stats.asciidoc
new file mode 100644
index 00000000000..550374abd54
--- /dev/null
+++ b/docs/reference/ingest/apis/enrich/enrich-stats.asciidoc
@@ -0,0 +1,135 @@
+[role="xpack"]
+[testenv="basic"]
+[[enrich-stats-api]]
+=== Enrich stats API
+++++
+Enrich stats
+++++
+
+Returns <> statistics
+and information about enrich policies
+that are currently executing.
+
+[source,console]
+----
+GET /_enrich/_stats
+----
+
+
+[[enrich-stats-api-request]]
+==== {api-request-title}
+
+`GET /_enrich/_stats`
+
+
+[[enrich-stats-api-response-body]]
+==== {api-response-body-title}
+
+`executing_policies`::
++
+--
+(Array of objects)
+Objects containing information
+about each enrich policy
+that is currently executing.
+
+Returned parameters include:
+
+`name`::
+(String)
+Name of the enrich policy.
+
+`task`::
+(<>)
+Object containing detailed information
+about the policy execution task.
+--
+
+`coordinator_stats`::
++
+--
+(Array of objects)
+Objects containing information
+about each <>
+for configured enrich processors.
+
+Returned parameters include:
+
+`node_id`::
+(String)
+ID of the ingest node coordinating search requests
+for configured enrich processors.
+
+`queue_size`::
+(Integer)
+Number of search requests in the queue.
+
+`remote_requests_current`::
+(Integer)
+Current number of outstanding remote requests.
+
+`remote_requests_total`::
+(Integer)
+Number of outstanding remote requests executed
+since node startup.
++
+In most cases,
+a remote request includes multiple search requests.
+This depends on the number of search requests in the queue
+when the remote request is executed.
+
+`executed_searches_total`::
+(Integer)
+Number of search requests
+that enrich processors have executed
+since node startup.
+--
+
+
+[[enrich-stats-api-example]]
+==== {api-examples-title}
+
+
+[source,console]
+----
+GET /_enrich/_stats
+----
+//TEST[s/^/PUT \/_enrich\/policy\/my-policy\/_execute\/n/\
+
+The API returns the following response:
+
+[source,console-result]
+----
+{
+ "executing_policies": [
+ {
+ "name": "my-policy",
+ "task": {
+ "id" : 124,
+ "type" : "direct",
+ "action" : "cluster:admin/xpack/enrich/execute",
+ "start_time_in_millis" : 1458585884904,
+ "running_time_in_nanos" : 47402,
+ "cancellable" : false,
+ "parent_task_id" : "oTUltX4IQMOUUVeiohTt8A:123",
+ "headers" : {
+ "X-Opaque-Id" : "123456"
+ }
+ },
+ }
+ ],
+ "coordinator_stats": [
+ {
+ "node_id": "1sFM8cmSROZYhPxVsiWew",
+ "queue_size": 0,
+ "remote_requests_current": 0,
+ "remote_requests_total": 0,
+ "executed_searches_total": 0
+ }
+ ]
+}
+----
+// TESTRESPONSE[s/"executing_policies": \[[^\]]*\]/"executing_policies": $body.$_path/]
+// TESTRESPONSE[s/"node_id": "1sFM8cmSROZYhPxVsiWew"/"node_id" : $body.coordinator_stats.0.node_id/]
+// TESTRESPONSE[s/"remote_requests_total": 0/"remote_requests_total" : $body.coordinator_stats.0.remote_requests_total/]
+// TESTRESPONSE[s/"executed_searches_total": 0/"executed_searches_total" : $body.coordinator_stats.0.executed_searches_total/]
diff --git a/docs/reference/ingest/apis/enrich/execute-enrich-policy.asciidoc b/docs/reference/ingest/apis/enrich/execute-enrich-policy.asciidoc
new file mode 100644
index 00000000000..f859c1201d9
--- /dev/null
+++ b/docs/reference/ingest/apis/enrich/execute-enrich-policy.asciidoc
@@ -0,0 +1,103 @@
+[role="xpack"]
+[testenv="basic"]
+[[execute-enrich-policy-api]]
+=== Execute enrich policy API
+++++
+Execute enrich policy
+++++
+
+Executes an existing enrich policy.
+
+////
+
+[source,console]
+----
+PUT /users/_doc/1?refresh
+{
+ "email": "mardy.brown@asciidocsmith.com",
+ "first_name": "Mardy",
+ "last_name": "Brown",
+ "city": "New Orleans",
+ "county": "Orleans",
+ "state": "LA",
+ "zip": 70116,
+ "web": "mardy.asciidocsmith.com"
+}
+
+PUT /_enrich/policy/my-policy
+{
+ "match": {
+ "indices": "users",
+ "match_field": "email",
+ "enrich_fields": ["first_name", "last_name", "city", "zip", "state"]
+ }
+}
+----
+// TESTSETUP
+////
+
+[source,console]
+--------------------------------------------------
+PUT /_enrich/policy/my-policy/_execute
+--------------------------------------------------
+
+////
+[source,console]
+--------------------------------------------------
+DELETE /_enrich/policy/my-policy
+--------------------------------------------------
+// TEST[continued]
+////
+
+
+[[execute-enrich-policy-api-request]]
+==== {api-request-title}
+
+`PUT /_enrich/policy//_execute`
+
+`POST /_enrich/policy//_execute`
+
+
+[[execute-enrich-policy-api-prereqs]]
+==== {api-prereq-title}
+
+include::put-enrich-policy.asciidoc[tag=enrich-policy-api-prereqs]
+
+
+[[execute-enrich-policy-api-desc]]
+==== {api-description-title}
+
+Use the execute enrich policy API
+to create the enrich index for an existing enrich policy.
+
+// tag::execute-enrich-policy-def[]
+The _enrich index_ contains documents from the policy's source indices.
+Enrich indices always begin with `.enrich-*`,
+are read-only,
+and are <>.
+
+[WARNING]
+====
+Enrich indices should be used by the <> only.
+Avoid using enrich indices for other purposes.
+====
+// end::execute-enrich-policy-def[]
+
+// tag::update-enrich-index[]
+Once created, you cannot update
+or index documents to an enrich index.
+Instead, update your source indices
+and execute the enrich policy again.
+This creates a new enrich index from your updated source indices
+and deletes the previous enrich index.
+// end::update-enrich-index[]
+
+Because this API request performs several operations,
+it may take a while to return a response.
+
+[[execute-enrich-policy-api-path-params]]
+==== {api-path-parms-title}
+
+``::
+(Required, string)
+Enrich policy to execute.
\ No newline at end of file
diff --git a/docs/reference/ingest/apis/enrich/get-enrich-policy.asciidoc b/docs/reference/ingest/apis/enrich/get-enrich-policy.asciidoc
new file mode 100644
index 00000000000..b3c0fe8f2ff
--- /dev/null
+++ b/docs/reference/ingest/apis/enrich/get-enrich-policy.asciidoc
@@ -0,0 +1,225 @@
+[role="xpack"]
+[testenv="basic"]
+[[get-enrich-policy-api]]
+=== Get enrich policy API
+++++
+Get enrich policy
+++++
+
+Returns information about an enrich policy.
+
+////
+[source,console]
+----
+PUT /users
+
+PUT /_enrich/policy/my-policy
+{
+ "match": {
+ "indices": "users",
+ "match_field": "email",
+ "enrich_fields": ["first_name", "last_name", "city", "zip", "state"]
+ }
+}
+
+PUT /_enrich/policy/other-policy
+{
+ "match": {
+ "indices": "users",
+ "match_field": "email",
+ "enrich_fields": ["first_name", "last_name", "city", "zip", "state"]
+ }
+}
+----
+////
+
+[source,console]
+--------------------------------------------------
+GET /_enrich/policy/my-policy
+--------------------------------------------------
+// TEST[continued]
+
+
+[[get-enrich-policy-api-request]]
+==== {api-request-title}
+
+`GET /_enrich/policy/`
+
+`GET /_enrich/policy`
+
+`GET /_enrich/policy1,policy2`
+
+
+[[get-enrich-policy-api-prereqs]]
+==== {api-prereq-title}
+
+include::put-enrich-policy.asciidoc[tag=enrich-policy-api-prereqs]
+
+
+[[get-enrich-policy-api-path-params]]
+==== {api-path-parms-title}
+
+``::
++
+--
+(Optional, string)
+Comma-separated list of enrich policy names
+used to limit the request.
+
+To return information for all enrich policies,
+omit this parameter.
+--
+
+
+[[get-enrich-policy-api-example]]
+==== {api-examples-title}
+
+
+[[get-enrich-policy-api-single-ex]]
+===== Get a single policy
+
+[source,console]
+--------------------------------------------------
+GET /_enrich/policy/my-policy
+--------------------------------------------------
+// TEST[continued]
+
+The API returns the following response:
+
+[source,console-result]
+--------------------------------------------------
+{
+ "policies": [
+ {
+ "config": {
+ "match": {
+ "name" : "my-policy",
+ "indices" : ["users"],
+ "match_field" : "email",
+ "enrich_fields" : [
+ "first_name",
+ "last_name",
+ "city",
+ "zip",
+ "state"
+ ]
+ }
+ }
+ }
+ ]
+}
+--------------------------------------------------
+
+
+[[get-enrich-policy-api-commas-ex]]
+===== Get multiple policies
+
+[source,console]
+--------------------------------------------------
+GET /_enrich/policy/my-policy,other-policy
+--------------------------------------------------
+// TEST[continued]
+
+The API returns the following response:
+
+[source,js]
+--------------------------------------------------
+{
+ "policies": [
+ {
+ "config": {
+ "match": {
+ "name" : "my-policy",
+ "indices" : ["users"],
+ "match_field" : "email",
+ "enrich_fields" : [
+ "first_name",
+ "last_name",
+ "city",
+ "zip",
+ "state"
+ ]
+ }
+ }
+ },
+ {
+ "config": {
+ "match": {
+ "name" : "other-policy",
+ "indices" : ["users"],
+ "match_field" : "email",
+ "enrich_fields" : [
+ "first_name",
+ "last_name",
+ "city",
+ "zip",
+ "state"
+ ]
+ }
+ }
+ }
+ ]
+}
+--------------------------------------------------
+// TESTRESPONSE
+
+
+[[get-enrich-policy-api-all-ex]]
+===== Get all policies
+
+[source,console]
+--------------------------------------------------
+GET /_enrich/policy
+--------------------------------------------------
+// TEST[continued]
+
+The API returns the following response:
+
+[source,console-result]
+--------------------------------------------------
+{
+ "policies": [
+ {
+ "config": {
+ "match": {
+ "name" : "my-policy",
+ "indices" : ["users"],
+ "match_field" : "email",
+ "enrich_fields" : [
+ "first_name",
+ "last_name",
+ "city",
+ "zip",
+ "state"
+ ]
+ }
+ }
+ },
+ {
+ "config": {
+ "match": {
+ "name" : "other-policy",
+ "indices" : ["users"],
+ "match_field" : "email",
+ "enrich_fields" : [
+ "first_name",
+ "last_name",
+ "city",
+ "zip",
+ "state"
+ ]
+ }
+ }
+ }
+ ]
+}
+--------------------------------------------------
+
+////
+[source,console]
+--------------------------------------------------
+DELETE /_enrich/policy/my-policy
+DELETE /_enrich/policy/other-policy
+--------------------------------------------------
+// TEST[continued]
+////
diff --git a/docs/reference/ingest/apis/enrich/index.asciidoc b/docs/reference/ingest/apis/enrich/index.asciidoc
new file mode 100644
index 00000000000..bd24e73c059
--- /dev/null
+++ b/docs/reference/ingest/apis/enrich/index.asciidoc
@@ -0,0 +1,21 @@
+[[enrich-apis]]
+== Enrich APIs
+
+The following enrich APIs are available for managing enrich policies:
+
+* <> to add or update an enrich policy
+* <> to delete an enrich policy
+* <> to return information about an enrich policy
+* <> to execute an enrich policy
+* <> to get enrich-related stats
+
+
+include::put-enrich-policy.asciidoc[]
+
+include::delete-enrich-policy.asciidoc[]
+
+include::get-enrich-policy.asciidoc[]
+
+include::execute-enrich-policy.asciidoc[]
+
+include::enrich-stats.asciidoc[]
diff --git a/docs/reference/ingest/apis/enrich/put-enrich-policy.asciidoc b/docs/reference/ingest/apis/enrich/put-enrich-policy.asciidoc
new file mode 100644
index 00000000000..359d5db262d
--- /dev/null
+++ b/docs/reference/ingest/apis/enrich/put-enrich-policy.asciidoc
@@ -0,0 +1,349 @@
+[role="xpack"]
+[testenv="basic"]
+[[put-enrich-policy-api]]
+=== Put enrich policy API
+++++
+Put enrich policy
+++++
+
+Creates an enrich policy.
+
+////
+[source,console]
+----
+PUT /users
+----
+////
+
+[source,console]
+----
+PUT /_enrich/policy/my-policy
+{
+ "match": {
+ "indices": "users",
+ "match_field": "email",
+ "enrich_fields": ["first_name", "last_name", "city", "zip", "state"]
+ }
+}
+----
+// TEST[continued]
+
+////
+[source,console]
+--------------------------------------------------
+DELETE /_enrich/policy/my-policy
+--------------------------------------------------
+// TEST[continued]
+////
+
+
+[[put-enrich-policy-api-request]]
+==== {api-request-title}
+
+`PUT /_enrich/policy/`
+
+
+[[put-enrich-policy-api-prereqs]]
+==== {api-prereq-title}
+
+// tag::enrich-policy-api-prereqs[]
+If you use {es} {security-features}, you must have:
+
+* `read` index privileges for any indices used
+* The `enrich_user` {stack-ov}/built-in-roles.html[built-in role]
+// end::enrich-policy-api-prereqs[]
+
+
+[[put-enrich-policy-api-desc]]
+==== {api-description-title}
+
+Use the put enrich policy API
+to create a new enrich policy.
+
+// tag::enrich-policy-def[]
+An *enrich policy* is a set of rules the enrich processor uses
+to append the appropriate data to incoming documents.
+An enrich policy contains:
+
+* The *policy type*,
+ which determines how the processor enriches incoming documents
+* A list of source indices
+* The *match field* used to match incoming documents
+* *Enrich fields* appended to incoming documents
+ from matching documents
+// end::enrich-policy-def[]
+
+
+===== Update an enrich policy
+
+// tag::update-enrich-policy[]
+You cannot update an existing enrich policy.
+Instead, you can:
+
+. Create and execute a new enrich policy.
+
+. Replace the previous enrich policy
+ with the new enrich policy
+ in any in-use enrich processors.
+
+. Use the <> API
+ to delete the previous enrich policy.
+// end::update-enrich-policy[]
+
+
+[[put-enrich-policy-api-path-params]]
+==== {api-path-parms-title}
+
+``::
+(Required, string)
+include::{docdir}/rest-api/common-parms.asciidoc[tag=enrich-policy]
+
+
+[[put-enrich-policy-api-request-body]]
+==== {api-request-body-title}
+
+``::
++
+--
+(Required, enrich policy object)
+The parameter key is the enrich policy type.
+The enrich policy type indicates
+how the enrich processor matches incoming documents
+to documents in the enrich index.
+
+Valid key values are:
+
+`match`::
+Match documents in the enrich index
+using a <> for the `match_field`.
+See <> for an example.
+
+`geo_match`::
+Match documents in the enrich index
+using a <> for the `match_field`.
+See <> for an example.
+
+The parameter value is the enrich policy.
+The enrich policy is a set of rules
+used to create an <>.
+The enrich processor also uses these rules
+to append field data to incoming documents.
+
+Parameters include:
+
+`indices`::
+(Required, array of strings)
+Source indices used to create the enrich index.
+
+`query`::
+(Optional, string)
+Query type used to find and select documents in the enrich index.
+Valid value is <> (default).
+
+`match_field`::
+(Required, string)
+Field used to match incoming documents
+to documents in the enrich index.
+
+`enrich_fields`::
+(Required, Array of string)
+Fields appended to incoming documents
+from matching documents in the enrich index.
+--
+
+[[put-enrich-policy-api-example]]
+==== {api-examples-title}
+
+[[put-enrich-policy-geo-match-ex]]
+===== `geo_match` policy type
+
+You can use the `geo_match` enrich policy type
+to enrich incoming documents
+based on matching geo_shapes.
+For example,
+you can add postal codes
+to incoming documents
+based on a set of coordinates.
+
+To see how the `geo_match` policy type works,
+try the following example.
+
+Use the <>
+to create a source index.
+The field mappings for the source index
+must contain:
+
+* A <> field
+ which the enrich processor can use to match incoming documents
+* One or more enrich fields
+ you'd like to append to incoming documents
+
+[source,console]
+----
+PUT /postal_codes
+{
+ "mappings": {
+ "properties": {
+ "location": {
+ "type": "geo_shape"
+ },
+ "postal_code": {
+ "type": "keyword"
+ }
+ }
+ }
+}
+----
+
+Use the <>
+to index data to this source index.
+
+[source,console]
+----
+PUT /postal_codes/_doc/1?refresh=wait_for
+{
+ "location": {
+ "type": "envelope",
+ "coordinates": [[13.0, 53.0], [14.0, 52.0]]
+ },
+ "postal_code": "96598"
+}
+----
+// TEST[continued]
+
+Use the put enrich policy API
+to create an enrich policy
+with the `geo_match` policy type.
+This policy must include:
+
+* One or more source indices
+* A `match_field`,
+ the `geo_shape` field from the source indices
+ used to match incoming documents
+* Enrich fields from the source indices
+ you'd like to append to incoming documents
+
+[source,console]
+----
+PUT /_enrich/policy/postal_policy
+{
+ "geo_match": {
+ "indices": "postal_codes",
+ "match_field": "location",
+ "enrich_fields": ["location","postal_code"]
+ }
+}
+----
+// TEST[continued]
+
+Use the <>
+to create an enrich index for the policy.
+
+include::execute-enrich-policy.asciidoc[tag=execute-enrich-policy-def]
+
+[source,console]
+----
+POST /_enrich/policy/postal_policy/_execute
+----
+// TEST[continued]
+
+Use the <>
+to create an ingest pipeline.
+In the pipeline,
+add an <>
+that includes:
+
+* Your enrich policy
+* The `field` of incoming documents used
+ to match the geo_shape of documents from the enrich index.
+* The `target_field` used
+ to store appended enrich data for incoming documents.
+* The `shape_relation`,
+ which indicates how the processor matches geo_shapes in incoming documents
+ to geo_shapes in documents from the enrich index.
+ See <<_spatial_relations>> for valid options and more information.
+
+[source,console]
+----
+PUT /_ingest/pipeline/postal_lookup
+{
+ "description": "Enrich postal codes",
+ "processors": [
+ {
+ "enrich": {
+ "policy_name": "postal_policy",
+ "field": "geo_location",
+ "target_field": "geo_data",
+ "shape_relation": "INTERSECTS"
+ }
+ }
+ ]
+}
+----
+// TEST[continued]
+
+Use the ingest pipeline
+to index a document.
+The incoming document
+should include the `field`
+specified in your enrich processor.
+
+[source,console]
+----
+PUT /users/_doc/0?pipeline=postal_lookup
+{
+ "first_name": "Mardy",
+ "last_name": "Brown",
+ "geo_location": "POINT (13.5 52.5)"
+}
+----
+// TEST[continued]
+
+To verify the enrich processor matched
+and appended the appropriate field data,
+use the <>
+to view the indexed document.
+
+[source,console]
+----
+GET /users/_doc/0
+----
+// TEST[continued]
+
+The API returns the following response:
+
+[source,console-result]
+----
+{
+ "found": true,
+ "_index": "users",
+ "_type": "_doc",
+ "_id": "0",
+ "_version": 1,
+ "_seq_no": 55,
+ "_primary_term": 1,
+ "_source": {
+ "geo_data": {
+ "location": {
+ "type": "envelope",
+ "coordinates": [[13.0, 53.0], [14.0, 52.0]]
+ },
+ "postal_code": "96598"
+ },
+ "first_name": "Mardy",
+ "last_name": "Brown",
+ "geo_location": "POINT (13.5 52.5)"
+ }
+}
+----
+// TESTRESPONSE[s/"_seq_no": \d+/"_seq_no" : $body._seq_no/ s/"_primary_term":1/"_primary_term" : $body._primary_term/]
+
+////
+[source,console]
+--------------------------------------------------
+DELETE /_ingest/pipeline/postal_lookup
+
+DELETE /_enrich/policy/postal_policy
+--------------------------------------------------
+// TEST[continued]
+////
\ No newline at end of file
diff --git a/docs/reference/ingest/enrich.asciidoc b/docs/reference/ingest/enrich.asciidoc
new file mode 100644
index 00000000000..2054746ae6d
--- /dev/null
+++ b/docs/reference/ingest/enrich.asciidoc
@@ -0,0 +1,288 @@
+[role="xpack"]
+[testenv="basic"]
+[[ingest-enriching-data]]
+== Enrich your data
+
+You can use the <>
+to append data from existing indices
+to incoming documents during ingest.
+
+For example, you can use the enrich processor to:
+
+* Identify web services or vendors based on known IP addresses
+* Add product information to retail orders based on product IDs
+* Supplement contact information based on an email address
+* Add postal codes based on user coordinates
+
+
+[float]
+[[enrich-setup]]
+=== Set up an enrich processor
+
+To set up an enrich processor and learn how it works,
+follow these steps:
+
+. Check the <>.
+. <>.
+. <>.
+. <>.
+. <>.
+. <>.
+
+Once you have an enrich processor set up,
+you can <>
+and <>
+using the <>.
+
+[IMPORTANT]
+====
+The enrich processor performs several operations
+and may impact the speed of your <>.
+
+We strongly recommend testing and benchmarking your enrich processors
+before deploying them in production.
+
+We do not recommend using the enrich processor to append real-time data.
+The enrich processor works best with reference data
+that doesn't change frequently.
+====
+
+[float]
+[[enrich-prereqs]]
+==== Prerequisites
+
+include::{docdir}/ingest/apis/enrich/put-enrich-policy.asciidoc[tag=enrich-policy-api-prereqs]
+
+[float]
+[[create-enrich-source-index]]
+==== Create a source index
+
+To begin,
+create one or more source indices.
+
+A _source index_ contains data you want to append to incoming documents.
+You can index and manage documents in a source index
+like a regular index.
+
+The following <> request creates the `users` source index
+containing user data.
+This request also indexes a new document to the `users` source index.
+
+[source,console]
+----
+PUT /users/_doc/1?refresh=wait_for
+{
+ "email": "mardy.brown@asciidocsmith.com",
+ "first_name": "Mardy",
+ "last_name": "Brown",
+ "city": "New Orleans",
+ "county": "Orleans",
+ "state": "LA",
+ "zip": 70116,
+ "web": "mardy.asciidocsmith.com"
+}
+----
+
+You also can set up {beats-ref}/getting-started.html[{beats}],
+such as a {filebeat-ref}/filebeat-getting-started.html[{filebeat}],
+to automatically send and index documents
+to your source indices.
+See {beats-ref}/getting-started.html[Getting started with {beats}].
+
+
+[float]
+[[create-enrich-policy]]
+==== Create an enrich policy
+
+Use the <>
+to create an enrich policy.
+
+include::{docdir}/ingest/apis/enrich/put-enrich-policy.asciidoc[tag=enrich-policy-def]
+
+[source,console]
+----
+PUT /_enrich/policy/users-policy
+{
+ "match": {
+ "indices": "users",
+ "match_field": "email",
+ "enrich_fields": ["first_name", "last_name", "city", "zip", "state"]
+ }
+}
+----
+// TEST[continued]
+
+
+[float]
+[[execute-enrich-policy]]
+==== Execute an enrich policy
+
+Use the <>
+to create an enrich index for the policy.
+
+include::apis/enrich/execute-enrich-policy.asciidoc[tag=execute-enrich-policy-def]
+
+The following request executes the `users-policy` enrich policy.
+Because this API request performs several operations,
+it may take a while to return a response.
+
+[source,console]
+----
+POST /_enrich/policy/users-policy/_execute
+----
+// TEST[continued]
+
+
+[float]
+[[add-enrich-processor]]
+==== Add the enrich processor to an ingest pipeline
+
+Use the <>
+to create an ingest pipeline.
+Include an <>
+that uses your enrich policy.
+
+When defining an enrich processor,
+you must include the following:
+
+* The field used to match incoming documents
+ to documents in the enrich index.
++
+This field should be included in incoming documents.
+
+* The target field added to incoming documents.
+ This field contains all appended enrich data.
+
+The following request adds a new pipeline, `user_lookup`.
+This pipeline includes an enrich processor
+that uses the `users-policy` enrich policy.
+
+[source,console]
+----
+PUT /_ingest/pipeline/user_lookup
+{
+ "description" : "Enriching user details to messages",
+ "processors" : [
+ {
+ "enrich" : {
+ "policy_name": "users-policy",
+ "field" : "email",
+ "target_field": "user",
+ "max_matches": "1"
+ }
+ }
+ ]
+}
+----
+// TEST[continued]
+
+Because the enrich policy type is `match`,
+the enrich processor matches incoming documents
+to documents in the enrich index
+based on match field values.
+The enrich processor then appends the enrich field data
+from matching documents in the enrich index
+to the target field of incoming documents.
+
+Because the `max_matches` option for the enrich processor is `1`,
+the enrich processor appends the data from only the best matching document
+to each incoming document's target field as an object.
+
+If the `max_matches` option were greater than `1`,
+the processor could append data from up to the `max_matches` number of documents
+to the target field as an array.
+
+If the incoming document matches no documents in the enrich index,
+the processor appends no data.
+
+You also can add other <>
+to your ingest pipeline.
+You can use these processors to change or drop incoming documents
+based on your criteria.
+See <> for a list of built-in processors.
+
+
+[float]
+[[ingest-enrich-docs]]
+==== Ingest and enrich documents
+
+Index incoming documents using your ingest pipeline.
+
+The following <> request uses the ingest pipeline
+to index a document
+containing the `email` field
+specified in the enrich processor.
+
+[source,console]
+----
+PUT /my_index/_doc/my_id?pipeline=user_lookup
+{
+ "email": "mardy.brown@asciidocsmith.com"
+}
+----
+// TEST[continued]
+
+To verify the enrich processor matched
+and appended the appropriate field data,
+use the <> to view the indexed document.
+
+[source,console]
+----
+GET /my_index/_doc/my_id
+----
+// TEST[continued]
+
+The API returns the following response:
+
+[source,console-result]
+----
+{
+ "found": true,
+ "_index": "my_index",
+ "_type": "_doc",
+ "_id": "my_id",
+ "_version": 1,
+ "_seq_no": 55,
+ "_primary_term": 1,
+ "_source": {
+ "user": {
+ "email": "mardy.brown@asciidocsmith.com",
+ "first_name": "Mardy",
+ "last_name": "Brown",
+ "zip": 70116,
+ "city": "New Orleans",
+ "state": "LA"
+ },
+ "email": "mardy.brown@asciidocsmith.com"
+ }
+}
+----
+// TESTRESPONSE[s/"_seq_no": \d+/"_seq_no" : $body._seq_no/ s/"_primary_term":1/"_primary_term" : $body._primary_term/]
+
+
+[float]
+[[update-enrich-data]]
+=== Update your enrich index
+
+include::{docdir}/ingest/apis/enrich/execute-enrich-policy.asciidoc[tag=update-enrich-index]
+
+If wanted, you can <>
+or <> any already ingested documents
+using your ingest pipeline.
+
+
+[float]
+[[update-enrich-policies]]
+=== Update an enrich policy
+
+include::apis/enrich/put-enrich-policy.asciidoc[tag=update-enrich-policy]
+
+////
+[source,console]
+--------------------------------------------------
+DELETE /_ingest/pipeline/user_lookup
+
+DELETE /_enrich/policy/users-policy
+--------------------------------------------------
+// TEST[continued]
+////
diff --git a/docs/reference/ingest/ingest-node.asciidoc b/docs/reference/ingest/ingest-node.asciidoc
index e9813f44f53..e1b349b84bd 100644
--- a/docs/reference/ingest/ingest-node.asciidoc
+++ b/docs/reference/ingest/ingest-node.asciidoc
@@ -753,6 +753,10 @@ metadata field to provide the error message.
--------------------------------------------------
// NOTCONSOLE
+
+include::enrich.asciidoc[]
+
+
[[ingest-processors]]
== Processors
@@ -829,6 +833,7 @@ include::processors/date-index-name.asciidoc[]
include::processors/dissect.asciidoc[]
include::processors/dot-expand.asciidoc[]
include::processors/drop.asciidoc[]
+include::processors/enrich.asciidoc[]
include::processors/fail.asciidoc[]
include::processors/foreach.asciidoc[]
include::processors/geoip.asciidoc[]
diff --git a/docs/reference/ingest/processors/enrich.asciidoc b/docs/reference/ingest/processors/enrich.asciidoc
new file mode 100644
index 00000000000..b02d4569dbb
--- /dev/null
+++ b/docs/reference/ingest/processors/enrich.asciidoc
@@ -0,0 +1,24 @@
+[role="xpack"]
+[testenv="basic"]
+[[enrich-processor]]
+=== Enrich Processor
+
+The `enrich` processor can enrich documents with data from another index.
+See <> section for more information how to set this up and
+check out the <> to get familiar with enrich policies and related APIs.
+
+[[enrich-options]]
+.Enrich Options
+[options="header"]
+|======
+| Name | Required | Default | Description
+| `policy_name` | yes | - | The name of the enrich policy to use.
+| `field` | yes | - | The field in the input document that matches the policies match_field used to retrieve the enrichment data.
+| `target_field` | yes | - | The field that will be used for the enrichment data.
+| `ignore_missing` | no | false | If `true` and `field` does not exist, the processor quietly exits without modifying the document
+| `override` | no | true | If processor will update fields with pre-existing non-null-valued field. When set to `false`, such fields will not be touched.
+| `max_matches` | no | 1 | The maximum number of matched documents to include under the configured target field. The `target_field` will be turned into a json array if `max_matches` is higher than 1, otherwise `target_field` will become a json object. In order to avoid documents getting too large, the maximum allowed value is 128.
+| `shape_relation` | no | `INTERSECTS` | A spatial relation operator used to match the <> of incoming documents to documents in the enrich index. This option is only used for `geo_match` enrich policy types. The <> mapping parameter determines which spatial relation operators are available. See <<_spatial_relations>> for operators and more information.
+
+include::common-options.asciidoc[]
+|======
diff --git a/docs/reference/rest-api/common-parms.asciidoc b/docs/reference/rest-api/common-parms.asciidoc
index 3a021b7e1ee..e5301f99715 100644
--- a/docs/reference/rest-api/common-parms.asciidoc
+++ b/docs/reference/rest-api/common-parms.asciidoc
@@ -77,7 +77,7 @@ tag::committed[]
If `true`,
the segments is synced to disk. Segments that are synced can survive a hard reboot.
+
-If `false`,
+If `false`,
the data from uncommitted segments is also stored in
the transaction log so that Elasticsearch is able to replay
changes on the next start.
@@ -122,6 +122,11 @@ is based on Lucene documents. {es} reclaims the disk space of deleted Lucene
documents when a segment is merged.
end::docs-deleted[]
+tag::enrich-policy[]
+Enrich policy name
+used to limit the request.
+end::enrich-policy[]
+
tag::expand-wildcards[]
`expand_wildcards`::
+
@@ -279,8 +284,8 @@ end::include-defaults[]
tag::include-segment-file-sizes[]
`include_segment_file_sizes`::
(Optional, boolean)
-If `true`, the call reports the aggregated disk usage of
-each one of the Lucene index files (only applies if segment stats are
+If `true`, the call reports the aggregated disk usage of
+each one of the Lucene index files (only applies if segment stats are
requested). Defaults to `false`.
end::include-segment-file-sizes[]
@@ -504,7 +509,7 @@ end::positions[]
tag::preference[]
`preference`::
-(Optional, string) Specifies the node or shard the operation should be
+(Optional, string) Specifies the node or shard the operation should be
performed on. Random by default.
end::preference[]
@@ -652,7 +657,7 @@ end::source_includes[]
tag::stats[]
`stats`::
-(Optional, string) Specific `tag` of the request for logging and statistical
+(Optional, string) Specific `tag` of the request for logging and statistical
purposes.
end::stats[]
diff --git a/docs/reference/rest-api/index.asciidoc b/docs/reference/rest-api/index.asciidoc
index c6a36b8e2ea..7250f146608 100644
--- a/docs/reference/rest-api/index.asciidoc
+++ b/docs/reference/rest-api/index.asciidoc
@@ -15,6 +15,7 @@ not be included yet.
* <>
* <>
* <>
+* <>
* <>
* <>
* <>
@@ -38,6 +39,7 @@ include::{es-repo-dir}/cat.asciidoc[]
include::{es-repo-dir}/cluster.asciidoc[]
include::{es-repo-dir}/ccr/apis/ccr-apis.asciidoc[]
include::{es-repo-dir}/docs.asciidoc[]
+include::{es-repo-dir}/ingest/apis/enrich/index.asciidoc[]
include::{es-repo-dir}/graph/explore.asciidoc[]
include::{es-repo-dir}/indices.asciidoc[]
include::{es-repo-dir}/ilm/apis/ilm-api.asciidoc[]
diff --git a/server/src/main/java/org/elasticsearch/action/ingest/SimulateExecutionService.java b/server/src/main/java/org/elasticsearch/action/ingest/SimulateExecutionService.java
index 070e99cc5c7..966190ee0ad 100644
--- a/server/src/main/java/org/elasticsearch/action/ingest/SimulateExecutionService.java
+++ b/server/src/main/java/org/elasticsearch/action/ingest/SimulateExecutionService.java
@@ -74,7 +74,7 @@ class SimulateExecutionService {
responses.add(response);
}
if (counter.incrementAndGet() == request.getDocuments().size()) {
- l.onResponse(new SimulatePipelineResponse(request.getPipeline().getId(),
+ listener.onResponse(new SimulatePipelineResponse(request.getPipeline().getId(),
request.isVerbose(), responses));
}
});
diff --git a/server/src/main/java/org/elasticsearch/action/search/MultiSearchResponse.java b/server/src/main/java/org/elasticsearch/action/search/MultiSearchResponse.java
index 971dede5b7f..cca8afd8c09 100644
--- a/server/src/main/java/org/elasticsearch/action/search/MultiSearchResponse.java
+++ b/server/src/main/java/org/elasticsearch/action/search/MultiSearchResponse.java
@@ -121,7 +121,7 @@ public class MultiSearchResponse extends ActionResponse implements Iterable
+ * This is available in for all license types except
+ * {@link OperationMode#MISSING}
+ *
+ * @return {@code true} as long as the license is valid. Otherwise
+ * {@code false}.
+ */
+ public boolean isEnrichAllowed() {
+ // status is volatile
+ Status localStatus = status;
+ // Should work on all active licenses
+ return localStatus.active;
+ }
+
/**
* Determine if SQL support should be enabled.
*
diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClient.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClient.java
index 41121878111..439abc808cb 100644
--- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClient.java
+++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClient.java
@@ -17,6 +17,7 @@ import org.elasticsearch.protocol.xpack.frozen.FreezeResponse;
import org.elasticsearch.xpack.core.action.XPackInfoAction;
import org.elasticsearch.xpack.core.action.XPackInfoRequestBuilder;
import org.elasticsearch.xpack.core.ccr.client.CcrClient;
+import org.elasticsearch.xpack.core.enrich.client.EnrichClient;
import org.elasticsearch.xpack.core.frozen.action.FreezeIndexAction;
import org.elasticsearch.xpack.core.ilm.client.ILMClient;
import org.elasticsearch.xpack.core.ml.client.MachineLearningClient;
@@ -43,6 +44,7 @@ public class XPackClient {
private final WatcherClient watcherClient;
private final MachineLearningClient machineLearning;
private final ILMClient ilmClient;
+ private final EnrichClient enrichClient;
public XPackClient(Client client) {
this.client = Objects.requireNonNull(client, "client");
@@ -53,6 +55,7 @@ public class XPackClient {
this.watcherClient = new WatcherClient(client);
this.machineLearning = new MachineLearningClient(client);
this.ilmClient = new ILMClient(client);
+ this.enrichClient = new EnrichClient(client);
}
public Client es() {
@@ -87,6 +90,10 @@ public class XPackClient {
return ilmClient;
}
+ public EnrichClient enrichClient() {
+ return enrichClient;
+ }
+
public XPackClient withHeaders(Map headers) {
return new XPackClient(client.filterWithHeader(headers));
}
diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java
index 03b8e2bc49f..ba0a77cd054 100644
--- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java
+++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java
@@ -6,8 +6,8 @@
package org.elasticsearch.xpack.core;
import org.elasticsearch.Version;
-import org.elasticsearch.action.ActionType;
import org.elasticsearch.action.ActionResponse;
+import org.elasticsearch.action.ActionType;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.NamedDiff;
import org.elasticsearch.cluster.metadata.MetaData;
@@ -43,6 +43,10 @@ import org.elasticsearch.xpack.core.ccr.AutoFollowMetadata;
import org.elasticsearch.xpack.core.ccr.CCRFeatureSet;
import org.elasticsearch.xpack.core.analytics.AnalyticsFeatureSetUsage;
import org.elasticsearch.xpack.core.deprecation.DeprecationInfoAction;
+import org.elasticsearch.xpack.core.enrich.action.DeleteEnrichPolicyAction;
+import org.elasticsearch.xpack.core.enrich.action.ExecuteEnrichPolicyAction;
+import org.elasticsearch.xpack.core.enrich.action.GetEnrichPolicyAction;
+import org.elasticsearch.xpack.core.enrich.action.PutEnrichPolicyAction;
import org.elasticsearch.xpack.core.flattened.FlattenedFeatureSetUsage;
import org.elasticsearch.xpack.core.frozen.FrozenIndicesFeatureSetUsage;
import org.elasticsearch.xpack.core.frozen.action.FreezeIndexAction;
@@ -436,8 +440,13 @@ public class XPackClientPlugin extends Plugin implements ActionPlugin, NetworkPl
DeleteTransformAction.INSTANCE,
GetTransformAction.INSTANCE,
GetTransformStatsAction.INSTANCE,
- PreviewTransformAction.INSTANCE
- );
+ PreviewTransformAction.INSTANCE,
+ // enrich
+ DeleteEnrichPolicyAction.INSTANCE,
+ ExecuteEnrichPolicyAction.INSTANCE,
+ GetEnrichPolicyAction.INSTANCE,
+ PutEnrichPolicyAction.INSTANCE
+ );
}
@Override
@@ -613,7 +622,7 @@ public class XPackClientPlugin extends Plugin implements ActionPlugin, NetworkPl
TransformState::fromXContent),
new NamedXContentRegistry.Entry(PersistentTaskState.class, new ParseField(TransformField.TASK_NAME),
TransformState::fromXContent)
- );
+ );
}
@Override
diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackSettings.java
index 72c9ae6f1ff..8b53297ca5e 100644
--- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackSettings.java
+++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackSettings.java
@@ -40,6 +40,11 @@ public class XPackSettings {
}
+ /**
+ * Setting for controlling whether or not enrich is enabled.
+ */
+ public static final Setting ENRICH_ENABLED_SETTING = Setting.boolSetting("xpack.enrich.enabled", true, Property.NodeScope);
+
/**
* Setting for controlling whether or not CCR is enabled.
*/
diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/EnrichPolicy.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/EnrichPolicy.java
new file mode 100644
index 00000000000..4b56c5b59a5
--- /dev/null
+++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/EnrichPolicy.java
@@ -0,0 +1,378 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+package org.elasticsearch.xpack.core.enrich;
+
+import org.elasticsearch.Version;
+import org.elasticsearch.common.ParseField;
+import org.elasticsearch.common.ParsingException;
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.bytes.BytesReference;
+import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.common.io.stream.StreamOutput;
+import org.elasticsearch.common.io.stream.Writeable;
+import org.elasticsearch.common.xcontent.ConstructingObjectParser;
+import org.elasticsearch.common.xcontent.ObjectParser.ValueType;
+import org.elasticsearch.common.xcontent.ToXContentFragment;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.common.xcontent.XContentHelper;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.common.xcontent.XContentParser.Token;
+import org.elasticsearch.common.xcontent.XContentType;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Represents an enrich policy including its configuration.
+ */
+public final class EnrichPolicy implements Writeable, ToXContentFragment {
+
+ public static final String ENRICH_INDEX_NAME_BASE = ".enrich-";
+
+ public static final String MATCH_TYPE = "match";
+ public static final String GEO_MATCH_TYPE = "geo_match";
+ public static final String[] SUPPORTED_POLICY_TYPES = new String[]{
+ MATCH_TYPE,
+ GEO_MATCH_TYPE
+ };
+
+ private static final ParseField QUERY = new ParseField("query");
+ private static final ParseField INDICES = new ParseField("indices");
+ private static final ParseField MATCH_FIELD = new ParseField("match_field");
+ private static final ParseField ENRICH_FIELDS = new ParseField("enrich_fields");
+ private static final ParseField ELASTICSEARCH_VERSION = new ParseField("elasticsearch_version");
+
+ @SuppressWarnings("unchecked")
+ private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(
+ "policy",
+ false,
+ (args, policyType) -> new EnrichPolicy(
+ policyType,
+ (QuerySource) args[0],
+ (List) args[1],
+ (String) args[2],
+ (List) args[3],
+ (Version) args[4]
+ )
+ );
+
+ static {
+ declareCommonConstructorParsingOptions(PARSER);
+ }
+
+ private static void declareCommonConstructorParsingOptions(ConstructingObjectParser parser) {
+ parser.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> {
+ XContentBuilder contentBuilder = XContentBuilder.builder(p.contentType().xContent());
+ contentBuilder.generator().copyCurrentStructure(p);
+ return new QuerySource(BytesReference.bytes(contentBuilder), contentBuilder.contentType());
+ }, QUERY);
+ parser.declareStringArray(ConstructingObjectParser.constructorArg(), INDICES);
+ parser.declareString(ConstructingObjectParser.constructorArg(), MATCH_FIELD);
+ parser.declareStringArray(ConstructingObjectParser.constructorArg(), ENRICH_FIELDS);
+ parser.declareField(ConstructingObjectParser.optionalConstructorArg(), ((p, c) -> Version.fromString(p.text())),
+ ELASTICSEARCH_VERSION, ValueType.STRING);
+ }
+
+ public static EnrichPolicy fromXContent(XContentParser parser) throws IOException {
+ Token token = parser.currentToken();
+ if (token != Token.START_OBJECT) {
+ token = parser.nextToken();
+ }
+ if (token != Token.START_OBJECT) {
+ throw new ParsingException(parser.getTokenLocation(), "unexpected token");
+ }
+ token = parser.nextToken();
+ if (token != Token.FIELD_NAME) {
+ throw new ParsingException(parser.getTokenLocation(), "unexpected token");
+ }
+ String policyType = parser.currentName();
+ EnrichPolicy policy = PARSER.parse(parser, policyType);
+ token = parser.nextToken();
+ if (token != Token.END_OBJECT) {
+ throw new ParsingException(parser.getTokenLocation(), "unexpected token");
+ }
+ return policy;
+ }
+
+ private final String type;
+ private final QuerySource query;
+ private final List indices;
+ private final String matchField;
+ private final List enrichFields;
+ private final Version elasticsearchVersion;
+
+ public EnrichPolicy(StreamInput in) throws IOException {
+ this(
+ in.readString(),
+ in.readOptionalWriteable(QuerySource::new),
+ in.readStringList(),
+ in.readString(),
+ in.readStringList(),
+ Version.readVersion(in)
+ );
+ }
+
+ public EnrichPolicy(String type,
+ QuerySource query,
+ List indices,
+ String matchField,
+ List enrichFields) {
+ this(type, query, indices, matchField, enrichFields, Version.CURRENT);
+ }
+
+ public EnrichPolicy(String type,
+ QuerySource query,
+ List indices,
+ String matchField,
+ List enrichFields,
+ Version elasticsearchVersion) {
+ this.type = type;
+ this.query = query;
+ this.indices = indices;
+ this.matchField = matchField;
+ this.enrichFields = enrichFields;
+ this.elasticsearchVersion = elasticsearchVersion != null ? elasticsearchVersion : Version.CURRENT;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public QuerySource getQuery() {
+ return query;
+ }
+
+ public List getIndices() {
+ return indices;
+ }
+
+ public String getMatchField() {
+ return matchField;
+ }
+
+ public List getEnrichFields() {
+ return enrichFields;
+ }
+
+ public Version getElasticsearchVersion() {
+ return elasticsearchVersion;
+ }
+
+ public static String getBaseName(String policyName) {
+ return ENRICH_INDEX_NAME_BASE + policyName;
+ }
+
+ @Override
+ public void writeTo(StreamOutput out) throws IOException {
+ out.writeString(type);
+ out.writeOptionalWriteable(query);
+ out.writeStringCollection(indices);
+ out.writeString(matchField);
+ out.writeStringCollection(enrichFields);
+ Version.writeVersion(elasticsearchVersion, out);
+ }
+
+ @Override
+ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+ builder.startObject(type);
+ {
+ toInnerXContent(builder, params);
+ }
+ builder.endObject();
+ return builder;
+ }
+
+ private void toInnerXContent(XContentBuilder builder, Params params) throws IOException {
+ if (query != null) {
+ builder.field(QUERY.getPreferredName(), query.getQueryAsMap());
+ }
+ builder.array(INDICES.getPreferredName(), indices.toArray(new String[0]));
+ builder.field(MATCH_FIELD.getPreferredName(), matchField);
+ builder.array(ENRICH_FIELDS.getPreferredName(), enrichFields.toArray(new String[0]));
+ if (params.paramAsBoolean("include_version", false) && elasticsearchVersion != null) {
+ builder.field(ELASTICSEARCH_VERSION.getPreferredName(), elasticsearchVersion.toString());
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ EnrichPolicy policy = (EnrichPolicy) o;
+ return type.equals(policy.type) &&
+ Objects.equals(query, policy.query) &&
+ indices.equals(policy.indices) &&
+ matchField.equals(policy.matchField) &&
+ enrichFields.equals(policy.enrichFields) &&
+ elasticsearchVersion.equals(policy.elasticsearchVersion);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ type,
+ query,
+ indices,
+ matchField,
+ enrichFields,
+ elasticsearchVersion
+ );
+ }
+
+ public String toString() {
+ return Strings.toString(this);
+ }
+
+ public static class QuerySource implements Writeable {
+
+ private final BytesReference query;
+ private final XContentType contentType;
+
+ QuerySource(StreamInput in) throws IOException {
+ this(in.readBytesReference(), in.readEnum(XContentType.class));
+ }
+
+ public QuerySource(BytesReference query, XContentType contentType) {
+ this.query = query;
+ this.contentType = contentType;
+ }
+
+ public BytesReference getQuery() {
+ return query;
+ }
+
+ public Map getQueryAsMap() {
+ return XContentHelper.convertToMap(query, true, contentType).v2();
+ }
+
+ public XContentType getContentType() {
+ return contentType;
+ }
+
+ @Override
+ public void writeTo(StreamOutput out) throws IOException {
+ out.writeBytesReference(query);
+ out.writeEnum(contentType);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ QuerySource that = (QuerySource) o;
+ return query.equals(that.query) &&
+ contentType == that.contentType;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(query, contentType);
+ }
+ }
+
+ public static class NamedPolicy implements Writeable, ToXContentFragment {
+
+ static final ParseField NAME = new ParseField("name");
+ @SuppressWarnings("unchecked")
+ static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(
+ "named_policy",
+ false,
+ (args, policyType) -> new NamedPolicy(
+ (String) args[0],
+ new EnrichPolicy(policyType,
+ (QuerySource) args[1],
+ (List) args[2],
+ (String) args[3],
+ (List) args[4],
+ (Version) args[5])
+ )
+ );
+
+ static {
+ PARSER.declareString(ConstructingObjectParser.constructorArg(), NAME);
+ declareCommonConstructorParsingOptions(PARSER);
+ }
+
+ private final String name;
+ private final EnrichPolicy policy;
+
+ public NamedPolicy(String name, EnrichPolicy policy) {
+ this.name = name;
+ this.policy = policy;
+ }
+
+ public NamedPolicy(StreamInput in) throws IOException {
+ name = in.readString();
+ policy = new EnrichPolicy(in);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public EnrichPolicy getPolicy() {
+ return policy;
+ }
+
+ @Override
+ public void writeTo(StreamOutput out) throws IOException {
+ out.writeString(name);
+ policy.writeTo(out);
+ }
+
+ @Override
+ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+ builder.startObject(policy.type);
+ {
+ builder.field(NAME.getPreferredName(), name);
+ policy.toInnerXContent(builder, params);
+ }
+ builder.endObject();
+ return builder;
+ }
+
+ public static NamedPolicy fromXContent(XContentParser parser) throws IOException {
+ Token token = parser.currentToken();
+ if (token != Token.START_OBJECT) {
+ token = parser.nextToken();
+ }
+ if (token != Token.START_OBJECT) {
+ throw new ParsingException(parser.getTokenLocation(), "unexpected token");
+ }
+ token = parser.nextToken();
+ if (token != Token.FIELD_NAME) {
+ throw new ParsingException(parser.getTokenLocation(), "unexpected token");
+ }
+ String policyType = parser.currentName();
+ token = parser.nextToken();
+ if (token != Token.START_OBJECT) {
+ throw new ParsingException(parser.getTokenLocation(), "unexpected token");
+ }
+ NamedPolicy policy = PARSER.parse(parser, policyType);
+ token = parser.nextToken();
+ if (token != Token.END_OBJECT) {
+ throw new ParsingException(parser.getTokenLocation(), "unexpected token");
+ }
+ return policy;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ NamedPolicy that = (NamedPolicy) o;
+ return name.equals(that.name) &&
+ policy.equals(that.policy);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, policy);
+ }
+ }
+}
diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/DeleteEnrichPolicyAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/DeleteEnrichPolicyAction.java
new file mode 100644
index 00000000000..0166e7c2594
--- /dev/null
+++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/DeleteEnrichPolicyAction.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+package org.elasticsearch.xpack.core.enrich.action;
+
+import org.elasticsearch.action.ActionType;
+import org.elasticsearch.action.ActionRequestValidationException;
+import org.elasticsearch.action.support.master.AcknowledgedResponse;
+import org.elasticsearch.action.support.master.MasterNodeRequest;
+import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.common.io.stream.StreamOutput;
+
+import java.io.IOException;
+import java.util.Objects;
+
+public class DeleteEnrichPolicyAction extends ActionType {
+
+ public static final DeleteEnrichPolicyAction INSTANCE = new DeleteEnrichPolicyAction();
+ public static final String NAME = "cluster:admin/xpack/enrich/delete";
+
+ private DeleteEnrichPolicyAction() {
+ super(NAME, AcknowledgedResponse::new);
+ }
+
+ public static class Request extends MasterNodeRequest {
+
+ private final String name;
+
+ public Request(String name) {
+ this.name = Objects.requireNonNull(name, "name cannot be null");
+ }
+
+ public Request(StreamInput in) throws IOException {
+ super(in);
+ this.name = in.readString();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public void writeTo(StreamOutput out) throws IOException {
+ super.writeTo(out);
+ out.writeString(name);
+ }
+
+ @Override
+ public ActionRequestValidationException validate() {
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Request request = (Request) o;
+ return name.equals(request.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name);
+ }
+ }
+}
diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/EnrichStatsAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/EnrichStatsAction.java
new file mode 100644
index 00000000000..3c19d2d33bd
--- /dev/null
+++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/EnrichStatsAction.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+package org.elasticsearch.xpack.core.enrich.action;
+
+import org.elasticsearch.action.ActionRequestValidationException;
+import org.elasticsearch.action.ActionResponse;
+import org.elasticsearch.action.ActionType;
+import org.elasticsearch.action.support.master.MasterNodeRequest;
+import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.common.io.stream.StreamOutput;
+import org.elasticsearch.common.io.stream.Writeable;
+import org.elasticsearch.common.xcontent.ToXContentFragment;
+import org.elasticsearch.common.xcontent.ToXContentObject;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.tasks.TaskInfo;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Objects;
+
+public class EnrichStatsAction extends ActionType {
+
+ public static final EnrichStatsAction INSTANCE = new EnrichStatsAction();
+ public static final String NAME = "cluster:admin/xpack/enrich/stats";
+
+ private EnrichStatsAction() {
+ super(NAME, Response::new);
+ }
+
+ public static class Request extends MasterNodeRequest {
+
+ public Request() {
+ }
+
+ public Request(StreamInput in) throws IOException {
+ super(in);
+ }
+
+ @Override
+ public ActionRequestValidationException validate() {
+ return null;
+ }
+ }
+
+ public static class Response extends ActionResponse implements ToXContentObject {
+
+ private final List executingPolicies;
+ private final List coordinatorStats;
+
+ public Response(List executingPolicies, List coordinatorStats) {
+ this.executingPolicies = executingPolicies;
+ this.coordinatorStats = coordinatorStats;
+ }
+
+ public Response(StreamInput in) throws IOException {
+ super(in);
+ executingPolicies = in.readList(ExecutingPolicy::new);
+ coordinatorStats = in.readList(CoordinatorStats::new);
+ }
+
+ public List getExecutingPolicies() {
+ return executingPolicies;
+ }
+
+ public List getCoordinatorStats() {
+ return coordinatorStats;
+ }
+
+ @Override
+ public void writeTo(StreamOutput out) throws IOException {
+ out.writeList(executingPolicies);
+ out.writeList(coordinatorStats);
+ }
+
+ @Override
+ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+ builder.startObject();
+ builder.startArray("executing_policies");
+ for (ExecutingPolicy policy : executingPolicies) {
+ builder.startObject();
+ policy.toXContent(builder, params);
+ builder.endObject();
+ }
+ builder.endArray();
+ builder.startArray("coordinator_stats");
+ for (CoordinatorStats entry : coordinatorStats) {
+ builder.startObject();
+ entry.toXContent(builder, params);
+ builder.endObject();
+ }
+ builder.endArray();
+ builder.endObject();
+ return builder;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Response response = (Response) o;
+ return executingPolicies.equals(response.executingPolicies) &&
+ coordinatorStats.equals(response.coordinatorStats);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(executingPolicies, coordinatorStats);
+ }
+
+ public static class CoordinatorStats implements Writeable, ToXContentFragment {
+
+ private final String nodeId;
+ private final int queueSize;
+ private final int remoteRequestsCurrent;
+ private final long remoteRequestsTotal;
+ private final long executedSearchesTotal;
+
+ public CoordinatorStats(String nodeId,
+ int queueSize,
+ int remoteRequestsCurrent,
+ long remoteRequestsTotal,
+ long executedSearchesTotal) {
+ this.nodeId = nodeId;
+ this.queueSize = queueSize;
+ this.remoteRequestsCurrent = remoteRequestsCurrent;
+ this.remoteRequestsTotal = remoteRequestsTotal;
+ this.executedSearchesTotal = executedSearchesTotal;
+ }
+
+ public CoordinatorStats(StreamInput in) throws IOException {
+ this(in.readString(), in.readVInt(), in.readVInt(), in.readVLong(), in.readVLong());
+ }
+
+ public String getNodeId() {
+ return nodeId;
+ }
+
+ public int getQueueSize() {
+ return queueSize;
+ }
+
+ public int getRemoteRequestsCurrent() {
+ return remoteRequestsCurrent;
+ }
+
+ public long getRemoteRequestsTotal() {
+ return remoteRequestsTotal;
+ }
+
+ public long getExecutedSearchesTotal() {
+ return executedSearchesTotal;
+ }
+
+ @Override
+ public void writeTo(StreamOutput out) throws IOException {
+ out.writeString(nodeId);
+ out.writeVInt(queueSize);
+ out.writeVInt(remoteRequestsCurrent);
+ out.writeVLong(remoteRequestsTotal);
+ out.writeVLong(executedSearchesTotal);
+ }
+
+ @Override
+ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+ builder.field("node_id", nodeId);
+ builder.field("queue_size", queueSize);
+ builder.field("remote_requests_current", remoteRequestsCurrent);
+ builder.field("remote_requests_total", remoteRequestsTotal);
+ builder.field("executed_searches_total", executedSearchesTotal);
+ return builder;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ CoordinatorStats stats = (CoordinatorStats) o;
+ return Objects.equals(nodeId, stats.nodeId) &&
+ queueSize == stats.queueSize &&
+ remoteRequestsCurrent == stats.remoteRequestsCurrent &&
+ remoteRequestsTotal == stats.remoteRequestsTotal &&
+ executedSearchesTotal == stats.executedSearchesTotal;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(nodeId, queueSize, remoteRequestsCurrent, remoteRequestsTotal, executedSearchesTotal);
+ }
+ }
+
+ public static class ExecutingPolicy implements Writeable, ToXContentFragment {
+
+ private final String name;
+ private final TaskInfo taskInfo;
+
+ public ExecutingPolicy(String name, TaskInfo taskInfo) {
+ this.name = name;
+ this.taskInfo = taskInfo;
+ }
+
+ ExecutingPolicy(StreamInput in) throws IOException {
+ this(in.readString(), new TaskInfo(in));
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public TaskInfo getTaskInfo() {
+ return taskInfo;
+ }
+
+ @Override
+ public void writeTo(StreamOutput out) throws IOException {
+ out.writeString(name);
+ taskInfo.writeTo(out);
+ }
+
+ @Override
+ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+ builder.field("name", name);
+ builder.startObject("task");
+ {
+ builder.value(taskInfo);
+ }
+ builder.endObject();
+ return builder;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ExecutingPolicy that = (ExecutingPolicy) o;
+ return name.equals(that.name) &&
+ taskInfo.equals(that.taskInfo);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, taskInfo);
+ }
+ }
+ }
+
+}
diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/ExecuteEnrichPolicyAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/ExecuteEnrichPolicyAction.java
new file mode 100644
index 00000000000..e5c6ab5eb67
--- /dev/null
+++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/ExecuteEnrichPolicyAction.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+package org.elasticsearch.xpack.core.enrich.action;
+
+import org.elasticsearch.action.ActionRequestValidationException;
+import org.elasticsearch.action.ActionResponse;
+import org.elasticsearch.action.ActionType;
+import org.elasticsearch.action.support.master.MasterNodeRequest;
+import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.common.io.stream.StreamOutput;
+import org.elasticsearch.common.xcontent.ToXContentObject;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.tasks.TaskId;
+
+import java.io.IOException;
+import java.util.Objects;
+
+public class ExecuteEnrichPolicyAction extends ActionType {
+
+ public static final ExecuteEnrichPolicyAction INSTANCE = new ExecuteEnrichPolicyAction();
+ public static final String NAME = "cluster:admin/xpack/enrich/execute";
+
+ private ExecuteEnrichPolicyAction() {
+ super(NAME, ExecuteEnrichPolicyAction.Response::new);
+ }
+
+ public static class Request extends MasterNodeRequest {
+
+ private final String name;
+ private boolean waitForCompletion;
+
+ public Request(String name) {
+ this.name = Objects.requireNonNull(name, "name cannot be null");
+ this.waitForCompletion = true;
+ }
+
+ public Request(StreamInput in) throws IOException {
+ super(in);
+ name = in.readString();
+ waitForCompletion = in.readBoolean();
+ }
+
+ @Override
+ public void writeTo(StreamOutput out) throws IOException {
+ super.writeTo(out);
+ out.writeString(name);
+ out.writeBoolean(waitForCompletion);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean isWaitForCompletion() {
+ return waitForCompletion;
+ }
+
+ public Request setWaitForCompletion(boolean waitForCompletion) {
+ this.waitForCompletion = waitForCompletion;
+ return this;
+ }
+
+ @Override
+ public ActionRequestValidationException validate() {
+ return null;
+ }
+
+ // This will be displayed in tasks api and allows stats api to figure out which policies are being executed.
+ @Override
+ public String getDescription() {
+ return name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Request request = (Request) o;
+ return waitForCompletion == request.waitForCompletion &&
+ Objects.equals(name, request.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, waitForCompletion);
+ }
+ }
+
+ public static class Response extends ActionResponse implements ToXContentObject {
+
+ private final TaskId taskId;
+ private final ExecuteEnrichPolicyStatus status;
+
+ public Response(ExecuteEnrichPolicyStatus status) {
+ this.taskId = null;
+ this.status = status;
+ }
+
+ public Response(TaskId taskId) {
+ this.taskId = taskId;
+ this.status = null;
+ }
+
+ public TaskId getTaskId() {
+ return taskId;
+ }
+
+ public ExecuteEnrichPolicyStatus getStatus() {
+ return status;
+ }
+
+ public Response(StreamInput in) throws IOException {
+ super(in);
+ if (in.readBoolean()) {
+ this.status = new ExecuteEnrichPolicyStatus(in);
+ this.taskId = null;
+ } else {
+ this.taskId = TaskId.readFromStream(in);
+ this.status = null;
+ }
+ }
+
+ @Override
+ public void writeTo(StreamOutput out) throws IOException {
+ boolean waitedForCompletion = status != null;
+ out.writeBoolean(waitedForCompletion);
+ if (waitedForCompletion) {
+ status.writeTo(out);
+ } else {
+ taskId.writeTo(out);
+ }
+ }
+
+ @Override
+ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+ builder.startObject();
+ {
+ if (taskId != null) {
+ builder.field("task", taskId.getNodeId() + ":" + taskId.getId());
+ } else {
+ builder.field("status", status);
+ }
+ }
+ builder.endObject();
+ return builder;
+ }
+ }
+}
diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/ExecuteEnrichPolicyStatus.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/ExecuteEnrichPolicyStatus.java
new file mode 100644
index 00000000000..96435b6f95f
--- /dev/null
+++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/ExecuteEnrichPolicyStatus.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+package org.elasticsearch.xpack.core.enrich.action;
+
+import java.io.IOException;
+
+import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.common.io.stream.StreamOutput;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.tasks.Task;
+
+public class ExecuteEnrichPolicyStatus implements Task.Status {
+
+ public static final class PolicyPhases {
+ private PolicyPhases() {}
+
+ public static final String SCHEDULED = "SCHEDULED";
+ public static final String RUNNING = "RUNNING";
+ public static final String COMPLETE = "COMPLETE";
+ public static final String FAILED = "FAILED";
+ }
+
+ public static final String NAME = "enrich-policy-execution";
+
+ private static final String PHASE_FIELD = "phase";
+
+ private final String phase;
+
+ public ExecuteEnrichPolicyStatus(String phase) {
+ this.phase = phase;
+ }
+
+ public ExecuteEnrichPolicyStatus(StreamInput in) throws IOException {
+ this.phase = in.readString();
+ }
+
+ public String getPhase() {
+ return phase;
+ }
+
+ public boolean isCompleted() {
+ return PolicyPhases.COMPLETE.equals(phase);
+ }
+
+ @Override
+ public String getWriteableName() {
+ return NAME;
+ }
+
+ @Override
+ public void writeTo(StreamOutput out) throws IOException {
+ out.writeString(phase);
+ }
+
+ @Override
+ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+ builder.startObject();
+ {
+ builder.field(PHASE_FIELD, phase);
+ }
+ builder.endObject();
+ return builder;
+ }
+}
diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/GetEnrichPolicyAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/GetEnrichPolicyAction.java
new file mode 100644
index 00000000000..c1543c8578b
--- /dev/null
+++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/GetEnrichPolicyAction.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+package org.elasticsearch.xpack.core.enrich.action;
+
+import org.elasticsearch.action.ActionType;
+import org.elasticsearch.action.ActionRequestValidationException;
+import org.elasticsearch.action.ActionResponse;
+import org.elasticsearch.action.support.master.MasterNodeReadRequest;
+import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.common.io.stream.StreamOutput;
+import org.elasticsearch.common.xcontent.ToXContentObject;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.xpack.core.enrich.EnrichPolicy;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+public class GetEnrichPolicyAction extends ActionType {
+
+ public static final GetEnrichPolicyAction INSTANCE = new GetEnrichPolicyAction();
+ public static final String NAME = "cluster:admin/xpack/enrich/get";
+
+ private GetEnrichPolicyAction() {
+ super(NAME, Response::new);
+ }
+
+ public static class Request extends MasterNodeReadRequest {
+
+ private final List names;
+
+ public Request() {
+ this.names = new ArrayList<>();
+ }
+
+ public Request(String[] names) {
+ this.names = Arrays.asList(names);
+ }
+
+ public Request(StreamInput in) throws IOException {
+ super(in);
+ this.names = in.readStringList();
+ }
+
+ @Override
+ public ActionRequestValidationException validate() {
+ return null;
+ }
+
+ public List getNames() {
+ return names;
+ }
+
+ @Override
+ public void writeTo(StreamOutput out) throws IOException {
+ super.writeTo(out);
+ out.writeStringCollection(names);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Request request = (Request) o;
+ return Objects.equals(names, request.names);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(names);
+ }
+ }
+
+ public static class Response extends ActionResponse implements ToXContentObject {
+
+ private final List policies;
+
+ public Response(Map policies) {
+ Objects.requireNonNull(policies, "policies cannot be null");
+ // use a treemap to guarantee ordering in the set, then transform it to the list of named policies
+ this.policies = new TreeMap<>(policies).entrySet().stream()
+ .map(entry -> new EnrichPolicy.NamedPolicy(entry.getKey(), entry.getValue())).collect(Collectors.toList());
+ }
+
+ public Response(StreamInput in) throws IOException {
+ policies = in.readList(EnrichPolicy.NamedPolicy::new);
+ }
+
+ @Override
+ public void writeTo(StreamOutput out) throws IOException {
+ out.writeList(policies);
+ }
+
+ @Override
+ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+ builder.startObject();
+ {
+ builder.startArray("policies");
+ {
+ for (EnrichPolicy.NamedPolicy policy : policies) {
+ builder.startObject();
+ {
+ builder.startObject("config");
+ {
+ policy.toXContent(builder, params);
+ }
+ builder.endObject();
+ }
+ builder.endObject();
+ }
+ }
+ builder.endArray();
+ }
+ builder.endObject();
+
+ return builder;
+ }
+
+ public List getPolicies() {
+ return policies;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Response response = (Response) o;
+ return policies.equals(response.policies);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(policies);
+ }
+ }
+}
diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/PutEnrichPolicyAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/PutEnrichPolicyAction.java
new file mode 100644
index 00000000000..d30ba4c383e
--- /dev/null
+++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/action/PutEnrichPolicyAction.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+package org.elasticsearch.xpack.core.enrich.action;
+
+import org.elasticsearch.Version;
+import org.elasticsearch.action.ActionRequestValidationException;
+import org.elasticsearch.action.ActionType;
+import org.elasticsearch.action.support.master.AcknowledgedResponse;
+import org.elasticsearch.action.support.master.MasterNodeRequest;
+import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.common.io.stream.StreamOutput;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.xpack.core.enrich.EnrichPolicy;
+
+import java.io.IOException;
+import java.util.Objects;
+
+public class PutEnrichPolicyAction extends ActionType {
+
+ public static final PutEnrichPolicyAction INSTANCE = new PutEnrichPolicyAction();
+ public static final String NAME = "cluster:admin/xpack/enrich/put";
+
+ private PutEnrichPolicyAction() {
+ super(NAME, AcknowledgedResponse::new);
+ }
+
+ public static Request fromXContent(XContentParser parser, String name) throws IOException {
+ return new Request(name, EnrichPolicy.fromXContent(parser));
+ }
+
+ public static class Request extends MasterNodeRequest {
+
+ private final EnrichPolicy policy;
+ private final String name;
+
+ public Request(String name, EnrichPolicy policy) {
+ this.name = Objects.requireNonNull(name, "name cannot be null");
+ if (!Version.CURRENT.equals(policy.getElasticsearchVersion())) {
+ throw new IllegalArgumentException("Cannot set [version_created] field on enrich policy [" + name +
+ "]. Found [" + policy.getElasticsearchVersion() + "]");
+ }
+ this.policy = policy;
+ }
+
+ public Request(StreamInput in) throws IOException {
+ super(in);
+ name = in.readString();
+ policy = new EnrichPolicy(in);
+ }
+
+ @Override
+ public void writeTo(StreamOutput out) throws IOException {
+ super.writeTo(out);
+ out.writeString(name);
+ policy.writeTo(out);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public EnrichPolicy getPolicy() {
+ return policy;
+ }
+
+ @Override
+ public ActionRequestValidationException validate() {
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Request request = (Request) o;
+ return policy.equals(request.policy) &&
+ name.equals(request.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(policy, name);
+ }
+ }
+}
diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/client/EnrichClient.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/client/EnrichClient.java
new file mode 100644
index 00000000000..c12df5b49d2
--- /dev/null
+++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/client/EnrichClient.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+package org.elasticsearch.xpack.core.enrich.client;
+
+import org.elasticsearch.action.ActionFuture;
+import org.elasticsearch.action.ActionListener;
+import org.elasticsearch.action.support.PlainActionFuture;
+import org.elasticsearch.action.support.master.AcknowledgedResponse;
+import org.elasticsearch.client.ElasticsearchClient;
+import org.elasticsearch.xpack.core.enrich.action.DeleteEnrichPolicyAction;
+import org.elasticsearch.xpack.core.enrich.action.ExecuteEnrichPolicyAction;
+import org.elasticsearch.xpack.core.enrich.action.GetEnrichPolicyAction;
+import org.elasticsearch.xpack.core.enrich.action.PutEnrichPolicyAction;
+
+import java.util.Objects;
+
+public class EnrichClient {
+
+ private final ElasticsearchClient client;
+
+ public EnrichClient(ElasticsearchClient client) {
+ this.client = Objects.requireNonNull(client, "client");
+ }
+
+ public void deleteEnrichPolicy(
+ final DeleteEnrichPolicyAction.Request request,
+ final ActionListener listener) {
+ client.execute(DeleteEnrichPolicyAction.INSTANCE, request, listener);
+ }
+
+ public ActionFuture deleteEnrichPolicy(final DeleteEnrichPolicyAction.Request request) {
+ final PlainActionFuture listener = PlainActionFuture.newFuture();
+ client.execute(DeleteEnrichPolicyAction.INSTANCE, request, listener);
+ return listener;
+ }
+
+ public void executeEnrichPolicy(
+ final ExecuteEnrichPolicyAction.Request request,
+ final ActionListener listener) {
+ client.execute(ExecuteEnrichPolicyAction.INSTANCE, request, listener);
+ }
+
+ public ActionFuture executeEnrichPolicy(final ExecuteEnrichPolicyAction.Request request) {
+ final PlainActionFuture listener = PlainActionFuture.newFuture();
+ client.execute(ExecuteEnrichPolicyAction.INSTANCE, request, listener);
+ return listener;
+ }
+
+ public void getEnrichPolicy(
+ final GetEnrichPolicyAction.Request request,
+ final ActionListener listener) {
+ client.execute(GetEnrichPolicyAction.INSTANCE, request, listener);
+ }
+
+ public ActionFuture getEnrichPolicy(final GetEnrichPolicyAction.Request request) {
+ final PlainActionFuture listener = PlainActionFuture.newFuture();
+ client.execute(GetEnrichPolicyAction.INSTANCE, request, listener);
+ return listener;
+ }
+
+ public void putEnrichPolicy(
+ final PutEnrichPolicyAction.Request request,
+ final ActionListener listener) {
+ client.execute(PutEnrichPolicyAction.INSTANCE, request, listener);
+ }
+
+ public ActionFuture putEnrichPolicy(final PutEnrichPolicyAction.Request request) {
+ final PlainActionFuture listener = PlainActionFuture.newFuture();
+ client.execute(PutEnrichPolicyAction.INSTANCE, request, listener);
+ return listener;
+ }
+}
diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptor.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptor.java
index fbd1cd58932..89016ab8b41 100644
--- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptor.java
+++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptor.java
@@ -774,6 +774,10 @@ public class RoleDescriptor implements ToXContentObject, Writeable {
return this;
}
+ public Builder indices(Collection indices) {
+ return indices(indices.toArray(new String[indices.size()]));
+ }
+
public Builder privileges(String... privileges) {
indicesPrivileges.privileges = privileges;
return this;
diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilegeResolver.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilegeResolver.java
index 57a4325062f..920d0e6e22f 100644
--- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilegeResolver.java
+++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilegeResolver.java
@@ -84,6 +84,7 @@ public class ClusterPrivilegeResolver {
Collections.unmodifiableSet(Sets.newHashSet("cluster:admin/slm/*", StartILMAction.NAME, StopILMAction.NAME, GetStatusAction.NAME));
private static final Set READ_SLM_PATTERN = Collections.unmodifiableSet(Sets.newHashSet(GetSnapshotLifecycleAction.NAME,
GetStatusAction.NAME));
+ private static final Set MANAGE_ENRICH_AUTOMATON = Collections.unmodifiableSet(Sets.newHashSet("cluster:admin/xpack/enrich/*"));
public static final NamedClusterPrivilege NONE = new ActionClusterPrivilege("none", Collections.emptySet(), Collections.emptySet());
public static final NamedClusterPrivilege ALL = new ActionClusterPrivilege("all", ALL_CLUSTER_PATTERN);
@@ -128,6 +129,7 @@ public class ClusterPrivilegeResolver {
Sets.newHashSet(DelegatePkiAuthenticationAction.NAME, InvalidateTokenAction.NAME));
public static final NamedClusterPrivilege MANAGE_OWN_API_KEY = ManageOwnApiKeyClusterPrivilege.INSTANCE;
+ public static final NamedClusterPrivilege MANAGE_ENRICH = new ActionClusterPrivilege("manage_enrich", MANAGE_ENRICH_AUTOMATON);
private static final Map VALUES = Collections.unmodifiableMap(
Stream.of(
@@ -162,7 +164,8 @@ public class ClusterPrivilegeResolver {
MANAGE_SLM,
READ_SLM,
DELEGATE_PKI,
- MANAGE_OWN_API_KEY).collect(Collectors.toMap(cp -> cp.name(), cp -> cp)));
+ MANAGE_OWN_API_KEY,
+ MANAGE_ENRICH).collect(Collectors.toMap(cp -> cp.name(), cp -> cp)));
/**
* Resolves a {@link NamedClusterPrivilege} from a given name if it exists.
diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStore.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStore.java
index 9a9fb8bdbec..ed80944a376 100644
--- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStore.java
+++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStore.java
@@ -264,6 +264,11 @@ public class ReservedRolesStore implements BiConsumer, ActionListene
.privileges("view_index_metadata")
.allowRestrictedIndices(true)
.build() }, null, null, null, MetadataUtils.DEFAULT_RESERVED_METADATA, null))
+ .put("enrich_user", new RoleDescriptor("enrich_user", new String[]{ "manage_enrich", "manage_ingest_pipelines", "monitor" },
+ new RoleDescriptor.IndicesPrivileges[]{ RoleDescriptor.IndicesPrivileges.builder()
+ .indices(".enrich-*")
+ .privileges("manage", "read", "write")
+ .build() }, null, MetadataUtils.DEFAULT_RESERVED_METADATA))
.immutableMap();
}
diff --git a/x-pack/plugin/core/src/main/resources/monitoring-es.json b/x-pack/plugin/core/src/main/resources/monitoring-es.json
index 89b97abac61..fb7d2d7764a 100644
--- a/x-pack/plugin/core/src/main/resources/monitoring-es.json
+++ b/x-pack/plugin/core/src/main/resources/monitoring-es.json
@@ -1093,6 +1093,62 @@
}
}
}
+ },
+ "enrich_coordinator_stats" : {
+ "properties": {
+ "node_id": {
+ "type": "keyword"
+ },
+ "queue_size": {
+ "type": "integer"
+ },
+ "remote_requests_current" : {
+ "type": "long"
+ },
+ "remote_requests_total" : {
+ "type": "long"
+ },
+ "executed_searches_total" : {
+ "type": "long"
+ }
+ }
+ },
+ "enrich_executing_policy_stats": {
+ "properties": {
+ "name": {
+ "type": "keyword"
+ },
+ "task": {
+ "type": "object",
+ "properties": {
+ "node": {
+ "type": "keyword"
+ },
+ "id": {
+ "type": "long"
+ },
+ "type": {
+ "type": "keyword"
+ },
+ "action": {
+ "type": "keyword"
+ },
+ "description": {
+ "type": "keyword"
+ },
+ "start_time_in_millis": {
+ "type": "date",
+ "format": "epoch_millis"
+ },
+ "running_time_in_nanos": {
+ "type": "long"
+ },
+ "cancellable": {
+ "type": "boolean"
+ }
+ }
+ }
+ }
}
}
}
diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/PrivilegeTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/PrivilegeTests.java
index e02c9301016..3a01936de7d 100644
--- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/PrivilegeTests.java
+++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/PrivilegeTests.java
@@ -8,6 +8,10 @@ package org.elasticsearch.xpack.core.security.authz.privilege;
import org.apache.lucene.util.automaton.Operations;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.xpack.core.enrich.action.DeleteEnrichPolicyAction;
+import org.elasticsearch.xpack.core.enrich.action.ExecuteEnrichPolicyAction;
+import org.elasticsearch.xpack.core.enrich.action.GetEnrichPolicyAction;
+import org.elasticsearch.xpack.core.enrich.action.PutEnrichPolicyAction;
import org.elasticsearch.transport.TransportRequest;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authz.permission.ClusterPermission;
@@ -177,6 +181,15 @@ public class PrivilegeTests extends ESTestCase {
}
+ public void testManageEnrichPrivilege() {
+ verifyClusterActionAllowed(ClusterPrivilegeResolver.MANAGE_ENRICH, DeleteEnrichPolicyAction.NAME);
+ verifyClusterActionAllowed(ClusterPrivilegeResolver.MANAGE_ENRICH, ExecuteEnrichPolicyAction.NAME);
+ verifyClusterActionAllowed(ClusterPrivilegeResolver.MANAGE_ENRICH, GetEnrichPolicyAction.NAME);
+ verifyClusterActionAllowed(ClusterPrivilegeResolver.MANAGE_ENRICH, PutEnrichPolicyAction.NAME);
+ verifyClusterActionAllowed(ClusterPrivilegeResolver.MANAGE_ENRICH, "cluster:admin/xpack/enrich/brand_new_api");
+ verifyClusterActionDenied(ClusterPrivilegeResolver.MANAGE_ENRICH, "cluster:admin/xpack/whatever");
+ }
+
public void testIlmPrivileges() {
{
verifyClusterActionAllowed(ClusterPrivilegeResolver.MANAGE_ILM, "cluster:admin/ilm/delete",
diff --git a/x-pack/plugin/enrich/build.gradle b/x-pack/plugin/enrich/build.gradle
new file mode 100644
index 00000000000..5d40ad3ff6d
--- /dev/null
+++ b/x-pack/plugin/enrich/build.gradle
@@ -0,0 +1,40 @@
+evaluationDependsOn(xpackModule('core'))
+
+apply plugin: 'elasticsearch.esplugin'
+esplugin {
+ name 'x-pack-enrich'
+ description 'Elasticsearch Expanded Pack Plugin - Enrich'
+ classname 'org.elasticsearch.xpack.enrich.EnrichPlugin'
+ extendedPlugins = ['x-pack-core']
+}
+archivesBaseName = 'x-pack-enrich'
+
+dependencies {
+ compileOnly project(path: xpackModule('core'), configuration: 'default')
+ testCompile project(path: xpackModule('core'), configuration: 'testArtifacts')
+ testCompile project(path: ':modules:ingest-common')
+ testCompile project(path: xpackModule('monitoring'), configuration: 'testArtifacts')
+}
+
+// No real integ tests in the module:
+integTest.enabled = false
+
+// Instead we create a separate task to run the tests based on ESIntegTestCase
+task internalClusterTest(type: Test) {
+ description = '🌈🌈🌈🦄 Welcome to fantasy integration tests land! 🦄🌈🌈🌈'
+ mustRunAfter test
+
+ include '**/*IT.class'
+ systemProperty 'es.set.netty.runtime.available.processors', 'false'
+}
+
+check.dependsOn internalClusterTest
+
+// add all sub-projects of the qa sub-project
+gradle.projectsEvaluated {
+ project.subprojects
+ .find { it.path == project.path + ":qa" }
+ .subprojects
+ .findAll { it.path.startsWith(project.path + ":qa") }
+ .each { check.dependsOn it.check }
+}
diff --git a/x-pack/plugin/enrich/qa/build.gradle b/x-pack/plugin/enrich/qa/build.gradle
new file mode 100644
index 00000000000..d3e95d997c3
--- /dev/null
+++ b/x-pack/plugin/enrich/qa/build.gradle
@@ -0,0 +1,17 @@
+import org.elasticsearch.gradle.test.RestIntegTestTask
+
+apply plugin: 'elasticsearch.build'
+test.enabled = false
+
+dependencies {
+ compile project(':test:framework')
+}
+
+subprojects {
+ project.tasks.withType(RestIntegTestTask) {
+ final File xPackResources = new File(xpackProject('plugin').projectDir, 'src/test/resources')
+ project.copyRestSpec.from(xPackResources) {
+ include 'rest-api-spec/api/**'
+ }
+ }
+}
diff --git a/x-pack/plugin/enrich/qa/common/build.gradle b/x-pack/plugin/enrich/qa/common/build.gradle
new file mode 100644
index 00000000000..4b8496dc2fd
--- /dev/null
+++ b/x-pack/plugin/enrich/qa/common/build.gradle
@@ -0,0 +1,6 @@
+apply plugin: 'elasticsearch.build'
+test.enabled = false
+
+dependencies {
+ compile project(':test:framework')
+}
\ No newline at end of file
diff --git a/x-pack/plugin/enrich/qa/common/src/main/java/org/elasticsearch/test/enrich/CommonEnrichRestTestCase.java b/x-pack/plugin/enrich/qa/common/src/main/java/org/elasticsearch/test/enrich/CommonEnrichRestTestCase.java
new file mode 100644
index 00000000000..06e15730788
--- /dev/null
+++ b/x-pack/plugin/enrich/qa/common/src/main/java/org/elasticsearch/test/enrich/CommonEnrichRestTestCase.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+package org.elasticsearch.test.enrich;
+
+import org.apache.http.util.EntityUtils;
+import org.elasticsearch.client.Request;
+import org.elasticsearch.client.Response;
+import org.elasticsearch.client.ResponseException;
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.common.xcontent.XContentHelper;
+import org.elasticsearch.common.xcontent.json.JsonXContent;
+import org.elasticsearch.common.xcontent.support.XContentMapValues;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.test.rest.ESRestTestCase;
+import org.junit.After;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+
+public abstract class CommonEnrichRestTestCase extends ESRestTestCase {
+
+ @After
+ public void deletePolicies() throws Exception {
+ Map responseMap = toMap(adminClient().performRequest(new Request("GET", "/_enrich/policy")));
+ @SuppressWarnings("unchecked")
+ List