Skip to content

Commit b8993c3

Browse files
authored
[9.2] Fix multi fields in downsampling (#138869) (#139049)
* Fix multi fields in downsampling (#138869) (cherry picked from commit 5918605)
1 parent 071c803 commit b8993c3

File tree

23 files changed

+689
-183
lines changed

23 files changed

+689
-183
lines changed

docs/changelog/138869.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 138869
2+
summary: Fix multi fields in downsampling
3+
area: Downsampling
4+
type: bug
5+
issues: []

server/src/main/java/org/elasticsearch/action/admin/cluster/stats/MappingVisitor.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,22 @@ public final class MappingVisitor {
1717
private MappingVisitor() {}
1818

1919
public static void visitMapping(Map<String, ?> mapping, BiConsumer<String, Map<String, ?>> fieldMappingConsumer) {
20-
visitMapping(mapping, "", fieldMappingConsumer);
20+
visitMapping(mapping, "", fieldMappingConsumer, fieldMappingConsumer);
21+
}
22+
23+
public static void visitMapping(
24+
Map<String, ?> mapping,
25+
BiConsumer<String, Map<String, ?>> fieldMappingConsumer,
26+
final BiConsumer<String, Map<String, ?>> multiFieldsMappingConsumer
27+
) {
28+
visitMapping(mapping, "", fieldMappingConsumer, multiFieldsMappingConsumer);
2129
}
2230

2331
private static void visitMapping(
2432
final Map<String, ?> mapping,
2533
final String path,
26-
final BiConsumer<String, Map<String, ?>> fieldMappingConsumer
34+
final BiConsumer<String, Map<String, ?>> propertiesMappingConsumer,
35+
final BiConsumer<String, Map<String, ?>> multiFieldsMappingConsumer
2736
) {
2837
Object properties = mapping.get("properties");
2938
if (properties instanceof Map) {
@@ -36,8 +45,8 @@ private static void visitMapping(
3645
@SuppressWarnings("unchecked")
3746
Map<String, ?> fieldMapping = (Map<String, ?>) v;
3847
final String prefix = path + entry.getKey();
39-
fieldMappingConsumer.accept(prefix, fieldMapping);
40-
visitMapping(fieldMapping, prefix + ".", fieldMappingConsumer);
48+
propertiesMappingConsumer.accept(prefix, fieldMapping);
49+
visitMapping(fieldMapping, prefix + ".", propertiesMappingConsumer, multiFieldsMappingConsumer);
4150

4251
// Multi fields
4352
Object fieldsO = fieldMapping.get("fields");
@@ -49,7 +58,7 @@ private static void visitMapping(
4958
if (v2 instanceof Map) {
5059
@SuppressWarnings("unchecked")
5160
Map<String, ?> fieldMapping2 = (Map<String, ?>) v2;
52-
fieldMappingConsumer.accept(prefix + "." + subfieldEntry.getKey(), fieldMapping2);
61+
multiFieldsMappingConsumer.accept(prefix + "." + subfieldEntry.getKey(), fieldMapping2);
5362
}
5463
}
5564
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
9232000,9185013,9112016,8841077
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
initial_8.19.9,8841076
1+
downsample_add_multi_field_sources,8841077
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
initial_9.1.9,9112015
1+
downsample_add_multi_field_sources,9112016
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
initial_9.2.3,9185012
1+
downsample_add_multi_field_sources,9185013
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
esql_use_minimum_version_for_enrich_resolution,9231000
1+
downsample_add_multi_field_sources,9232000

server/src/test/java/org/elasticsearch/action/admin/cluster/stats/MappingVisitorTests.java

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ private static void collectTypes(Map<String, ?> mapping, Set<String> types) {
3030
});
3131
}
3232

33+
private static void collectFieldsAndSubFields(Map<String, ?> mapping, Set<String> fields, Set<String> subFields) {
34+
MappingVisitor.visitMapping(mapping, (f, m) -> fields.add(f), (f, m) -> subFields.add(f));
35+
}
36+
3337
public void testCountTopLevelFields() {
3438
Map<String, Object> mapping = new HashMap<>();
3539
Set<String> fields = new HashSet<>();
@@ -45,14 +49,14 @@ public void testCountTopLevelFields() {
4549
collectTypes(mapping, fields);
4650
assertEquals(Collections.singleton("keyword"), fields);
4751

48-
Map<String, Object> IndexField = new HashMap<>();
49-
IndexField.put("type", "integer");
50-
properties.put("bar", IndexField);
52+
Map<String, Object> indexField = new HashMap<>();
53+
indexField.put("type", "integer");
54+
properties.put("bar", indexField);
5155
fields = new HashSet<>();
5256
collectTypes(mapping, fields);
5357
assertEquals(new HashSet<>(Arrays.asList("keyword", "integer")), fields);
5458

55-
properties.put("baz", IndexField);
59+
properties.put("baz", indexField);
5660
fields = new HashSet<>();
5761
collectTypes(mapping, fields);
5862
assertEquals(new HashSet<>(Arrays.asList("keyword", "integer")), fields);
@@ -80,6 +84,35 @@ public void testCountMultiFields() {
8084
assertEquals(new HashSet<>(Arrays.asList("keyword", "text")), usedFields);
8185
}
8286

87+
public void testFieldsAndMultiFields() {
88+
Map<String, Object> keywordType = new HashMap<>();
89+
keywordType.put("type", "keyword");
90+
91+
Map<String, Object> textType = new HashMap<>();
92+
textType.put("type", "text");
93+
94+
Map<String, Object> multiFields = new HashMap<>();
95+
multiFields.put("keyword", keywordType);
96+
textType.put("fields", multiFields);
97+
98+
Map<String, Object> subObject = new HashMap<>();
99+
subObject.put("properties", Map.of("baz", keywordType));
100+
subObject.put("type", "keyword");
101+
102+
Map<String, Object> properties = new HashMap<>();
103+
properties.put("foo", textType);
104+
properties.put("bar", subObject);
105+
106+
Map<String, Object> mapping = new HashMap<>();
107+
mapping.put("properties", properties);
108+
109+
Set<String> fields = new HashSet<>();
110+
Set<String> subFields = new HashSet<>();
111+
collectFieldsAndSubFields(mapping, fields, subFields);
112+
assertEquals(Set.of("foo", "bar", "bar.baz"), fields);
113+
assertEquals(Set.of("foo.keyword"), subFields);
114+
}
115+
83116
public void testCountInnerFields() {
84117
Map<String, Object> keywordField = new HashMap<>();
85118
keywordField.put("type", "keyword");

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

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

2626
restResources {
2727
restApi {
28-
include '_common', 'bulk', 'cluster', 'indices', 'search', 'ingest.put_pipeline', 'ingest.delete_pipeline'
28+
include '_common', 'bulk', 'cluster', 'indices', 'search', 'ingest.put_pipeline', 'ingest.delete_pipeline', 'capabilities'
2929
}
3030
}
3131

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
setup:
2+
- requires:
3+
capabilities:
4+
- method: POST
5+
path: /{index}/_downsample/{target_index}
6+
capabilities: ['downsample.multi_field_fix']
7+
test_runner_features: [ "capabilities" ]
8+
reason: Requires the fix for downsampling multi fields
9+
10+
---
11+
"Downsample index with multi-fields":
12+
- do:
13+
indices.create:
14+
index: test
15+
body:
16+
settings:
17+
number_of_shards: 1
18+
index:
19+
mode: time_series
20+
routing_path: [ dimension ]
21+
time_series:
22+
start_time: 2021-04-28T00:00:00Z
23+
end_time: 2021-04-29T00:00:00Z
24+
mappings:
25+
properties:
26+
"@timestamp":
27+
type: date
28+
dimension:
29+
type: keyword
30+
time_series_dimension: true
31+
label-dimension:
32+
type: keyword
33+
fields:
34+
dimension:
35+
type: keyword
36+
time_series_dimension: true
37+
label-text:
38+
type: text
39+
fields:
40+
keyword:
41+
type: keyword
42+
other-keyword:
43+
type: keyword
44+
metric:
45+
type: long
46+
time_series_metric: gauge
47+
- is_true: shards_acknowledged
48+
49+
- do:
50+
bulk:
51+
refresh: true
52+
index: test
53+
body:
54+
- '{"index": {}}'
55+
- '{"@timestamp": "2021-04-28T18:50:04.467Z", "dimension": "pod", "label-dimension": "my label", "label-text": "my text", "metric": 1}'
56+
- '{"index": {}}'
57+
- '{"@timestamp": "2021-04-28T18:50:24.467Z", "dimension": "pod", "label-dimension": "my label", "label-text": "my other text", "metric": 3}'
58+
- '{"index": {}}'
59+
- '{"@timestamp": "2021-04-28T20:50:44.467Z", "dimension": "pod", "label-dimension": "my label", "label-text": "my random text", "metric": 2}'
60+
- '{"index": {}}'
61+
- '{"@timestamp": "2021-04-28T20:51:04.467Z", "dimension": "pod", "label-dimension": "my other label", "label-text": "some text", "metric": 4}'
62+
- '{"index": {}}'
63+
- '{"@timestamp": "2021-04-28T18:50:03.142Z", "dimension": "pod", "label-dimension": "my label", "label-text": "some other text", "metric": 6}'
64+
- '{"index": {}}'
65+
- '{"@timestamp": "2021-04-28T18:50:23.142Z", "dimension": "pod", "label-dimension": "my label", "label-text": "some random text", "metric": 3}'
66+
67+
- do:
68+
indices.put_settings:
69+
index: test
70+
body:
71+
index.blocks.write: true
72+
- is_true: acknowledged
73+
74+
- do:
75+
indices.downsample:
76+
index: test
77+
target_index: test-downsample
78+
body: >
79+
{
80+
"fixed_interval": "1h"
81+
}
82+
- is_true: acknowledged
83+
84+
- do:
85+
search:
86+
index: test-downsample
87+
body:
88+
sort: [ "@timestamp", "_tsid" ]
89+
90+
- length: { hits.hits: 3 }
91+
- match: { hits.hits.0._source._doc_count: 4 }
92+
- match: { hits.hits.0._source.dimension: pod }
93+
- match: { hits.hits.0._source.@timestamp: 2021-04-28T18:00:00.000Z }
94+
- match: { hits.hits.0._source.label-dimension: "my label" }
95+
- match: { hits.hits.0._source.label-text: "my other text" }
96+
- match: { hits.hits.0._source.metric.sum: 13 }
97+
- match: { hits.hits.0._source.metric.value_count: 4 }
98+
- match: { hits.hits.0._source.metric.min: 1 }
99+
- match: { hits.hits.0._source.metric.max: 6 }
100+
101+
---
102+
"Downsampling index fails with metrics as multi-fields":
103+
- do:
104+
indices.create:
105+
index: test
106+
body:
107+
settings:
108+
number_of_shards: 1
109+
index:
110+
mode: time_series
111+
routing_path: [ dimension ]
112+
time_series:
113+
start_time: 2021-04-28T00:00:00Z
114+
end_time: 2021-04-29T00:00:00Z
115+
mappings:
116+
properties:
117+
"@timestamp":
118+
type: date
119+
dimension:
120+
type: keyword
121+
time_series_dimension: true
122+
cpu_usage:
123+
type: long
124+
fields:
125+
gauge:
126+
type: long
127+
time_series_metric: gauge
128+
- is_true: shards_acknowledged
129+
130+
- do:
131+
bulk:
132+
refresh: true
133+
index: test
134+
body:
135+
- '{"index": {}}'
136+
- '{"@timestamp": "2021-04-28T18:50:04.467Z", "dimension": "pod", "cpu_usage": 1}'
137+
- '{"index": {}}'
138+
- '{"@timestamp": "2021-04-28T18:50:24.467Z", "dimension": "pod", "cpu_usage": 3}'
139+
140+
- do:
141+
indices.put_settings:
142+
index: test
143+
body:
144+
index.blocks.write: true
145+
- is_true: acknowledged
146+
147+
- do:
148+
catch: /Downsampling failed because index mapping contains time series metrics as a multi field/
149+
indices.downsample:
150+
index: test
151+
target_index: test-downsample
152+
body: >
153+
{
154+
"fixed_interval": "1h"
155+
}

0 commit comments

Comments
 (0)