From 3590a77b2b0d04441125d11853251f127afdad63 Mon Sep 17 00:00:00 2001 From: Andrei Dan Date: Thu, 24 Sep 2020 16:45:50 +0100 Subject: [PATCH] HLRC: add support for the searchable_snapshot ILM action (#62323) (#62887) (cherry picked from commit 681eb58718c4cce9ed18a835f4eadb06997e91a0) Signed-off-by: Andrei Dan --- .../IndexLifecycleNamedXContentProvider.java | 3 + .../indexlifecycle/LifecyclePolicy.java | 2 +- .../SearchableSnapshotAction.java | 100 ++++++++++++++++++ .../client/IndexLifecycleIT.java | 2 + .../client/RestHighLevelClientTests.java | 18 ++-- .../GetLifecyclePolicyResponseTests.java | 2 + .../LifecyclePolicyMetadataTests.java | 2 + .../indexlifecycle/LifecyclePolicyTests.java | 8 +- .../SearchableSnapshotActionTests.java | 59 +++++++++++ 9 files changed, 186 insertions(+), 10 deletions(-) create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/indexlifecycle/SearchableSnapshotAction.java create mode 100644 client/rest-high-level/src/test/java/org/elasticsearch/client/indexlifecycle/SearchableSnapshotActionTests.java diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/indexlifecycle/IndexLifecycleNamedXContentProvider.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/indexlifecycle/IndexLifecycleNamedXContentProvider.java index 466abfa240c..51f37157637 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/indexlifecycle/IndexLifecycleNamedXContentProvider.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/indexlifecycle/IndexLifecycleNamedXContentProvider.java @@ -60,6 +60,9 @@ public class IndexLifecycleNamedXContentProvider implements NamedXContentProvide new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(MigrateAction.NAME), MigrateAction::parse), + new NamedXContentRegistry.Entry(LifecycleAction.class, + new ParseField(SearchableSnapshotAction.NAME), + SearchableSnapshotAction::parse), new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(UnfollowAction.NAME), UnfollowAction::parse) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/indexlifecycle/LifecyclePolicy.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/indexlifecycle/LifecyclePolicy.java index 703c6a7ef94..4e6632b577a 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/indexlifecycle/LifecyclePolicy.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/indexlifecycle/LifecyclePolicy.java @@ -61,7 +61,7 @@ public class LifecyclePolicy implements ToXContentObject { ALLOWED_ACTIONS.put("warm", Sets.newHashSet(UnfollowAction.NAME, SetPriorityAction.NAME, MigrateAction.NAME, AllocateAction.NAME, ForceMergeAction.NAME, ReadOnlyAction.NAME, ShrinkAction.NAME)); ALLOWED_ACTIONS.put("cold", Sets.newHashSet(UnfollowAction.NAME, SetPriorityAction.NAME, MigrateAction.NAME, AllocateAction.NAME, - FreezeAction.NAME)); + FreezeAction.NAME, SearchableSnapshotAction.NAME)); ALLOWED_ACTIONS.put("delete", Sets.newHashSet(DeleteAction.NAME)); } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/indexlifecycle/SearchableSnapshotAction.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/indexlifecycle/SearchableSnapshotAction.java new file mode 100644 index 00000000000..f11514347bc --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/indexlifecycle/SearchableSnapshotAction.java @@ -0,0 +1,100 @@ +/* + * 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.indexlifecycle; + +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; + +import java.io.IOException; +import java.util.Objects; + +/** + * A {@link LifecycleAction} that will convert the index into a searchable snapshot. + */ +public class SearchableSnapshotAction implements LifecycleAction, ToXContentObject { + public static final String NAME = "searchable_snapshot"; + + public static final ParseField SNAPSHOT_REPOSITORY = new ParseField("snapshot_repository"); + public static final ParseField FORCE_MERGE_INDEX = new ParseField("force_merge_index"); + + + private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(NAME, + true, a -> new SearchableSnapshotAction((String) a[0], a[1] == null || (boolean) a[1])); + + static { + PARSER.declareString(ConstructingObjectParser.constructorArg(), SNAPSHOT_REPOSITORY); + PARSER.declareBoolean(ConstructingObjectParser.optionalConstructorArg(), FORCE_MERGE_INDEX); + } + + public static SearchableSnapshotAction parse(XContentParser parser) { + return PARSER.apply(parser, null); + } + + private final String snapshotRepository; + private final boolean forceMergeIndex; + + public SearchableSnapshotAction(String snapshotRepository, boolean forceMergeIndex) { + if (Strings.hasText(snapshotRepository) == false) { + throw new IllegalArgumentException("the snapshot repository must be specified"); + } + this.snapshotRepository = snapshotRepository; + this.forceMergeIndex = forceMergeIndex; + } + + public SearchableSnapshotAction(String snapshotRepository) { + this(snapshotRepository, true); + } + + boolean isForceMergeIndex() { + return forceMergeIndex; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException { + builder.startObject(); + builder.field(SNAPSHOT_REPOSITORY.getPreferredName(), snapshotRepository); + builder.field(FORCE_MERGE_INDEX.getPreferredName(), forceMergeIndex); + builder.endObject(); + return builder; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SearchableSnapshotAction that = (SearchableSnapshotAction) o; + return forceMergeIndex == that.forceMergeIndex && + snapshotRepository.equals(that.snapshotRepository); + } + + @Override + public int hashCode() { + return Objects.hash(snapshotRepository, forceMergeIndex); + } + + @Override + public String getName() { + return NAME; + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndexLifecycleIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndexLifecycleIT.java index f74ba00436c..a429272b7c7 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndexLifecycleIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndexLifecycleIT.java @@ -45,6 +45,7 @@ import org.elasticsearch.client.indexlifecycle.RemoveIndexLifecyclePolicyRequest import org.elasticsearch.client.indexlifecycle.RemoveIndexLifecyclePolicyResponse; import org.elasticsearch.client.indexlifecycle.RetryLifecyclePolicyRequest; import org.elasticsearch.client.indexlifecycle.RolloverAction; +import org.elasticsearch.client.indexlifecycle.SearchableSnapshotAction; import org.elasticsearch.client.indexlifecycle.ShrinkAction; import org.elasticsearch.client.indexlifecycle.StartILMRequest; import org.elasticsearch.client.indexlifecycle.StopILMRequest; @@ -160,6 +161,7 @@ public class IndexLifecycleIT extends ESRestHighLevelClientTestCase { Map coldActions = new HashMap<>(); coldActions.put(UnfollowAction.NAME, new UnfollowAction()); coldActions.put(AllocateAction.NAME, new AllocateAction(0, null, null, null)); + coldActions.put(SearchableSnapshotAction.NAME, new SearchableSnapshotAction("repo")); lifecyclePhases.put("cold", new Phase("cold", TimeValue.timeValueSeconds(2000), coldActions)); Map deleteActions = Collections.singletonMap(DeleteAction.NAME, new DeleteAction()); 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 77bf8126d5b..403a048410a 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 @@ -52,6 +52,7 @@ import org.elasticsearch.client.indexlifecycle.FreezeAction; import org.elasticsearch.client.indexlifecycle.LifecycleAction; import org.elasticsearch.client.indexlifecycle.ReadOnlyAction; import org.elasticsearch.client.indexlifecycle.RolloverAction; +import org.elasticsearch.client.indexlifecycle.SearchableSnapshotAction; import org.elasticsearch.client.indexlifecycle.SetPriorityAction; import org.elasticsearch.client.indexlifecycle.ShrinkAction; import org.elasticsearch.client.indexlifecycle.UnfollowAction; @@ -59,16 +60,16 @@ import org.elasticsearch.client.ml.dataframe.DataFrameAnalysis; import org.elasticsearch.client.ml.dataframe.evaluation.classification.AccuracyMetric; import org.elasticsearch.client.ml.dataframe.evaluation.classification.Classification; import org.elasticsearch.client.ml.dataframe.evaluation.classification.MulticlassConfusionMatrixMetric; -import org.elasticsearch.client.ml.dataframe.evaluation.regression.MeanSquaredErrorMetric; -import org.elasticsearch.client.ml.dataframe.evaluation.regression.MeanSquaredLogarithmicErrorMetric; -import org.elasticsearch.client.ml.dataframe.evaluation.regression.HuberMetric; -import org.elasticsearch.client.ml.dataframe.evaluation.regression.RSquaredMetric; -import org.elasticsearch.client.ml.dataframe.evaluation.regression.Regression; import org.elasticsearch.client.ml.dataframe.evaluation.outlierdetection.AucRocMetric; -import org.elasticsearch.client.ml.dataframe.evaluation.outlierdetection.OutlierDetection; import org.elasticsearch.client.ml.dataframe.evaluation.outlierdetection.ConfusionMatrixMetric; +import org.elasticsearch.client.ml.dataframe.evaluation.outlierdetection.OutlierDetection; import org.elasticsearch.client.ml.dataframe.evaluation.outlierdetection.PrecisionMetric; import org.elasticsearch.client.ml.dataframe.evaluation.outlierdetection.RecallMetric; +import org.elasticsearch.client.ml.dataframe.evaluation.regression.HuberMetric; +import org.elasticsearch.client.ml.dataframe.evaluation.regression.MeanSquaredErrorMetric; +import org.elasticsearch.client.ml.dataframe.evaluation.regression.MeanSquaredLogarithmicErrorMetric; +import org.elasticsearch.client.ml.dataframe.evaluation.regression.RSquaredMetric; +import org.elasticsearch.client.ml.dataframe.evaluation.regression.Regression; import org.elasticsearch.client.ml.dataframe.stats.classification.ClassificationStats; import org.elasticsearch.client.ml.dataframe.stats.outlierdetection.OutlierDetectionStats; import org.elasticsearch.client.ml.dataframe.stats.regression.RegressionStats; @@ -705,7 +706,7 @@ public class RestHighLevelClientTests extends ESTestCase { public void testProvidedNamedXContents() { List namedXContents = RestHighLevelClient.getProvidedNamedXContents(); - assertEquals(71, namedXContents.size()); + assertEquals(72, namedXContents.size()); Map, Integer> categories = new HashMap<>(); List names = new ArrayList<>(); for (NamedXContentRegistry.Entry namedXContent : namedXContents) { @@ -731,7 +732,7 @@ public class RestHighLevelClientTests extends ESTestCase { assertTrue(names.contains(MeanReciprocalRank.NAME)); assertTrue(names.contains(DiscountedCumulativeGain.NAME)); assertTrue(names.contains(ExpectedReciprocalRank.NAME)); - assertEquals(Integer.valueOf(10), categories.get(LifecycleAction.class)); + assertEquals(Integer.valueOf(11), categories.get(LifecycleAction.class)); assertTrue(names.contains(UnfollowAction.NAME)); assertTrue(names.contains(AllocateAction.NAME)); assertTrue(names.contains(DeleteAction.NAME)); @@ -741,6 +742,7 @@ public class RestHighLevelClientTests extends ESTestCase { assertTrue(names.contains(ShrinkAction.NAME)); assertTrue(names.contains(FreezeAction.NAME)); assertTrue(names.contains(SetPriorityAction.NAME)); + assertTrue(names.contains(SearchableSnapshotAction.NAME)); assertEquals(Integer.valueOf(3), categories.get(DataFrameAnalysis.class)); assertTrue(names.contains(org.elasticsearch.client.ml.dataframe.OutlierDetection.NAME.getPreferredName())); assertTrue(names.contains(org.elasticsearch.client.ml.dataframe.Regression.NAME.getPreferredName())); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/indexlifecycle/GetLifecyclePolicyResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/indexlifecycle/GetLifecyclePolicyResponseTests.java index ff1733498e3..fdae6c3f73f 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/indexlifecycle/GetLifecyclePolicyResponseTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/indexlifecycle/GetLifecyclePolicyResponseTests.java @@ -86,6 +86,8 @@ public class GetLifecyclePolicyResponseTests extends AbstractXContentTestCase VALID_WARM_ACTIONS = Sets.newHashSet(UnfollowAction.NAME, SetPriorityAction.NAME, AllocateAction.NAME, ForceMergeAction.NAME, ReadOnlyAction.NAME, ShrinkAction.NAME); private static final Set VALID_COLD_ACTIONS = Sets.newHashSet(UnfollowAction.NAME, SetPriorityAction.NAME, AllocateAction.NAME, - FreezeAction.NAME); + FreezeAction.NAME, SearchableSnapshotAction.NAME); private static final Set VALID_DELETE_ACTIONS = Sets.newHashSet(DeleteAction.NAME); private String lifecycleName; @@ -77,6 +77,8 @@ public class LifecyclePolicyTests extends AbstractXContentTestCase { + + @Override + protected SearchableSnapshotAction doParseInstance(XContentParser parser) throws IOException { + return SearchableSnapshotAction.parse(parser); + } + + @Override + protected SearchableSnapshotAction createTestInstance() { + return randomInstance(); + } + + static SearchableSnapshotAction randomInstance() { + return new SearchableSnapshotAction(randomAlphaOfLengthBetween(5, 10), randomBoolean()); + } + + @Override + protected boolean supportsUnknownFields() { + return false; + } + + public void testEmptyOrNullRepository() { + { + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> new SearchableSnapshotAction("")); + assertThat(e.getMessage(), equalTo("the snapshot repository must be specified")); + } + { + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> new SearchableSnapshotAction(null)); + assertThat(e.getMessage(), equalTo("the snapshot repository must be specified")); + } + } +}