Skip to content

Commit b9f20e9

Browse files
authored
[TSDB] Add support for downsampling aggregate_metric_double fields (#90029)
his PR adds support for downsampling metric fields of type aggregate_metric_double, enabling the rollup-of-rollups functionality.
1 parent 56dd7c7 commit b9f20e9

File tree

16 files changed

+653
-239
lines changed

16 files changed

+653
-239
lines changed

x-pack/plugin/mapper-aggregate-metric/build.gradle

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,13 @@ apply plugin: 'elasticsearch.internal-es-plugin'
1313

1414
esplugin {
1515
name 'x-pack-aggregate-metric'
16-
description 'Module for the aggregate_metric field type, which allows pre-aggregated fields to be stored a single field.'
16+
description 'Module for the aggregate_metric_double field type, which allows pre-aggregated fields to be stored as a single field'
1717
classname 'org.elasticsearch.xpack.aggregatemetric.AggregateMetricMapperPlugin'
1818
extendedPlugins = ['x-pack-core']
1919
}
2020
archivesBaseName = 'x-pack-aggregate-metric'
2121

2222
dependencies {
23-
compileOnly project(":server")
24-
2523
compileOnly project(path: xpackModule('core'))
2624
testImplementation(testArtifact(project(xpackModule('core'))))
2725
}

x-pack/plugin/mapper-aggregate-metric/src/main/java/org/elasticsearch/xpack/aggregatemetric/AggregateMetricMapperPlugin.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.elasticsearch.action.ActionResponse;
1212
import org.elasticsearch.index.mapper.Mapper;
1313
import org.elasticsearch.plugins.ActionPlugin;
14+
import org.elasticsearch.plugins.ExtensiblePlugin;
1415
import org.elasticsearch.plugins.MapperPlugin;
1516
import org.elasticsearch.plugins.Plugin;
1617
import org.elasticsearch.plugins.SearchPlugin;
@@ -27,7 +28,7 @@
2728

2829
import static java.util.Collections.singletonMap;
2930

30-
public class AggregateMetricMapperPlugin extends Plugin implements MapperPlugin, ActionPlugin, SearchPlugin {
31+
public class AggregateMetricMapperPlugin extends Plugin implements MapperPlugin, ActionPlugin, SearchPlugin, ExtensiblePlugin {
3132

3233
@Override
3334
public Map<String, Mapper.TypeParser> getMappers() {

x-pack/plugin/mapper-aggregate-metric/src/main/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateDoubleMetricFieldMapper.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,10 @@ private void setMetricFields(EnumMap<Metric, NumberFieldMapper.NumberFieldType>
307307
this.metricFields = metricFields;
308308
}
309309

310+
public Map<Metric, NumberFieldMapper.NumberFieldType> getMetricFields() {
311+
return Collections.unmodifiableMap(metricFields);
312+
}
313+
310314
public void addMetricField(Metric m, NumberFieldMapper.NumberFieldType subfield) {
311315
if (metricFields == null) {
312316
metricFields = new EnumMap<>(AggregateDoubleMetricFieldMapper.Metric.class);

x-pack/plugin/rollup/build.gradle

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,18 @@
1-
import org.elasticsearch.gradle.internal.info.BuildParams
2-
31
apply plugin: 'elasticsearch.internal-es-plugin'
42
esplugin {
53
name 'x-pack-rollup'
64
description 'Elasticsearch Expanded Pack Plugin - Rollup'
75
classname 'org.elasticsearch.xpack.rollup.Rollup'
8-
extendedPlugins = ['x-pack-core']
6+
extendedPlugins = ['x-pack-aggregate-metric']
97
}
108

119
archivesBaseName = 'x-pack-rollup'
1210

1311
dependencies {
14-
compileOnly project(":server")
1512
compileOnly project(path: xpackModule('core'))
16-
compileOnly project(path: xpackModule('analytics'))
17-
compileOnly project(path: xpackModule('mapper-aggregate-metric'))
18-
compileOnly project(path: xpackModule('ilm'))
1913
compileOnly project(':modules:data-streams')
14+
compileOnly project(path: xpackModule('ilm'))
15+
compileOnly project(path: xpackModule('mapper-aggregate-metric'))
2016
testImplementation(testArtifact(project(xpackModule('core'))))
2117
}
2218

x-pack/plugin/rollup/qa/rest/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ dependencies {
1717

1818
restResources {
1919
restApi {
20-
include '_common', 'bulk', 'cluster', 'indices', 'search', 'downsample'
20+
include '_common', 'bulk', 'cluster', 'indices', 'search'
2121
}
2222
}
2323

x-pack/plugin/rollup/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/rollup/10_basic.yml

Lines changed: 162 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ setup:
8787
index.blocks.write: true
8888

8989
---
90-
"Rollup index":
90+
"Downsample index":
9191
- skip:
9292
version: " - 8.4.99"
9393
reason: "rollup renamed to downsample in 8.5.0"
@@ -141,6 +141,24 @@ setup:
141141
- match: { rollup-test.settings.index.number_of_shards: "1" }
142142
- match: { rollup-test.settings.index.number_of_replicas: "0" }
143143

144+
# Assert rollup index mapping
145+
- do:
146+
indices.get_mapping:
147+
index: rollup-test
148+
149+
- match: { [email protected]: date }
150+
- match: { [email protected]_interval: 1h }
151+
- match: { [email protected]_zone: UTC }
152+
- match: { rollup-test.mappings.properties.k8s.properties.pod.properties.multi-gauge.type: aggregate_metric_double }
153+
- match: { rollup-test.mappings.properties.k8s.properties.pod.properties.multi-gauge.metrics: [ "min", "max", "sum", "value_count" ] }
154+
- match: { rollup-test.mappings.properties.k8s.properties.pod.properties.multi-gauge.default_metric: max }
155+
- match: { rollup-test.mappings.properties.k8s.properties.pod.properties.multi-gauge.time_series_metric: gauge }
156+
- match: { rollup-test.mappings.properties.k8s.properties.pod.properties.multi-counter.type: long }
157+
- match: { rollup-test.mappings.properties.k8s.properties.pod.properties.multi-counter.time_series_metric: counter }
158+
- match: { rollup-test.mappings.properties.k8s.properties.pod.properties.uid.type: keyword }
159+
- match: { rollup-test.mappings.properties.k8s.properties.pod.properties.uid.time_series_dimension: true }
160+
161+
144162
# Assert source index has not been deleted
145163
- do:
146164
indices.get:
@@ -156,7 +174,7 @@ setup:
156174
- match: { indices.rollup-test.shards.0.0.num_search_segments: 1}
157175

158176
---
159-
"Rollup non-existing index":
177+
"Downsample non-existing index":
160178
- skip:
161179
version: " - 8.4.99"
162180
reason: "rollup renamed to downsample in 8.5.0"
@@ -172,7 +190,7 @@ setup:
172190
}
173191
174192
---
175-
"Rollup to existing rollup index":
193+
"Downsample to existing index":
176194
- skip:
177195
version: " - 8.4.99"
178196
reason: "rollup renamed to downsample in 8.5.0"
@@ -192,7 +210,7 @@ setup:
192210
}
193211
194212
---
195-
"Rollup not time_series index":
213+
"Downsample not time_series index":
196214
- skip:
197215
version: " - 8.4.99"
198216
reason: "rollup renamed to downsample in 8.5.0"
@@ -213,7 +231,7 @@ setup:
213231
214232
215233
---
216-
"Rollup no metric index":
234+
"Downsample no metric index":
217235
- skip:
218236
version: " - 8.4.99"
219237
reason: "rollup renamed to downsample in 8.5.0"
@@ -254,3 +272,142 @@ setup:
254272
{
255273
"fixed_interval": "1h"
256274
}
275+
276+
---
277+
"Downsample a downsampled index":
278+
- skip:
279+
version: " - 8.4.99"
280+
reason: "Rollup of rollups introduced in 8.5.0"
281+
282+
- do:
283+
indices.downsample:
284+
index: test
285+
target_index: rollup-test
286+
body: >
287+
{
288+
"fixed_interval": "1h"
289+
}
290+
- is_true: acknowledged
291+
292+
- do:
293+
indices.downsample:
294+
index: rollup-test
295+
target_index: rollup-test-2
296+
body: >
297+
{
298+
"fixed_interval": "2h"
299+
}
300+
- is_true: acknowledged
301+
302+
303+
# Assert rollup index mapping
304+
- do:
305+
indices.get_mapping:
306+
index: rollup-test-2
307+
308+
- match: { [email protected]: date }
309+
- match: { [email protected]_interval: 2h }
310+
- match: { [email protected]_zone: UTC }
311+
- match: { rollup-test-2.mappings.properties.k8s.properties.pod.properties.multi-gauge.type: aggregate_metric_double }
312+
- match: { rollup-test-2.mappings.properties.k8s.properties.pod.properties.multi-gauge.metrics: [ "min", "max", "sum", "value_count" ] }
313+
- match: { rollup-test-2.mappings.properties.k8s.properties.pod.properties.multi-gauge.default_metric: max }
314+
- match: { rollup-test-2.mappings.properties.k8s.properties.pod.properties.multi-gauge.time_series_metric: gauge }
315+
- match: { rollup-test-2.mappings.properties.k8s.properties.pod.properties.multi-counter.type: long }
316+
- match: { rollup-test-2.mappings.properties.k8s.properties.pod.properties.multi-counter.time_series_metric: counter }
317+
- match: { rollup-test-2.mappings.properties.k8s.properties.pod.properties.uid.type: keyword }
318+
- match: { rollup-test-2.mappings.properties.k8s.properties.pod.properties.uid.time_series_dimension: true }
319+
- match: { rollup-test-2.mappings.properties.k8s.properties.pod.properties.network.properties.tx.type: aggregate_metric_double }
320+
- match: { rollup-test-2.mappings.properties.k8s.properties.pod.properties.network.properties.tx.metrics: [ "min", "max", "sum", "value_count" ] }
321+
- match: { rollup-test-2.mappings.properties.k8s.properties.pod.properties.network.properties.tx.default_metric: max }
322+
- match: { rollup-test-2.mappings.properties.k8s.properties.pod.properties.network.properties.tx.time_series_metric: gauge }
323+
324+
- do:
325+
search:
326+
index: rollup-test-2
327+
body:
328+
sort: [ "_tsid", "@timestamp" ]
329+
330+
- length: { hits.hits: 3 }
331+
- match: { hits.hits.0._source._doc_count: 2 }
332+
- match: { hits.hits.0._source.k8s\.pod\.uid: 947e4ced-1786-4e53-9e0c-5c447e959507 }
333+
- match: { hits.hits.0._source.metricset: pod }
334+
- match: { hits.hits.0._source.@timestamp: 2021-04-28T18:00:00.000Z }
335+
- match: { hits.hits.0._source.k8s\.pod\.multi-counter: 21 }
336+
- match: { hits.hits.0._source.k8s\.pod\.multi-gauge.min: 90 }
337+
- match: { hits.hits.0._source.k8s\.pod\.multi-gauge.max: 200 }
338+
- match: { hits.hits.0._source.k8s\.pod\.multi-gauge.sum: 726 }
339+
- match: { hits.hits.0._source.k8s\.pod\.multi-gauge.value_count: 6 }
340+
- match: { hits.hits.0._source.k8s\.pod\.network\.tx.min: 2001818691 }
341+
- match: { hits.hits.0._source.k8s\.pod\.network\.tx.max: 2005177954 }
342+
- match: { hits.hits.0._source.k8s\.pod\.network\.tx.value_count: 2 }
343+
- match: { hits.hits.0._source.k8s\.pod\.ip: "10.10.55.26" }
344+
- match: { hits.hits.0._source.k8s\.pod\.created_at: "2021-04-28T19:35:00.000Z" }
345+
- match: { hits.hits.0._source.k8s\.pod\.number_of_containers: 2 }
346+
- match: { hits.hits.0._source.k8s\.pod\.tags: [ "backend", "prod", "us-west1" ] }
347+
- match: { hits.hits.0._source.k8s\.pod\.values: [ 1, 1, 3 ] }
348+
349+
- match: { hits.hits.1._source.k8s\.pod\.uid: 947e4ced-1786-4e53-9e0c-5c447e959507 }
350+
- match: { hits.hits.1._source.metricset: pod }
351+
- match: { hits.hits.1._source.@timestamp: 2021-04-28T20:00:00.000Z }
352+
- match: { hits.hits.1._source._doc_count: 2 }
353+
354+
- match: { hits.hits.2._source.k8s\.pod\.uid: df3145b3-0563-4d3b-a0f7-897eb2876ea9 }
355+
- match: { hits.hits.2._source.metricset: pod }
356+
- match: { hits.hits.2._source.@timestamp: 2021-04-28T18:00:00.000Z }
357+
- match: { hits.hits.2._source._doc_count: 4 }
358+
359+
- do:
360+
indices.downsample:
361+
index: rollup-test
362+
target_index: rollup-test-3
363+
body: >
364+
{
365+
"fixed_interval": "180m"
366+
}
367+
- is_true: acknowledged
368+
369+
---
370+
"Downsample a downsampled index with wrong intervals":
371+
- skip:
372+
version: " - 8.4.99"
373+
reason: "Rollup of rollups introduced in 8.5.0"
374+
375+
- do:
376+
indices.downsample:
377+
index: test
378+
target_index: rollup-test
379+
body: >
380+
{
381+
"fixed_interval": "1h"
382+
}
383+
- is_true: acknowledged
384+
385+
- do:
386+
catch: /Downsampling interval \[1h\] must be greater than the the source index interval \[1h\]/
387+
indices.downsample:
388+
index: rollup-test
389+
target_index: rollup-test-2
390+
body: >
391+
{
392+
"fixed_interval": "1h"
393+
}
394+
395+
- do:
396+
catch: /Downsampling interval \[30m\] must be greater than the the source index interval \[1h\]/
397+
indices.downsample:
398+
index: rollup-test
399+
target_index: rollup-test-2
400+
body: >
401+
{
402+
"fixed_interval": "30m"
403+
}
404+
405+
- do:
406+
catch: /Downsampling interval \[90m\] must be a multiple of the source index interval \[1h\]/
407+
indices.downsample:
408+
index: rollup-test
409+
target_index: rollup-test-2
410+
body: >
411+
{
412+
"fixed_interval": "90m"
413+
}

x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/downsample/AbstractRollupFieldProducer.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77

88
package org.elasticsearch.xpack.downsample;
99

10+
import org.elasticsearch.xcontent.XContentBuilder;
11+
12+
import java.io.IOException;
13+
1014
/**
1115
* Base class for classes that read metric and label fields.
1216
*/
@@ -22,9 +26,11 @@ abstract class AbstractRollupFieldProducer<T> {
2226

2327
/**
2428
* Collect a value for the field applying the specific subclass collection strategy.
29+
*
30+
* @param field the name of the field to collect
2531
* @param value the value to collect.
2632
*/
27-
public abstract void collect(T value);
33+
public abstract void collect(String field, T value);
2834

2935
/**
3036
* @return the name of the field.
@@ -34,14 +40,14 @@ public String name() {
3440
}
3541

3642
/**
37-
* @return the value of the field.
43+
* Resets the producer to an empty value.
3844
*/
39-
public abstract Object value();
45+
public abstract void reset();
4046

4147
/**
42-
* Resets the collected value to the specific subclass reset value.
48+
* Serialize the downsampled value of the field.
4349
*/
44-
public abstract void reset();
50+
public abstract void write(XContentBuilder builder) throws IOException;
4551

4652
/**
4753
* @return true if the field has not collected any value.

0 commit comments

Comments
 (0)