Skip to content

Commit 235e5ed

Browse files
authored
[7.x] ILM: add force-merge step to searchable snapshots action (#60819) (#60882)
This adds a force-merge step to the searchable snapshot action, enabled by default, but parameterizable using the `force_merge-index" optional boolean. eg. ``` PUT _ilm/policy/my_policy { "policy": { "phases": { "cold": { "actions": { "searchable_snapshot" : { "snapshot_repository" : "backing_repo", "force_merge_index": true } } } } } } ``` (cherry picked from commit d0a17b2) Signed-off-by: Andrei Dan <[email protected]>
1 parent e03993d commit 235e5ed

File tree

10 files changed

+410
-200
lines changed

10 files changed

+410
-200
lines changed

docs/reference/ilm/actions/ilm-forcemerge.asciidoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ This action makes the index <<dynamic-index-settings,read-only>>.
1212
To use the `forcemerge` action in the `hot` phase, the `rollover` action *must* be present.
1313
If no rollover action is configured, {ilm-init} will reject the policy.
1414

15+
[NOTE]
16+
The `forcemerge` action is best effort. It might happen that some of the
17+
shards are relocating, in which case they will not be merged.
18+
1519
[[ilm-forcemerge-options]]
1620
==== Options
1721

docs/reference/ilm/actions/ilm-searchable-snapshot.asciidoc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,20 @@ To keep the snapshot, set `delete_searchable_snapshot` to `false` in the delete
3030
Specifies where to store the snapshot.
3131
See <<snapshots-register-repository>> for more information.
3232

33+
`force_merge_index`::
34+
(Optional, boolean)
35+
Force merges the managed index to one segment.
36+
Defaults to `true`.
37+
If the managed index was already force merged using the
38+
<<ilm-forcemerge, force merge action>> in a previous action
39+
the `searchable snapshot` action force merge step will be a no-op.
40+
41+
[NOTE]
42+
The `forcemerge` action is best effort. It might happen that some of
43+
the shards are relocating, in which case they will not be merged.
44+
The `searchable-snapshot` action will continue executing even if not all shards
45+
are force merged.
46+
3347
[[ilm-searchable-snapshot-ex]]
3448
==== Examples
3549
[source,console]

test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1046,7 +1046,7 @@ protected static void assertOK(Response response) {
10461046
* in an non green state
10471047
* @param index index to test for
10481048
**/
1049-
protected static void ensureGreen(String index) throws IOException {
1049+
public static void ensureGreen(String index) throws IOException {
10501050
ensureHealth(index, (request) -> {
10511051
request.addParameter("wait_for_status", "green");
10521052
request.addParameter("wait_for_no_relocating_shards", "true");

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/SearchableSnapshotAction.java

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
package org.elasticsearch.xpack.core.ilm;
77

8+
import org.elasticsearch.Version;
89
import org.elasticsearch.client.Client;
910
import org.elasticsearch.cluster.health.ClusterHealthStatus;
1011
import org.elasticsearch.cluster.metadata.IndexAbstraction;
@@ -18,7 +19,7 @@
1819
import org.elasticsearch.xpack.core.ilm.Step.StepKey;
1920

2021
import java.io.IOException;
21-
import java.util.Arrays;
22+
import java.util.ArrayList;
2223
import java.util.List;
2324
import java.util.Objects;
2425

@@ -31,38 +32,52 @@ public class SearchableSnapshotAction implements LifecycleAction {
3132
public static final String NAME = "searchable_snapshot";
3233

3334
public static final ParseField SNAPSHOT_REPOSITORY = new ParseField("snapshot_repository");
35+
public static final ParseField FORCE_MERGE_INDEX = new ParseField("force_merge_index");
3436
public static final String CONDITIONAL_DATASTREAM_CHECK_KEY = BranchingStep.NAME + "-on-datastream-check";
3537

3638
public static final String RESTORED_INDEX_PREFIX = "restored-";
3739

3840
private static final ConstructingObjectParser<SearchableSnapshotAction, Void> PARSER = new ConstructingObjectParser<>(NAME,
39-
a -> new SearchableSnapshotAction((String) a[0]));
41+
a -> new SearchableSnapshotAction((String) a[0], a[1] == null || (boolean) a[1]));
4042

4143
static {
4244
PARSER.declareString(ConstructingObjectParser.constructorArg(), SNAPSHOT_REPOSITORY);
45+
PARSER.declareBoolean(ConstructingObjectParser.optionalConstructorArg(), FORCE_MERGE_INDEX);
4346
}
4447

4548
public static SearchableSnapshotAction parse(XContentParser parser) {
4649
return PARSER.apply(parser, null);
4750
}
4851

4952
private final String snapshotRepository;
53+
private final boolean forceMergeIndex;
5054

51-
public SearchableSnapshotAction(String snapshotRepository) {
55+
public SearchableSnapshotAction(String snapshotRepository, boolean forceMergeIndex) {
5256
if (Strings.hasText(snapshotRepository) == false) {
5357
throw new IllegalArgumentException("the snapshot repository must be specified");
5458
}
5559
this.snapshotRepository = snapshotRepository;
60+
this.forceMergeIndex = forceMergeIndex;
61+
}
62+
63+
public SearchableSnapshotAction(String snapshotRepository) {
64+
this(snapshotRepository, true);
5665
}
5766

5867
public SearchableSnapshotAction(StreamInput in) throws IOException {
59-
this(in.readString());
68+
this(in.readString(), in.getVersion().onOrAfter(Version.V_7_10_0) ? in.readBoolean() : true);
69+
}
70+
71+
boolean isForceMergeIndex() {
72+
return forceMergeIndex;
6073
}
6174

6275
@Override
6376
public List<Step> toSteps(Client client, String phase, StepKey nextStepKey) {
6477
StepKey checkNoWriteIndex = new StepKey(phase, NAME, CheckNotDataStreamWriteIndexStep.NAME);
6578
StepKey waitForNoFollowerStepKey = new StepKey(phase, NAME, WaitForNoFollowersStep.NAME);
79+
StepKey forceMergeStepKey = new StepKey(phase, NAME, ForceMergeStep.NAME);
80+
StepKey waitForSegmentCountKey = new StepKey(phase, NAME, SegmentCountStep.NAME);
6681
StepKey generateSnapshotNameKey = new StepKey(phase, NAME, GenerateSnapshotNameStep.NAME);
6782
StepKey cleanSnapshotKey = new StepKey(phase, NAME, CleanupSnapshotStep.NAME);
6883
StepKey createSnapshotKey = new StepKey(phase, NAME, CreateSnapshotStep.NAME);
@@ -77,8 +92,14 @@ public List<Step> toSteps(Client client, String phase, StepKey nextStepKey) {
7792

7893
CheckNotDataStreamWriteIndexStep checkNoWriteIndexStep = new CheckNotDataStreamWriteIndexStep(checkNoWriteIndex,
7994
waitForNoFollowerStepKey);
80-
WaitForNoFollowersStep waitForNoFollowersStep = new WaitForNoFollowersStep(waitForNoFollowerStepKey, generateSnapshotNameKey,
81-
client);
95+
final WaitForNoFollowersStep waitForNoFollowersStep;
96+
if (forceMergeIndex) {
97+
waitForNoFollowersStep = new WaitForNoFollowersStep(waitForNoFollowerStepKey, forceMergeStepKey, client);
98+
} else {
99+
waitForNoFollowersStep = new WaitForNoFollowersStep(waitForNoFollowerStepKey, generateSnapshotNameKey, client);
100+
}
101+
ForceMergeStep forceMergeStep = new ForceMergeStep(forceMergeStepKey, waitForSegmentCountKey, client, 1);
102+
SegmentCountStep segmentCountStep = new SegmentCountStep(waitForSegmentCountKey, generateSnapshotNameKey, client, 1);
82103
GenerateSnapshotNameStep generateSnapshotNameStep = new GenerateSnapshotNameStep(generateSnapshotNameKey, cleanSnapshotKey,
83104
snapshotRepository);
84105
CleanupSnapshotStep cleanupSnapshotStep = new CleanupSnapshotStep(cleanSnapshotKey, createSnapshotKey, client);
@@ -108,9 +129,25 @@ public List<Step> toSteps(Client client, String phase, StepKey nextStepKey) {
108129
SwapAliasesAndDeleteSourceIndexStep swapAliasesAndDeleteSourceIndexStep = new SwapAliasesAndDeleteSourceIndexStep(swapAliasesKey,
109130
null, client, RESTORED_INDEX_PREFIX);
110131

111-
return Arrays.asList(checkNoWriteIndexStep, waitForNoFollowersStep, generateSnapshotNameStep, cleanupSnapshotStep,
112-
createSnapshotBranchingStep, mountSnapshotStep, waitForGreenIndexHealthStep, copyMetadataStep, copySettingsStep,
113-
isDataStreamBranchingStep, replaceDataStreamBackingIndex, deleteSourceIndexStep, swapAliasesAndDeleteSourceIndexStep);
132+
List<Step> steps = new ArrayList<>();
133+
steps.add(checkNoWriteIndexStep);
134+
steps.add(waitForNoFollowersStep);
135+
if (forceMergeIndex) {
136+
steps.add(forceMergeStep);
137+
steps.add(segmentCountStep);
138+
}
139+
steps.add(generateSnapshotNameStep);
140+
steps.add(cleanupSnapshotStep);
141+
steps.add(createSnapshotBranchingStep);
142+
steps.add(mountSnapshotStep);
143+
steps.add(waitForGreenIndexHealthStep);
144+
steps.add(copyMetadataStep);
145+
steps.add(copySettingsStep);
146+
steps.add(isDataStreamBranchingStep);
147+
steps.add(replaceDataStreamBackingIndex);
148+
steps.add(deleteSourceIndexStep);
149+
steps.add(swapAliasesAndDeleteSourceIndexStep);
150+
return steps;
114151
}
115152

116153
@Override
@@ -126,12 +163,16 @@ public String getWriteableName() {
126163
@Override
127164
public void writeTo(StreamOutput out) throws IOException {
128165
out.writeString(snapshotRepository);
166+
if (out.getVersion().onOrAfter(Version.V_7_10_0)) {
167+
out.writeBoolean(forceMergeIndex);
168+
}
129169
}
130170

131171
@Override
132172
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
133173
builder.startObject();
134174
builder.field(SNAPSHOT_REPOSITORY.getPreferredName(), snapshotRepository);
175+
builder.field(FORCE_MERGE_INDEX.getPreferredName(), forceMergeIndex);
135176
builder.endObject();
136177
return builder;
137178
}

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/SegmentCountStep.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ public void evaluateCondition(Metadata metadata, Index index, Listener listener,
5757
if (idxSegments == null || (response.getShardFailures() != null && response.getShardFailures().length > 0)) {
5858
final DefaultShardOperationFailedException[] failures = response.getShardFailures();
5959
logger.info("[{}] retrieval of segment counts after force merge did not succeed, " +
60-
"there were {} shard failures. " +
61-
"failures: {}",
60+
"there were {} shard failures. failures: {}",
6261
index.getName(),
6362
response.getFailedShards(),
6463
failures == null ? "n/a" : Strings.collectionToDelimitedString(Arrays.stream(failures)

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/SearchableSnapshotActionTests.java

Lines changed: 64 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -20,42 +20,73 @@ public class SearchableSnapshotActionTests extends AbstractActionTestCase<Search
2020
@Override
2121
public void testToSteps() {
2222
String phase = randomAlphaOfLengthBetween(1, 10);
23-
StepKey expectedFirstStep = new StepKey(phase, NAME, CheckNotDataStreamWriteIndexStep.NAME);
24-
StepKey expectedSecondStep = new StepKey(phase, NAME, WaitForNoFollowersStep.NAME);
25-
StepKey expectedThirdStep = new StepKey(phase, NAME, GenerateSnapshotNameStep.NAME);
26-
StepKey expectedFourthStep = new StepKey(phase, NAME, CleanupSnapshotStep.NAME);
27-
StepKey expectedFifthStep = new StepKey(phase, NAME, CreateSnapshotStep.NAME);
28-
StepKey expectedSixthStep = new StepKey(phase, NAME, MountSnapshotStep.NAME);
29-
StepKey expectedSeventhStep = new StepKey(phase, NAME, WaitForIndexColorStep.NAME);
30-
StepKey expectedEighthStep = new StepKey(phase, NAME, CopyExecutionStateStep.NAME);
31-
StepKey expectedNinthStep = new StepKey(phase, NAME, CopySettingsStep.NAME);
32-
StepKey expectedTenthStep = new StepKey(phase, NAME, SearchableSnapshotAction.CONDITIONAL_DATASTREAM_CHECK_KEY);
33-
StepKey expectedElevenStep = new StepKey(phase, NAME, ReplaceDataStreamBackingIndexStep.NAME);
34-
StepKey expectedTwelveStep = new StepKey(phase, NAME, DeleteStep.NAME);
35-
StepKey expectedThirteenStep = new StepKey(phase, NAME, SwapAliasesAndDeleteSourceIndexStep.NAME);
36-
3723
SearchableSnapshotAction action = createTestInstance();
3824
StepKey nextStepKey = new StepKey(phase, randomAlphaOfLengthBetween(1, 5), randomAlphaOfLengthBetween(1, 5));
3925

4026
List<Step> steps = action.toSteps(null, phase, nextStepKey);
41-
assertThat(steps.size(), is(13));
42-
43-
assertThat(steps.get(0).getKey(), is(expectedFirstStep));
44-
assertThat(steps.get(1).getKey(), is(expectedSecondStep));
45-
assertThat(steps.get(2).getKey(), is(expectedThirdStep));
46-
assertThat(steps.get(3).getKey(), is(expectedFourthStep));
47-
assertThat(steps.get(4).getKey(), is(expectedFifthStep));
48-
assertThat(steps.get(5).getKey(), is(expectedSixthStep));
49-
assertThat(steps.get(6).getKey(), is(expectedSeventhStep));
50-
assertThat(steps.get(7).getKey(), is(expectedEighthStep));
51-
assertThat(steps.get(8).getKey(), is(expectedNinthStep));
52-
assertThat(steps.get(9).getKey(), is(expectedTenthStep));
53-
assertThat(steps.get(10).getKey(), is(expectedElevenStep));
54-
assertThat(steps.get(11).getKey(), is(expectedTwelveStep));
55-
assertThat(steps.get(12).getKey(), is(expectedThirteenStep));
56-
57-
AsyncActionBranchingStep branchStep = (AsyncActionBranchingStep) steps.get(4);
58-
assertThat(branchStep.getNextKeyOnIncompleteResponse(), is(expectedFourthStep));
27+
assertThat(steps.size(), is(action.isForceMergeIndex() ? 15 : 13));
28+
29+
List<StepKey> expectedSteps = action.isForceMergeIndex() ? expectedStepKeysWithForceMerge(phase) :
30+
expectedStepKeysNoForceMerge(phase);
31+
32+
assertThat(steps.get(0).getKey(), is(expectedSteps.get(0)));
33+
assertThat(steps.get(1).getKey(), is(expectedSteps.get(1)));
34+
assertThat(steps.get(2).getKey(), is(expectedSteps.get(2)));
35+
assertThat(steps.get(3).getKey(), is(expectedSteps.get(3)));
36+
assertThat(steps.get(4).getKey(), is(expectedSteps.get(4)));
37+
assertThat(steps.get(5).getKey(), is(expectedSteps.get(5)));
38+
assertThat(steps.get(6).getKey(), is(expectedSteps.get(6)));
39+
assertThat(steps.get(7).getKey(), is(expectedSteps.get(7)));
40+
assertThat(steps.get(8).getKey(), is(expectedSteps.get(8)));
41+
assertThat(steps.get(9).getKey(), is(expectedSteps.get(9)));
42+
assertThat(steps.get(10).getKey(), is(expectedSteps.get(10)));
43+
assertThat(steps.get(11).getKey(), is(expectedSteps.get(11)));
44+
assertThat(steps.get(12).getKey(), is(expectedSteps.get(12)));
45+
46+
if (action.isForceMergeIndex()) {
47+
assertThat(steps.get(13).getKey(), is(expectedSteps.get(13)));
48+
AsyncActionBranchingStep branchStep = (AsyncActionBranchingStep) steps.get(6);
49+
assertThat(branchStep.getNextKeyOnIncompleteResponse(), is(expectedSteps.get(5)));
50+
} else {
51+
AsyncActionBranchingStep branchStep = (AsyncActionBranchingStep) steps.get(4);
52+
assertThat(branchStep.getNextKeyOnIncompleteResponse(), is(expectedSteps.get(3)));
53+
}
54+
}
55+
56+
private List<StepKey> expectedStepKeysWithForceMerge(String phase) {
57+
return org.elasticsearch.common.collect.List.of(
58+
new StepKey(phase, NAME, CheckNotDataStreamWriteIndexStep.NAME),
59+
new StepKey(phase, NAME, WaitForNoFollowersStep.NAME),
60+
new StepKey(phase, NAME, ForceMergeStep.NAME),
61+
new StepKey(phase, NAME, SegmentCountStep.NAME),
62+
new StepKey(phase, NAME, GenerateSnapshotNameStep.NAME),
63+
new StepKey(phase, NAME, CleanupSnapshotStep.NAME),
64+
new StepKey(phase, NAME, CreateSnapshotStep.NAME),
65+
new StepKey(phase, NAME, MountSnapshotStep.NAME),
66+
new StepKey(phase, NAME, WaitForIndexColorStep.NAME),
67+
new StepKey(phase, NAME, CopyExecutionStateStep.NAME),
68+
new StepKey(phase, NAME, CopySettingsStep.NAME),
69+
new StepKey(phase, NAME, SearchableSnapshotAction.CONDITIONAL_DATASTREAM_CHECK_KEY),
70+
new StepKey(phase, NAME, ReplaceDataStreamBackingIndexStep.NAME),
71+
new StepKey(phase, NAME, DeleteStep.NAME),
72+
new StepKey(phase, NAME, SwapAliasesAndDeleteSourceIndexStep.NAME));
73+
}
74+
75+
private List<StepKey> expectedStepKeysNoForceMerge(String phase) {
76+
return org.elasticsearch.common.collect.List.of(
77+
new StepKey(phase, NAME, CheckNotDataStreamWriteIndexStep.NAME),
78+
new StepKey(phase, NAME, WaitForNoFollowersStep.NAME),
79+
new StepKey(phase, NAME, GenerateSnapshotNameStep.NAME),
80+
new StepKey(phase, NAME, CleanupSnapshotStep.NAME),
81+
new StepKey(phase, NAME, CreateSnapshotStep.NAME),
82+
new StepKey(phase, NAME, MountSnapshotStep.NAME),
83+
new StepKey(phase, NAME, WaitForIndexColorStep.NAME),
84+
new StepKey(phase, NAME, CopyExecutionStateStep.NAME),
85+
new StepKey(phase, NAME, CopySettingsStep.NAME),
86+
new StepKey(phase, NAME, SearchableSnapshotAction.CONDITIONAL_DATASTREAM_CHECK_KEY),
87+
new StepKey(phase, NAME, ReplaceDataStreamBackingIndexStep.NAME),
88+
new StepKey(phase, NAME, DeleteStep.NAME),
89+
new StepKey(phase, NAME, SwapAliasesAndDeleteSourceIndexStep.NAME));
5990
}
6091

6192
@Override
@@ -79,6 +110,6 @@ protected SearchableSnapshotAction mutateInstance(SearchableSnapshotAction insta
79110
}
80111

81112
static SearchableSnapshotAction randomInstance() {
82-
return new SearchableSnapshotAction(randomAlphaOfLengthBetween(5, 10));
113+
return new SearchableSnapshotAction(randomAlphaOfLengthBetween(5, 10), randomBoolean());
83114
}
84115
}

x-pack/plugin/ilm/qa/multi-node/src/test/java/org/elasticsearch/xpack/TimeSeriesRestDriver.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.elasticsearch.client.RestClient;
1616
import org.elasticsearch.cluster.metadata.Template;
1717
import org.elasticsearch.common.Strings;
18+
import org.elasticsearch.common.settings.Settings;
1819
import org.elasticsearch.common.unit.TimeValue;
1920
import org.elasticsearch.common.xcontent.ToXContent;
2021
import org.elasticsearch.common.xcontent.XContentBuilder;
@@ -36,12 +37,15 @@
3637
import java.io.InputStream;
3738
import java.util.Collections;
3839
import java.util.HashMap;
40+
import java.util.List;
3941
import java.util.Locale;
4042
import java.util.Map;
4143

4244
import static java.util.Collections.singletonMap;
4345
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
4446
import static org.elasticsearch.test.ESTestCase.randomAlphaOfLengthBetween;
47+
import static org.elasticsearch.test.ESTestCase.randomBoolean;
48+
import static org.elasticsearch.test.rest.ESRestTestCase.ensureGreen;
4549

4650
/**
4751
* This class provides the operational REST functions needed to control an ILM time series lifecycle.
@@ -204,4 +208,36 @@ public static Map<String, Object> getOnlyIndexSettings(RestClient client, String
204208
}
205209
}
206210

211+
public static void createIndexWithSettings(RestClient client, String index, String alias, Settings.Builder settings)
212+
throws IOException {
213+
createIndexWithSettings(client, index, alias, settings, randomBoolean());
214+
}
215+
216+
public static void createIndexWithSettings(RestClient client, String index, String alias, Settings.Builder settings,
217+
boolean useWriteIndex) throws IOException {
218+
Request request = new Request("PUT", "/" + index);
219+
220+
String writeIndexSnippet = "";
221+
if (useWriteIndex) {
222+
writeIndexSnippet = "\"is_write_index\": true";
223+
}
224+
request.setJsonEntity("{\n \"settings\": " + Strings.toString(settings.build())
225+
+ ", \"aliases\" : { \"" + alias + "\": { " + writeIndexSnippet + " } } }");
226+
client.performRequest(request);
227+
// wait for the shards to initialize
228+
ensureGreen(index);
229+
}
230+
231+
@SuppressWarnings("unchecked")
232+
public static Integer getNumberOfSegments(RestClient client, String index) throws IOException {
233+
Response response = client.performRequest(new Request("GET", index + "/_segments"));
234+
XContentType entityContentType = XContentType.fromMediaTypeOrFormat(response.getEntity().getContentType().getValue());
235+
Map<String, Object> responseEntity = XContentHelper.convertToMap(entityContentType.xContent(),
236+
response.getEntity().getContent(), false);
237+
responseEntity = (Map<String, Object>) responseEntity.get("indices");
238+
responseEntity = (Map<String, Object>) responseEntity.get(index);
239+
responseEntity = (Map<String, Object>) responseEntity.get("shards");
240+
List<Map<String, Object>> shards = (List<Map<String, Object>>) responseEntity.get("0");
241+
return (Integer) shards.get(0).get("num_search_segments");
242+
}
207243
}

x-pack/plugin/ilm/qa/multi-node/src/test/java/org/elasticsearch/xpack/ilm/TimeSeriesDataStreamsIT.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,10 +223,10 @@ public void testGetDataStreamReturnsILMPolicy() throws Exception {
223223
}
224224

225225
private static Template getTemplate(String policyName) throws IOException {
226-
return new Template(getLifcycleSettings(policyName), null, null);
226+
return new Template(getLifecycleSettings(policyName), null, null);
227227
}
228228

229-
private static Settings getLifcycleSettings(String policyName) {
229+
private static Settings getLifecycleSettings(String policyName) {
230230
return Settings.builder()
231231
.put(LifecycleSettings.LIFECYCLE_NAME, policyName)
232232
.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 3)

0 commit comments

Comments
 (0)