Skip to content

Commit ec82c24

Browse files
Add support to VALUES aggregation for spatial types (#122886)
The original work at #106065 did not support geospatial types with this comment: > I made this work for everything but geo_point and cartesian_point because I'm not 100% sure how to integrate with those. We can grab those in a follow up. The geospatial types should be possible to collect using the VALUES aggregation with similar behavior to the `ST_COLLECT` OGC function, based on the Elasticsearch convention that treats multi-value geospatial fields as behaving similarly to any geometry collection. So this implementation is a trivial addition to the existing values types support.
1 parent 12fcdd8 commit ec82c24

File tree

11 files changed

+189
-36
lines changed

11 files changed

+189
-36
lines changed

docs/changelog/122886.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 122886
2+
summary: Add support to VALUES aggregation for spatial types
3+
area: ES|QL
4+
type: bug
5+
issues:
6+
- 122413

docs/reference/esql/functions/kibana/definition/values.json

Lines changed: 48 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x-pack/plugin/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ tasks.named("yamlRestCompatTestTransform").configure({ task ->
102102
task.skipTest("esql/190_lookup_join/alias-pattern-multiple", "LOOKUP JOIN does not support index aliases for now")
103103
task.skipTest("esql/190_lookup_join/alias-pattern-single", "LOOKUP JOIN does not support index aliases for now")
104104
task.skipTest("esql/180_match_operator/match with disjunctions", "Disjunctions in full text functions work now")
105+
task.skipTest("esql/130_spatial/values unsupported for geo_point", "Spatial types are now supported in VALUES aggregation")
106+
task.skipTest("esql/130_spatial/values unsupported for geo_point status code", "Spatial types are now supported in VALUES aggregation")
105107
// Expected deprecation warning to compat yaml tests:
106108
task.addAllowedWarningRegex(".*rollup functionality will be removed in Elasticsearch.*")
107109
task.skipTest("esql/40_tsdb/from doc with aggregate_metric_double", "TODO: support for subset of metric fields")

x-pack/plugin/esql/qa/testFixtures/src/main/resources/spatial.csv-spec

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,70 @@ c:long | x:double | y:double
144144
19 | null | null
145145
;
146146

147+
values
148+
required_capability: agg_values_spatial
149+
150+
FROM airports
151+
| WHERE scalerank == 9
152+
| STATS locations=VALUES(location)
153+
| EVAL locations = MV_SORT(TO_STRING(locations))
154+
;
155+
156+
locations:keyword
157+
[POINT (101.446569298441 0.464600872998505), POINT (105.176060419161 -5.242566777132), POINT (112.711418617258 -7.92998002840567), POINT (126.810839481226 35.1400051390198), POINT (127.495916124681 36.7220227766673), POINT (128.637537699933 35.8999277969087), POINT (129.355731047528 35.5928957527107), POINT (145.243980298582 14.1717712971216), POINT (35.3018728575279 47.8732635579023), POINT (42.97109630194 14.7552534413725), POINT (48.7471065435931 31.3431585560757), POINT (60.900708564915 29.4752941956573), POINT (61.5122589740201 55.2977919496055), POINT (63.0279333519181 25.988794590011), POINT (66.9487311480949 30.249043186181), POINT (72.9878190922305 31.3627435480862), POINT (73.0320498392002 33.5614146278861), POINT (73.3163595376585 54.9576482934059), POINT (73.4084964764375 61.3401672194481), POINT (73.8105674924689 19.9660205672806), POINT (75.3958432922005 19.8672969621082), POINT (75.7584828456005 31.4329422397715), POINT (75.8092915005895 22.727749187571), POINT (75.9330597710755 17.625415183635), POINT (75.9570722403652 30.8503598561702), POINT (76.8017261105242 30.6707248949667), POINT (78.2172186546348 26.285487697937), POINT (78.7089578747476 10.7603571306554), POINT (79.452002687657 28.4218087161144), POINT (81.7317271462187 25.443522027821), POINT (82.6671524525865 55.0095847136264), POINT (83.5504532124038 53.3633850813046), POINT (85.3235970368767 23.3177245989962)]
158+
;
159+
160+
valuesGrouped
161+
required_capability: agg_values_spatial
162+
163+
FROM airports
164+
| WHERE scalerank == 9
165+
| EVAL first_letter = SUBSTRING(abbrev, 0, 1)
166+
| STATS locations=VALUES(location) BY first_letter
167+
| EVAL locations = MV_SORT(TO_STRING(locations))
168+
| SORT first_letter
169+
| KEEP first_letter, locations
170+
;
171+
172+
first_letter:keyword | locations:keyword
173+
A | POINT (48.7471065435931 31.3431585560757)
174+
B | POINT (83.5504532124038 53.3633850813046)
175+
C | [POINT (127.495916124681 36.7220227766673), POINT (61.5122589740201 55.2977919496055)]
176+
G | POINT (78.2172186546348 26.285487697937)
177+
H | POINT (42.97109630194 14.7552534413725)
178+
I | [POINT (73.8105674924689 19.9660205672806), POINT (75.3958432922005 19.8672969621082), POINT (75.8092915005895 22.727749187571), POINT (76.8017261105242 30.6707248949667), POINT (81.7317271462187 25.443522027821), POINT (85.3235970368767 23.3177245989962)]
179+
K | POINT (126.810839481226 35.1400051390198)
180+
L | [POINT (72.9878190922305 31.3627435480862), POINT (75.9570722403652 30.8503598561702)]
181+
M | POINT (112.711418617258 -7.92998002840567)
182+
O | [POINT (35.3018728575279 47.8732635579023), POINT (73.0320498392002 33.5614146278861), POINT (73.3163595376585 54.9576482934059), POINT (82.6671524525865 55.0095847136264)]
183+
P | POINT (101.446569298441 0.464600872998505)
184+
R | POINT (145.243980298582 14.1717712971216)
185+
S | [POINT (73.4084964764375 61.3401672194481), POINT (75.9330597710755 17.625415183635)]
186+
T | [POINT (128.637537699933 35.8999277969087), POINT (63.0279333519181 25.988794590011), POINT (78.7089578747476 10.7603571306554)]
187+
U | [POINT (129.355731047528 35.5928957527107), POINT (66.9487311480949 30.249043186181)]
188+
V | [POINT (75.7584828456005 31.4329422397715), POINT (79.452002687657 28.4218087161144)]
189+
W | POINT (105.176060419161 -5.242566777132)
190+
Z | POINT (60.900708564915 29.4752941956573)
191+
;
192+
193+
valuesGroupedByOrdinals
194+
required_capability: agg_values_spatial
195+
196+
FROM airports
197+
| WHERE scalerank == 9
198+
| STATS locations=VALUES(location) BY type
199+
| EVAL locations = MV_SORT(TO_STRING(locations))
200+
| SORT type
201+
| KEEP type, locations
202+
;
203+
204+
type:keyword | locations:keyword
205+
major | [POINT (127.495916124681 36.7220227766673), POINT (76.8017261105242 30.6707248949667)]
206+
mid | [POINT (101.446569298441 0.464600872998505), POINT (105.176060419161 -5.242566777132), POINT (112.711418617258 -7.92998002840567), POINT (126.810839481226 35.1400051390198), POINT (128.637537699933 35.8999277969087), POINT (129.355731047528 35.5928957527107), POINT (145.243980298582 14.1717712971216), POINT (35.3018728575279 47.8732635579023), POINT (42.97109630194 14.7552534413725), POINT (48.7471065435931 31.3431585560757), POINT (60.900708564915 29.4752941956573), POINT (61.5122589740201 55.2977919496055), POINT (63.0279333519181 25.988794590011), POINT (66.9487311480949 30.249043186181), POINT (72.9878190922305 31.3627435480862), POINT (73.3163595376585 54.9576482934059), POINT (73.4084964764375 61.3401672194481), POINT (73.8105674924689 19.9660205672806), POINT (75.3958432922005 19.8672969621082), POINT (75.7584828456005 31.4329422397715), POINT (75.8092915005895 22.727749187571), POINT (75.9330597710755 17.625415183635), POINT (78.2172186546348 26.285487697937), POINT (78.7089578747476 10.7603571306554), POINT (82.6671524525865 55.0095847136264), POINT (83.5504532124038 53.3633850813046), POINT (85.3235970368767 23.3177245989962)]
207+
military | [POINT (112.711418617258 -7.92998002840567), POINT (126.810839481226 35.1400051390198), POINT (35.3018728575279 47.8732635579023), POINT (72.9878190922305 31.3627435480862), POINT (75.7584828456005 31.4329422397715), POINT (76.8017261105242 30.6707248949667), POINT (78.2172186546348 26.285487697937), POINT (79.452002687657 28.4218087161144), POINT (81.7317271462187 25.443522027821)]
208+
small | [POINT (73.0320498392002 33.5614146278861), POINT (75.9570722403652 30.8503598561702)]
209+
;
210+
147211
###############################################
148212
# Tests for ST_CENTROID_AGG on GEO_POINT type
149213

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ public enum Cap {
8181
*/
8282
AGG_VALUES,
8383

84+
/**
85+
* Expand the {@code VALUES} agg to cover spatial types.
86+
*/
87+
AGG_VALUES_SPATIAL,
88+
8489
/**
8590
* Does ESQL support async queries.
8691
*/

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/EsqlTypeResolutions.java

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,6 @@ public static Expression.TypeResolution isExact(Expression e, String operationNa
6363
GEO_SHAPE.typeName(),
6464
CARTESIAN_SHAPE.typeName() };
6565
private static final String[] POINT_TYPE_NAMES = new String[] { GEO_POINT.typeName(), CARTESIAN_POINT.typeName() };
66-
private static final String[] NON_SPATIAL_TYPE_NAMES = DataType.types()
67-
.stream()
68-
.filter(DataType::isRepresentable)
69-
.filter(t -> DataType.isSpatial(t) == false)
70-
.map(DataType::esType)
71-
.toArray(String[]::new);
7266

7367
public static Expression.TypeResolution isSpatialPoint(Expression e, String operationName, TypeResolutions.ParamOrdinal paramOrd) {
7468
return isType(e, DataType::isSpatialPoint, operationName, paramOrd, POINT_TYPE_NAMES);
@@ -77,9 +71,4 @@ public static Expression.TypeResolution isSpatialPoint(Expression e, String oper
7771
public static Expression.TypeResolution isSpatial(Expression e, String operationName, TypeResolutions.ParamOrdinal paramOrd) {
7872
return isType(e, DataType::isSpatial, operationName, paramOrd, SPATIAL_TYPE_NAMES);
7973
}
80-
81-
public static Expression.TypeResolution isNotSpatial(Expression e, String operationName, TypeResolutions.ParamOrdinal paramOrd) {
82-
return isType(e, t -> DataType.isSpatial(t) == false, operationName, paramOrd, NON_SPATIAL_TYPE_NAMES);
83-
}
84-
8574
}

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Values.java

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,28 @@ public class Values extends AggregateFunction implements ToAggregator {
5050
Map.entry(DataType.SEMANTIC_TEXT, ValuesBytesRefAggregatorFunctionSupplier::new),
5151
Map.entry(DataType.IP, ValuesBytesRefAggregatorFunctionSupplier::new),
5252
Map.entry(DataType.VERSION, ValuesBytesRefAggregatorFunctionSupplier::new),
53+
Map.entry(DataType.GEO_POINT, ValuesBytesRefAggregatorFunctionSupplier::new),
54+
Map.entry(DataType.CARTESIAN_POINT, ValuesBytesRefAggregatorFunctionSupplier::new),
55+
Map.entry(DataType.GEO_SHAPE, ValuesBytesRefAggregatorFunctionSupplier::new),
56+
Map.entry(DataType.CARTESIAN_SHAPE, ValuesBytesRefAggregatorFunctionSupplier::new),
5357
Map.entry(DataType.BOOLEAN, ValuesBooleanAggregatorFunctionSupplier::new)
5458
);
5559

5660
@FunctionInfo(
57-
returnType = { "boolean", "date", "date_nanos", "double", "integer", "ip", "keyword", "long", "version" },
61+
returnType = {
62+
"boolean",
63+
"cartesian_point",
64+
"cartesian_shape",
65+
"date",
66+
"date_nanos",
67+
"double",
68+
"geo_point",
69+
"geo_shape",
70+
"integer",
71+
"ip",
72+
"keyword",
73+
"long",
74+
"version" },
5875
preview = true,
5976
description = "Returns all values in a group as a multivalued field. The order of the returned values isn't guaranteed. "
6077
+ "If you need the values returned in order use <<esql-mv_sort>>.",
@@ -74,7 +91,21 @@ public Values(
7491
Source source,
7592
@Param(
7693
name = "field",
77-
type = { "boolean", "date", "date_nanos", "double", "integer", "ip", "keyword", "long", "text", "version" }
94+
type = {
95+
"boolean",
96+
"cartesian_point",
97+
"cartesian_shape",
98+
"date",
99+
"date_nanos",
100+
"double",
101+
"geo_point",
102+
"geo_shape",
103+
"integer",
104+
"ip",
105+
"keyword",
106+
"long",
107+
"text",
108+
"version" }
78109
) Expression v
79110
) {
80111
this(source, v, Literal.TRUE);
@@ -115,13 +146,7 @@ public DataType dataType() {
115146

116147
@Override
117148
protected TypeResolution resolveType() {
118-
return TypeResolutions.isType(
119-
field(),
120-
SUPPLIERS::containsKey,
121-
sourceText(),
122-
DEFAULT,
123-
"any type except unsigned_long and spatial types"
124-
);
149+
return TypeResolutions.isType(field(), SUPPLIERS::containsKey, sourceText(), DEFAULT, "any type except unsigned_long");
125150
}
126151

127152
@Override

x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,9 @@ protected final void assertTypeResolutionFailure(Expression expression) {
858858

859859
@AfterClass
860860
public static void renderSignature() throws IOException {
861-
if (System.getProperty("generateDocs") == null) {
861+
// Temporarily turn off docs generation during docs freeze
862+
// TODO: Only turn this back on once this generates the correct MD files
863+
if (System.getProperty("generateDocs") == null || true) {
862864
return;
863865
}
864866
String name = functionName();
@@ -933,7 +935,9 @@ public static void renderDocs() throws IOException {
933935
}
934936

935937
protected static void renderDocs(String name) throws IOException {
936-
if (System.getProperty("generateDocs") == null) {
938+
// Temporarily turn off docs generation during docs freeze
939+
// TODO: Only turn this back on once this generates the correct MD files
940+
if (System.getProperty("generateDocs") == null || true) {
937941
return;
938942
}
939943
if (binaryOperator(name) != null || unaryOperator(name) != null || searchOperator(name) != null || likeOrInOperator(name)) {

x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/ValuesErrorTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@ protected Expression build(Source source, List<Expression> args) {
3232

3333
@Override
3434
protected Matcher<String> expectedTypeErrorMatcher(List<Set<DataType>> validPerPosition, List<DataType> signature) {
35-
return equalTo(typeErrorMessage(false, validPerPosition, signature, (v, p) -> "any type except unsigned_long and spatial types"));
35+
return equalTo(typeErrorMessage(false, validPerPosition, signature, (v, p) -> "any type except unsigned_long"));
3636
}
3737
}

0 commit comments

Comments
 (0)