Fix unmapped field handling in the composite aggregation (#41280)
The `composite` aggregation maps unknown fields as numerics, this means that any `after` value that is set on a query with an unmapped field on some indices will fail if the provided value is not numeric. This commit changes the default value source to use keyword instead in order to be able to parse any type of after values.
This commit is contained in:
parent
754037b71e
commit
8f73e1e883
|
@ -18,6 +18,22 @@ setup:
|
|||
nested_long:
|
||||
type: long
|
||||
|
||||
- do:
|
||||
indices.create:
|
||||
index: other
|
||||
body:
|
||||
mappings:
|
||||
properties:
|
||||
date:
|
||||
type: date
|
||||
long:
|
||||
type: long
|
||||
nested:
|
||||
type: nested
|
||||
properties:
|
||||
nested_long:
|
||||
type: long
|
||||
|
||||
- do:
|
||||
index:
|
||||
index: test
|
||||
|
@ -54,9 +70,15 @@ setup:
|
|||
id: 6
|
||||
body: { "date": "2017-10-21T07:00:00" }
|
||||
|
||||
- do:
|
||||
index:
|
||||
index: other
|
||||
id: 0
|
||||
body: { "date": "2017-10-20T03:08:45" }
|
||||
|
||||
- do:
|
||||
indices.refresh:
|
||||
index: [test]
|
||||
index: [test, other]
|
||||
|
||||
---
|
||||
"Simple Composite aggregation":
|
||||
|
@ -419,3 +441,84 @@ setup:
|
|||
- match: { aggregations.1.2.buckets.0.doc_count: 2 }
|
||||
- match: { aggregations.1.2.buckets.1.key.nested: 1000 }
|
||||
- match: { aggregations.1.2.buckets.1.doc_count: 1 }
|
||||
|
||||
---
|
||||
"Composite aggregation with unmapped field":
|
||||
- skip:
|
||||
version: " - 7.0.99"
|
||||
reason: starting in 7.1 the composite aggregation handles unmapped fields as keywords
|
||||
|
||||
- do:
|
||||
search:
|
||||
rest_total_hits_as_int: true
|
||||
index: [test, other]
|
||||
body:
|
||||
aggregations:
|
||||
test:
|
||||
composite:
|
||||
sources: [
|
||||
{
|
||||
"long": {
|
||||
"terms": {
|
||||
"field": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kw": {
|
||||
"terms": {
|
||||
"field": "keyword"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
- match: {hits.total: 7}
|
||||
- length: { aggregations.test.buckets: 5 }
|
||||
- match: { aggregations.test.buckets.0.key.long: 0}
|
||||
- match: { aggregations.test.buckets.0.key.kw: "bar" }
|
||||
- match: { aggregations.test.buckets.0.doc_count: 2 }
|
||||
- match: { aggregations.test.buckets.1.key.long: 10 }
|
||||
- match: { aggregations.test.buckets.1.key.kw: "foo"}
|
||||
- match: { aggregations.test.buckets.1.doc_count: 1 }
|
||||
- match: { aggregations.test.buckets.2.key.long: 20 }
|
||||
- match: { aggregations.test.buckets.2.key.kw: "foo" }
|
||||
- match: { aggregations.test.buckets.2.doc_count: 1 }
|
||||
- match: { aggregations.test.buckets.3.key.long: 100}
|
||||
- match: { aggregations.test.buckets.3.key.kw: "bar" }
|
||||
- match: { aggregations.test.buckets.3.doc_count: 1 }
|
||||
- match: { aggregations.test.buckets.4.key.long: 1000 }
|
||||
- match: { aggregations.test.buckets.4.key.kw: "bar" }
|
||||
- match: { aggregations.test.buckets.4.doc_count: 1 }
|
||||
|
||||
- do:
|
||||
search:
|
||||
rest_total_hits_as_int: true
|
||||
index: [test, other]
|
||||
body:
|
||||
aggregations:
|
||||
test:
|
||||
composite:
|
||||
after: { "long": 100, "kw": "bar" }
|
||||
sources: [
|
||||
{
|
||||
"long": {
|
||||
"terms": {
|
||||
"field": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kw": {
|
||||
"terms": {
|
||||
"field": "keyword"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
- match: {hits.total: 7}
|
||||
- length: { aggregations.test.buckets: 1 }
|
||||
- match: { aggregations.test.buckets.0.key.long: 1000 }
|
||||
- match: { aggregations.test.buckets.0.key.kw: "bar" }
|
||||
- match: { aggregations.test.buckets.0.doc_count: 1 }
|
||||
|
|
|
@ -83,7 +83,9 @@ public class TermsValuesSourceBuilder extends CompositeValuesSourceBuilder<Terms
|
|||
protected CompositeValuesSourceConfig innerBuild(SearchContext context, ValuesSourceConfig<?> config) throws IOException {
|
||||
ValuesSource vs = config.toValuesSource(context.getQueryShardContext());
|
||||
if (vs == null) {
|
||||
vs = ValuesSource.Numeric.EMPTY;
|
||||
// The field is unmapped so we use a value source that can parse any type of values.
|
||||
// This is needed because the after values are parsed even when there are no values to process.
|
||||
vs = ValuesSource.Bytes.WithOrdinals.EMPTY;
|
||||
}
|
||||
final MappedFieldType fieldType = config.fieldContext() != null ? config.fieldContext().fieldType() : null;
|
||||
final DocValueFormat format;
|
||||
|
|
Loading…
Reference in New Issue