Skip to content

Commit 3fb873b

Browse files
committed
Add index setting that disables the index.dimensions based routing and _tsid creation strategy
1 parent fe1cf4f commit 3fb873b

File tree

7 files changed

+96
-28
lines changed

7 files changed

+96
-28
lines changed

docs/reference/elasticsearch/index-settings/serverless.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ This page lists the {{es}} index settings available in {{serverless-full}} proje
1313
### General settings
1414

1515
* [`index.codec`](./index-modules.md#index-codec)
16-
* [`index.default_pipeline`](./index-modules.md#index-default-pipeline)
16+
* [`index.default_pipeline`](./index-modules.md#index-default-pipeline)
1717
* [`index.dense_vector.hnsw_filter_heuristic`](./index-modules.md#index-dense-vector-hnsw-filter-heuristic)
18-
* [`index.final_pipeline`](./index-modules.md#index-final-pipeline)
18+
* [`index.final_pipeline`](./index-modules.md#index-final-pipeline)
1919
* [`index.hidden`](./index-modules.md#index-hidden)
2020
* [`index.mode`](./index-modules.md#index-mode-setting)
21-
* [`index.query.default_field`](./index-modules.md#index-query-default-field)
22-
* [`index.refresh_interval`](./index-modules.md#index-refresh-interval-setting)
21+
* [`index.query.default_field`](./index-modules.md#index-query-default-field)
22+
* [`index.refresh_interval`](./index-modules.md#index-refresh-interval-setting)
2323

2424
### Index sorting settings
2525

@@ -30,10 +30,10 @@ This page lists the {{es}} index settings available in {{serverless-full}} proje
3030

3131
### Index blocks settings
3232

33-
* [`index.blocks.read_only`](./index-block.md#index-blocks-read-only)
34-
* [`index.blocks.read`](./index-block.md#index-blocks-read)
35-
* [`index.blocks.write`](./index-block.md#index-blocks-write)
36-
* [`index.blocks.metadata`](./index-block.md#index-blocks-metadata)
33+
* [`index.blocks.read_only`](./index-block.md#index-blocks-read-only)
34+
* [`index.blocks.read`](./index-block.md#index-blocks-read)
35+
* [`index.blocks.write`](./index-block.md#index-blocks-write)
36+
* [`index.blocks.metadata`](./index-block.md#index-blocks-metadata)
3737

3838
### Field and mapping related settings
3939

@@ -56,8 +56,9 @@ This page lists the {{es}} index settings available in {{serverless-full}} proje
5656
* [`index.look_ahead_time`](./time-series.md#index-look-ahead-time)
5757
* [`index.look_back_time`](./time-series.md#index-look-back-time)
5858
* [`index.routing_path`](./time-series.md#index-routing-path)
59+
* [`index.index_dimensions_tsid_strategy_enabled`](./time-series.md#index-dimensions-tsid-strategy-enabled)
5960

6061
### Similarity and analyzers
6162

6263
* [`index.similarity.*`](../mapping-reference/similarity.md)
63-
* [`index.analysis.*`](../mapping-reference/analyzer.md)
64+
* [`index.analysis.*`](../mapping-reference/analyzer.md)

docs/reference/elasticsearch/index-settings/time-series.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,30 @@ $$$index-look-back-time$$$
4444
: (Static, [time units](/reference/elasticsearch/rest-apis/api-conventions.md#time-units)) Interval used to calculate the `index.time_series.start_time` for a TSDS’s first backing index when a tsdb data stream is created. Defaults to `2h` (2 hours). Accepts `1m` (one minute) to `7d` (seven days). Only indices with an `index.mode` of `time_series` support this setting. For more information, refer to [Look-back time](docs-content://manage-data/data-store/data-streams/time-series-data-stream-tsds.md#tsds-look-back-time).
4545

4646
$$$index-routing-path$$$ `index.routing_path` {applies_to}`serverless: all`
47-
: (Static, string or array of strings) Plain `keyword` fields used to route documents in a TSDS to index shards. Supports wildcards (`*`). Only indices with an `index.mode` of `time_series` support this setting. Defaults to an empty list, except for data streams then defaults to the list of [dimension fields](docs-content://manage-data/data-store/data-streams/time-series-data-stream-tsds.md#time-series-dimension) with a `time_series_dimension` value of `true` defined in your component and index templates. For more information, refer to [Dimension-based routing](docs-content://manage-data/data-store/data-streams/time-series-data-stream-tsds.md#dimension-based-routing).
47+
: (Static, string or array of strings) Time series dimension fields used to route documents in a TSDS to index shards. Supports wildcards (`*`). Only indices with an `index.mode` of `time_series` support this setting. Defaults to an empty list, except for data streams then defaults to the list of [dimension fields](docs-content://manage-data/data-store/data-streams/time-series-data-stream-tsds.md#time-series-dimension) with a `time_series_dimension` value of `true` defined in your component and index templates. For more information, refer to [Dimension-based routing](docs-content://manage-data/data-store/data-streams/time-series-data-stream-tsds.md#dimension-based-routing).
48+
49+
$$$index-dimensions-tsid-strategy-enabled$$$
50+
51+
`index.index_dimensions_tsid_strategy_enabled` {applies_to}`serverless: all`
52+
: (Static, boolean) Controls if the `_tsid` can be created using the `index.dimensions` index setting.
53+
This is an internal setting that will be automatically populated and updated for eligible time series data streams and is not user-configurable.
54+
This strategy offers an improved ingestion performance that avoids processing dimensions multiple times for the purposes of shard routing and creating the `_tsid`.
55+
When used, `index.routing_path` will not be set and shard routing uses the full `_tsid`,
56+
which can help to avoid shard hot-spotting.
57+
58+
: If set to `false`,
59+
or `index.routing_path` is configured manually,
60+
or in case the index isn't eligible (see below),
61+
shard routing will be based on the `index.routing_path` instead.
62+
The `_tsid` will then be created during document parsing rather than during shard routing.
63+
64+
: Defaults to `true`.
65+
66+
: This optimized `_tsid` creation strategy is only available for data streams and if there are no dynamic templates that set `time_series_dimension: true`.
67+
Trying to add such a dynamic template to existing backing indices after the fact will fail the update mapping request with the following message:
68+
```text
69+
Cannot add dynamic templates that define dimension fields on an existing index with index.dimensions. Please change the index template and roll over the data stream instead of modifying the mappings of the backing indices.
70+
```
4871

4972
$$$index-mapping-dimension-fields-limit$$$
5073

modules/data-streams/src/internalClusterTest/java/org/elasticsearch/datastreams/TSDBIndexingIT.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ public void testTsdbTemplatesNoKeywordFieldType() throws Exception {
333333
Settings.builder()
334334
.put("index.mode", "time_series")
335335
.put("index.routing_path", randomBoolean() ? null : "metricset")
336+
.put("index.index_dimensions_tsid_strategy_enabled", usually())
336337
.build(),
337338
new CompressedXContent(mappingTemplate),
338339
null
@@ -640,12 +641,16 @@ public void testReindexing() throws Exception {
640641
public void testAddDimensionToMapping() throws Exception {
641642
String dataStreamName = "my-ds";
642643
var putTemplateRequest = new TransportPutComposableIndexTemplateAction.Request("id");
644+
boolean indexDimensionsTsidStrategyEnabled = randomBoolean();
643645
putTemplateRequest.indexTemplate(
644646
ComposableIndexTemplate.builder()
645647
.indexPatterns(List.of(dataStreamName))
646648
.template(
647649
new Template(
648-
Settings.builder().put("index.mode", "time_series").build(),
650+
Settings.builder()
651+
.put("index.mode", "time_series")
652+
.put("index.index_dimensions_tsid_strategy_enabled", indexDimensionsTsidStrategyEnabled)
653+
.build(),
649654
new CompressedXContent(MAPPING_TEMPLATE),
650655
null
651656
)
@@ -662,8 +667,13 @@ public void testAddDimensionToMapping() throws Exception {
662667
"my-ds"
663668
);
664669
assertAcked(client().execute(CreateDataStreamAction.INSTANCE, createDsRequest));
665-
assertThat(getSetting(dataStreamName, IndexMetadata.INDEX_DIMENSIONS), equalTo(List.of("metricset")));
666-
assertThat(getSetting(dataStreamName, IndexMetadata.INDEX_ROUTING_PATH), empty());
670+
if (indexDimensionsTsidStrategyEnabled) {
671+
assertThat(getSetting(dataStreamName, IndexMetadata.INDEX_DIMENSIONS), equalTo(List.of("metricset")));
672+
assertThat(getSetting(dataStreamName, IndexMetadata.INDEX_ROUTING_PATH), empty());
673+
} else {
674+
assertThat(getSetting(dataStreamName, IndexMetadata.INDEX_DIMENSIONS), empty());
675+
assertThat(getSetting(dataStreamName, IndexMetadata.INDEX_ROUTING_PATH), equalTo(List.of("metricset")));
676+
}
667677

668678
// put mapping with k8s.pod.uid as another time series dimension
669679
var putMappingRequest = new PutMappingRequest(dataStreamName).source("""
@@ -677,8 +687,13 @@ public void testAddDimensionToMapping() throws Exception {
677687
}
678688
""", XContentType.JSON);
679689
assertAcked(client().execute(TransportPutMappingAction.TYPE, putMappingRequest).actionGet());
680-
assertThat(getSetting(dataStreamName, IndexMetadata.INDEX_DIMENSIONS), containsInAnyOrder("metricset", "k8s.pod.name"));
681-
assertThat(getSetting(dataStreamName, IndexMetadata.INDEX_ROUTING_PATH), empty());
690+
if (indexDimensionsTsidStrategyEnabled) {
691+
assertThat(getSetting(dataStreamName, IndexMetadata.INDEX_DIMENSIONS), containsInAnyOrder("metricset", "k8s.pod.name"));
692+
assertThat(getSetting(dataStreamName, IndexMetadata.INDEX_ROUTING_PATH), empty());
693+
} else {
694+
assertThat(getSetting(dataStreamName, IndexMetadata.INDEX_DIMENSIONS), empty());
695+
assertThat(getSetting(dataStreamName, IndexMetadata.INDEX_ROUTING_PATH), equalTo(List.of("metricset")));
696+
}
682697

683698
// put dynamic template defining time series dimensions
684699
// we don't support index.dimensions in that case

modules/data-streams/src/main/java/org/elasticsearch/datastreams/DataStreamIndexSettingsProvider.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,9 @@ public void provideAdditionalSettings(
130130
dimensions
131131
);
132132
if (dimensions.isEmpty() == false) {
133-
if (matchesAllDimensions && indexVersion.onOrAfter(IndexVersions.TSID_CREATED_DURING_ROUTING)) {
133+
if (matchesAllDimensions
134+
&& IndexMetadata.INDEX_DIMENSIONS_TSID_STRATEGY_ENABLED.get(indexTemplateAndCreateRequestSettings)
135+
&& indexVersion.onOrAfter(IndexVersions.TSID_CREATED_DURING_ROUTING)) {
134136
// Only set index.dimensions if the paths in the dimensions list match all potential dimension fields.
135137
// This is not the case e.g. if a dynamic template matches by match_mapping_type instead of path_match
136138
additionalSettings.putList(INDEX_DIMENSIONS.getKey(), dimensions);

modules/data-streams/src/test/java/org/elasticsearch/datastreams/DataStreamIndexSettingsProviderTests.java

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ public class DataStreamIndexSettingsProviderTests extends ESTestCase {
4949
private static final TimeValue DEFAULT_LOOK_AHEAD_TIME = TimeValue.timeValueMinutes(30); // default
5050

5151
DataStreamIndexSettingsProvider provider;
52-
private boolean indexDimensionsTsidOptimizationEnabled;
52+
private boolean indexDimensionsTsidStrategyEnabledSetting;
53+
private boolean expectedIndexDimensionsTsidOptimizationEnabled;
5354
private IndexVersion indexVersion;
5455

5556
@Before
@@ -60,7 +61,9 @@ public void setup() {
6061
indexVersion = randomBoolean()
6162
? IndexVersionUtils.randomPreviousCompatibleVersion(random(), IndexVersions.TSID_CREATED_DURING_ROUTING)
6263
: IndexVersionUtils.randomVersionBetween(random(), IndexVersions.TSID_CREATED_DURING_ROUTING, IndexVersion.current());
63-
indexDimensionsTsidOptimizationEnabled = indexVersion.onOrAfter(IndexVersions.TSID_CREATED_DURING_ROUTING);
64+
indexDimensionsTsidStrategyEnabledSetting = usually();
65+
expectedIndexDimensionsTsidOptimizationEnabled = indexDimensionsTsidStrategyEnabledSetting
66+
&& indexVersion.onOrAfter(IndexVersions.TSID_CREATED_DURING_ROUTING);
6467
}
6568

6669
public void testGetAdditionalIndexSettings() throws Exception {
@@ -114,12 +117,15 @@ public void testGetAdditionalIndexSettings() throws Exception {
114117
Settings result = additionalSettings.build();
115118
// The index.time_series.end_time setting requires index.mode to be set to time_series adding it here so that we read this setting:
116119
// (in production the index.mode setting is usually provided in an index or component template)
117-
result = builder().put(result).put("index.mode", "time_series").build();
118-
assertThat(result.size(), equalTo(4));
120+
result = builder().put(result)
121+
.put("index.mode", "time_series")
122+
.put("index.index_dimensions_tsid_strategy_enabled", indexDimensionsTsidStrategyEnabledSetting)
123+
.build();
124+
assertThat(result.size(), equalTo(5));
119125
assertThat(IndexSettings.MODE.get(result), equalTo(IndexMode.TIME_SERIES));
120126
assertThat(IndexSettings.TIME_SERIES_START_TIME.get(result), equalTo(now.minusMillis(DEFAULT_LOOK_BACK_TIME.getMillis())));
121127
assertThat(IndexSettings.TIME_SERIES_END_TIME.get(result), equalTo(now.plusMillis(DEFAULT_LOOK_AHEAD_TIME.getMillis())));
122-
if (indexDimensionsTsidOptimizationEnabled) {
128+
if (expectedIndexDimensionsTsidOptimizationEnabled) {
123129
assertThat(IndexMetadata.INDEX_DIMENSIONS.get(result), containsInAnyOrder("field3", "field4", "field5", "field6"));
124130
assertThat(IndexMetadata.INDEX_ROUTING_PATH.get(result), empty());
125131
} else {
@@ -243,12 +249,15 @@ public void testGetAdditionalIndexSettingsMappingsMerging() throws Exception {
243249
Settings result = additionalSettings.build();
244250
// The index.time_series.end_time setting requires index.mode to be set to time_series adding it here so that we read this setting:
245251
// (in production the index.mode setting is usually provided in an index or component template)
246-
result = builder().put(result).put("index.mode", "time_series").build();
247-
assertThat(result.size(), equalTo(4));
252+
result = builder().put(result)
253+
.put("index.mode", "time_series")
254+
.put("index.index_dimensions_tsid_strategy_enabled", indexDimensionsTsidStrategyEnabledSetting)
255+
.build();
256+
assertThat(result.size(), equalTo(5));
248257
assertThat(IndexSettings.MODE.get(result), equalTo(IndexMode.TIME_SERIES));
249258
assertThat(IndexSettings.TIME_SERIES_START_TIME.get(result), equalTo(now.minusMillis(DEFAULT_LOOK_BACK_TIME.getMillis())));
250259
assertThat(IndexSettings.TIME_SERIES_END_TIME.get(result), equalTo(now.plusMillis(DEFAULT_LOOK_AHEAD_TIME.getMillis())));
251-
if (indexDimensionsTsidOptimizationEnabled) {
260+
if (expectedIndexDimensionsTsidOptimizationEnabled) {
252261
assertThat(IndexMetadata.INDEX_DIMENSIONS.get(result), containsInAnyOrder("field1", "field3"));
253262
assertThat(IndexMetadata.INDEX_ROUTING_PATH.get(result), empty());
254263
} else {
@@ -719,7 +728,7 @@ public void testGenerateNonDimensionDynamicTemplate() throws Exception {
719728
assertThat(IndexSettings.MODE.get(result), equalTo(IndexMode.TIME_SERIES));
720729
assertThat(IndexSettings.TIME_SERIES_START_TIME.get(result), equalTo(now.minusMillis(DEFAULT_LOOK_BACK_TIME.getMillis())));
721730
assertThat(IndexSettings.TIME_SERIES_END_TIME.get(result), equalTo(now.plusMillis(DEFAULT_LOOK_AHEAD_TIME.getMillis())));
722-
if (indexDimensionsTsidOptimizationEnabled) {
731+
if (expectedIndexDimensionsTsidOptimizationEnabled) {
723732
assertThat(IndexMetadata.INDEX_DIMENSIONS.get(result), containsInAnyOrder("host.id"));
724733
assertThat(IndexMetadata.INDEX_ROUTING_PATH.get(result), empty());
725734
} else {
@@ -807,7 +816,7 @@ public void testGenerateRoutingPathFromPassThroughObject() throws Exception {
807816
assertThat(IndexSettings.MODE.get(result), equalTo(IndexMode.TIME_SERIES));
808817
assertThat(IndexSettings.TIME_SERIES_START_TIME.get(result), equalTo(now.minusMillis(DEFAULT_LOOK_BACK_TIME.getMillis())));
809818
assertThat(IndexSettings.TIME_SERIES_END_TIME.get(result), equalTo(now.plusMillis(DEFAULT_LOOK_AHEAD_TIME.getMillis())));
810-
if (indexDimensionsTsidOptimizationEnabled) {
819+
if (expectedIndexDimensionsTsidOptimizationEnabled) {
811820
assertThat(IndexMetadata.INDEX_DIMENSIONS.get(result), containsInAnyOrder("labels.*"));
812821
assertThat(IndexMetadata.INDEX_ROUTING_PATH.get(result), empty());
813822
} else {
@@ -971,7 +980,9 @@ public void testAddDynamicTemplate() throws Exception {
971980
private Settings generateTsdbSettings(String mapping, Instant now) throws IOException {
972981
ProjectMetadata projectMetadata = emptyProject();
973982
String dataStreamName = "logs-app1";
974-
Settings settings = Settings.EMPTY;
983+
Settings settings = Settings.builder()
984+
.put("index.index_dimensions_tsid_strategy_enabled", indexDimensionsTsidStrategyEnabledSetting)
985+
.build();
975986

976987
Settings.Builder additionalSettings = builder();
977988
provider.provideAdditionalSettings(

server/src/main/java/org/elasticsearch/cluster/metadata/IndexMetadata.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,22 @@ public Iterator<Setting<?>> settings() {
534534
"index.dimensions",
535535
Setting.Property.IndexScope,
536536
Property.Dynamic,
537-
Property.PrivateIndex
537+
Property.PrivateIndex,
538+
Property.ServerlessPublic
539+
);
540+
541+
/**
542+
* Allows to disable the {@link #INDEX_DIMENSIONS}-based tsid creation strategy on a per-index basis.
543+
* This can help to mitigate potential issues with that strategy.
544+
* For example, when using this strategy,
545+
* it's not allowed to add a dynamic template that defines dimension fields to existing backing indices of a time series data stream.
546+
*/
547+
public static final Setting<Boolean> INDEX_DIMENSIONS_TSID_STRATEGY_ENABLED = Setting.boolSetting(
548+
"index.index_dimensions_tsid_strategy_enabled",
549+
true,
550+
Setting.Property.IndexScope,
551+
Property.Final,
552+
Property.ServerlessPublic
538553
);
539554

540555
/**

server/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ public final class IndexScopedSettings extends AbstractScopedSettings {
224224
IndexSettings.MODE,
225225
IndexMetadata.INDEX_ROUTING_PATH,
226226
IndexMetadata.INDEX_DIMENSIONS,
227+
IndexMetadata.INDEX_DIMENSIONS_TSID_STRATEGY_ENABLED,
227228
IndexSettings.TIME_SERIES_START_TIME,
228229
IndexSettings.TIME_SERIES_END_TIME,
229230
IndexSettings.SEQ_NO_INDEX_OPTIONS_SETTING,

0 commit comments

Comments
 (0)