diff --git a/docs/changelog/112063.yaml b/docs/changelog/112063.yaml new file mode 100644 index 0000000000000..190993967a074 --- /dev/null +++ b/docs/changelog/112063.yaml @@ -0,0 +1,32 @@ +pr: 112063 +summary: Spatial search functions support multi-valued fields in compute engine +area: ES|QL +type: bug +issues: + - 112102 + - 112505 + - 110830 +highlight: + title: "ESQL: Multi-value fields supported in Geospatial predicates" + body: |- + Supporting multi-value fields in `WHERE` predicates is a challenge due to not knowing whether `ALL` or `ANY` + of the values in the field should pass the predicate. + For example, should the field `age:[10,30]` pass the predicate `WHERE age>20` or not? + This ambiguity does not exist with the spatial predicates + `ST_INTERSECTS` and `ST_DISJOINT`, because the choice between `ANY` or `ALL` + is implied by the predicate itself. + Consider a predicate checking a field named `location` against a test geometry named `shape`: + + * `ST_INTERSECTS(field, shape)` - true if `ANY` value can intersect the shape + * `ST_DISJOINT(field, shape)` - true only if `ALL` values are disjoint from the shape + + This works even if the shape argument is itself a complex or compound geometry. + + Similar logic exists for `ST_CONTAINS` and `ST_WITHIN` predicates, but these are not as easily solved + with `ANY` or `ALL`, because a collection of geometries contains another collection if each of the contained + geometries is within at least one of the containing geometries. Evaluating this requires that the multi-value + field is first combined into a single geometry before performing the predicate check. + + * `ST_CONTAINS(field, shape)` - true if the combined geometry contains the shape + * `ST_WITHIN(field, shape)` - true if the combined geometry is within the shape + notable: false diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestUtils.java b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestUtils.java index 70a054f233a3c..eaec6811fbc24 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestUtils.java +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestUtils.java @@ -122,8 +122,19 @@ public static Tuple> loadPageFromCsv(URL source, Map 1) { + builderWrapper().builder().beginPositionEntry(); + for (String mvString : mvStrings) { + mvString = mvString.replace(ESCAPED_COMMA_SEQUENCE, ","); + builderWrapper().append().accept(mvString.length() == 0 ? null : type.convert(mvString)); + } + builderWrapper().builder().endPositionEntry(); + return; + } + stringValue = mvStrings[0].replace(ESCAPED_COMMA_SEQUENCE, ","); } else if (stringValue.contains(",")) {// multi-value field builderWrapper().builder().beginPositionEntry(); @@ -376,7 +387,20 @@ public static ExpectedResults loadCsvSpecValues(String csv) { } List listOfMvValues = new ArrayList<>(); for (String mvValue : multiValues) { - listOfMvValues.add(columnTypes.get(i).convert(mvValue.trim().replace(ESCAPED_COMMA_SEQUENCE, ","))); + try { + listOfMvValues.add(columnTypes.get(i).convert(mvValue.trim().replace(ESCAPED_COMMA_SEQUENCE, ","))); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException( + "Error parsing multi-value field [" + + columnNames.get(i) + + "] with value [" + + mvValue + + "] on row " + + values.size(), + e + ); + + } } rowValues.add(listOfMvValues); } else { diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestsDataLoader.java b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestsDataLoader.java index 068adf190653a..d63585086f1cd 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestsDataLoader.java +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestsDataLoader.java @@ -75,6 +75,8 @@ public class CsvTestsDataLoader { private static final TestsDataset COUNTRIES_BBOX_WEB = new TestsDataset("countries_bbox_web"); private static final TestsDataset AIRPORT_CITY_BOUNDARIES = new TestsDataset("airport_city_boundaries"); private static final TestsDataset CARTESIAN_MULTIPOLYGONS = new TestsDataset("cartesian_multipolygons"); + private static final TestsDataset MULTIVALUE_GEOMETRIES = new TestsDataset("multivalue_geometries"); + private static final TestsDataset MULTIVALUE_POINTS = new TestsDataset("multivalue_points"); private static final TestsDataset DISTANCES = new TestsDataset("distances"); private static final TestsDataset K8S = new TestsDataset("k8s", "k8s-mappings.json", "k8s.csv").withSetting("k8s-settings.json"); private static final TestsDataset ADDRESSES = new TestsDataset("addresses"); @@ -104,6 +106,8 @@ public class CsvTestsDataLoader { Map.entry(COUNTRIES_BBOX_WEB.indexName, COUNTRIES_BBOX_WEB), Map.entry(AIRPORT_CITY_BOUNDARIES.indexName, AIRPORT_CITY_BOUNDARIES), Map.entry(CARTESIAN_MULTIPOLYGONS.indexName, CARTESIAN_MULTIPOLYGONS), + Map.entry(MULTIVALUE_GEOMETRIES.indexName, MULTIVALUE_GEOMETRIES), + Map.entry(MULTIVALUE_POINTS.indexName, MULTIVALUE_POINTS), Map.entry(DATE_NANOS.indexName, DATE_NANOS), Map.entry(K8S.indexName, K8S), Map.entry(DISTANCES.indexName, DISTANCES), diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mapping-airports-no-doc-values.json b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mapping-airports-no-doc-values.json new file mode 100644 index 0000000000000..a11f1352035ec --- /dev/null +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mapping-airports-no-doc-values.json @@ -0,0 +1,30 @@ +{ + "properties": { + "abbrev": { + "type": "keyword" + }, + "name": { + "type": "text" + }, + "scalerank": { + "type": "integer" + }, + "type": { + "type": "keyword" + }, + "location": { + "type": "geo_point", + "index": false, + "doc_values": false + }, + "country": { + "type": "keyword" + }, + "city": { + "type": "keyword" + }, + "city_location": { + "type": "geo_point" + } + } +} diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mapping-multivalue_geometries.json b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mapping-multivalue_geometries.json new file mode 100644 index 0000000000000..3912e515b9f43 --- /dev/null +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mapping-multivalue_geometries.json @@ -0,0 +1,19 @@ +{ + "properties": { + "id": { + "type": "long" + }, + "intersects": { + "type": "boolean" + }, + "contains": { + "type": "boolean" + }, + "shape": { + "type": "geo_shape" + }, + "smaller": { + "type": "geo_shape" + } + } +} diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mapping-multivalue_points.json b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mapping-multivalue_points.json new file mode 100644 index 0000000000000..98a3794d977e2 --- /dev/null +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mapping-multivalue_points.json @@ -0,0 +1,22 @@ +{ + "properties": { + "id": { + "type": "long" + }, + "intersects": { + "type": "boolean" + }, + "within": { + "type": "boolean" + }, + "centroid": { + "type": "geo_point" + }, + "location": { + "type": "geo_point" + }, + "subset": { + "type": "geo_point" + } + } +} diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/multivalue_geometries.csv b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/multivalue_geometries.csv new file mode 100644 index 0000000000000..5741dbe1d5a34 --- /dev/null +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/multivalue_geometries.csv @@ -0,0 +1,13 @@ +id:l, intersects:boolean, contains:boolean, shape:geo_shape, smaller:geo_shape +0, true, true, ["GEOMETRYCOLLECTION(POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))\, POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0)))"], ["GEOMETRYCOLLECTION(POLYGON ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))\, POLYGON ((1 1\, 9 1\, 9 9\, 1 9\, 1 1)))"] +1, true, true, ["MULTIPOLYGON( ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))\, ((0 0\, 10 0\, 10 10\, 0 10\, 0 0)))"], ["MULTIPOLYGON( ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))\, ((1 1\, 9 1\, 9 9\, 1 9\, 1 1)))"] +2, true, true, ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))"], ["POLYGON ((-14 -14\, 14 -14\, 14 14\, -14 14\, -14 -14))"] +3, true, true, ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"], ["POLYGON ((-14 -14\, 14 -14\, 14 14\, -14 14\, -14 -14))", "POLYGON ((16 16\, 24 16\, 24 24\, 16 24\, 16 16))"] +4, true, true, ["POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))", "POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0))"], ["POLYGON ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))", "POLYGON ((1 1\, 9 1\, 9 9\, 1 9\, 1 1))"] +5, true, false, ["POLYGON ((-5 -5\, 5 -5\, 5 5\, -5 5\, -5 -5))"], ["POLYGON ((-4 -4\, 4 -4\, 4 4\, -4 4\, -4 -4))"] +6, true, false, ["POLYGON ((-5 -5\, 5 -5\, 5 5\, -5 5\, -5 -5))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"], ["POLYGON ((-4 -4\, 4 -4\, 4 4\, -4 4\, -4 -4))", "POLYGON ((16 16\, 24 16\, 24 24\, 16 24\, 16 16))"] +7, true, false, ["POLYGON ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))", "POLYGON ((1 1\, 9 1\, 9 9\, 1 9\, 1 1))"], ["POLYGON ((-8 -8\, -2 -8\, -2 -2\, -8 -2\, -8 -8))", "POLYGON ((2 2\, 8 2\, 8 8\, 2 8\, 2 2))"] +8, false, false, ["POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"], ["POLYGON ((16 16\, 24 16\, 24 24\, 16 24\, 16 16))"] +9, false, false, ["POLYGON ((-25 -25\, -15 -25\, -15 -15\, -25 -15\, -25 -25))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"], ["POLYGON ((-24 -24\, -16 -24\, -16 -16\, -24 -16\, -24 -24))", "POLYGON ((16 16\, 24 16\, 24 24\, 16 24\, 16 16))"] +10, true, false, ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))", "POLYGON ((5 5\, 15 5\, 15 15\, 5 15\, 5 5))"], ["POLYGON ((-14 -14\, 14 -14\, 14 14\, -14 14\, -14 -14))", "POLYGON ((6 6\, 14 6\, 14 14\, 6 14\, 6 6))"] +11, true, false, ["POLYGON ((-11 -11\, 1 -11\, 1 1\, -11 1\, -11 -11))", "POLYGON ((-1 -1\, 11 -1\, 11 11\, -1 11\, -1 -1))"], ["POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))", "POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0))"] diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/multivalue_geometries.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/multivalue_geometries.csv-spec new file mode 100644 index 0000000000000..d79f40711e9f6 --- /dev/null +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/multivalue_geometries.csv-spec @@ -0,0 +1,383 @@ +#################################################################################################### +# The test data contains multi-value geometries, with three ways of describing the same things: +# 1. A GEOMETRYCOLLECTION with two POLYGONs +# 2. A MULTIPOLYGON with two POLYGONs +# 3. An array (multi-value) of two single polygons +# We will test the same queries against all three representations to ensure they all work the same. +#################################################################################################### + +spatialGeometryCollectionStats + +FROM multivalue_geometries +| MV_EXPAND shape +| STATS c=COUNT(*) BY id +| KEEP id, c +| SORT id +; + +id:l | c:long +0 | 1 +1 | 1 +2 | 1 +3 | 2 +4 | 2 +5 | 1 +6 | 2 +7 | 2 +8 | 1 +9 | 2 +10 | 2 +11 | 2 +; + +spatialRelationGeometryCollection +required_capability: st_intersects +required_capability: st_contains_within +required_capability: st_disjoint +required_capability: spatial_predicates_support_multivalues + +FROM multivalue_geometries +| EVAL twoSmallPolygons=TO_GEOSHAPE("GEOMETRYCOLLECTION(POLYGON ((-9 -9, -1 -9, -1 -1, -9 -1, -9 -9)),POLYGON ((1 1, 9 1, 9 9, 1 9, 1 1)))") +| EVAL twoBiggerPolygons=TO_GEOSHAPE("GEOMETRYCOLLECTION(POLYGON ((-11 -11, 1 -11, 1 1, -11 1, -11 -11)),POLYGON ((-1 -1, 11 -1, 11 11, -1 11, -1 -1)))") +| EVAL st_intersects=ST_INTERSECTS(shape, twoSmallPolygons) +| EVAL st_contains=ST_CONTAINS(shape, twoSmallPolygons) +| EVAL st_within=ST_WITHIN(shape, twoBiggerPolygons) +| EVAL st_disjoint=ST_DISJOINT(shape, twoSmallPolygons) +| KEEP id, intersects, st_intersects, contains, st_contains, st_within, st_disjoint, shape +| SORT id +; + +id:l | intersects:boolean | st_intersects:boolean | contains:boolean | st_contains:boolean | st_within:boolean | st_disjoint:boolean | shape:geo_shape +0 | true | true | true | true | true | false | ["GEOMETRYCOLLECTION(POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))\,POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0)))"] +1 | true | true | true | true | true | false | ["MULTIPOLYGON( ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))\, ((0 0\, 10 0\, 10 10\, 0 10\, 0 0)))"] +2 | true | true | true | true | false | false | ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))"] +3 | true | true | true | true | false | false | ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] +4 | true | true | true | true | true | false | ["POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))", "POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0))"] +5 | true | true | false | false | false | false | ["POLYGON ((-5 -5\, 5 -5\, 5 5\, -5 5\, -5 -5))"] +6 | true | true | false | false | false | false | ["POLYGON ((-5 -5\, 5 -5\, 5 5\, -5 5\, -5 -5))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] +7 | true | true | false | false | true | false | ["POLYGON ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))", "POLYGON ((1 1\, 9 1\, 9 9\, 1 9\, 1 1))"] +8 | false | false | false | false | false | true | ["POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] +9 | false | false | false | false | false | true | ["POLYGON ((-25 -25\, -15 -25\, -15 -15\, -25 -15\, -25 -25))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] +10 | true | true | false | false | false | false | ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))", "POLYGON ((5 5\, 15 5\, 15 15\, 5 15\, 5 5))"] +11 | true | true | false | false | true | false | ["POLYGON ((-11 -11\, 1 -11\, 1 1\, -11 1\, -11 -11))", "POLYGON ((-1 -1\, 11 -1\, 11 11\, -1 11\, -1 -1))"] +; + +whereIntersectsGeometryCollection +required_capability: st_intersects + +FROM multivalue_geometries +| WHERE ST_INTERSECTS(shape, TO_GEOSHAPE("GEOMETRYCOLLECTION(POLYGON ((-9 -9, -1 -9, -1 -1, -9 -1, -9 -9)),POLYGON ((1 1, 9 1, 9 9, 1 9, 1 1)))")) +| KEEP id, intersects, contains, shape +| SORT id +; + +id:l | intersects:boolean | contains:boolean | shape:geo_shape +0 | true | true | ["GEOMETRYCOLLECTION(POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))\,POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0)))"] +1 | true | true | ["MULTIPOLYGON( ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))\, ((0 0\, 10 0\, 10 10\, 0 10\, 0 0)))"] +2 | true | true | ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))"] +3 | true | true | ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] +4 | true | true | ["POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))", "POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0))"] +5 | true | false | ["POLYGON ((-5 -5\, 5 -5\, 5 5\, -5 5\, -5 -5))"] +6 | true | false | ["POLYGON ((-5 -5\, 5 -5\, 5 5\, -5 5\, -5 -5))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] +7 | true | false | ["POLYGON ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))", "POLYGON ((1 1\, 9 1\, 9 9\, 1 9\, 1 1))"] +10 | true | false | ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))", "POLYGON ((5 5\, 15 5\, 15 15\, 5 15\, 5 5))"] +11 | true | false | ["POLYGON ((-11 -11\, 1 -11\, 1 1\, -11 1\, -11 -11))", "POLYGON ((-1 -1\, 11 -1\, 11 11\, -1 11\, -1 -1))"] +; + +whereIntersectsGeometryCollectionStats +required_capability: st_intersects + +FROM multivalue_geometries +| WHERE ST_INTERSECTS(shape, TO_GEOSHAPE("GEOMETRYCOLLECTION(POLYGON ((-9 -9, -1 -9, -1 -1, -9 -1, -9 -9)),POLYGON ((1 1, 9 1, 9 9, 1 9, 1 1)))")) | STATS c=COUNT(*) +; + +c:l +10 +; + +whereContainsGeometryCollection +required_capability: st_contains_within + +FROM multivalue_geometries +| WHERE ST_CONTAINS(shape, TO_GEOSHAPE("GEOMETRYCOLLECTION(POLYGON ((-9 -9, -1 -9, -1 -1, -9 -1, -9 -9)),POLYGON ((1 1, 9 1, 9 9, 1 9, 1 1)))")) +| KEEP id, intersects, contains, shape +| SORT id +; + +id:l | intersects:boolean | contains:boolean | shape:geo_shape +0 | true | true | ["GEOMETRYCOLLECTION(POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))\,POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0)))"] +1 | true | true | ["MULTIPOLYGON( ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))\, ((0 0\, 10 0\, 10 10\, 0 10\, 0 0)))"] +2 | true | true | ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))"] +3 | true | true | ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] +4 | true | true | ["POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))", "POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0))"] +; + +whereContainsGeometryCollectionStats +required_capability: st_contains_within + +FROM multivalue_geometries +| WHERE ST_CONTAINS(shape, TO_GEOSHAPE("GEOMETRYCOLLECTION(POLYGON ((-9 -9, -1 -9, -1 -1, -9 -1, -9 -9)),POLYGON ((1 1, 9 1, 9 9, 1 9, 1 1)))")) | STATS c=COUNT(*) +; + +c:l +5 +; + +whereWithinGeometryCollection +required_capability: st_contains_within + +FROM multivalue_geometries +| WHERE ST_WITHIN(shape, TO_GEOSHAPE("GEOMETRYCOLLECTION(POLYGON ((-11 -11, 1 -11, 1 1, -11 1, -11 -11)),POLYGON ((-1 -1, 11 -1, 11 11, -1 11, -1 -1)))")) +| KEEP id, intersects, contains, shape +| SORT id +; + +id:l | intersects:boolean | contains:boolean | shape:geo_shape +0 | true | true | ["GEOMETRYCOLLECTION(POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))\,POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0)))"] +1 | true | true | ["MULTIPOLYGON( ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))\, ((0 0\, 10 0\, 10 10\, 0 10\, 0 0)))"] +4 | true | true | ["POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))", "POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0))"] +7 | true | false | ["POLYGON ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))", "POLYGON ((1 1\, 9 1\, 9 9\, 1 9\, 1 1))"] +11 | true | false | ["POLYGON ((-11 -11\, 1 -11\, 1 1\, -11 1\, -11 -11))", "POLYGON ((-1 -1\, 11 -1\, 11 11\, -1 11\, -1 -1))"] +; + +whereWithinGeometryCollectionStats +required_capability: st_contains_within + +FROM multivalue_geometries +| WHERE ST_WITHIN(shape, TO_GEOSHAPE("GEOMETRYCOLLECTION(POLYGON ((-11 -11, 1 -11, 1 1, -11 1, -11 -11)),POLYGON ((-1 -1, 11 -1, 11 11, -1 11, -1 -1)))")) | STATS c=COUNT(*) +; + +c:l +5 +; + +whereDisjointGeometryCollection +required_capability: st_disjoint + +FROM multivalue_geometries +| WHERE ST_DISJOINT(shape, TO_GEOSHAPE("GEOMETRYCOLLECTION(POLYGON ((-9 -9, -1 -9, -1 -1, -9 -1, -9 -9)),POLYGON ((1 1, 9 1, 9 9, 1 9, 1 1)))")) +| KEEP id, intersects, contains, shape +| SORT id +; + +id:l | intersects:boolean | contains:boolean | shape:geo_shape +8 | false | false | ["POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] +9 | false | false | ["POLYGON ((-25 -25\, -15 -25\, -15 -15\, -25 -15\, -25 -25))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] +; + +whereDisjointGeometryCollectionStats +required_capability: st_disjoint + +FROM multivalue_geometries +| WHERE ST_DISJOINT(shape, TO_GEOSHAPE("GEOMETRYCOLLECTION(POLYGON ((-9 -9, -1 -9, -1 -1, -9 -1, -9 -9)),POLYGON ((1 1, 9 1, 9 9, 1 9, 1 1)))")) | STATS c=COUNT(*) +; + +c:l +2 +; + +disjointGeometryCollection +required_capability: st_disjoint +required_capability: spatial_predicates_support_multivalues + +FROM multivalue_geometries +| WHERE id==9 +| EVAL disjoint=ST_DISJOINT(shape, TO_GEOSHAPE("GEOMETRYCOLLECTION(POLYGON ((-9 -9, -1 -9, -1 -1, -9 -1, -9 -9)),POLYGON ((1 1, 9 1, 9 9, 1 9, 1 1)))")) +| KEEP id, intersects, disjoint, shape +| SORT id +; + +id:l | intersects:boolean | disjoint:boolean | shape:geo_shape +9 | false | true | ["POLYGON ((-25 -25\, -15 -25\, -15 -15\, -25 -15\, -25 -25))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] +; + +literalGeometryCollection +required_capability: st_intersects +required_capability: st_contains_within +required_capability: st_disjoint + +ROW shape = TO_GEOSHAPE("GEOMETRYCOLLECTION(POLYGON ((-9 -9, -1 -9, -1 -1, -9 -1, -9 -9)),POLYGON ((1 1, 9 1, 9 9, 1 9, 1 1)))") +| EVAL st_intersects=ST_INTERSECTS(shape, TO_GEOSHAPE("GEOMETRYCOLLECTION(POLYGON ((-8 -8, -2 -8, -2 -2, -8 -2, -8 -8)),POLYGON ((2 2, 8 2, 8 8, 2 8, 2 2)))")) +| EVAL st_contains=ST_CONTAINS(shape, TO_GEOSHAPE("GEOMETRYCOLLECTION(POLYGON ((-8 -8, -2 -8, -2 -2, -8 -2, -8 -8)),POLYGON ((2 2, 8 2, 8 8, 2 8, 2 2)))")) +| EVAL st_within=ST_WITHIN(shape, TO_GEOSHAPE("GEOMETRYCOLLECTION(POLYGON ((-10 -10, 0 -10, 0 0, -10 0, -10 -10)),POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0)))")) +| EVAL st_disjoint=ST_DISJOINT(shape, TO_GEOSHAPE("GEOMETRYCOLLECTION(POLYGON ((-8 -8, -2 -8, -2 -2, -8 -2, -8 -8)),POLYGON ((2 2, 8 2, 8 8, 2 8, 2 2)))")) +| KEEP st_intersects, st_contains, st_within, st_disjoint +; + +st_intersects:boolean | st_contains:boolean | st_within:boolean | st_disjoint:boolean +true | true | true | false +; + +literalMultiPolygon +required_capability: st_intersects +required_capability: st_contains_within +required_capability: st_disjoint + +ROW shape = TO_GEOSHAPE("MULTIPOLYGON(((-9 -9, -1 -9, -1 -1, -9 -1, -9 -9)), ((1 1, 9 1, 9 9, 1 9, 1 1)))") +| EVAL st_intersects=ST_INTERSECTS(shape, TO_GEOSHAPE("MULTIPOLYGON(((-8 -8, -2 -8, -2 -2, -8 -2, -8 -8)), ((2 2, 8 2, 8 8, 2 8, 2 2)))")) +| EVAL st_contains=ST_CONTAINS(shape, TO_GEOSHAPE("MULTIPOLYGON(((-8 -8, -2 -8, -2 -2, -8 -2, -8 -8)), ((2 2, 8 2, 8 8, 2 8, 2 2)))")) +| EVAL st_within=ST_WITHIN(shape, TO_GEOSHAPE("MULTIPOLYGON(((-10 -10, 0 -10, 0 0, -10 0, -10 -10)), ((0 0, 10 0, 10 10, 0 10, 0 0)))")) +| EVAL st_disjoint=ST_DISJOINT(shape, TO_GEOSHAPE("MULTIPOLYGON(((-8 -8, -2 -8, -2 -2, -8 -2, -8 -8)), ((2 2, 8 2, 8 8, 2 8, 2 2)))")) +| KEEP st_intersects, st_contains, st_within, st_disjoint +; + +st_intersects:boolean | st_contains:boolean | st_within:boolean | st_disjoint:boolean +true | true | true | false +; + +literalPolygonArray +required_capability: st_intersects +required_capability: st_contains_within +required_capability: st_disjoint +required_capability: spatial_predicates_support_multivalues + +ROW wkt = ["POLYGON((-9 -9, -1 -9, -1 -1, -9 -1, -9 -9))","POLYGON((1 1, 9 1, 9 9, 1 9, 1 1))"] +| EVAL shape = TO_GEOSHAPE(wkt) +| EVAL st_intersects=ST_INTERSECTS(shape, TO_GEOSHAPE("MULTIPOLYGON(((-8 -8, -2 -8, -2 -2, -8 -2, -8 -8)), ((2 2, 8 2, 8 8, 2 8, 2 2)))")) +| EVAL st_contains=ST_CONTAINS(shape, TO_GEOSHAPE("MULTIPOLYGON(((-8 -8, -2 -8, -2 -2, -8 -2, -8 -8)), ((2 2, 8 2, 8 8, 2 8, 2 2)))")) +| EVAL st_within=ST_WITHIN(shape, TO_GEOSHAPE("MULTIPOLYGON(((-10 -10, 0 -10, 0 0, -10 0, -10 -10)), ((0 0, 10 0, 10 10, 0 10, 0 0)))")) +| EVAL st_disjoint=ST_DISJOINT(shape, TO_GEOSHAPE("MULTIPOLYGON(((-8 -8, -2 -8, -2 -2, -8 -2, -8 -8)), ((2 2, 8 2, 8 8, 2 8, 2 2)))")) +| KEEP st_intersects, st_contains, st_within, st_disjoint +; + +st_intersects:boolean | st_contains:boolean | st_within:boolean | st_disjoint:boolean +true | true | true | false +; + +spatialRelationGeometryCollectionFields +required_capability: st_intersects +required_capability: st_contains_within +required_capability: st_disjoint +required_capability: spatial_predicates_support_multivalues + +FROM multivalue_geometries +| EVAL st_intersects=ST_INTERSECTS(shape, smaller) +| EVAL st_contains=ST_CONTAINS(shape, smaller) +| EVAL st_within=ST_WITHIN(smaller, shape) +| KEEP id, st_intersects, st_contains, st_within, shape, smaller +| SORT id +; + +id:l | st_intersects:boolean | st_contains:boolean | st_within:boolean | shape:geo_shape | smaller:geo_shape +0 | true | true | true | ["GEOMETRYCOLLECTION(POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))\,POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0)))"] | ["GEOMETRYCOLLECTION(POLYGON ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))\, POLYGON ((1 1\, 9 1\, 9 9\, 1 9\, 1 1)))"] +1 | true | true | true | ["MULTIPOLYGON( ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))\, ((0 0\, 10 0\, 10 10\, 0 10\, 0 0)))"] | ["MULTIPOLYGON( ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))\, ((1 1\, 9 1\, 9 9\, 1 9\, 1 1)))"] +2 | true | true | true | ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))"] | ["POLYGON ((-14 -14\, 14 -14\, 14 14\, -14 14\, -14 -14))"] +3 | true | true | true | ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] | ["POLYGON ((-14 -14\, 14 -14\, 14 14\, -14 14\, -14 -14))", "POLYGON ((16 16\, 24 16\, 24 24\, 16 24\, 16 16))"] +4 | true | true | true | ["POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))", "POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0))"] | ["POLYGON ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))", "POLYGON ((1 1\, 9 1\, 9 9\, 1 9\, 1 1))"] +5 | true | true | true | ["POLYGON ((-5 -5\, 5 -5\, 5 5\, -5 5\, -5 -5))"] | ["POLYGON ((-4 -4\, 4 -4\, 4 4\, -4 4\, -4 -4))"] +6 | true | true | true | ["POLYGON ((-5 -5\, 5 -5\, 5 5\, -5 5\, -5 -5))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] | ["POLYGON ((-4 -4\, 4 -4\, 4 4\, -4 4\, -4 -4))", "POLYGON ((16 16\, 24 16\, 24 24\, 16 24\, 16 16))"] +7 | true | true | true | ["POLYGON ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))", "POLYGON ((1 1\, 9 1\, 9 9\, 1 9\, 1 1))"] | ["POLYGON ((-8 -8\, -2 -8\, -2 -2\, -8 -2\, -8 -8))", "POLYGON ((2 2\, 8 2\, 8 8\, 2 8\, 2 2))"] +8 | true | true | true | ["POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] | ["POLYGON ((16 16\, 24 16\, 24 24\, 16 24\, 16 16))"] +9 | true | true | true | ["POLYGON ((-25 -25\, -15 -25\, -15 -15\, -25 -15\, -25 -25))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] | ["POLYGON ((-24 -24\, -16 -24\, -16 -16\, -24 -16\, -24 -24))", "POLYGON ((16 16\, 24 16\, 24 24\, 16 24\, 16 16))"] +10 | true | false | true | ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))", "POLYGON ((5 5\, 15 5\, 15 15\, 5 15\, 5 5))"] | ["POLYGON ((-14 -14\, 14 -14\, 14 14\, -14 14\, -14 -14))", "POLYGON ((6 6\, 14 6\, 14 14\, 6 14\, 6 6))"] +11 | true | false | true | ["POLYGON ((-11 -11\, 1 -11\, 1 1\, -11 1\, -11 -11))", "POLYGON ((-1 -1\, 11 -1\, 11 11\, -1 11\, -1 -1))"] | ["POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))", "POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0))"] +; + +whereIntersectsGeometryCollectionFields +required_capability: st_intersects +required_capability: spatial_predicates_support_multivalues + +FROM multivalue_geometries +| WHERE ST_INTERSECTS(shape, smaller) +| KEEP id, shape, smaller +| SORT id +; + +id:l | shape:geo_shape | smaller:geo_shape +0 | ["GEOMETRYCOLLECTION(POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))\,POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0)))"] | ["GEOMETRYCOLLECTION(POLYGON ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))\, POLYGON ((1 1\, 9 1\, 9 9\, 1 9\, 1 1)))"] +1 | ["MULTIPOLYGON( ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))\, ((0 0\, 10 0\, 10 10\, 0 10\, 0 0)))"] | ["MULTIPOLYGON( ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))\, ((1 1\, 9 1\, 9 9\, 1 9\, 1 1)))"] +2 | ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))"] | ["POLYGON ((-14 -14\, 14 -14\, 14 14\, -14 14\, -14 -14))"] +3 | ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] | ["POLYGON ((-14 -14\, 14 -14\, 14 14\, -14 14\, -14 -14))", "POLYGON ((16 16\, 24 16\, 24 24\, 16 24\, 16 16))"] +4 | ["POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))", "POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0))"] | ["POLYGON ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))", "POLYGON ((1 1\, 9 1\, 9 9\, 1 9\, 1 1))"] +5 | ["POLYGON ((-5 -5\, 5 -5\, 5 5\, -5 5\, -5 -5))"] | ["POLYGON ((-4 -4\, 4 -4\, 4 4\, -4 4\, -4 -4))"] +6 | ["POLYGON ((-5 -5\, 5 -5\, 5 5\, -5 5\, -5 -5))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] | ["POLYGON ((-4 -4\, 4 -4\, 4 4\, -4 4\, -4 -4))", "POLYGON ((16 16\, 24 16\, 24 24\, 16 24\, 16 16))"] +7 | ["POLYGON ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))", "POLYGON ((1 1\, 9 1\, 9 9\, 1 9\, 1 1))"] | ["POLYGON ((-8 -8\, -2 -8\, -2 -2\, -8 -2\, -8 -8))", "POLYGON ((2 2\, 8 2\, 8 8\, 2 8\, 2 2))"] +8 | ["POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] | ["POLYGON ((16 16\, 24 16\, 24 24\, 16 24\, 16 16))"] +9 | ["POLYGON ((-25 -25\, -15 -25\, -15 -15\, -25 -15\, -25 -25))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] | ["POLYGON ((-24 -24\, -16 -24\, -16 -16\, -24 -16\, -24 -24))", "POLYGON ((16 16\, 24 16\, 24 24\, 16 24\, 16 16))"] +10 | ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))", "POLYGON ((5 5\, 15 5\, 15 15\, 5 15\, 5 5))"] | ["POLYGON ((-14 -14\, 14 -14\, 14 14\, -14 14\, -14 -14))", "POLYGON ((6 6\, 14 6\, 14 14\, 6 14\, 6 6))"] +11 | ["POLYGON ((-11 -11\, 1 -11\, 1 1\, -11 1\, -11 -11))", "POLYGON ((-1 -1\, 11 -1\, 11 11\, -1 11\, -1 -1))"] | ["POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))", "POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0))"] +; + +whereIntersectsGeometryCollectionStatsFields +required_capability: st_intersects +required_capability: spatial_predicates_support_multivalues + +FROM multivalue_geometries +| WHERE ST_INTERSECTS(shape, smaller) | STATS c=COUNT(*) +; + +c:l +12 +; + +whereContainsGeometryCollectionFields +required_capability: st_contains_within +required_capability: spatial_predicates_support_multivalues + +FROM multivalue_geometries +| WHERE ST_CONTAINS(shape, smaller) +| KEEP id, shape, smaller +| SORT id +; + +id:l | shape:geo_shape | smaller:geo_shape +0 | ["GEOMETRYCOLLECTION(POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))\,POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0)))"] | ["GEOMETRYCOLLECTION(POLYGON ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))\, POLYGON ((1 1\, 9 1\, 9 9\, 1 9\, 1 1)))"] +1 | ["MULTIPOLYGON( ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))\, ((0 0\, 10 0\, 10 10\, 0 10\, 0 0)))"] | ["MULTIPOLYGON( ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))\, ((1 1\, 9 1\, 9 9\, 1 9\, 1 1)))"] +2 | ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))"] | ["POLYGON ((-14 -14\, 14 -14\, 14 14\, -14 14\, -14 -14))"] +3 | ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] | ["POLYGON ((-14 -14\, 14 -14\, 14 14\, -14 14\, -14 -14))", "POLYGON ((16 16\, 24 16\, 24 24\, 16 24\, 16 16))"] +4 | ["POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))", "POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0))"] | ["POLYGON ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))", "POLYGON ((1 1\, 9 1\, 9 9\, 1 9\, 1 1))"] +5 | ["POLYGON ((-5 -5\, 5 -5\, 5 5\, -5 5\, -5 -5))"] | ["POLYGON ((-4 -4\, 4 -4\, 4 4\, -4 4\, -4 -4))"] +6 | ["POLYGON ((-5 -5\, 5 -5\, 5 5\, -5 5\, -5 -5))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] | ["POLYGON ((-4 -4\, 4 -4\, 4 4\, -4 4\, -4 -4))", "POLYGON ((16 16\, 24 16\, 24 24\, 16 24\, 16 16))"] +7 | ["POLYGON ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))", "POLYGON ((1 1\, 9 1\, 9 9\, 1 9\, 1 1))"] | ["POLYGON ((-8 -8\, -2 -8\, -2 -2\, -8 -2\, -8 -8))", "POLYGON ((2 2\, 8 2\, 8 8\, 2 8\, 2 2))"] +8 | ["POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] | ["POLYGON ((16 16\, 24 16\, 24 24\, 16 24\, 16 16))"] +9 | ["POLYGON ((-25 -25\, -15 -25\, -15 -15\, -25 -15\, -25 -25))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] | ["POLYGON ((-24 -24\, -16 -24\, -16 -16\, -24 -16\, -24 -24))", "POLYGON ((16 16\, 24 16\, 24 24\, 16 24\, 16 16))"] +; + +whereContainsGeometryCollectionStatsFields +required_capability: st_contains_within +required_capability: spatial_predicates_support_multivalues + +FROM multivalue_geometries +| WHERE ST_CONTAINS(shape, smaller) | STATS c=COUNT(*) +; + +c:l +10 +; + +whereWithinGeometryCollectionFields +required_capability: st_contains_within +required_capability: spatial_predicates_support_multivalues + +FROM multivalue_geometries +| WHERE ST_WITHIN(smaller, shape) +| KEEP id, shape, smaller +| SORT id +; + +id:l | shape:geo_shape | smaller:geo_shape +0 | ["GEOMETRYCOLLECTION(POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))\,POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0)))"] | ["GEOMETRYCOLLECTION(POLYGON ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))\, POLYGON ((1 1\, 9 1\, 9 9\, 1 9\, 1 1)))"] +1 | ["MULTIPOLYGON( ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))\, ((0 0\, 10 0\, 10 10\, 0 10\, 0 0)))"] | ["MULTIPOLYGON( ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))\, ((1 1\, 9 1\, 9 9\, 1 9\, 1 1)))"] +2 | ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))"] | ["POLYGON ((-14 -14\, 14 -14\, 14 14\, -14 14\, -14 -14))"] +3 | ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] | ["POLYGON ((-14 -14\, 14 -14\, 14 14\, -14 14\, -14 -14))", "POLYGON ((16 16\, 24 16\, 24 24\, 16 24\, 16 16))"] +4 | ["POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))", "POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0))"] | ["POLYGON ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))", "POLYGON ((1 1\, 9 1\, 9 9\, 1 9\, 1 1))"] +5 | ["POLYGON ((-5 -5\, 5 -5\, 5 5\, -5 5\, -5 -5))"] | ["POLYGON ((-4 -4\, 4 -4\, 4 4\, -4 4\, -4 -4))"] +6 | ["POLYGON ((-5 -5\, 5 -5\, 5 5\, -5 5\, -5 -5))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] | ["POLYGON ((-4 -4\, 4 -4\, 4 4\, -4 4\, -4 -4))", "POLYGON ((16 16\, 24 16\, 24 24\, 16 24\, 16 16))"] +7 | ["POLYGON ((-9 -9\, -1 -9\, -1 -1\, -9 -1\, -9 -9))", "POLYGON ((1 1\, 9 1\, 9 9\, 1 9\, 1 1))"] | ["POLYGON ((-8 -8\, -2 -8\, -2 -2\, -8 -2\, -8 -8))", "POLYGON ((2 2\, 8 2\, 8 8\, 2 8\, 2 2))"] +8 | ["POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] | ["POLYGON ((16 16\, 24 16\, 24 24\, 16 24\, 16 16))"] +9 | ["POLYGON ((-25 -25\, -15 -25\, -15 -15\, -25 -15\, -25 -25))", "POLYGON ((15 15\, 25 15\, 25 25\, 15 25\, 15 15))"] | ["POLYGON ((-24 -24\, -16 -24\, -16 -16\, -24 -16\, -24 -24))", "POLYGON ((16 16\, 24 16\, 24 24\, 16 24\, 16 16))"] +10 | ["POLYGON ((-15 -15\, 15 -15\, 15 15\, -15 15\, -15 -15))", "POLYGON ((5 5\, 15 5\, 15 15\, 5 15\, 5 5))"] | ["POLYGON ((-14 -14\, 14 -14\, 14 14\, -14 14\, -14 -14))", "POLYGON ((6 6\, 14 6\, 14 14\, 6 14\, 6 6))"] +11 | ["POLYGON ((-11 -11\, 1 -11\, 1 1\, -11 1\, -11 -11))", "POLYGON ((-1 -1\, 11 -1\, 11 11\, -1 11\, -1 -1))"] | ["POLYGON ((-10 -10\, 0 -10\, 0 0\, -10 0\, -10 -10))", "POLYGON ((0 0\, 10 0\, 10 10\, 0 10\, 0 0))"] +; + +whereWithinGeometryCollectionStatsFields +required_capability: st_contains_within +required_capability: spatial_predicates_support_multivalues + +FROM multivalue_geometries +| WHERE ST_WITHIN(smaller, shape) | STATS c=COUNT(*) +; + +c:l +12 +; diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/multivalue_points.csv b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/multivalue_points.csv new file mode 100644 index 0000000000000..c5d7c7f4ee305 --- /dev/null +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/multivalue_points.csv @@ -0,0 +1,14 @@ +id:l, intersects:boolean, within:boolean, centroid:geo_point, location:geo_point, subset:geo_point +0, true, true, "POINT(0.0 5.0)", ["POINT(5 5)", "POINT(-5 5)"], "POINT(5 5)" +1, true, true, "POINT(0.5 0.5)", ["POINT(0 1)","POINT(1 0)"], "POINT(0 1)" +2, true, true, "POINT(9.0 9.0)", "POINT(9 9)", "POINT(9 9)" +3, true, true, "POINT(0.0 0.0)", ["POINT(-9 -9)","POINT(9 9)"], "POINT(-9 -9)" +4, true, false, "POINT(10.0 10.0)", ["POINT(5 5)", "POINT(15 15)"], "POINT(5 5)" +5, true, false, "POINT(5.5 5.5)", ["POINT(0 0)","POINT(11 11)"], "POINT(0 0)" +6, true, false, "POINT(0.0 -5.0)", ["POINT(-9 -19)","POINT(9 9)"], "POINT(-9 -19)" +7, false, false, "POINT(10.0 10.0)", ["POINT(5 15)", "POINT(15 5)"], "POINT(5 15)" +8, false, false, "POINT(5.5 5.5)", ["POINT(0 11)","POINT(11 0)"], "POINT(0 11)" +9, false, false, "POINT(19.0 9.0)", "POINT(19 9)", "POINT(19 9)" +10, false, false, "POINT(5.0 -5.0)", ["POINT(-9 -19)","POINT(19 9)"], "POINT(-9 -19)" +11, true, false, "POINT(0.0 0.0)", ["POINT(0 0)", "POINT(55 55)", "POINT(-55 -55)"], ["POINT(0 0)", "POINT(55 55)"] +12, true, false, "POINT(0.0 0.0)", ["POINT(0 0)", "POINT(55 55)", "POINT(-55 -55)"], ["POINT(0 0)", "POINT(55 54)"] diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/multivalue_points.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/multivalue_points.csv-spec new file mode 100644 index 0000000000000..86ab1bd6ec678 --- /dev/null +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/multivalue_points.csv-spec @@ -0,0 +1,425 @@ +#################################################################################################### +# The test data contains multi-value points, some are single valued and others contain two points. +# We will test the same queries against all both representations to ensure they all work the same. +#################################################################################################### + +spatialMultiValuePointsStats + +FROM multivalue_points +| MV_EXPAND location +| STATS c=COUNT(*) BY id +| KEEP id, c +| SORT id +; + +id:l | c:long +0 | 2 +1 | 2 +2 | 1 +3 | 2 +4 | 2 +5 | 2 +6 | 2 +7 | 2 +8 | 2 +9 | 1 +10 | 2 +11 | 3 +12 | 3 +; + +spatialRelationPolygon +required_capability: st_intersects +required_capability: st_contains_within +required_capability: st_disjoint +required_capability: spatial_predicates_support_multivalues + +FROM multivalue_points +| EVAL polygon=TO_GEOSHAPE("POLYGON ((-10 -10, -10 10, 10 10, 10 -10, -10 -10))") +| EVAL st_intersects=ST_INTERSECTS(location, polygon) +| EVAL st_within=ST_WITHIN(location, polygon) +| EVAL st_disjoint=ST_DISJOINT(location, polygon) +| KEEP id, intersects, within, st_intersects, st_within, st_disjoint, centroid, location +| SORT id +; + +id:l | intersects:boolean | within:boolean | st_intersects:boolean | st_within:boolean | st_disjoint:boolean | centroid:geo_point | location:geo_point +0 | true | true | true | true | false | "POINT(0.0 5.0)" | ["POINT(5 5)", "POINT(-5 5)"] +1 | true | true | true | true | false | "POINT(0.5 0.5)" | ["POINT(0 1)","POINT(1 0)"] +2 | true | true | true | true | false | "POINT(9.0 9.0)" | "POINT(9 9)" +3 | true | true | true | true | false | "POINT(0.0 0.0)" | ["POINT(-9 -9)","POINT(9 9)"] +4 | true | false | true | false | false | "POINT(10.0 10.0)" | ["POINT(5 5)", "POINT(15 15)"] +5 | true | false | true | false | false | "POINT(5.5 5.5)" | ["POINT(0 0)","POINT(11 11)"] +6 | true | false | true | false | false | "POINT(0.0 -5.0)" | ["POINT(-9 -19)","POINT(9 9)"] +7 | false | false | false | false | true | "POINT(10.0 10.0)" | ["POINT(5 15)", "POINT(15 5)"] +8 | false | false | false | false | true | "POINT(5.5 5.5)" | ["POINT(0 11)","POINT(11 0)"] +9 | false | false | false | false | true | "POINT(19.0 9.0)" | "POINT(19 9)" +10 | false | false | false | false | true | "POINT(5.0 -5.0)" | ["POINT(-9 -19)","POINT(19 9)"] +11 | true | false | true | false | false | "POINT(0.0 0.0)" | ["POINT(0 0)", "POINT(55 55)", "POINT(-55 -55)"] +12 | true | false | true | false | false | "POINT(0.0 0.0)" | ["POINT(0 0)", "POINT(55 55)", "POINT(-55 -55)"] +; + +whereIntersectsPolygon +required_capability: st_intersects + +FROM multivalue_points +| WHERE ST_INTERSECTS(location, TO_GEOSHAPE("POLYGON ((-10 -10, -10 10, 10 10, 10 -10, -10 -10))")) +| KEEP id, intersects, within, centroid, location +| SORT id +; + +id:l | intersects:boolean | within:boolean | centroid:geo_point | location:geo_point +0 | true | true | "POINT(0.0 5.0)" | ["POINT(5 5)", "POINT(-5 5)"] +1 | true | true | "POINT(0.5 0.5)" | ["POINT(0 1)","POINT(1 0)"] +2 | true | true | "POINT(9.0 9.0)" | "POINT(9 9)" +3 | true | true | "POINT(0.0 0.0)" | ["POINT(-9 -9)","POINT(9 9)"] +4 | true | false | "POINT(10.0 10.0)" | ["POINT(5 5)", "POINT(15 15)"] +5 | true | false | "POINT(5.5 5.5)" | ["POINT(0 0)","POINT(11 11)"] +6 | true | false | "POINT(0.0 -5.0)" | ["POINT(-9 -19)","POINT(9 9)"] +11 | true | false | "POINT(0.0 0.0)" | ["POINT(0 0)", "POINT(55 55)", "POINT(-55 -55)"] +12 | true | false | "POINT(0.0 0.0)" | ["POINT(0 0)", "POINT(55 55)", "POINT(-55 -55)"] +; + +whereIntersectsPolygonStats +required_capability: st_intersects + +FROM multivalue_points +| WHERE ST_INTERSECTS(location, TO_GEOSHAPE("POLYGON ((-10 -10, -10 10, 10 10, 10 -10, -10 -10))")) | STATS c=COUNT(*) +; + +c:l +9 +; + +whereWithinPolygon +required_capability: st_contains_within + +FROM multivalue_points +| WHERE ST_WITHIN(location, TO_GEOSHAPE("POLYGON ((-10 -10, -10 10, 10 10, 10 -10, -10 -10))")) +| KEEP id, intersects, within, centroid, location +| SORT id +; + +id:l | intersects:boolean | within:boolean | centroid:geo_point | location:geo_point +0 | true | true | "POINT(0.0 5.0)" | ["POINT(5 5)", "POINT(-5 5)"] +1 | true | true | "POINT(0.5 0.5)" | ["POINT(0 1)","POINT(1 0)"] +2 | true | true | "POINT(9.0 9.0)" | "POINT(9 9)" +3 | true | true | "POINT(0.0 0.0)" | ["POINT(-9 -9)","POINT(9 9)"] +; + +whereWithinPolygonStats +required_capability: st_contains_within + +FROM multivalue_points +| WHERE ST_WITHIN(location, TO_GEOSHAPE("POLYGON ((-10 -10, -10 10, 10 10, 10 -10, -10 -10))")) | STATS c=COUNT(*) +; + +c:l +4 +; + +whereWithinContainsMultiPoint +required_capability: st_contains_within +required_capability: spatial_predicates_support_multivalues + +FROM multivalue_points +| WHERE ST_WITHIN(location, TO_GEOSHAPE("MULTIPOINT(-55 -55, 0 0, 55 55)")) +| EVAL within=ST_WITHIN(location, TO_GEOSHAPE("MULTIPOINT(-55 -55, 0 0, 55 55)")) +| EVAL contains=ST_CONTAINS(location, TO_GEOSHAPE("MULTIPOINT(-55 -55, 0 0, 55 55)")) +| KEEP id, within, contains, centroid, location +| SORT id +; + +id:l | within:boolean | contains:boolean | centroid:geo_point | location:geo_point +11 | true | true | "POINT(0.0 0.0)" | ["POINT(0 0)", "POINT(55 55)", "POINT(-55 -55)"] +12 | true | true | "POINT(0.0 0.0)" | ["POINT(0 0)", "POINT(55 55)", "POINT(-55 -55)"] +; + +whereWithinPolygonStats +required_capability: st_contains_within + +FROM multivalue_points +| WHERE ST_WITHIN(location, TO_GEOSHAPE("POLYGON ((-10 -10, -10 10, 10 10, 10 -10, -10 -10))")) | STATS c=COUNT(*) +; + +c:l +4 +; + +literalPointContainsPoint +required_capability: st_contains_within + +ROW location = TO_GEOPOINT("POINT(5 5)") +| EVAL contains=ST_CONTAINS(location, TO_GEOPOINT("POINT(5 5)")) +| EVAL within=ST_WITHIN(location, TO_GEOPOINT("POINT(5 5)")) +; + +location:geo_point | contains:boolean | within:boolean +"POINT(5 5)" | true | true +; + +literalMultiPointContainsMultiPoint +required_capability: st_contains_within + +ROW location = TO_GEOSHAPE("MULTIPOINT(5 5, -5 -5)") +| EVAL contains=ST_CONTAINS(location, TO_GEOSHAPE("MULTIPOINT(-5 -5, 5 5)")) +| EVAL within=ST_WITHIN(location, TO_GEOSHAPE("MULTIPOINT(-5 -5, 5 5)")) +; + +location:geo_shape | contains:boolean | within:boolean +"MULTIPOINT(5 5, -5 -5)" | true | true +; + +literalPointCollectionContainsPointCollection +required_capability: st_contains_within + +ROW location = TO_GEOSHAPE("GEOMETRYCOLLECTION(POINT(5 5), POINT(-5 -5))") +| EVAL contains=ST_CONTAINS(location, TO_GEOSHAPE("GEOMETRYCOLLECTION(POINT(-5 -5), POINT(5 5))")) +| EVAL within=ST_WITHIN(location, TO_GEOSHAPE("GEOMETRYCOLLECTION(POINT(-5 -5), POINT(5 5))")) +; + +location:geo_shape | contains:boolean | within:boolean +"GEOMETRYCOLLECTION(POINT(5 5), POINT(-5 -5))" | true | true +; + +literalPointArrayContainsPointCollection +required_capability: st_contains_within +required_capability: spatial_predicates_support_multivalues + +ROW location = ["POINT(5 5)", "POINT(-5 -5))"] +| EVAL location = TO_GEOPOINT(location) +| EVAL contains=ST_CONTAINS(location, TO_GEOSHAPE("GEOMETRYCOLLECTION(POINT(-5 -5), POINT(5 5))")) +| EVAL within=ST_WITHIN(location, TO_GEOSHAPE("GEOMETRYCOLLECTION(POINT(-5 -5), POINT(5 5))")) +; + +location:geo_point | contains:boolean | within:boolean +["POINT(5 5)", "POINT(-5 -5))"] | true | true +; + +literalGeometryCollection +required_capability: st_intersects +required_capability: st_contains_within +required_capability: st_disjoint + +ROW locations = TO_GEOSHAPE("GEOMETRYCOLLECTION(POINT(5 5),POINT(-5 5),POINT(0 1),POINT(1 0),POINT(9 9),POINT(-9 -9),POINT(9 9),POINT(5 5),POINT(15 15),POINT(0 0),POINT(11 11),POINT(-9 -19),POINT(9 9),POINT(5 15),POINT(15 5),POINT(0 11),POINT(11 0),POINT(19 9),POINT(-9 -19),POINT(19 9))") +| EVAL st_intersects=ST_INTERSECTS(locations, TO_GEOSHAPE("POLYGON ((-10 -10, -10 10, 10 10, 10 -10, -10 -10))")) +| EVAL st_contains_one=ST_CONTAINS(locations, TO_GEOPOINT("POINT(0 0)")) +| EVAL st_contains_none=ST_CONTAINS(locations, TO_GEOPOINT("POINT(-5 -5)")) +| EVAL st_contains_all=ST_CONTAINS(locations, locations) +| EVAL st_within_small=ST_WITHIN(locations, TO_GEOSHAPE("POLYGON ((-10 -10, -10 10, 10 10, 10 -10, -10 -10))")) +| EVAL st_within_big=ST_WITHIN(locations, TO_GEOSHAPE("POLYGON ((-20 -20, -20 20, 20 20, 20 -20, -20 -20))")) +| EVAL st_disjoint=ST_DISJOINT(locations, TO_GEOSHAPE("POLYGON ((-10 -10, -10 10, 10 10, 10 -10, -10 -10))")) +| KEEP st_intersects, st_contains_one, st_contains_none, st_contains_all, st_within_small, st_within_big, st_disjoint +; + +st_intersects:boolean | st_contains_one:boolean | st_contains_none:boolean | st_contains_all:boolean | st_within_small:boolean | st_within_big:boolean | st_disjoint:boolean +true | true | false | true | false | true | false +; + +literalMultiPoint +required_capability: st_intersects +required_capability: st_contains_within +required_capability: st_disjoint + +ROW locations = TO_GEOSHAPE("MULTIPOINT(5 5,-5 5,0 1,1 0,9 9,-9 -9,9 9,5 5,15 15,0 0,11 11,-9 -19,9 9,5 15,15 5,0 11,11 0,19 9,-9 -19,19 9)") +| EVAL st_intersects=ST_INTERSECTS(locations, TO_GEOSHAPE("POLYGON ((-10 -10, -10 10, 10 10, 10 -10, -10 -10))")) +| EVAL st_contains_one=ST_CONTAINS(locations, TO_GEOPOINT("POINT(0 0)")) +| EVAL st_contains_none=ST_CONTAINS(locations, TO_GEOPOINT("POINT(-5 -5)")) +| EVAL st_contains_all=ST_CONTAINS(locations, locations) +| EVAL st_within_small=ST_WITHIN(locations, TO_GEOSHAPE("POLYGON ((-10 -10, -10 10, 10 10, 10 -10, -10 -10))")) +| EVAL st_within_big=ST_WITHIN(locations, TO_GEOSHAPE("POLYGON ((-20 -20, -20 20, 20 20, 20 -20, -20 -20))")) +| EVAL st_disjoint=ST_DISJOINT(locations, TO_GEOSHAPE("POLYGON ((-10 -10, -10 10, 10 10, 10 -10, -10 -10))")) +| KEEP st_intersects, st_contains_one, st_contains_none, st_contains_all, st_within_small, st_within_big, st_disjoint +; + +st_intersects:boolean | st_contains_one:boolean | st_contains_none:boolean | st_contains_all:boolean | st_within_small:boolean | st_within_big:boolean | st_disjoint:boolean +true | true | false | true | false | true | false +; + +literalPointArray +required_capability: st_intersects +required_capability: st_contains_within +required_capability: st_disjoint +required_capability: spatial_predicates_support_multivalues + +ROW locations = ["POINT(5 5)","POINT(-5 5)","POINT(0 1)","POINT(1 0)","POINT(9 9)","POINT(-9 -9)","POINT(9 9)","POINT(5 5)","POINT(15 15)","POINT(0 0)","POINT(11 11)","POINT(-9 -19)","POINT(9 9)","POINT(5 15)","POINT(15 5)","POINT(0 11)","POINT(11 0)","POINT(19 9)","POINT(-9 -19)","POINT(19 9))"] +| EVAL locations = TO_GEOPOINT(locations) +| EVAL st_intersects=ST_INTERSECTS(locations, TO_GEOSHAPE("POLYGON ((-10 -10, -10 10, 10 10, 10 -10, -10 -10))")) +| EVAL st_contains_one=ST_CONTAINS(locations, TO_GEOPOINT("POINT(0 0)")) +| EVAL st_contains_none=ST_CONTAINS(locations, TO_GEOPOINT("POINT(-5 -5)")) +| EVAL st_contains_all=ST_CONTAINS(locations, locations) +| EVAL st_within_small=ST_WITHIN(locations, TO_GEOSHAPE("POLYGON ((-10 -10, -10 10, 10 10, 10 -10, -10 -10))")) +| EVAL st_within_big=ST_WITHIN(locations, TO_GEOSHAPE("POLYGON ((-20 -20, -20 20, 20 20, 20 -20, -20 -20))")) +| EVAL st_disjoint=ST_DISJOINT(locations, TO_GEOSHAPE("POLYGON ((-10 -10, -10 10, 10 10, 10 -10, -10 -10))")) +| KEEP st_intersects, st_contains_one, st_contains_none, st_contains_all, st_within_small, st_within_big, st_disjoint +; + +st_intersects:boolean | st_contains_one:boolean | st_contains_none:boolean | st_contains_all:boolean | st_within_small:boolean | st_within_big:boolean | st_disjoint:boolean +true | true | false | true | false | true | false +; + +spatialRelationMultiValuePointsFields +required_capability: st_intersects +required_capability: st_contains_within +required_capability: spatial_predicates_support_multivalues + +FROM multivalue_points +| EVAL contains_ab = ST_CONTAINS(location, subset), contains_ba = ST_CONTAINS(subset, location) +| EVAL within_ab = ST_WITHIN(location, subset), within_ba = ST_WITHIN(subset, location) +| KEEP id, contains_ab, contains_ba, within_ab, within_ba, location, subset +| SORT id +; + +id:l | contains_ab:boolean | contains_ba:boolean | within_ab:boolean | within_ba:boolean | location:geo_point | subset:geo_point +0 | true | false | false | true | ["POINT(5 5)", "POINT(-5 5)"] | "POINT(5 5)" +1 | true | false | false | true | ["POINT(0 1)","POINT(1 0)"] | "POINT(0 1)" +2 | true | true | true | true | "POINT(9 9)" | "POINT(9 9)" +3 | true | false | false | true | ["POINT(-9 -9)","POINT(9 9)"] | "POINT(-9 -9)" +4 | true | false | false | true | ["POINT(5 5)", "POINT(15 15)"] | "POINT(5 5)" +5 | true | false | false | true | ["POINT(0 0)","POINT(11 11)"] | "POINT(0 0)" +6 | true | false | false | true | ["POINT(-9 -19)","POINT(9 9)"] | "POINT(-9 -19)" +7 | true | false | false | true | ["POINT(5 15)", "POINT(15 5)"] | "POINT(5 15)" +8 | true | false | false | true | ["POINT(0 11)","POINT(11 0)"] | "POINT(0 11)" +9 | true | true | true | true | "POINT(19 9)" | "POINT(19 9)" +10 | true | false | false | true | ["POINT(-9 -19)","POINT(19 9)"] | "POINT(-9 -19)" +11 | true | false | false | true | ["POINT(0 0)", "POINT(55 55)", "POINT(-55 -55)"] | ["POINT(0 0)", "POINT(55 55)"] +12 | false | false | false | false | ["POINT(0 0)", "POINT(55 55)", "POINT(-55 -55)"] | ["POINT(0 0)", "POINT(55 54)"] +; + +whereIntersectsMultiValuePointsFields +required_capability: st_intersects +required_capability: spatial_predicates_support_multivalues + +FROM multivalue_points +| WHERE ST_INTERSECTS(location, subset) +| KEEP id, location, subset +| SORT id +; + +id:l | location:geo_point | subset:geo_point +0 | ["POINT(5 5)", "POINT(-5 5)"] | "POINT(5 5)" +1 | ["POINT(0 1)","POINT(1 0)"] | "POINT(0 1)" +2 | "POINT(9 9)" | "POINT(9 9)" +3 | ["POINT(-9 -9)","POINT(9 9)"] | "POINT(-9 -9)" +4 | ["POINT(5 5)", "POINT(15 15)"] | "POINT(5 5)" +5 | ["POINT(0 0)","POINT(11 11)"] | "POINT(0 0)" +6 | ["POINT(-9 -19)","POINT(9 9)"] | "POINT(-9 -19)" +7 | ["POINT(5 15)", "POINT(15 5)"] | "POINT(5 15)" +8 | ["POINT(0 11)","POINT(11 0)"] | "POINT(0 11)" +9 | "POINT(19 9)" | "POINT(19 9)" +10 | ["POINT(-9 -19)","POINT(19 9)"] | "POINT(-9 -19)" +11 | ["POINT(0 0)", "POINT(55 55)", "POINT(-55 -55)"] | ["POINT(0 0)", "POINT(55 55)"] +12 | ["POINT(0 0)", "POINT(55 55)", "POINT(-55 -55)"] | ["POINT(0 0)", "POINT(55 54)"] +; + +whereIntersectsMultiValuePointsStatsFields +required_capability: st_intersects +required_capability: spatial_predicates_support_multivalues + +FROM multivalue_points +| WHERE ST_INTERSECTS(location, subset) | STATS c=COUNT(*) +; + +c:l +13 +; + +whereContainsMultiValuePointsFields +required_capability: st_contains_within +required_capability: spatial_predicates_support_multivalues + +FROM multivalue_points +| WHERE ST_CONTAINS(location, subset) +| KEEP id, location, subset +| SORT id +; + +id:l | location:geo_point | subset:geo_point +0 | ["POINT(5 5)", "POINT(-5 5)"] | "POINT(5 5)" +1 | ["POINT(0 1)","POINT(1 0)"] | "POINT(0 1)" +2 | "POINT(9 9)" | "POINT(9 9)" +3 | ["POINT(-9 -9)","POINT(9 9)"] | "POINT(-9 -9)" +4 | ["POINT(5 5)", "POINT(15 15)"] | "POINT(5 5)" +5 | ["POINT(0 0)","POINT(11 11)"] | "POINT(0 0)" +6 | ["POINT(-9 -19)","POINT(9 9)"] | "POINT(-9 -19)" +7 | ["POINT(5 15)", "POINT(15 5)"] | "POINT(5 15)" +8 | ["POINT(0 11)","POINT(11 0)"] | "POINT(0 11)" +9 | "POINT(19 9)" | "POINT(19 9)" +10 | ["POINT(-9 -19)","POINT(19 9)"] | "POINT(-9 -19)" +11 | ["POINT(0 0)", "POINT(55 55)", "POINT(-55 -55)"] | ["POINT(0 0)", "POINT(55 55)"] +; + +whereContainsMultiValuePointsStatsFields +required_capability: st_contains_within +required_capability: spatial_predicates_support_multivalues + +FROM multivalue_points +| WHERE ST_CONTAINS(location, subset) | STATS c=COUNT(*) +; + +c:l +12 +; + +whereContainsMultiValuePointsStatsFieldsCentroid +required_capability: st_contains_within +required_capability: spatial_predicates_support_multivalues + +FROM multivalue_points +| WHERE ST_CONTAINS(location, subset) +| STATS c=COUNT(*), outer=ST_CENTROID_AGG(location), inner=ST_CENTROID_AGG(subset) +; + +c:l | outer:geo_point | inner:geo_point +12 | "POINT (4.391304308386601 3.086956503558094)" | "POINT (5.461538461538462 4.846153846153846)" +; + +whereWithinMultiValuePointsFields +required_capability: st_contains_within +required_capability: spatial_predicates_support_multivalues + +FROM multivalue_points +| WHERE ST_WITHIN(subset, location) +| KEEP id, location, subset +| SORT id +; + +id:l | location:geo_point | subset:geo_point +0 | ["POINT(5 5)", "POINT(-5 5)"] | "POINT(5 5)" +1 | ["POINT(0 1)","POINT(1 0)"] | "POINT(0 1)" +2 | "POINT(9 9)" | "POINT(9 9)" +3 | ["POINT(-9 -9)","POINT(9 9)"] | "POINT(-9 -9)" +4 | ["POINT(5 5)", "POINT(15 15)"] | "POINT(5 5)" +5 | ["POINT(0 0)","POINT(11 11)"] | "POINT(0 0)" +6 | ["POINT(-9 -19)","POINT(9 9)"] | "POINT(-9 -19)" +7 | ["POINT(5 15)", "POINT(15 5)"] | "POINT(5 15)" +8 | ["POINT(0 11)","POINT(11 0)"] | "POINT(0 11)" +9 | "POINT(19 9)" | "POINT(19 9)" +10 | ["POINT(-9 -19)","POINT(19 9)"] | "POINT(-9 -19)" +11 | ["POINT(0 0)", "POINT(55 55)", "POINT(-55 -55)"] | ["POINT(0 0)", "POINT(55 55)"] +; + +whereWithinMultiValuePointsStatsFields +required_capability: st_contains_within +required_capability: spatial_predicates_support_multivalues + +FROM multivalue_points +| WHERE ST_WITHIN(subset, location) | STATS c=COUNT(*) +; + +c:l +12 +; + +whereWithinMultiValuePointsStatsFieldsCentroid +required_capability: st_contains_within +required_capability: spatial_predicates_support_multivalues + +FROM multivalue_points +| WHERE ST_WITHIN(subset, location) +| STATS c=COUNT(*), inner=ST_CENTROID_AGG(subset), outer=ST_CENTROID_AGG(location) +; + +c:l | inner:geo_point | outer:geo_point +12 | "POINT (5.461538432595821 4.846153828100516)" | "POINT (4.391304347826087 3.0869565217391304)" +; diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownCartesianPointIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownCartesianPointIT.java index 1a31ba01d3e05..93701552b94aa 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownCartesianPointIT.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownCartesianPointIT.java @@ -10,7 +10,7 @@ import org.elasticsearch.geo.ShapeTestUtils; import org.elasticsearch.geometry.Geometry; -public class SpatialPushDownCartesianPointIT extends SpatialPushDownTestCase { +public class SpatialPushDownCartesianPointIT extends SpatialPushDownPointsTestCase { @Override protected String fieldType() { diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownCartesianShapeIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownCartesianShapeIT.java index 3ab7a0d516ed9..ff08475d6c1b6 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownCartesianShapeIT.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownCartesianShapeIT.java @@ -10,7 +10,7 @@ import org.elasticsearch.geo.ShapeTestUtils; import org.elasticsearch.geometry.Geometry; -public class SpatialPushDownCartesianShapeIT extends SpatialPushDownTestCase { +public class SpatialPushDownCartesianShapeIT extends SpatialPushDownShapeTestCase { @Override protected String fieldType() { diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownGeoPointIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownGeoPointIT.java index bea924ea2c22d..871fb222de3d4 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownGeoPointIT.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownGeoPointIT.java @@ -11,7 +11,7 @@ import org.elasticsearch.geo.GeometryTestUtils; import org.elasticsearch.geometry.Geometry; -public class SpatialPushDownGeoPointIT extends SpatialPushDownTestCase { +public class SpatialPushDownGeoPointIT extends SpatialPushDownPointsTestCase { private static final double LAT_MAX_VALUE = GeoEncodingUtils.decodeLatitude(Integer.MAX_VALUE - 3); diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownGeoShapeIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownGeoShapeIT.java index 3fa0385ea3681..0dbee9efbb7be 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownGeoShapeIT.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownGeoShapeIT.java @@ -10,7 +10,7 @@ import org.elasticsearch.geo.GeometryTestUtils; import org.elasticsearch.geometry.Geometry; -public class SpatialPushDownGeoShapeIT extends SpatialPushDownTestCase { +public class SpatialPushDownGeoShapeIT extends SpatialPushDownShapeTestCase { @Override protected String fieldType() { diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownPointsTestCase.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownPointsTestCase.java new file mode 100644 index 0000000000000..411106f008986 --- /dev/null +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownPointsTestCase.java @@ -0,0 +1,192 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.spatial; + +import org.elasticsearch.geometry.Point; +import org.elasticsearch.geometry.utils.GeometryValidator; +import org.elasticsearch.geometry.utils.WellKnownText; +import org.elasticsearch.lucene.spatial.CentroidCalculator; +import org.elasticsearch.xpack.core.esql.action.EsqlQueryRequestBuilder; +import org.elasticsearch.xpack.core.esql.action.EsqlQueryResponse; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + +import java.io.IOException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Locale; + +import static org.hamcrest.Matchers.closeTo; + +/** + * Base class to check that a query than can be pushed down gives the same result + * if it is actually pushed down and when it is executed by the compute engine, + * + * For doing that we create two indices, one fully indexed and another with index + * and doc values disabled. Then we index the same data in both indices and we check + * that the same ES|QL queries produce the same results in both. + */ +public abstract class SpatialPushDownPointsTestCase extends SpatialPushDownTestCase { + public void testSimplePointInPolygon() throws IOException, ParseException { + assumeTrue("Test for points only", fieldType().contains("point")); + initIndexes(); + + ArrayList data = new ArrayList<>(); + // data that intersects and is within the polygon + data.add(new MultiPointTest("[[5,5],[-5,5]]", true, true, new TestCentroid(0, 10, 2))); + data.add(new MultiPointTest("[\"0,1\",\"1,0\"]", true, true, new TestCentroid(1, 1, 2))); + data.add(new MultiPointTest("\"POINT(9 9)\"", true, true, new TestCentroid(9, 9, 1))); + data.add(new MultiPointTest("[\"POINT(-9 -9)\",\"POINT(9 9)\"]", true, true, new TestCentroid(0, 0, 2))); + // data that intersects but is not within the polygon + data.add(new MultiPointTest("[[5,5],[15,15]]", true, false, new TestCentroid(20, 20, 2))); + data.add(new MultiPointTest("[\"0,0\",\"11,11\"]", true, false, new TestCentroid(11, 11, 2))); + data.add(new MultiPointTest("[\"POINT(-9 -19)\",\"POINT(9 9)\"]", true, false, new TestCentroid(0, -10, 2))); + // data that does not intersect + data.add(new MultiPointTest("[[5,15],[15,5]]", false, false, new TestCentroid(20, 20, 2))); + data.add(new MultiPointTest("[\"0,11\",\"11,0\"]", false, false, new TestCentroid(11, 11, 2))); + data.add(new MultiPointTest("\"POINT(19 9)\"", false, false, new TestCentroid(19, 9, 1))); + data.add(new MultiPointTest("[\"POINT(-9 -19)\",\"POINT(19 9)\"]", false, false, new TestCentroid(10, -10, 2))); + + int expectedIntersects = 0; + int expectedWithin = 0; + int expectedDisjoint = 0; + CentroidCalculator intersectsCentroid = new CentroidCalculator(); + CentroidCalculator withinCentroid = new CentroidCalculator(); + CentroidCalculator disjointCentroid = new CentroidCalculator(); + for (int i = 0; i < data.size(); i++) { + index("indexed", i + "", "{\"location\" : " + data.get(i).data + " }"); + index("not-indexed", i + "", "{\"location\" : " + data.get(i).data + " }"); + if (data.get(i).intersects) { + expectedIntersects++; + data.get(i).centroid.addTo(intersectsCentroid); + } else { + expectedDisjoint++; + data.get(i).centroid.addTo(disjointCentroid); + } + if (data.get(i).within) { + expectedWithin++; + data.get(i).centroid.addTo(withinCentroid); + } + } + refresh("indexed", "not-indexed"); + + for (String polygon : new String[] { + "POLYGON ((-10 -10, -10 10, 10 10, 10 -10, -10 -10))", + "POLYGON ((-10 -10, 10 -10, 10 10, -10 10, -10 -10))" }) { + assertFunction("ST_WITHIN", polygon, expectedWithin, withinCentroid); + assertFunction("ST_INTERSECTS", polygon, expectedIntersects, intersectsCentroid); + assertFunction("ST_DISJOINT", polygon, expectedDisjoint, disjointCentroid); + } + } + + protected void assertFunction(String spatialFunction, String wkt, long expected, CentroidCalculator centroid) throws IOException, + ParseException { + final String query1 = String.format(Locale.ROOT, """ + FROM indexed | WHERE %s(location, %s("%s")) | STATS COUNT(*), ST_CENTROID_AGG(location) + """, spatialFunction, castingFunction(), wkt); + final String query2 = String.format(Locale.ROOT, """ + FROM not-indexed | WHERE %s(location, %s("%s")) | STATS COUNT(*), ST_CENTROID_AGG(location) + """, spatialFunction, castingFunction(), wkt); + try ( + EsqlQueryResponse response1 = EsqlQueryRequestBuilder.newRequestBuilder(client()).query(query1).get(); + EsqlQueryResponse response2 = EsqlQueryRequestBuilder.newRequestBuilder(client()).query(query2).get(); + ) { + Object indexedCount = response1.response().column(0).iterator().next(); + Object notIndexedCount = response2.response().column(0).iterator().next(); + assertEquals(spatialFunction + "[expected=" + expected + "]", expected, indexedCount); + assertEquals(spatialFunction + "[expected=" + expected + "]", expected, notIndexedCount); + Object indexedCentroid = response1.response().column(1).iterator().next(); + Object notIndexedCentroid = response2.response().column(1).iterator().next(); + assertThat(spatialFunction + "[expected=" + toString(centroid) + "]", centroid, matchesCentroid(indexedCentroid)); + assertThat(spatialFunction + "[expected=" + toString(centroid) + "]", centroid, matchesCentroid(notIndexedCentroid)); + } + } + + private String toString(CentroidCalculator centroid) { + return "Centroid (x:" + centroid.getX() + ", y:" + centroid.getY() + ")"; + } + + private record MultiPointTest(String data, boolean intersects, boolean within, TestCentroid centroid) {} + + private static class TestCentroid { + private final double x; + private final double y; + private final long count; + + TestCentroid(double x, double y, long count) { + this.x = x; + this.y = y; + this.count = count; + } + + private void addTo(CentroidCalculator calculator) { + for (long i = 0; i < count; i++) { + calculator.add(asPoint()); + } + } + + private double x() { + return x / count; + } + + private double y() { + return y / count; + } + + private Point asPoint() { + return new Point(x(), y()); + } + } + + private Matcher matchesCentroid(Object result) throws IOException, ParseException { + Point point = (Point) WellKnownText.fromWKT(GeometryValidator.NOOP, false, result.toString()); + return matchesCentroid(point); + } + + private Matcher matchesCentroid(Point point) { + return new TestCentroidMatcher(point.getX(), point.getY()); + } + + private static class TestCentroidMatcher extends TypeSafeMatcher { + private final Matcher xMatcher; + private final Matcher yMatcher; + + private TestCentroidMatcher(double x, double y) { + this.xMatcher = matchDouble(x); + this.yMatcher = matchDouble(y); + } + + private Matcher matchDouble(double value) { + return closeTo(value, 0.0000001); + } + + @Override + public boolean matchesSafely(CentroidCalculator actualCentroid) { + return xMatcher.matches(actualCentroid.getX()) && yMatcher.matches(actualCentroid.getY()); + } + + @Override + public void describeMismatchSafely(CentroidCalculator actualCentroid, Description description) { + describeSubMismatch(xMatcher, actualCentroid.getX(), "X value", description); + describeSubMismatch(yMatcher, actualCentroid.getY(), "Y value", description); + } + + private void describeSubMismatch(Matcher matcher, double value, String name, Description description) { + if (matcher.matches(value) == false) { + description.appendText("\n\t" + name + " "); + matcher.describeMismatch(value, description); + } + } + + @Override + public void describeTo(Description description) { + description.appendText("Centroid (x:" + xMatcher.toString() + ", y:" + yMatcher + ")"); + } + } +} diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownShapeTestCase.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownShapeTestCase.java new file mode 100644 index 0000000000000..4ed5a890b4da6 --- /dev/null +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownShapeTestCase.java @@ -0,0 +1,278 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.spatial; + +import org.elasticsearch.xpack.core.esql.action.EsqlQueryRequestBuilder; +import org.elasticsearch.xpack.core.esql.action.EsqlQueryResponse; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Locale; + +import static org.hamcrest.Matchers.greaterThanOrEqualTo; + +public abstract class SpatialPushDownShapeTestCase extends SpatialPushDownTestCase { + + public void testSimpleShapeContainsPolygon() { + assumeTrue("Test for shapes only", fieldType().contains("shape")); + initIndexes(); + ArrayList data = new ArrayList<>(); + + // data that intersects and contains the polygon + data.add(new ShapeContainsTest(true, true, square(0, 0, 15))); + data.add(new ShapeContainsTest(true, true, square(0, 0, 15), square(20, 20, 5))); + // data that intersects but does not contain the polygon + data.add(new ShapeContainsTest(true, false, square(0, 0, 5))); + data.add(new ShapeContainsTest(true, false, square(0, 0, 5), square(20, 20, 5))); + data.add(new ShapeContainsTest(true, false, square(-5, -5, 5), square(5, 5, 5))); + // data that does not intersect the polygon + data.add(new ShapeContainsTest(false, false, square(20, 20, 5))); + data.add(new ShapeContainsTest(false, false, square(-20, -20, 5), square(20, 20, 5))); + // data that geometrically contains the polygon but due to lucene's triangle-tree implementation, it cannot + data.add(new ShapeContainsTest(true, false, square(0, 0, 15), square(10, 10, 5))); + + int expectedIntersects = 0; + int expectedContains = 0; + for (int i = 0; i < data.size(); i++) { + index("indexed", i + "", "{\"location\" : " + data.get(i).toJson() + " }"); + index("not-indexed", i + "", "{\"location\" : " + data.get(i).toJson() + " }"); + expectedIntersects += data.get(i).intersects ? 1 : 0; + expectedContains += data.get(i).contains ? 1 : 0; + } + refresh("indexed", "not-indexed"); + int expectedDisjoint = data.size() - expectedIntersects; + + for (String polygon : new String[] { + "POLYGON ((-10 -10, -10 10, 10 10, 10 -10, -10 -10))", + "POLYGON ((-10 -10, 10 -10, 10 10, -10 10, -10 -10))" }) { + assertFunction("ST_CONTAINS", polygon, expectedContains); + assertFunction("ST_INTERSECTS", polygon, expectedIntersects); + assertFunction("ST_DISJOINT", polygon, expectedDisjoint); + } + } + + public void testSimpleShapeContainsTwoPolygons() { + assumeTrue("Test for shapes only", fieldType().contains("shape")); + initIndexes(); + String twoPolygonsInCollection = "GEOMETRYCOLLECTION(" + square(-5, -5, 4) + "," + square(5, 5, 4) + ")"; + String twoPolygonsInMultiPolygon = collectionToMultiPolygon(twoPolygonsInCollection); + String twoPolygonsInCollectionField = "GEOMETRYCOLLECTION(" + square(-5, -5, 5) + "," + square(5, 5, 5) + ")"; + String twoPolygonsInMultiPolygonField = collectionToMultiPolygon(twoPolygonsInCollectionField); + + ArrayList data = new ArrayList<>(); + // data that intersects and contains the geometrycollection + data.add(new ShapeContainsTest(true, true, twoPolygonsInCollectionField)); + data.add(new ShapeContainsTest(true, true, twoPolygonsInMultiPolygonField)); + data.add(new ShapeContainsTest(true, true, square(0, 0, 15))); + data.add(new ShapeContainsTest(true, true, square(0, 0, 15), square(20, 20, 5))); + data.add(new ShapeContainsTest(true, true, square(-5, -5, 5), square(5, 5, 5))); + // data that intersects but does not contain the geometrycollection + data.add(new ShapeContainsTest(true, false, square(0, 0, 5))); + data.add(new ShapeContainsTest(true, false, square(0, 0, 5), square(20, 20, 5))); + data.add(new ShapeContainsTest(true, false, square(-5, -5, 4), square(5, 5, 4))); + // data that does not intersect the geometrycollection + data.add(new ShapeContainsTest(false, false, square(20, 20, 5))); + data.add(new ShapeContainsTest(false, false, square(-20, -20, 5), square(20, 20, 5))); + // data that geometrically contains the geometrycollection but due to lucene's triangle-tree implementation, it cannot + data.add(new ShapeContainsTest(true, false, square(0, 0, 15), square(10, 10, 5))); + data.add(new ShapeContainsTest(true, false, square(-5, -5, 6), square(5, 5, 6))); + + int expectedIntersects = 0; + int expectedContains = 0; + for (int i = 0; i < data.size(); i++) { + index("indexed", i + "", "{\"location\" : " + data.get(i).toJson() + " }"); + index("not-indexed", i + "", "{\"location\" : " + data.get(i).toJson() + " }"); + expectedIntersects += data.get(i).intersects ? 1 : 0; + expectedContains += data.get(i).contains ? 1 : 0; + } + refresh("indexed", "not-indexed"); + int expectedDisjoint = data.size() - expectedIntersects; + + for (String twoPolygons : new String[] { twoPolygonsInCollection, twoPolygonsInMultiPolygon }) { + assertFunction("ST_CONTAINS", twoPolygons, expectedContains); + assertFunction("ST_INTERSECTS", twoPolygons, expectedIntersects); + assertFunction("ST_DISJOINT", twoPolygons, expectedDisjoint); + } + } + + public void testMultiShapeContainsMultiPolygon() { + assumeTrue("Test for shapes only", fieldType().contains("shape")); + initIndexes(); + ArrayList data = new ArrayList<>(); + + // Contains succeeds with multiple non-intersecting polygons + data.add(new MultiShapeContainsTest(true).small(square(0, 0, 4), square(20, 20, 4)).big(square(0, 0, 5), square(20, 20, 5))); + data.add(new MultiShapeContainsTest(true).small(square(-5, -5, 3), square(5, 5, 3)).big(square(-5, -5, 4), square(5, 5, 4))); + + // Contains fails with multiple intersecting polygons due to the way it is implemented in the lucene triangle tree + data.add(new MultiShapeContainsTest(false).small(square(0, 0, 14), square(10, 10, 4)).big(square(0, 0, 15), square(10, 10, 5))); + data.add(new MultiShapeContainsTest(false).small(square(-5, -5, 5), square(5, 5, 5)).big(square(-5, -5, 6), square(5, 5, 6))); + + for (int i = 0; i < data.size(); i++) { + index("indexed", "" + i, "{\"location\" : " + data.get(i).smallJson() + " }"); + index("not-indexed", "" + i, "{\"location\" : " + data.get(i).smallJson() + " }"); + index("indexed", "" + (i + 100), "{\"location\" : " + data.get(i).bigJson() + " }"); + index("not-indexed", "" + (i + 100), "{\"location\" : " + data.get(i).bigJson() + " }"); + } + refresh("indexed", "not-indexed"); + + for (int i = 0; i < data.size(); i++) { + MultiShapeContainsTest datum = data.get(i); + assertFunction(i, datum.smallJson(), "ST_WITHIN", datum.bigQuery(), true); + assertFunction(i, datum.smallJson(), "ST_INTERSECTS", datum.bigQuery(), true); + assertFunction(i + 100, datum.bigJson(), "ST_CONTAINS", datum.smallQuery(), datum.contains); + assertFunction(i + 100, datum.bigJson(), "ST_INTERSECTS", datum.smallQuery(), true); + } + } + + private String collectionToMultiPolygon(String geometrytCollection) { + return geometrytCollection.replace("POLYGON", "").replace("GEOMETRYCOLLECTION", "MULTIPOLYGON"); + } + + protected void assertFunction(String spatialFunction, String wkt, long expected) { + final String query1 = String.format(Locale.ROOT, """ + FROM indexed | WHERE %s(location, %s("%s")) | STATS COUNT(*) + """, spatialFunction, castingFunction(), wkt); + final String query2 = String.format(Locale.ROOT, """ + FROM not-indexed | WHERE %s(location, %s("%s")) | STATS COUNT(*) + """, spatialFunction, castingFunction(), wkt); + try ( + EsqlQueryResponse response1 = EsqlQueryRequestBuilder.newRequestBuilder(client()).query(query1).get(); + EsqlQueryResponse response2 = EsqlQueryRequestBuilder.newRequestBuilder(client()).query(query2).get(); + ) { + Object indexedResult = response1.response().column(0).iterator().next(); + Object notIndexedResult = response2.response().column(0).iterator().next(); + assertEquals(spatialFunction + "[expected=" + expected + "]", expected, indexedResult); + assertEquals(spatialFunction + "[expected=" + expected + "]", indexedResult, notIndexedResult); + } + } + + private void assertFunction(int id, String expected, String spatialFunction, String wkt, boolean expectToFind) { + expected = expected.replaceAll("\\.0+", ".0").replace("\"", ""); + final String predicate = String.format(Locale.ROOT, "WHERE %s(location, %s(\"%s\"))", spatialFunction, castingFunction(), wkt); + final String query1 = "FROM indexed METADATA _id | " + predicate + " | KEEP _id, location"; + final String query2 = "FROM not-indexed METADATA _id | " + predicate + " | KEEP _id, location"; + try ( + EsqlQueryResponse response1 = EsqlQueryRequestBuilder.newRequestBuilder(client()).query(query1).get(); + EsqlQueryResponse response2 = EsqlQueryRequestBuilder.newRequestBuilder(client()).query(query2).get(); + ) { + record Result(int id, String location) { + Result(Iterator iterator) { + this(Integer.parseInt(iterator.next().toString()), iterator.next().toString()); + } + } + ArrayList indexedResults = new ArrayList<>(); + ArrayList notIndexedResults = new ArrayList<>(); + response1.response().rows().forEach(row -> indexedResults.add(new Result(row.iterator()))); + response2.response().rows().forEach(row -> notIndexedResults.add(new Result(row.iterator()))); + assertThat("No results found at all", indexedResults.size() + notIndexedResults.size(), greaterThanOrEqualTo(0)); + boolean found = false; + ArrayList missingFromIndexedResults = new ArrayList<>(); + ArrayList missingFromNotIndexedResults = new ArrayList<>(); + for (int i = 0, j = 0; i < indexedResults.size() && j < notIndexedResults.size();) { + Result indexedResult = indexedResults.get(i); + Result notIndexedResult = indexedResults.get(j); + if (indexedResult.id() == notIndexedResult.id()) { + if (indexedResult.id() == id) { + assertEquals(spatialFunction + "[expected=" + expected + "]", expected, indexedResult.location); + assertEquals(spatialFunction + "[expected=" + expected + "]", indexedResult, notIndexedResult); + found = true; + } + i++; + j++; + } else { + if (indexedResult.id() < notIndexedResult.id()) { + missingFromNotIndexedResults.add(indexedResult); + i++; + } else { + missingFromIndexedResults.add(notIndexedResult); + j++; + } + } + } + if (missingFromIndexedResults.isEmpty() == false || missingFromNotIndexedResults.isEmpty() == false) { + StringBuilder sb = new StringBuilder("Mismatching results between indexed and not-indexed: "); + if (missingFromIndexedResults.isEmpty() == false) { + sb.append("Missing from indexed: ").append(missingFromIndexedResults); + } + if (missingFromNotIndexedResults.isEmpty() == false) { + sb.append("Missing from not-indexed: ").append(missingFromNotIndexedResults); + } + fail(sb.toString()); + } + if (expectToFind && found == false) { + fail("Expected result not found: " + expected); + } + if (expectToFind == false && found) { + fail("Unexpected result found: " + expected); + } + } + } + + private String square(double x, double y, double size) { + return String.format( + Locale.ROOT, + "POLYGON ((%.2f %.2f, %.2f %.2f, %.2f %.2f, %.2f %.2f, %.2f %.2f))", + x - size, + y - size, + x + size, + y - size, + x + size, + y + size, + x - size, + y + size, + x - size, + y - size + ); + } + + protected record ShapeContainsTest(boolean intersects, boolean contains, String... data) { + private String toJson() { + return Arrays.toString(Arrays.stream(data).map(s -> "\"" + s + "\"").toArray()); + } + } + + protected record MultiShapeContainsTest(boolean contains, String[] bigger, String[] smaller) { + private MultiShapeContainsTest(boolean contains) { + this(contains, new String[] {}, new String[] {}); + } + + private MultiShapeContainsTest small(String... smaller) { + return new MultiShapeContainsTest(contains, bigger, smaller); + } + + private MultiShapeContainsTest big(String... bigger) { + return new MultiShapeContainsTest(contains, bigger, smaller); + } + + private String bigQuery() { + return query(bigger); + } + + private String smallQuery() { + return query(smaller); + } + + private String smallJson() { + return json(smaller); + } + + private String bigJson() { + return json(bigger); + } + + private static String json(String[] data) { + return Arrays.toString(Arrays.stream(data).map(s -> "\"" + s + "\"").toArray()); + } + + private static String query(String[] data) { + return data.length == 1 ? data[0] : "GEOMETRYCOLLECTION(" + String.join(", ", data) + ")"; + } + } +} diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownTestCase.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownTestCase.java index ead9d76f0b74d..9dff647763b6b 100644 --- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownTestCase.java +++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialPushDownTestCase.java @@ -64,12 +64,11 @@ public void testPushedDownQueriesSingleValue() throws RuntimeException { assertPushedDownQueries(false); } - @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/110830") public void testPushedDownQueriesMultiValue() throws RuntimeException { assertPushedDownQueries(true); } - private void assertPushedDownQueries(boolean multiValue) throws RuntimeException { + protected void initIndexes() { assertAcked(prepareCreate("indexed").setMapping(String.format(Locale.ROOT, """ { "properties" : { @@ -85,6 +84,10 @@ private void assertPushedDownQueries(boolean multiValue) throws RuntimeException } } """, fieldType()))); + } + + private void assertPushedDownQueries(boolean multiValue) throws RuntimeException { + initIndexes(); for (int i = 0; i < random().nextInt(50, 100); i++) { if (multiValue) { final String[] values = new String[randomIntBetween(1, 5)]; @@ -102,6 +105,10 @@ private void assertPushedDownQueries(boolean multiValue) throws RuntimeException refresh("indexed", "not-indexed"); + String smallRectangleCW = "POLYGON ((-10 -10, -10 10, 10 10, 10 -10, -10 -10))"; + assertFunction("ST_WITHIN", smallRectangleCW); + String smallRectangleCCW = "POLYGON ((-10 -10, 10 -10, 10 10, -10 10, -10 -10))"; + assertFunction("ST_WITHIN", smallRectangleCCW); for (int i = 0; i < 10; i++) { final Geometry geometry = getQueryGeometry(); final String wkt = WellKnownText.toWKT(geometry); @@ -115,7 +122,7 @@ private void assertPushedDownQueries(boolean multiValue) throws RuntimeException } } - private void assertFunction(String spatialFunction, String wkt) { + protected void assertFunction(String spatialFunction, String wkt) { final String query1 = String.format(Locale.ROOT, """ FROM indexed | WHERE %s(location, %s("%s")) | STATS COUNT(*) """, spatialFunction, castingFunction(), wkt); @@ -126,7 +133,9 @@ private void assertFunction(String spatialFunction, String wkt) { EsqlQueryResponse response1 = EsqlQueryRequestBuilder.newRequestBuilder(client()).query(query1).get(); EsqlQueryResponse response2 = EsqlQueryRequestBuilder.newRequestBuilder(client()).query(query2).get(); ) { - assertEquals(response1.response().column(0).iterator().next(), response2.response().column(0).iterator().next()); + Object indexedResult = response1.response().column(0).iterator().next(); + Object notIndexedResult = response2.response().column(0).iterator().next(); + assertEquals(spatialFunction, indexedResult, notIndexedResult); } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianPointDocValuesAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianPointDocValuesAndConstantEvaluator.java index 30f5ef487f612..fbe0b57f775e5 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianPointDocValuesAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianPointDocValuesAndConstantEvaluator.java @@ -4,6 +4,7 @@ // 2.0. package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; +import java.io.IOException; import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; @@ -11,7 +12,6 @@ import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.LongBlock; -import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -26,63 +26,41 @@ public final class SpatialContainsCartesianPointDocValuesAndConstantEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final Component2D[] rightValue; + private final Component2D[] right; private final DriverContext driverContext; public SpatialContainsCartesianPointDocValuesAndConstantEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, Component2D[] rightValue, - DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + EvalOperator.ExpressionEvaluator left, Component2D[] right, DriverContext driverContext) { + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (LongBlock leftValueBlock = (LongBlock) leftValue.eval(page)) { - LongVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock); - } - return eval(page.getPositionCount(), leftValueVector); + try (LongBlock leftBlock = (LongBlock) left.eval(page)) { + return eval(page.getPositionCount(), leftBlock); } } - public BooleanBlock eval(int positionCount, LongBlock leftValueBlock) { + public BooleanBlock eval(int positionCount, LongBlock leftBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + if (allBlocksAreNulls) { result.appendNull(); continue position; } try { - result.appendBoolean(SpatialContains.processCartesianPointDocValuesAndConstant(leftValueBlock.getLong(leftValueBlock.getFirstValueIndex(p)), this.rightValue)); - } catch (IllegalArgumentException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, LongVector leftValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - position: for (int p = 0; p < positionCount; p++) { - try { - result.appendBoolean(SpatialContains.processCartesianPointDocValuesAndConstant(leftValueVector.getLong(p), this.rightValue)); - } catch (IllegalArgumentException e) { + SpatialContains.processCartesianPointDocValuesAndConstant(result, p, leftBlock, this.right); + } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); } @@ -93,36 +71,36 @@ public BooleanBlock eval(int positionCount, LongVector leftValueVector) { @Override public String toString() { - return "SpatialContainsCartesianPointDocValuesAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialContainsCartesianPointDocValuesAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue); + Releasables.closeExpectNoException(left); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final Component2D[] rightValue; + private final Component2D[] right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - Component2D[] rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + Component2D[] right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialContainsCartesianPointDocValuesAndConstantEvaluator get(DriverContext context) { - return new SpatialContainsCartesianPointDocValuesAndConstantEvaluator(source, leftValue.get(context), rightValue, context); + return new SpatialContainsCartesianPointDocValuesAndConstantEvaluator(source, left.get(context), right, context); } @Override public String toString() { - return "SpatialContainsCartesianPointDocValuesAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialContainsCartesianPointDocValuesAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianPointDocValuesAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianPointDocValuesAndSourceEvaluator.java index 1d9da890a1b48..074415f0eb4dd 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianPointDocValuesAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianPointDocValuesAndSourceEvaluator.java @@ -4,17 +4,14 @@ // 2.0. package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; +import java.io.IOException; import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; -import org.elasticsearch.compute.data.BooleanVector; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.LongBlock; -import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -29,77 +26,50 @@ public final class SpatialContainsCartesianPointDocValuesAndSourceEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final EvalOperator.ExpressionEvaluator rightValue; + private final EvalOperator.ExpressionEvaluator right; private final DriverContext driverContext; public SpatialContainsCartesianPointDocValuesAndSourceEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, EvalOperator.ExpressionEvaluator rightValue, + EvalOperator.ExpressionEvaluator left, EvalOperator.ExpressionEvaluator right, DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (LongBlock leftValueBlock = (LongBlock) leftValue.eval(page)) { - try (BytesRefBlock rightValueBlock = (BytesRefBlock) rightValue.eval(page)) { - LongVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - BytesRefVector rightValueVector = rightValueBlock.asVector(); - if (rightValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - return eval(page.getPositionCount(), leftValueVector, rightValueVector).asBlock(); + try (LongBlock leftBlock = (LongBlock) left.eval(page)) { + try (BytesRefBlock rightBlock = (BytesRefBlock) right.eval(page)) { + return eval(page.getPositionCount(), leftBlock, rightBlock); } } } - public BooleanBlock eval(int positionCount, LongBlock leftValueBlock, - BytesRefBlock rightValueBlock) { + public BooleanBlock eval(int positionCount, LongBlock leftBlock, BytesRefBlock rightBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef rightValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; + if (!rightBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (rightValueBlock.isNull(p)) { + if (allBlocksAreNulls) { result.appendNull(); continue position; } - if (rightValueBlock.getValueCount(p) != 1) { - if (rightValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + try { + SpatialContains.processCartesianPointDocValuesAndSource(result, p, leftBlock, rightBlock); + } catch (IllegalArgumentException | IOException e) { + warnings.registerException(e); result.appendNull(); - continue position; } - result.appendBoolean(SpatialContains.processCartesianPointDocValuesAndSource(leftValueBlock.getLong(leftValueBlock.getFirstValueIndex(p)), rightValueBlock.getBytesRef(rightValueBlock.getFirstValueIndex(p), rightValueScratch))); - } - return result.build(); - } - } - - public BooleanVector eval(int positionCount, LongVector leftValueVector, - BytesRefVector rightValueVector) { - try(BooleanVector.FixedBuilder result = driverContext.blockFactory().newBooleanVectorFixedBuilder(positionCount)) { - BytesRef rightValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { - result.appendBoolean(p, SpatialContains.processCartesianPointDocValuesAndSource(leftValueVector.getLong(p), rightValueVector.getBytesRef(p, rightValueScratch))); } return result.build(); } @@ -107,36 +77,36 @@ public BooleanVector eval(int positionCount, LongVector leftValueVector, @Override public String toString() { - return "SpatialContainsCartesianPointDocValuesAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialContainsCartesianPointDocValuesAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue, rightValue); + Releasables.closeExpectNoException(left, right); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final EvalOperator.ExpressionEvaluator.Factory rightValue; + private final EvalOperator.ExpressionEvaluator.Factory right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - EvalOperator.ExpressionEvaluator.Factory rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + EvalOperator.ExpressionEvaluator.Factory right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialContainsCartesianPointDocValuesAndSourceEvaluator get(DriverContext context) { - return new SpatialContainsCartesianPointDocValuesAndSourceEvaluator(source, leftValue.get(context), rightValue.get(context), context); + return new SpatialContainsCartesianPointDocValuesAndSourceEvaluator(source, left.get(context), right.get(context), context); } @Override public String toString() { - return "SpatialContainsCartesianPointDocValuesAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialContainsCartesianPointDocValuesAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianSourceAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianSourceAndConstantEvaluator.java index 9205f1faaa3d0..e20df8977b978 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianSourceAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianSourceAndConstantEvaluator.java @@ -9,11 +9,9 @@ import java.lang.Override; import java.lang.String; import org.apache.lucene.geo.Component2D; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -28,64 +26,40 @@ public final class SpatialContainsCartesianSourceAndConstantEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final Component2D[] rightValue; + private final Component2D[] right; private final DriverContext driverContext; public SpatialContainsCartesianSourceAndConstantEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, Component2D[] rightValue, - DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + EvalOperator.ExpressionEvaluator left, Component2D[] right, DriverContext driverContext) { + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (BytesRefBlock leftValueBlock = (BytesRefBlock) leftValue.eval(page)) { - BytesRefVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock); - } - return eval(page.getPositionCount(), leftValueVector); + try (BytesRefBlock leftBlock = (BytesRefBlock) left.eval(page)) { + return eval(page.getPositionCount(), leftBlock); } } - public BooleanBlock eval(int positionCount, BytesRefBlock leftValueBlock) { + public BooleanBlock eval(int positionCount, BytesRefBlock leftBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + if (allBlocksAreNulls) { result.appendNull(); continue position; } try { - result.appendBoolean(SpatialContains.processCartesianSourceAndConstant(leftValueBlock.getBytesRef(leftValueBlock.getFirstValueIndex(p), leftValueScratch), this.rightValue)); - } catch (IllegalArgumentException | IOException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { - try { - result.appendBoolean(SpatialContains.processCartesianSourceAndConstant(leftValueVector.getBytesRef(p, leftValueScratch), this.rightValue)); + SpatialContains.processCartesianSourceAndConstant(result, p, leftBlock, this.right); } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); @@ -97,36 +71,36 @@ public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector) { @Override public String toString() { - return "SpatialContainsCartesianSourceAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialContainsCartesianSourceAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue); + Releasables.closeExpectNoException(left); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final Component2D[] rightValue; + private final Component2D[] right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - Component2D[] rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + Component2D[] right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialContainsCartesianSourceAndConstantEvaluator get(DriverContext context) { - return new SpatialContainsCartesianSourceAndConstantEvaluator(source, leftValue.get(context), rightValue, context); + return new SpatialContainsCartesianSourceAndConstantEvaluator(source, left.get(context), right, context); } @Override public String toString() { - return "SpatialContainsCartesianSourceAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialContainsCartesianSourceAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianSourceAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianSourceAndSourceEvaluator.java index 9d19429519a6e..a3022e3ac3204 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianSourceAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianSourceAndSourceEvaluator.java @@ -8,11 +8,9 @@ import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -27,85 +25,46 @@ public final class SpatialContainsCartesianSourceAndSourceEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final EvalOperator.ExpressionEvaluator rightValue; + private final EvalOperator.ExpressionEvaluator right; private final DriverContext driverContext; public SpatialContainsCartesianSourceAndSourceEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, EvalOperator.ExpressionEvaluator rightValue, + EvalOperator.ExpressionEvaluator left, EvalOperator.ExpressionEvaluator right, DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (BytesRefBlock leftValueBlock = (BytesRefBlock) leftValue.eval(page)) { - try (BytesRefBlock rightValueBlock = (BytesRefBlock) rightValue.eval(page)) { - BytesRefVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - BytesRefVector rightValueVector = rightValueBlock.asVector(); - if (rightValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - return eval(page.getPositionCount(), leftValueVector, rightValueVector); + try (BytesRefBlock leftBlock = (BytesRefBlock) left.eval(page)) { + try (BytesRefBlock rightBlock = (BytesRefBlock) right.eval(page)) { + return eval(page.getPositionCount(), leftBlock, rightBlock); } } } - public BooleanBlock eval(int positionCount, BytesRefBlock leftValueBlock, - BytesRefBlock rightValueBlock) { + public BooleanBlock eval(int positionCount, BytesRefBlock leftBlock, BytesRefBlock rightBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - BytesRef rightValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; + if (!rightBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (rightValueBlock.isNull(p)) { + if (allBlocksAreNulls) { result.appendNull(); continue position; } - if (rightValueBlock.getValueCount(p) != 1) { - if (rightValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; - } - try { - result.appendBoolean(SpatialContains.processCartesianSourceAndSource(leftValueBlock.getBytesRef(leftValueBlock.getFirstValueIndex(p), leftValueScratch), rightValueBlock.getBytesRef(rightValueBlock.getFirstValueIndex(p), rightValueScratch))); - } catch (IllegalArgumentException | IOException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector, - BytesRefVector rightValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - BytesRef rightValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { try { - result.appendBoolean(SpatialContains.processCartesianSourceAndSource(leftValueVector.getBytesRef(p, leftValueScratch), rightValueVector.getBytesRef(p, rightValueScratch))); + SpatialContains.processCartesianSourceAndSource(result, p, leftBlock, rightBlock); } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); @@ -117,36 +76,36 @@ public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector, @Override public String toString() { - return "SpatialContainsCartesianSourceAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialContainsCartesianSourceAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue, rightValue); + Releasables.closeExpectNoException(left, right); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final EvalOperator.ExpressionEvaluator.Factory rightValue; + private final EvalOperator.ExpressionEvaluator.Factory right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - EvalOperator.ExpressionEvaluator.Factory rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + EvalOperator.ExpressionEvaluator.Factory right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialContainsCartesianSourceAndSourceEvaluator get(DriverContext context) { - return new SpatialContainsCartesianSourceAndSourceEvaluator(source, leftValue.get(context), rightValue.get(context), context); + return new SpatialContainsCartesianSourceAndSourceEvaluator(source, left.get(context), right.get(context), context); } @Override public String toString() { - return "SpatialContainsCartesianSourceAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialContainsCartesianSourceAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoPointDocValuesAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoPointDocValuesAndConstantEvaluator.java index a76ccaadfc4bf..c5ca553840579 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoPointDocValuesAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoPointDocValuesAndConstantEvaluator.java @@ -4,6 +4,7 @@ // 2.0. package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; +import java.io.IOException; import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; @@ -11,7 +12,6 @@ import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.LongBlock; -import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -26,63 +26,41 @@ public final class SpatialContainsGeoPointDocValuesAndConstantEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final Component2D[] rightValue; + private final Component2D[] right; private final DriverContext driverContext; public SpatialContainsGeoPointDocValuesAndConstantEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, Component2D[] rightValue, - DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + EvalOperator.ExpressionEvaluator left, Component2D[] right, DriverContext driverContext) { + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (LongBlock leftValueBlock = (LongBlock) leftValue.eval(page)) { - LongVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock); - } - return eval(page.getPositionCount(), leftValueVector); + try (LongBlock leftBlock = (LongBlock) left.eval(page)) { + return eval(page.getPositionCount(), leftBlock); } } - public BooleanBlock eval(int positionCount, LongBlock leftValueBlock) { + public BooleanBlock eval(int positionCount, LongBlock leftBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + if (allBlocksAreNulls) { result.appendNull(); continue position; } try { - result.appendBoolean(SpatialContains.processGeoPointDocValuesAndConstant(leftValueBlock.getLong(leftValueBlock.getFirstValueIndex(p)), this.rightValue)); - } catch (IllegalArgumentException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, LongVector leftValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - position: for (int p = 0; p < positionCount; p++) { - try { - result.appendBoolean(SpatialContains.processGeoPointDocValuesAndConstant(leftValueVector.getLong(p), this.rightValue)); - } catch (IllegalArgumentException e) { + SpatialContains.processGeoPointDocValuesAndConstant(result, p, leftBlock, this.right); + } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); } @@ -93,36 +71,36 @@ public BooleanBlock eval(int positionCount, LongVector leftValueVector) { @Override public String toString() { - return "SpatialContainsGeoPointDocValuesAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialContainsGeoPointDocValuesAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue); + Releasables.closeExpectNoException(left); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final Component2D[] rightValue; + private final Component2D[] right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - Component2D[] rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + Component2D[] right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialContainsGeoPointDocValuesAndConstantEvaluator get(DriverContext context) { - return new SpatialContainsGeoPointDocValuesAndConstantEvaluator(source, leftValue.get(context), rightValue, context); + return new SpatialContainsGeoPointDocValuesAndConstantEvaluator(source, left.get(context), right, context); } @Override public String toString() { - return "SpatialContainsGeoPointDocValuesAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialContainsGeoPointDocValuesAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoPointDocValuesAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoPointDocValuesAndSourceEvaluator.java index bd083e382927c..593818c577305 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoPointDocValuesAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoPointDocValuesAndSourceEvaluator.java @@ -4,16 +4,14 @@ // 2.0. package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; +import java.io.IOException; import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.LongBlock; -import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -28,84 +26,47 @@ public final class SpatialContainsGeoPointDocValuesAndSourceEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final EvalOperator.ExpressionEvaluator rightValue; + private final EvalOperator.ExpressionEvaluator right; private final DriverContext driverContext; public SpatialContainsGeoPointDocValuesAndSourceEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, EvalOperator.ExpressionEvaluator rightValue, + EvalOperator.ExpressionEvaluator left, EvalOperator.ExpressionEvaluator right, DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (LongBlock leftValueBlock = (LongBlock) leftValue.eval(page)) { - try (BytesRefBlock rightValueBlock = (BytesRefBlock) rightValue.eval(page)) { - LongVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - BytesRefVector rightValueVector = rightValueBlock.asVector(); - if (rightValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - return eval(page.getPositionCount(), leftValueVector, rightValueVector); + try (LongBlock leftBlock = (LongBlock) left.eval(page)) { + try (BytesRefBlock rightBlock = (BytesRefBlock) right.eval(page)) { + return eval(page.getPositionCount(), leftBlock, rightBlock); } } } - public BooleanBlock eval(int positionCount, LongBlock leftValueBlock, - BytesRefBlock rightValueBlock) { + public BooleanBlock eval(int positionCount, LongBlock leftBlock, BytesRefBlock rightBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef rightValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; - } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (rightValueBlock.isNull(p)) { - result.appendNull(); - continue position; + if (!rightBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (rightValueBlock.getValueCount(p) != 1) { - if (rightValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + if (allBlocksAreNulls) { result.appendNull(); continue position; } try { - result.appendBoolean(SpatialContains.processGeoPointDocValuesAndSource(leftValueBlock.getLong(leftValueBlock.getFirstValueIndex(p)), rightValueBlock.getBytesRef(rightValueBlock.getFirstValueIndex(p), rightValueScratch))); - } catch (IllegalArgumentException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, LongVector leftValueVector, - BytesRefVector rightValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef rightValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { - try { - result.appendBoolean(SpatialContains.processGeoPointDocValuesAndSource(leftValueVector.getLong(p), rightValueVector.getBytesRef(p, rightValueScratch))); - } catch (IllegalArgumentException e) { + SpatialContains.processGeoPointDocValuesAndSource(result, p, leftBlock, rightBlock); + } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); } @@ -116,36 +77,36 @@ public BooleanBlock eval(int positionCount, LongVector leftValueVector, @Override public String toString() { - return "SpatialContainsGeoPointDocValuesAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialContainsGeoPointDocValuesAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue, rightValue); + Releasables.closeExpectNoException(left, right); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final EvalOperator.ExpressionEvaluator.Factory rightValue; + private final EvalOperator.ExpressionEvaluator.Factory right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - EvalOperator.ExpressionEvaluator.Factory rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + EvalOperator.ExpressionEvaluator.Factory right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialContainsGeoPointDocValuesAndSourceEvaluator get(DriverContext context) { - return new SpatialContainsGeoPointDocValuesAndSourceEvaluator(source, leftValue.get(context), rightValue.get(context), context); + return new SpatialContainsGeoPointDocValuesAndSourceEvaluator(source, left.get(context), right.get(context), context); } @Override public String toString() { - return "SpatialContainsGeoPointDocValuesAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialContainsGeoPointDocValuesAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoSourceAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoSourceAndConstantEvaluator.java index adb2e2ea0ced2..1b7d5243468ef 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoSourceAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoSourceAndConstantEvaluator.java @@ -9,11 +9,9 @@ import java.lang.Override; import java.lang.String; import org.apache.lucene.geo.Component2D; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -28,64 +26,40 @@ public final class SpatialContainsGeoSourceAndConstantEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final Component2D[] rightValue; + private final Component2D[] right; private final DriverContext driverContext; public SpatialContainsGeoSourceAndConstantEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, Component2D[] rightValue, - DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + EvalOperator.ExpressionEvaluator left, Component2D[] right, DriverContext driverContext) { + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (BytesRefBlock leftValueBlock = (BytesRefBlock) leftValue.eval(page)) { - BytesRefVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock); - } - return eval(page.getPositionCount(), leftValueVector); + try (BytesRefBlock leftBlock = (BytesRefBlock) left.eval(page)) { + return eval(page.getPositionCount(), leftBlock); } } - public BooleanBlock eval(int positionCount, BytesRefBlock leftValueBlock) { + public BooleanBlock eval(int positionCount, BytesRefBlock leftBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + if (allBlocksAreNulls) { result.appendNull(); continue position; } try { - result.appendBoolean(SpatialContains.processGeoSourceAndConstant(leftValueBlock.getBytesRef(leftValueBlock.getFirstValueIndex(p), leftValueScratch), this.rightValue)); - } catch (IllegalArgumentException | IOException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { - try { - result.appendBoolean(SpatialContains.processGeoSourceAndConstant(leftValueVector.getBytesRef(p, leftValueScratch), this.rightValue)); + SpatialContains.processGeoSourceAndConstant(result, p, leftBlock, this.right); } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); @@ -97,36 +71,36 @@ public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector) { @Override public String toString() { - return "SpatialContainsGeoSourceAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialContainsGeoSourceAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue); + Releasables.closeExpectNoException(left); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final Component2D[] rightValue; + private final Component2D[] right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - Component2D[] rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + Component2D[] right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialContainsGeoSourceAndConstantEvaluator get(DriverContext context) { - return new SpatialContainsGeoSourceAndConstantEvaluator(source, leftValue.get(context), rightValue, context); + return new SpatialContainsGeoSourceAndConstantEvaluator(source, left.get(context), right, context); } @Override public String toString() { - return "SpatialContainsGeoSourceAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialContainsGeoSourceAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoSourceAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoSourceAndSourceEvaluator.java index 7bce1a585f490..8cd5d5bc07dcd 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoSourceAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoSourceAndSourceEvaluator.java @@ -8,11 +8,9 @@ import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -27,85 +25,46 @@ public final class SpatialContainsGeoSourceAndSourceEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final EvalOperator.ExpressionEvaluator rightValue; + private final EvalOperator.ExpressionEvaluator right; private final DriverContext driverContext; public SpatialContainsGeoSourceAndSourceEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, EvalOperator.ExpressionEvaluator rightValue, + EvalOperator.ExpressionEvaluator left, EvalOperator.ExpressionEvaluator right, DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (BytesRefBlock leftValueBlock = (BytesRefBlock) leftValue.eval(page)) { - try (BytesRefBlock rightValueBlock = (BytesRefBlock) rightValue.eval(page)) { - BytesRefVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - BytesRefVector rightValueVector = rightValueBlock.asVector(); - if (rightValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - return eval(page.getPositionCount(), leftValueVector, rightValueVector); + try (BytesRefBlock leftBlock = (BytesRefBlock) left.eval(page)) { + try (BytesRefBlock rightBlock = (BytesRefBlock) right.eval(page)) { + return eval(page.getPositionCount(), leftBlock, rightBlock); } } } - public BooleanBlock eval(int positionCount, BytesRefBlock leftValueBlock, - BytesRefBlock rightValueBlock) { + public BooleanBlock eval(int positionCount, BytesRefBlock leftBlock, BytesRefBlock rightBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - BytesRef rightValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; + if (!rightBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (rightValueBlock.isNull(p)) { + if (allBlocksAreNulls) { result.appendNull(); continue position; } - if (rightValueBlock.getValueCount(p) != 1) { - if (rightValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; - } - try { - result.appendBoolean(SpatialContains.processGeoSourceAndSource(leftValueBlock.getBytesRef(leftValueBlock.getFirstValueIndex(p), leftValueScratch), rightValueBlock.getBytesRef(rightValueBlock.getFirstValueIndex(p), rightValueScratch))); - } catch (IllegalArgumentException | IOException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector, - BytesRefVector rightValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - BytesRef rightValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { try { - result.appendBoolean(SpatialContains.processGeoSourceAndSource(leftValueVector.getBytesRef(p, leftValueScratch), rightValueVector.getBytesRef(p, rightValueScratch))); + SpatialContains.processGeoSourceAndSource(result, p, leftBlock, rightBlock); } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); @@ -117,36 +76,36 @@ public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector, @Override public String toString() { - return "SpatialContainsGeoSourceAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialContainsGeoSourceAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue, rightValue); + Releasables.closeExpectNoException(left, right); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final EvalOperator.ExpressionEvaluator.Factory rightValue; + private final EvalOperator.ExpressionEvaluator.Factory right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - EvalOperator.ExpressionEvaluator.Factory rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + EvalOperator.ExpressionEvaluator.Factory right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialContainsGeoSourceAndSourceEvaluator get(DriverContext context) { - return new SpatialContainsGeoSourceAndSourceEvaluator(source, leftValue.get(context), rightValue.get(context), context); + return new SpatialContainsGeoSourceAndSourceEvaluator(source, left.get(context), right.get(context), context); } @Override public String toString() { - return "SpatialContainsGeoSourceAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialContainsGeoSourceAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianPointDocValuesAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianPointDocValuesAndConstantEvaluator.java index 3a50c1cc1f717..f4bcc51a6add2 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianPointDocValuesAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianPointDocValuesAndConstantEvaluator.java @@ -4,6 +4,7 @@ // 2.0. package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; +import java.io.IOException; import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; @@ -11,7 +12,6 @@ import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.LongBlock; -import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -26,63 +26,41 @@ public final class SpatialDisjointCartesianPointDocValuesAndConstantEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final Component2D rightValue; + private final Component2D right; private final DriverContext driverContext; public SpatialDisjointCartesianPointDocValuesAndConstantEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, Component2D rightValue, - DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + EvalOperator.ExpressionEvaluator left, Component2D right, DriverContext driverContext) { + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (LongBlock leftValueBlock = (LongBlock) leftValue.eval(page)) { - LongVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock); - } - return eval(page.getPositionCount(), leftValueVector); + try (LongBlock leftBlock = (LongBlock) left.eval(page)) { + return eval(page.getPositionCount(), leftBlock); } } - public BooleanBlock eval(int positionCount, LongBlock leftValueBlock) { + public BooleanBlock eval(int positionCount, LongBlock leftBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + if (allBlocksAreNulls) { result.appendNull(); continue position; } try { - result.appendBoolean(SpatialDisjoint.processCartesianPointDocValuesAndConstant(leftValueBlock.getLong(leftValueBlock.getFirstValueIndex(p)), this.rightValue)); - } catch (IllegalArgumentException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, LongVector leftValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - position: for (int p = 0; p < positionCount; p++) { - try { - result.appendBoolean(SpatialDisjoint.processCartesianPointDocValuesAndConstant(leftValueVector.getLong(p), this.rightValue)); - } catch (IllegalArgumentException e) { + SpatialDisjoint.processCartesianPointDocValuesAndConstant(result, p, leftBlock, this.right); + } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); } @@ -93,36 +71,36 @@ public BooleanBlock eval(int positionCount, LongVector leftValueVector) { @Override public String toString() { - return "SpatialDisjointCartesianPointDocValuesAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialDisjointCartesianPointDocValuesAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue); + Releasables.closeExpectNoException(left); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final Component2D rightValue; + private final Component2D right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - Component2D rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + Component2D right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialDisjointCartesianPointDocValuesAndConstantEvaluator get(DriverContext context) { - return new SpatialDisjointCartesianPointDocValuesAndConstantEvaluator(source, leftValue.get(context), rightValue, context); + return new SpatialDisjointCartesianPointDocValuesAndConstantEvaluator(source, left.get(context), right, context); } @Override public String toString() { - return "SpatialDisjointCartesianPointDocValuesAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialDisjointCartesianPointDocValuesAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianPointDocValuesAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianPointDocValuesAndSourceEvaluator.java index 4630ef9b01b47..e7e1945e5f3ff 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianPointDocValuesAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianPointDocValuesAndSourceEvaluator.java @@ -4,17 +4,14 @@ // 2.0. package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; +import java.io.IOException; import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; -import org.elasticsearch.compute.data.BooleanVector; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.LongBlock; -import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -29,77 +26,50 @@ public final class SpatialDisjointCartesianPointDocValuesAndSourceEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final EvalOperator.ExpressionEvaluator rightValue; + private final EvalOperator.ExpressionEvaluator right; private final DriverContext driverContext; public SpatialDisjointCartesianPointDocValuesAndSourceEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, EvalOperator.ExpressionEvaluator rightValue, + EvalOperator.ExpressionEvaluator left, EvalOperator.ExpressionEvaluator right, DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (LongBlock leftValueBlock = (LongBlock) leftValue.eval(page)) { - try (BytesRefBlock rightValueBlock = (BytesRefBlock) rightValue.eval(page)) { - LongVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - BytesRefVector rightValueVector = rightValueBlock.asVector(); - if (rightValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - return eval(page.getPositionCount(), leftValueVector, rightValueVector).asBlock(); + try (LongBlock leftBlock = (LongBlock) left.eval(page)) { + try (BytesRefBlock rightBlock = (BytesRefBlock) right.eval(page)) { + return eval(page.getPositionCount(), leftBlock, rightBlock); } } } - public BooleanBlock eval(int positionCount, LongBlock leftValueBlock, - BytesRefBlock rightValueBlock) { + public BooleanBlock eval(int positionCount, LongBlock leftBlock, BytesRefBlock rightBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef rightValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; + if (!rightBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (rightValueBlock.isNull(p)) { + if (allBlocksAreNulls) { result.appendNull(); continue position; } - if (rightValueBlock.getValueCount(p) != 1) { - if (rightValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + try { + SpatialDisjoint.processCartesianPointDocValuesAndSource(result, p, leftBlock, rightBlock); + } catch (IllegalArgumentException | IOException e) { + warnings.registerException(e); result.appendNull(); - continue position; } - result.appendBoolean(SpatialDisjoint.processCartesianPointDocValuesAndSource(leftValueBlock.getLong(leftValueBlock.getFirstValueIndex(p)), rightValueBlock.getBytesRef(rightValueBlock.getFirstValueIndex(p), rightValueScratch))); - } - return result.build(); - } - } - - public BooleanVector eval(int positionCount, LongVector leftValueVector, - BytesRefVector rightValueVector) { - try(BooleanVector.FixedBuilder result = driverContext.blockFactory().newBooleanVectorFixedBuilder(positionCount)) { - BytesRef rightValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { - result.appendBoolean(p, SpatialDisjoint.processCartesianPointDocValuesAndSource(leftValueVector.getLong(p), rightValueVector.getBytesRef(p, rightValueScratch))); } return result.build(); } @@ -107,36 +77,36 @@ public BooleanVector eval(int positionCount, LongVector leftValueVector, @Override public String toString() { - return "SpatialDisjointCartesianPointDocValuesAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialDisjointCartesianPointDocValuesAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue, rightValue); + Releasables.closeExpectNoException(left, right); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final EvalOperator.ExpressionEvaluator.Factory rightValue; + private final EvalOperator.ExpressionEvaluator.Factory right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - EvalOperator.ExpressionEvaluator.Factory rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + EvalOperator.ExpressionEvaluator.Factory right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialDisjointCartesianPointDocValuesAndSourceEvaluator get(DriverContext context) { - return new SpatialDisjointCartesianPointDocValuesAndSourceEvaluator(source, leftValue.get(context), rightValue.get(context), context); + return new SpatialDisjointCartesianPointDocValuesAndSourceEvaluator(source, left.get(context), right.get(context), context); } @Override public String toString() { - return "SpatialDisjointCartesianPointDocValuesAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialDisjointCartesianPointDocValuesAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianSourceAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianSourceAndConstantEvaluator.java index 64dcf096e0dd8..009eb5e50e3be 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianSourceAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianSourceAndConstantEvaluator.java @@ -9,11 +9,9 @@ import java.lang.Override; import java.lang.String; import org.apache.lucene.geo.Component2D; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -28,64 +26,40 @@ public final class SpatialDisjointCartesianSourceAndConstantEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final Component2D rightValue; + private final Component2D right; private final DriverContext driverContext; public SpatialDisjointCartesianSourceAndConstantEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, Component2D rightValue, - DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + EvalOperator.ExpressionEvaluator left, Component2D right, DriverContext driverContext) { + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (BytesRefBlock leftValueBlock = (BytesRefBlock) leftValue.eval(page)) { - BytesRefVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock); - } - return eval(page.getPositionCount(), leftValueVector); + try (BytesRefBlock leftBlock = (BytesRefBlock) left.eval(page)) { + return eval(page.getPositionCount(), leftBlock); } } - public BooleanBlock eval(int positionCount, BytesRefBlock leftValueBlock) { + public BooleanBlock eval(int positionCount, BytesRefBlock leftBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + if (allBlocksAreNulls) { result.appendNull(); continue position; } try { - result.appendBoolean(SpatialDisjoint.processCartesianSourceAndConstant(leftValueBlock.getBytesRef(leftValueBlock.getFirstValueIndex(p), leftValueScratch), this.rightValue)); - } catch (IllegalArgumentException | IOException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { - try { - result.appendBoolean(SpatialDisjoint.processCartesianSourceAndConstant(leftValueVector.getBytesRef(p, leftValueScratch), this.rightValue)); + SpatialDisjoint.processCartesianSourceAndConstant(result, p, leftBlock, this.right); } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); @@ -97,36 +71,36 @@ public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector) { @Override public String toString() { - return "SpatialDisjointCartesianSourceAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialDisjointCartesianSourceAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue); + Releasables.closeExpectNoException(left); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final Component2D rightValue; + private final Component2D right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - Component2D rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + Component2D right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialDisjointCartesianSourceAndConstantEvaluator get(DriverContext context) { - return new SpatialDisjointCartesianSourceAndConstantEvaluator(source, leftValue.get(context), rightValue, context); + return new SpatialDisjointCartesianSourceAndConstantEvaluator(source, left.get(context), right, context); } @Override public String toString() { - return "SpatialDisjointCartesianSourceAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialDisjointCartesianSourceAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianSourceAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianSourceAndSourceEvaluator.java index 5c888eddcac68..990354d3882c5 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianSourceAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianSourceAndSourceEvaluator.java @@ -8,11 +8,9 @@ import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -27,85 +25,46 @@ public final class SpatialDisjointCartesianSourceAndSourceEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final EvalOperator.ExpressionEvaluator rightValue; + private final EvalOperator.ExpressionEvaluator right; private final DriverContext driverContext; public SpatialDisjointCartesianSourceAndSourceEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, EvalOperator.ExpressionEvaluator rightValue, + EvalOperator.ExpressionEvaluator left, EvalOperator.ExpressionEvaluator right, DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (BytesRefBlock leftValueBlock = (BytesRefBlock) leftValue.eval(page)) { - try (BytesRefBlock rightValueBlock = (BytesRefBlock) rightValue.eval(page)) { - BytesRefVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - BytesRefVector rightValueVector = rightValueBlock.asVector(); - if (rightValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - return eval(page.getPositionCount(), leftValueVector, rightValueVector); + try (BytesRefBlock leftBlock = (BytesRefBlock) left.eval(page)) { + try (BytesRefBlock rightBlock = (BytesRefBlock) right.eval(page)) { + return eval(page.getPositionCount(), leftBlock, rightBlock); } } } - public BooleanBlock eval(int positionCount, BytesRefBlock leftValueBlock, - BytesRefBlock rightValueBlock) { + public BooleanBlock eval(int positionCount, BytesRefBlock leftBlock, BytesRefBlock rightBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - BytesRef rightValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; + if (!rightBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (rightValueBlock.isNull(p)) { + if (allBlocksAreNulls) { result.appendNull(); continue position; } - if (rightValueBlock.getValueCount(p) != 1) { - if (rightValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; - } - try { - result.appendBoolean(SpatialDisjoint.processCartesianSourceAndSource(leftValueBlock.getBytesRef(leftValueBlock.getFirstValueIndex(p), leftValueScratch), rightValueBlock.getBytesRef(rightValueBlock.getFirstValueIndex(p), rightValueScratch))); - } catch (IllegalArgumentException | IOException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector, - BytesRefVector rightValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - BytesRef rightValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { try { - result.appendBoolean(SpatialDisjoint.processCartesianSourceAndSource(leftValueVector.getBytesRef(p, leftValueScratch), rightValueVector.getBytesRef(p, rightValueScratch))); + SpatialDisjoint.processCartesianSourceAndSource(result, p, leftBlock, rightBlock); } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); @@ -117,36 +76,36 @@ public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector, @Override public String toString() { - return "SpatialDisjointCartesianSourceAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialDisjointCartesianSourceAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue, rightValue); + Releasables.closeExpectNoException(left, right); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final EvalOperator.ExpressionEvaluator.Factory rightValue; + private final EvalOperator.ExpressionEvaluator.Factory right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - EvalOperator.ExpressionEvaluator.Factory rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + EvalOperator.ExpressionEvaluator.Factory right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialDisjointCartesianSourceAndSourceEvaluator get(DriverContext context) { - return new SpatialDisjointCartesianSourceAndSourceEvaluator(source, leftValue.get(context), rightValue.get(context), context); + return new SpatialDisjointCartesianSourceAndSourceEvaluator(source, left.get(context), right.get(context), context); } @Override public String toString() { - return "SpatialDisjointCartesianSourceAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialDisjointCartesianSourceAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoPointDocValuesAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoPointDocValuesAndConstantEvaluator.java index 73912f2f4c5de..3b8f5b93fd24f 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoPointDocValuesAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoPointDocValuesAndConstantEvaluator.java @@ -4,6 +4,7 @@ // 2.0. package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; +import java.io.IOException; import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; @@ -11,7 +12,6 @@ import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.LongBlock; -import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -26,63 +26,41 @@ public final class SpatialDisjointGeoPointDocValuesAndConstantEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final Component2D rightValue; + private final Component2D right; private final DriverContext driverContext; public SpatialDisjointGeoPointDocValuesAndConstantEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, Component2D rightValue, - DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + EvalOperator.ExpressionEvaluator left, Component2D right, DriverContext driverContext) { + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (LongBlock leftValueBlock = (LongBlock) leftValue.eval(page)) { - LongVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock); - } - return eval(page.getPositionCount(), leftValueVector); + try (LongBlock leftBlock = (LongBlock) left.eval(page)) { + return eval(page.getPositionCount(), leftBlock); } } - public BooleanBlock eval(int positionCount, LongBlock leftValueBlock) { + public BooleanBlock eval(int positionCount, LongBlock leftBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + if (allBlocksAreNulls) { result.appendNull(); continue position; } try { - result.appendBoolean(SpatialDisjoint.processGeoPointDocValuesAndConstant(leftValueBlock.getLong(leftValueBlock.getFirstValueIndex(p)), this.rightValue)); - } catch (IllegalArgumentException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, LongVector leftValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - position: for (int p = 0; p < positionCount; p++) { - try { - result.appendBoolean(SpatialDisjoint.processGeoPointDocValuesAndConstant(leftValueVector.getLong(p), this.rightValue)); - } catch (IllegalArgumentException e) { + SpatialDisjoint.processGeoPointDocValuesAndConstant(result, p, leftBlock, this.right); + } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); } @@ -93,36 +71,36 @@ public BooleanBlock eval(int positionCount, LongVector leftValueVector) { @Override public String toString() { - return "SpatialDisjointGeoPointDocValuesAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialDisjointGeoPointDocValuesAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue); + Releasables.closeExpectNoException(left); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final Component2D rightValue; + private final Component2D right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - Component2D rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + Component2D right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialDisjointGeoPointDocValuesAndConstantEvaluator get(DriverContext context) { - return new SpatialDisjointGeoPointDocValuesAndConstantEvaluator(source, leftValue.get(context), rightValue, context); + return new SpatialDisjointGeoPointDocValuesAndConstantEvaluator(source, left.get(context), right, context); } @Override public String toString() { - return "SpatialDisjointGeoPointDocValuesAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialDisjointGeoPointDocValuesAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoPointDocValuesAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoPointDocValuesAndSourceEvaluator.java index 96a2a06dbe241..d243c8ebb9f01 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoPointDocValuesAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoPointDocValuesAndSourceEvaluator.java @@ -4,16 +4,14 @@ // 2.0. package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; +import java.io.IOException; import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.LongBlock; -import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -28,84 +26,47 @@ public final class SpatialDisjointGeoPointDocValuesAndSourceEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final EvalOperator.ExpressionEvaluator rightValue; + private final EvalOperator.ExpressionEvaluator right; private final DriverContext driverContext; public SpatialDisjointGeoPointDocValuesAndSourceEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, EvalOperator.ExpressionEvaluator rightValue, + EvalOperator.ExpressionEvaluator left, EvalOperator.ExpressionEvaluator right, DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (LongBlock leftValueBlock = (LongBlock) leftValue.eval(page)) { - try (BytesRefBlock rightValueBlock = (BytesRefBlock) rightValue.eval(page)) { - LongVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - BytesRefVector rightValueVector = rightValueBlock.asVector(); - if (rightValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - return eval(page.getPositionCount(), leftValueVector, rightValueVector); + try (LongBlock leftBlock = (LongBlock) left.eval(page)) { + try (BytesRefBlock rightBlock = (BytesRefBlock) right.eval(page)) { + return eval(page.getPositionCount(), leftBlock, rightBlock); } } } - public BooleanBlock eval(int positionCount, LongBlock leftValueBlock, - BytesRefBlock rightValueBlock) { + public BooleanBlock eval(int positionCount, LongBlock leftBlock, BytesRefBlock rightBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef rightValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; - } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (rightValueBlock.isNull(p)) { - result.appendNull(); - continue position; + if (!rightBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (rightValueBlock.getValueCount(p) != 1) { - if (rightValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + if (allBlocksAreNulls) { result.appendNull(); continue position; } try { - result.appendBoolean(SpatialDisjoint.processGeoPointDocValuesAndSource(leftValueBlock.getLong(leftValueBlock.getFirstValueIndex(p)), rightValueBlock.getBytesRef(rightValueBlock.getFirstValueIndex(p), rightValueScratch))); - } catch (IllegalArgumentException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, LongVector leftValueVector, - BytesRefVector rightValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef rightValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { - try { - result.appendBoolean(SpatialDisjoint.processGeoPointDocValuesAndSource(leftValueVector.getLong(p), rightValueVector.getBytesRef(p, rightValueScratch))); - } catch (IllegalArgumentException e) { + SpatialDisjoint.processGeoPointDocValuesAndSource(result, p, leftBlock, rightBlock); + } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); } @@ -116,36 +77,36 @@ public BooleanBlock eval(int positionCount, LongVector leftValueVector, @Override public String toString() { - return "SpatialDisjointGeoPointDocValuesAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialDisjointGeoPointDocValuesAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue, rightValue); + Releasables.closeExpectNoException(left, right); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final EvalOperator.ExpressionEvaluator.Factory rightValue; + private final EvalOperator.ExpressionEvaluator.Factory right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - EvalOperator.ExpressionEvaluator.Factory rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + EvalOperator.ExpressionEvaluator.Factory right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialDisjointGeoPointDocValuesAndSourceEvaluator get(DriverContext context) { - return new SpatialDisjointGeoPointDocValuesAndSourceEvaluator(source, leftValue.get(context), rightValue.get(context), context); + return new SpatialDisjointGeoPointDocValuesAndSourceEvaluator(source, left.get(context), right.get(context), context); } @Override public String toString() { - return "SpatialDisjointGeoPointDocValuesAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialDisjointGeoPointDocValuesAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoSourceAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoSourceAndConstantEvaluator.java index 1cd5e8504c7cf..84a0930c67a58 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoSourceAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoSourceAndConstantEvaluator.java @@ -9,11 +9,9 @@ import java.lang.Override; import java.lang.String; import org.apache.lucene.geo.Component2D; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -28,64 +26,40 @@ public final class SpatialDisjointGeoSourceAndConstantEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final Component2D rightValue; + private final Component2D right; private final DriverContext driverContext; public SpatialDisjointGeoSourceAndConstantEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, Component2D rightValue, - DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + EvalOperator.ExpressionEvaluator left, Component2D right, DriverContext driverContext) { + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (BytesRefBlock leftValueBlock = (BytesRefBlock) leftValue.eval(page)) { - BytesRefVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock); - } - return eval(page.getPositionCount(), leftValueVector); + try (BytesRefBlock leftBlock = (BytesRefBlock) left.eval(page)) { + return eval(page.getPositionCount(), leftBlock); } } - public BooleanBlock eval(int positionCount, BytesRefBlock leftValueBlock) { + public BooleanBlock eval(int positionCount, BytesRefBlock leftBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + if (allBlocksAreNulls) { result.appendNull(); continue position; } try { - result.appendBoolean(SpatialDisjoint.processGeoSourceAndConstant(leftValueBlock.getBytesRef(leftValueBlock.getFirstValueIndex(p), leftValueScratch), this.rightValue)); - } catch (IllegalArgumentException | IOException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { - try { - result.appendBoolean(SpatialDisjoint.processGeoSourceAndConstant(leftValueVector.getBytesRef(p, leftValueScratch), this.rightValue)); + SpatialDisjoint.processGeoSourceAndConstant(result, p, leftBlock, this.right); } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); @@ -97,36 +71,36 @@ public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector) { @Override public String toString() { - return "SpatialDisjointGeoSourceAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialDisjointGeoSourceAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue); + Releasables.closeExpectNoException(left); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final Component2D rightValue; + private final Component2D right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - Component2D rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + Component2D right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialDisjointGeoSourceAndConstantEvaluator get(DriverContext context) { - return new SpatialDisjointGeoSourceAndConstantEvaluator(source, leftValue.get(context), rightValue, context); + return new SpatialDisjointGeoSourceAndConstantEvaluator(source, left.get(context), right, context); } @Override public String toString() { - return "SpatialDisjointGeoSourceAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialDisjointGeoSourceAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoSourceAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoSourceAndSourceEvaluator.java index 467d2518d9a9c..461742e430e34 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoSourceAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoSourceAndSourceEvaluator.java @@ -8,11 +8,9 @@ import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -27,85 +25,46 @@ public final class SpatialDisjointGeoSourceAndSourceEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final EvalOperator.ExpressionEvaluator rightValue; + private final EvalOperator.ExpressionEvaluator right; private final DriverContext driverContext; public SpatialDisjointGeoSourceAndSourceEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, EvalOperator.ExpressionEvaluator rightValue, + EvalOperator.ExpressionEvaluator left, EvalOperator.ExpressionEvaluator right, DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (BytesRefBlock leftValueBlock = (BytesRefBlock) leftValue.eval(page)) { - try (BytesRefBlock rightValueBlock = (BytesRefBlock) rightValue.eval(page)) { - BytesRefVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - BytesRefVector rightValueVector = rightValueBlock.asVector(); - if (rightValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - return eval(page.getPositionCount(), leftValueVector, rightValueVector); + try (BytesRefBlock leftBlock = (BytesRefBlock) left.eval(page)) { + try (BytesRefBlock rightBlock = (BytesRefBlock) right.eval(page)) { + return eval(page.getPositionCount(), leftBlock, rightBlock); } } } - public BooleanBlock eval(int positionCount, BytesRefBlock leftValueBlock, - BytesRefBlock rightValueBlock) { + public BooleanBlock eval(int positionCount, BytesRefBlock leftBlock, BytesRefBlock rightBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - BytesRef rightValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; + if (!rightBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (rightValueBlock.isNull(p)) { + if (allBlocksAreNulls) { result.appendNull(); continue position; } - if (rightValueBlock.getValueCount(p) != 1) { - if (rightValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; - } - try { - result.appendBoolean(SpatialDisjoint.processGeoSourceAndSource(leftValueBlock.getBytesRef(leftValueBlock.getFirstValueIndex(p), leftValueScratch), rightValueBlock.getBytesRef(rightValueBlock.getFirstValueIndex(p), rightValueScratch))); - } catch (IllegalArgumentException | IOException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector, - BytesRefVector rightValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - BytesRef rightValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { try { - result.appendBoolean(SpatialDisjoint.processGeoSourceAndSource(leftValueVector.getBytesRef(p, leftValueScratch), rightValueVector.getBytesRef(p, rightValueScratch))); + SpatialDisjoint.processGeoSourceAndSource(result, p, leftBlock, rightBlock); } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); @@ -117,36 +76,36 @@ public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector, @Override public String toString() { - return "SpatialDisjointGeoSourceAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialDisjointGeoSourceAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue, rightValue); + Releasables.closeExpectNoException(left, right); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final EvalOperator.ExpressionEvaluator.Factory rightValue; + private final EvalOperator.ExpressionEvaluator.Factory right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - EvalOperator.ExpressionEvaluator.Factory rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + EvalOperator.ExpressionEvaluator.Factory right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialDisjointGeoSourceAndSourceEvaluator get(DriverContext context) { - return new SpatialDisjointGeoSourceAndSourceEvaluator(source, leftValue.get(context), rightValue.get(context), context); + return new SpatialDisjointGeoSourceAndSourceEvaluator(source, left.get(context), right.get(context), context); } @Override public String toString() { - return "SpatialDisjointGeoSourceAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialDisjointGeoSourceAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianPointDocValuesAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianPointDocValuesAndConstantEvaluator.java index 38386aa7d51f1..957a7c805a303 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianPointDocValuesAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianPointDocValuesAndConstantEvaluator.java @@ -4,6 +4,7 @@ // 2.0. package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; +import java.io.IOException; import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; @@ -11,7 +12,6 @@ import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.LongBlock; -import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -26,63 +26,41 @@ public final class SpatialIntersectsCartesianPointDocValuesAndConstantEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final Component2D rightValue; + private final Component2D right; private final DriverContext driverContext; public SpatialIntersectsCartesianPointDocValuesAndConstantEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, Component2D rightValue, - DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + EvalOperator.ExpressionEvaluator left, Component2D right, DriverContext driverContext) { + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (LongBlock leftValueBlock = (LongBlock) leftValue.eval(page)) { - LongVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock); - } - return eval(page.getPositionCount(), leftValueVector); + try (LongBlock leftBlock = (LongBlock) left.eval(page)) { + return eval(page.getPositionCount(), leftBlock); } } - public BooleanBlock eval(int positionCount, LongBlock leftValueBlock) { + public BooleanBlock eval(int positionCount, LongBlock leftBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + if (allBlocksAreNulls) { result.appendNull(); continue position; } try { - result.appendBoolean(SpatialIntersects.processCartesianPointDocValuesAndConstant(leftValueBlock.getLong(leftValueBlock.getFirstValueIndex(p)), this.rightValue)); - } catch (IllegalArgumentException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, LongVector leftValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - position: for (int p = 0; p < positionCount; p++) { - try { - result.appendBoolean(SpatialIntersects.processCartesianPointDocValuesAndConstant(leftValueVector.getLong(p), this.rightValue)); - } catch (IllegalArgumentException e) { + SpatialIntersects.processCartesianPointDocValuesAndConstant(result, p, leftBlock, this.right); + } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); } @@ -93,36 +71,36 @@ public BooleanBlock eval(int positionCount, LongVector leftValueVector) { @Override public String toString() { - return "SpatialIntersectsCartesianPointDocValuesAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialIntersectsCartesianPointDocValuesAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue); + Releasables.closeExpectNoException(left); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final Component2D rightValue; + private final Component2D right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - Component2D rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + Component2D right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialIntersectsCartesianPointDocValuesAndConstantEvaluator get(DriverContext context) { - return new SpatialIntersectsCartesianPointDocValuesAndConstantEvaluator(source, leftValue.get(context), rightValue, context); + return new SpatialIntersectsCartesianPointDocValuesAndConstantEvaluator(source, left.get(context), right, context); } @Override public String toString() { - return "SpatialIntersectsCartesianPointDocValuesAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialIntersectsCartesianPointDocValuesAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianPointDocValuesAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianPointDocValuesAndSourceEvaluator.java index a38dacc1e04b6..0188d796e4d26 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianPointDocValuesAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianPointDocValuesAndSourceEvaluator.java @@ -4,17 +4,14 @@ // 2.0. package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; +import java.io.IOException; import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; -import org.elasticsearch.compute.data.BooleanVector; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.LongBlock; -import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -29,77 +26,50 @@ public final class SpatialIntersectsCartesianPointDocValuesAndSourceEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final EvalOperator.ExpressionEvaluator rightValue; + private final EvalOperator.ExpressionEvaluator right; private final DriverContext driverContext; public SpatialIntersectsCartesianPointDocValuesAndSourceEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, EvalOperator.ExpressionEvaluator rightValue, + EvalOperator.ExpressionEvaluator left, EvalOperator.ExpressionEvaluator right, DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (LongBlock leftValueBlock = (LongBlock) leftValue.eval(page)) { - try (BytesRefBlock rightValueBlock = (BytesRefBlock) rightValue.eval(page)) { - LongVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - BytesRefVector rightValueVector = rightValueBlock.asVector(); - if (rightValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - return eval(page.getPositionCount(), leftValueVector, rightValueVector).asBlock(); + try (LongBlock leftBlock = (LongBlock) left.eval(page)) { + try (BytesRefBlock rightBlock = (BytesRefBlock) right.eval(page)) { + return eval(page.getPositionCount(), leftBlock, rightBlock); } } } - public BooleanBlock eval(int positionCount, LongBlock leftValueBlock, - BytesRefBlock rightValueBlock) { + public BooleanBlock eval(int positionCount, LongBlock leftBlock, BytesRefBlock rightBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef rightValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; + if (!rightBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (rightValueBlock.isNull(p)) { + if (allBlocksAreNulls) { result.appendNull(); continue position; } - if (rightValueBlock.getValueCount(p) != 1) { - if (rightValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + try { + SpatialIntersects.processCartesianPointDocValuesAndSource(result, p, leftBlock, rightBlock); + } catch (IllegalArgumentException | IOException e) { + warnings.registerException(e); result.appendNull(); - continue position; } - result.appendBoolean(SpatialIntersects.processCartesianPointDocValuesAndSource(leftValueBlock.getLong(leftValueBlock.getFirstValueIndex(p)), rightValueBlock.getBytesRef(rightValueBlock.getFirstValueIndex(p), rightValueScratch))); - } - return result.build(); - } - } - - public BooleanVector eval(int positionCount, LongVector leftValueVector, - BytesRefVector rightValueVector) { - try(BooleanVector.FixedBuilder result = driverContext.blockFactory().newBooleanVectorFixedBuilder(positionCount)) { - BytesRef rightValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { - result.appendBoolean(p, SpatialIntersects.processCartesianPointDocValuesAndSource(leftValueVector.getLong(p), rightValueVector.getBytesRef(p, rightValueScratch))); } return result.build(); } @@ -107,36 +77,36 @@ public BooleanVector eval(int positionCount, LongVector leftValueVector, @Override public String toString() { - return "SpatialIntersectsCartesianPointDocValuesAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialIntersectsCartesianPointDocValuesAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue, rightValue); + Releasables.closeExpectNoException(left, right); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final EvalOperator.ExpressionEvaluator.Factory rightValue; + private final EvalOperator.ExpressionEvaluator.Factory right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - EvalOperator.ExpressionEvaluator.Factory rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + EvalOperator.ExpressionEvaluator.Factory right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialIntersectsCartesianPointDocValuesAndSourceEvaluator get(DriverContext context) { - return new SpatialIntersectsCartesianPointDocValuesAndSourceEvaluator(source, leftValue.get(context), rightValue.get(context), context); + return new SpatialIntersectsCartesianPointDocValuesAndSourceEvaluator(source, left.get(context), right.get(context), context); } @Override public String toString() { - return "SpatialIntersectsCartesianPointDocValuesAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialIntersectsCartesianPointDocValuesAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianSourceAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianSourceAndConstantEvaluator.java index 70fd91ed0a1ab..9fe1ca365f267 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianSourceAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianSourceAndConstantEvaluator.java @@ -9,11 +9,9 @@ import java.lang.Override; import java.lang.String; import org.apache.lucene.geo.Component2D; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -28,64 +26,40 @@ public final class SpatialIntersectsCartesianSourceAndConstantEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final Component2D rightValue; + private final Component2D right; private final DriverContext driverContext; public SpatialIntersectsCartesianSourceAndConstantEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, Component2D rightValue, - DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + EvalOperator.ExpressionEvaluator left, Component2D right, DriverContext driverContext) { + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (BytesRefBlock leftValueBlock = (BytesRefBlock) leftValue.eval(page)) { - BytesRefVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock); - } - return eval(page.getPositionCount(), leftValueVector); + try (BytesRefBlock leftBlock = (BytesRefBlock) left.eval(page)) { + return eval(page.getPositionCount(), leftBlock); } } - public BooleanBlock eval(int positionCount, BytesRefBlock leftValueBlock) { + public BooleanBlock eval(int positionCount, BytesRefBlock leftBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + if (allBlocksAreNulls) { result.appendNull(); continue position; } try { - result.appendBoolean(SpatialIntersects.processCartesianSourceAndConstant(leftValueBlock.getBytesRef(leftValueBlock.getFirstValueIndex(p), leftValueScratch), this.rightValue)); - } catch (IllegalArgumentException | IOException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { - try { - result.appendBoolean(SpatialIntersects.processCartesianSourceAndConstant(leftValueVector.getBytesRef(p, leftValueScratch), this.rightValue)); + SpatialIntersects.processCartesianSourceAndConstant(result, p, leftBlock, this.right); } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); @@ -97,36 +71,36 @@ public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector) { @Override public String toString() { - return "SpatialIntersectsCartesianSourceAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialIntersectsCartesianSourceAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue); + Releasables.closeExpectNoException(left); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final Component2D rightValue; + private final Component2D right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - Component2D rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + Component2D right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialIntersectsCartesianSourceAndConstantEvaluator get(DriverContext context) { - return new SpatialIntersectsCartesianSourceAndConstantEvaluator(source, leftValue.get(context), rightValue, context); + return new SpatialIntersectsCartesianSourceAndConstantEvaluator(source, left.get(context), right, context); } @Override public String toString() { - return "SpatialIntersectsCartesianSourceAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialIntersectsCartesianSourceAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianSourceAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianSourceAndSourceEvaluator.java index 8ad15d9f5a881..d3301d829d8e2 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianSourceAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianSourceAndSourceEvaluator.java @@ -8,11 +8,9 @@ import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -27,85 +25,46 @@ public final class SpatialIntersectsCartesianSourceAndSourceEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final EvalOperator.ExpressionEvaluator rightValue; + private final EvalOperator.ExpressionEvaluator right; private final DriverContext driverContext; public SpatialIntersectsCartesianSourceAndSourceEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, EvalOperator.ExpressionEvaluator rightValue, + EvalOperator.ExpressionEvaluator left, EvalOperator.ExpressionEvaluator right, DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (BytesRefBlock leftValueBlock = (BytesRefBlock) leftValue.eval(page)) { - try (BytesRefBlock rightValueBlock = (BytesRefBlock) rightValue.eval(page)) { - BytesRefVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - BytesRefVector rightValueVector = rightValueBlock.asVector(); - if (rightValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - return eval(page.getPositionCount(), leftValueVector, rightValueVector); + try (BytesRefBlock leftBlock = (BytesRefBlock) left.eval(page)) { + try (BytesRefBlock rightBlock = (BytesRefBlock) right.eval(page)) { + return eval(page.getPositionCount(), leftBlock, rightBlock); } } } - public BooleanBlock eval(int positionCount, BytesRefBlock leftValueBlock, - BytesRefBlock rightValueBlock) { + public BooleanBlock eval(int positionCount, BytesRefBlock leftBlock, BytesRefBlock rightBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - BytesRef rightValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; + if (!rightBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (rightValueBlock.isNull(p)) { + if (allBlocksAreNulls) { result.appendNull(); continue position; } - if (rightValueBlock.getValueCount(p) != 1) { - if (rightValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; - } - try { - result.appendBoolean(SpatialIntersects.processCartesianSourceAndSource(leftValueBlock.getBytesRef(leftValueBlock.getFirstValueIndex(p), leftValueScratch), rightValueBlock.getBytesRef(rightValueBlock.getFirstValueIndex(p), rightValueScratch))); - } catch (IllegalArgumentException | IOException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector, - BytesRefVector rightValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - BytesRef rightValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { try { - result.appendBoolean(SpatialIntersects.processCartesianSourceAndSource(leftValueVector.getBytesRef(p, leftValueScratch), rightValueVector.getBytesRef(p, rightValueScratch))); + SpatialIntersects.processCartesianSourceAndSource(result, p, leftBlock, rightBlock); } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); @@ -117,36 +76,36 @@ public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector, @Override public String toString() { - return "SpatialIntersectsCartesianSourceAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialIntersectsCartesianSourceAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue, rightValue); + Releasables.closeExpectNoException(left, right); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final EvalOperator.ExpressionEvaluator.Factory rightValue; + private final EvalOperator.ExpressionEvaluator.Factory right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - EvalOperator.ExpressionEvaluator.Factory rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + EvalOperator.ExpressionEvaluator.Factory right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialIntersectsCartesianSourceAndSourceEvaluator get(DriverContext context) { - return new SpatialIntersectsCartesianSourceAndSourceEvaluator(source, leftValue.get(context), rightValue.get(context), context); + return new SpatialIntersectsCartesianSourceAndSourceEvaluator(source, left.get(context), right.get(context), context); } @Override public String toString() { - return "SpatialIntersectsCartesianSourceAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialIntersectsCartesianSourceAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoPointDocValuesAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoPointDocValuesAndConstantEvaluator.java index f6c16997bedc3..c11cd69d916cd 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoPointDocValuesAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoPointDocValuesAndConstantEvaluator.java @@ -4,6 +4,7 @@ // 2.0. package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; +import java.io.IOException; import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; @@ -11,7 +12,6 @@ import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.LongBlock; -import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -26,63 +26,41 @@ public final class SpatialIntersectsGeoPointDocValuesAndConstantEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final Component2D rightValue; + private final Component2D right; private final DriverContext driverContext; public SpatialIntersectsGeoPointDocValuesAndConstantEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, Component2D rightValue, - DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + EvalOperator.ExpressionEvaluator left, Component2D right, DriverContext driverContext) { + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (LongBlock leftValueBlock = (LongBlock) leftValue.eval(page)) { - LongVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock); - } - return eval(page.getPositionCount(), leftValueVector); + try (LongBlock leftBlock = (LongBlock) left.eval(page)) { + return eval(page.getPositionCount(), leftBlock); } } - public BooleanBlock eval(int positionCount, LongBlock leftValueBlock) { + public BooleanBlock eval(int positionCount, LongBlock leftBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + if (allBlocksAreNulls) { result.appendNull(); continue position; } try { - result.appendBoolean(SpatialIntersects.processGeoPointDocValuesAndConstant(leftValueBlock.getLong(leftValueBlock.getFirstValueIndex(p)), this.rightValue)); - } catch (IllegalArgumentException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, LongVector leftValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - position: for (int p = 0; p < positionCount; p++) { - try { - result.appendBoolean(SpatialIntersects.processGeoPointDocValuesAndConstant(leftValueVector.getLong(p), this.rightValue)); - } catch (IllegalArgumentException e) { + SpatialIntersects.processGeoPointDocValuesAndConstant(result, p, leftBlock, this.right); + } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); } @@ -93,36 +71,36 @@ public BooleanBlock eval(int positionCount, LongVector leftValueVector) { @Override public String toString() { - return "SpatialIntersectsGeoPointDocValuesAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialIntersectsGeoPointDocValuesAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue); + Releasables.closeExpectNoException(left); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final Component2D rightValue; + private final Component2D right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - Component2D rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + Component2D right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialIntersectsGeoPointDocValuesAndConstantEvaluator get(DriverContext context) { - return new SpatialIntersectsGeoPointDocValuesAndConstantEvaluator(source, leftValue.get(context), rightValue, context); + return new SpatialIntersectsGeoPointDocValuesAndConstantEvaluator(source, left.get(context), right, context); } @Override public String toString() { - return "SpatialIntersectsGeoPointDocValuesAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialIntersectsGeoPointDocValuesAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoPointDocValuesAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoPointDocValuesAndSourceEvaluator.java index f385ee992096c..12337bf888e59 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoPointDocValuesAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoPointDocValuesAndSourceEvaluator.java @@ -4,16 +4,14 @@ // 2.0. package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; +import java.io.IOException; import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.LongBlock; -import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -28,84 +26,47 @@ public final class SpatialIntersectsGeoPointDocValuesAndSourceEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final EvalOperator.ExpressionEvaluator rightValue; + private final EvalOperator.ExpressionEvaluator right; private final DriverContext driverContext; public SpatialIntersectsGeoPointDocValuesAndSourceEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, EvalOperator.ExpressionEvaluator rightValue, + EvalOperator.ExpressionEvaluator left, EvalOperator.ExpressionEvaluator right, DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (LongBlock leftValueBlock = (LongBlock) leftValue.eval(page)) { - try (BytesRefBlock rightValueBlock = (BytesRefBlock) rightValue.eval(page)) { - LongVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - BytesRefVector rightValueVector = rightValueBlock.asVector(); - if (rightValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - return eval(page.getPositionCount(), leftValueVector, rightValueVector); + try (LongBlock leftBlock = (LongBlock) left.eval(page)) { + try (BytesRefBlock rightBlock = (BytesRefBlock) right.eval(page)) { + return eval(page.getPositionCount(), leftBlock, rightBlock); } } } - public BooleanBlock eval(int positionCount, LongBlock leftValueBlock, - BytesRefBlock rightValueBlock) { + public BooleanBlock eval(int positionCount, LongBlock leftBlock, BytesRefBlock rightBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef rightValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; - } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (rightValueBlock.isNull(p)) { - result.appendNull(); - continue position; + if (!rightBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (rightValueBlock.getValueCount(p) != 1) { - if (rightValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + if (allBlocksAreNulls) { result.appendNull(); continue position; } try { - result.appendBoolean(SpatialIntersects.processGeoPointDocValuesAndSource(leftValueBlock.getLong(leftValueBlock.getFirstValueIndex(p)), rightValueBlock.getBytesRef(rightValueBlock.getFirstValueIndex(p), rightValueScratch))); - } catch (IllegalArgumentException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, LongVector leftValueVector, - BytesRefVector rightValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef rightValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { - try { - result.appendBoolean(SpatialIntersects.processGeoPointDocValuesAndSource(leftValueVector.getLong(p), rightValueVector.getBytesRef(p, rightValueScratch))); - } catch (IllegalArgumentException e) { + SpatialIntersects.processGeoPointDocValuesAndSource(result, p, leftBlock, rightBlock); + } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); } @@ -116,36 +77,36 @@ public BooleanBlock eval(int positionCount, LongVector leftValueVector, @Override public String toString() { - return "SpatialIntersectsGeoPointDocValuesAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialIntersectsGeoPointDocValuesAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue, rightValue); + Releasables.closeExpectNoException(left, right); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final EvalOperator.ExpressionEvaluator.Factory rightValue; + private final EvalOperator.ExpressionEvaluator.Factory right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - EvalOperator.ExpressionEvaluator.Factory rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + EvalOperator.ExpressionEvaluator.Factory right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialIntersectsGeoPointDocValuesAndSourceEvaluator get(DriverContext context) { - return new SpatialIntersectsGeoPointDocValuesAndSourceEvaluator(source, leftValue.get(context), rightValue.get(context), context); + return new SpatialIntersectsGeoPointDocValuesAndSourceEvaluator(source, left.get(context), right.get(context), context); } @Override public String toString() { - return "SpatialIntersectsGeoPointDocValuesAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialIntersectsGeoPointDocValuesAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoSourceAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoSourceAndConstantEvaluator.java index 94ecf64f7252e..f75c1c6987921 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoSourceAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoSourceAndConstantEvaluator.java @@ -9,11 +9,9 @@ import java.lang.Override; import java.lang.String; import org.apache.lucene.geo.Component2D; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -28,64 +26,40 @@ public final class SpatialIntersectsGeoSourceAndConstantEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final Component2D rightValue; + private final Component2D right; private final DriverContext driverContext; public SpatialIntersectsGeoSourceAndConstantEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, Component2D rightValue, - DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + EvalOperator.ExpressionEvaluator left, Component2D right, DriverContext driverContext) { + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (BytesRefBlock leftValueBlock = (BytesRefBlock) leftValue.eval(page)) { - BytesRefVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock); - } - return eval(page.getPositionCount(), leftValueVector); + try (BytesRefBlock leftBlock = (BytesRefBlock) left.eval(page)) { + return eval(page.getPositionCount(), leftBlock); } } - public BooleanBlock eval(int positionCount, BytesRefBlock leftValueBlock) { + public BooleanBlock eval(int positionCount, BytesRefBlock leftBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + if (allBlocksAreNulls) { result.appendNull(); continue position; } try { - result.appendBoolean(SpatialIntersects.processGeoSourceAndConstant(leftValueBlock.getBytesRef(leftValueBlock.getFirstValueIndex(p), leftValueScratch), this.rightValue)); - } catch (IllegalArgumentException | IOException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { - try { - result.appendBoolean(SpatialIntersects.processGeoSourceAndConstant(leftValueVector.getBytesRef(p, leftValueScratch), this.rightValue)); + SpatialIntersects.processGeoSourceAndConstant(result, p, leftBlock, this.right); } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); @@ -97,36 +71,36 @@ public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector) { @Override public String toString() { - return "SpatialIntersectsGeoSourceAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialIntersectsGeoSourceAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue); + Releasables.closeExpectNoException(left); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final Component2D rightValue; + private final Component2D right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - Component2D rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + Component2D right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialIntersectsGeoSourceAndConstantEvaluator get(DriverContext context) { - return new SpatialIntersectsGeoSourceAndConstantEvaluator(source, leftValue.get(context), rightValue, context); + return new SpatialIntersectsGeoSourceAndConstantEvaluator(source, left.get(context), right, context); } @Override public String toString() { - return "SpatialIntersectsGeoSourceAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialIntersectsGeoSourceAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoSourceAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoSourceAndSourceEvaluator.java index 2b5dd689ca3a9..a8a3f02ddbd93 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoSourceAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoSourceAndSourceEvaluator.java @@ -8,11 +8,9 @@ import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -27,85 +25,46 @@ public final class SpatialIntersectsGeoSourceAndSourceEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final EvalOperator.ExpressionEvaluator rightValue; + private final EvalOperator.ExpressionEvaluator right; private final DriverContext driverContext; public SpatialIntersectsGeoSourceAndSourceEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, EvalOperator.ExpressionEvaluator rightValue, + EvalOperator.ExpressionEvaluator left, EvalOperator.ExpressionEvaluator right, DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (BytesRefBlock leftValueBlock = (BytesRefBlock) leftValue.eval(page)) { - try (BytesRefBlock rightValueBlock = (BytesRefBlock) rightValue.eval(page)) { - BytesRefVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - BytesRefVector rightValueVector = rightValueBlock.asVector(); - if (rightValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - return eval(page.getPositionCount(), leftValueVector, rightValueVector); + try (BytesRefBlock leftBlock = (BytesRefBlock) left.eval(page)) { + try (BytesRefBlock rightBlock = (BytesRefBlock) right.eval(page)) { + return eval(page.getPositionCount(), leftBlock, rightBlock); } } } - public BooleanBlock eval(int positionCount, BytesRefBlock leftValueBlock, - BytesRefBlock rightValueBlock) { + public BooleanBlock eval(int positionCount, BytesRefBlock leftBlock, BytesRefBlock rightBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - BytesRef rightValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; + if (!rightBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (rightValueBlock.isNull(p)) { + if (allBlocksAreNulls) { result.appendNull(); continue position; } - if (rightValueBlock.getValueCount(p) != 1) { - if (rightValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; - } - try { - result.appendBoolean(SpatialIntersects.processGeoSourceAndSource(leftValueBlock.getBytesRef(leftValueBlock.getFirstValueIndex(p), leftValueScratch), rightValueBlock.getBytesRef(rightValueBlock.getFirstValueIndex(p), rightValueScratch))); - } catch (IllegalArgumentException | IOException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector, - BytesRefVector rightValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - BytesRef rightValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { try { - result.appendBoolean(SpatialIntersects.processGeoSourceAndSource(leftValueVector.getBytesRef(p, leftValueScratch), rightValueVector.getBytesRef(p, rightValueScratch))); + SpatialIntersects.processGeoSourceAndSource(result, p, leftBlock, rightBlock); } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); @@ -117,36 +76,36 @@ public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector, @Override public String toString() { - return "SpatialIntersectsGeoSourceAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialIntersectsGeoSourceAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue, rightValue); + Releasables.closeExpectNoException(left, right); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final EvalOperator.ExpressionEvaluator.Factory rightValue; + private final EvalOperator.ExpressionEvaluator.Factory right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - EvalOperator.ExpressionEvaluator.Factory rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + EvalOperator.ExpressionEvaluator.Factory right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialIntersectsGeoSourceAndSourceEvaluator get(DriverContext context) { - return new SpatialIntersectsGeoSourceAndSourceEvaluator(source, leftValue.get(context), rightValue.get(context), context); + return new SpatialIntersectsGeoSourceAndSourceEvaluator(source, left.get(context), right.get(context), context); } @Override public String toString() { - return "SpatialIntersectsGeoSourceAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialIntersectsGeoSourceAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianPointDocValuesAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianPointDocValuesAndConstantEvaluator.java index 0619d401154da..b4780c8829b23 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianPointDocValuesAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianPointDocValuesAndConstantEvaluator.java @@ -4,6 +4,7 @@ // 2.0. package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; +import java.io.IOException; import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; @@ -11,7 +12,6 @@ import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.LongBlock; -import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -26,63 +26,41 @@ public final class SpatialWithinCartesianPointDocValuesAndConstantEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final Component2D rightValue; + private final Component2D right; private final DriverContext driverContext; public SpatialWithinCartesianPointDocValuesAndConstantEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, Component2D rightValue, - DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + EvalOperator.ExpressionEvaluator left, Component2D right, DriverContext driverContext) { + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (LongBlock leftValueBlock = (LongBlock) leftValue.eval(page)) { - LongVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock); - } - return eval(page.getPositionCount(), leftValueVector); + try (LongBlock leftBlock = (LongBlock) left.eval(page)) { + return eval(page.getPositionCount(), leftBlock); } } - public BooleanBlock eval(int positionCount, LongBlock leftValueBlock) { + public BooleanBlock eval(int positionCount, LongBlock leftBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + if (allBlocksAreNulls) { result.appendNull(); continue position; } try { - result.appendBoolean(SpatialWithin.processCartesianPointDocValuesAndConstant(leftValueBlock.getLong(leftValueBlock.getFirstValueIndex(p)), this.rightValue)); - } catch (IllegalArgumentException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, LongVector leftValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - position: for (int p = 0; p < positionCount; p++) { - try { - result.appendBoolean(SpatialWithin.processCartesianPointDocValuesAndConstant(leftValueVector.getLong(p), this.rightValue)); - } catch (IllegalArgumentException e) { + SpatialWithin.processCartesianPointDocValuesAndConstant(result, p, leftBlock, this.right); + } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); } @@ -93,36 +71,36 @@ public BooleanBlock eval(int positionCount, LongVector leftValueVector) { @Override public String toString() { - return "SpatialWithinCartesianPointDocValuesAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialWithinCartesianPointDocValuesAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue); + Releasables.closeExpectNoException(left); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final Component2D rightValue; + private final Component2D right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - Component2D rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + Component2D right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialWithinCartesianPointDocValuesAndConstantEvaluator get(DriverContext context) { - return new SpatialWithinCartesianPointDocValuesAndConstantEvaluator(source, leftValue.get(context), rightValue, context); + return new SpatialWithinCartesianPointDocValuesAndConstantEvaluator(source, left.get(context), right, context); } @Override public String toString() { - return "SpatialWithinCartesianPointDocValuesAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialWithinCartesianPointDocValuesAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianPointDocValuesAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianPointDocValuesAndSourceEvaluator.java index dae80c04b43d3..006ff30af5e1b 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianPointDocValuesAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianPointDocValuesAndSourceEvaluator.java @@ -4,17 +4,14 @@ // 2.0. package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; +import java.io.IOException; import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; -import org.elasticsearch.compute.data.BooleanVector; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.LongBlock; -import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -29,77 +26,50 @@ public final class SpatialWithinCartesianPointDocValuesAndSourceEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final EvalOperator.ExpressionEvaluator rightValue; + private final EvalOperator.ExpressionEvaluator right; private final DriverContext driverContext; public SpatialWithinCartesianPointDocValuesAndSourceEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, EvalOperator.ExpressionEvaluator rightValue, + EvalOperator.ExpressionEvaluator left, EvalOperator.ExpressionEvaluator right, DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (LongBlock leftValueBlock = (LongBlock) leftValue.eval(page)) { - try (BytesRefBlock rightValueBlock = (BytesRefBlock) rightValue.eval(page)) { - LongVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - BytesRefVector rightValueVector = rightValueBlock.asVector(); - if (rightValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - return eval(page.getPositionCount(), leftValueVector, rightValueVector).asBlock(); + try (LongBlock leftBlock = (LongBlock) left.eval(page)) { + try (BytesRefBlock rightBlock = (BytesRefBlock) right.eval(page)) { + return eval(page.getPositionCount(), leftBlock, rightBlock); } } } - public BooleanBlock eval(int positionCount, LongBlock leftValueBlock, - BytesRefBlock rightValueBlock) { + public BooleanBlock eval(int positionCount, LongBlock leftBlock, BytesRefBlock rightBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef rightValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; + if (!rightBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (rightValueBlock.isNull(p)) { + if (allBlocksAreNulls) { result.appendNull(); continue position; } - if (rightValueBlock.getValueCount(p) != 1) { - if (rightValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + try { + SpatialWithin.processCartesianPointDocValuesAndSource(result, p, leftBlock, rightBlock); + } catch (IllegalArgumentException | IOException e) { + warnings.registerException(e); result.appendNull(); - continue position; } - result.appendBoolean(SpatialWithin.processCartesianPointDocValuesAndSource(leftValueBlock.getLong(leftValueBlock.getFirstValueIndex(p)), rightValueBlock.getBytesRef(rightValueBlock.getFirstValueIndex(p), rightValueScratch))); - } - return result.build(); - } - } - - public BooleanVector eval(int positionCount, LongVector leftValueVector, - BytesRefVector rightValueVector) { - try(BooleanVector.FixedBuilder result = driverContext.blockFactory().newBooleanVectorFixedBuilder(positionCount)) { - BytesRef rightValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { - result.appendBoolean(p, SpatialWithin.processCartesianPointDocValuesAndSource(leftValueVector.getLong(p), rightValueVector.getBytesRef(p, rightValueScratch))); } return result.build(); } @@ -107,36 +77,36 @@ public BooleanVector eval(int positionCount, LongVector leftValueVector, @Override public String toString() { - return "SpatialWithinCartesianPointDocValuesAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialWithinCartesianPointDocValuesAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue, rightValue); + Releasables.closeExpectNoException(left, right); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final EvalOperator.ExpressionEvaluator.Factory rightValue; + private final EvalOperator.ExpressionEvaluator.Factory right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - EvalOperator.ExpressionEvaluator.Factory rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + EvalOperator.ExpressionEvaluator.Factory right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialWithinCartesianPointDocValuesAndSourceEvaluator get(DriverContext context) { - return new SpatialWithinCartesianPointDocValuesAndSourceEvaluator(source, leftValue.get(context), rightValue.get(context), context); + return new SpatialWithinCartesianPointDocValuesAndSourceEvaluator(source, left.get(context), right.get(context), context); } @Override public String toString() { - return "SpatialWithinCartesianPointDocValuesAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialWithinCartesianPointDocValuesAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianSourceAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianSourceAndConstantEvaluator.java index 82de0c349dc7d..d835170c8604f 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianSourceAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianSourceAndConstantEvaluator.java @@ -9,11 +9,9 @@ import java.lang.Override; import java.lang.String; import org.apache.lucene.geo.Component2D; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -28,64 +26,40 @@ public final class SpatialWithinCartesianSourceAndConstantEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final Component2D rightValue; + private final Component2D right; private final DriverContext driverContext; public SpatialWithinCartesianSourceAndConstantEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, Component2D rightValue, - DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + EvalOperator.ExpressionEvaluator left, Component2D right, DriverContext driverContext) { + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (BytesRefBlock leftValueBlock = (BytesRefBlock) leftValue.eval(page)) { - BytesRefVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock); - } - return eval(page.getPositionCount(), leftValueVector); + try (BytesRefBlock leftBlock = (BytesRefBlock) left.eval(page)) { + return eval(page.getPositionCount(), leftBlock); } } - public BooleanBlock eval(int positionCount, BytesRefBlock leftValueBlock) { + public BooleanBlock eval(int positionCount, BytesRefBlock leftBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + if (allBlocksAreNulls) { result.appendNull(); continue position; } try { - result.appendBoolean(SpatialWithin.processCartesianSourceAndConstant(leftValueBlock.getBytesRef(leftValueBlock.getFirstValueIndex(p), leftValueScratch), this.rightValue)); - } catch (IllegalArgumentException | IOException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { - try { - result.appendBoolean(SpatialWithin.processCartesianSourceAndConstant(leftValueVector.getBytesRef(p, leftValueScratch), this.rightValue)); + SpatialWithin.processCartesianSourceAndConstant(result, p, leftBlock, this.right); } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); @@ -97,36 +71,36 @@ public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector) { @Override public String toString() { - return "SpatialWithinCartesianSourceAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialWithinCartesianSourceAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue); + Releasables.closeExpectNoException(left); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final Component2D rightValue; + private final Component2D right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - Component2D rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + Component2D right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialWithinCartesianSourceAndConstantEvaluator get(DriverContext context) { - return new SpatialWithinCartesianSourceAndConstantEvaluator(source, leftValue.get(context), rightValue, context); + return new SpatialWithinCartesianSourceAndConstantEvaluator(source, left.get(context), right, context); } @Override public String toString() { - return "SpatialWithinCartesianSourceAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialWithinCartesianSourceAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianSourceAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianSourceAndSourceEvaluator.java index 43440a165de74..5e46c1afd9e4b 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianSourceAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianSourceAndSourceEvaluator.java @@ -8,11 +8,9 @@ import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -27,85 +25,46 @@ public final class SpatialWithinCartesianSourceAndSourceEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final EvalOperator.ExpressionEvaluator rightValue; + private final EvalOperator.ExpressionEvaluator right; private final DriverContext driverContext; public SpatialWithinCartesianSourceAndSourceEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, EvalOperator.ExpressionEvaluator rightValue, + EvalOperator.ExpressionEvaluator left, EvalOperator.ExpressionEvaluator right, DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (BytesRefBlock leftValueBlock = (BytesRefBlock) leftValue.eval(page)) { - try (BytesRefBlock rightValueBlock = (BytesRefBlock) rightValue.eval(page)) { - BytesRefVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - BytesRefVector rightValueVector = rightValueBlock.asVector(); - if (rightValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - return eval(page.getPositionCount(), leftValueVector, rightValueVector); + try (BytesRefBlock leftBlock = (BytesRefBlock) left.eval(page)) { + try (BytesRefBlock rightBlock = (BytesRefBlock) right.eval(page)) { + return eval(page.getPositionCount(), leftBlock, rightBlock); } } } - public BooleanBlock eval(int positionCount, BytesRefBlock leftValueBlock, - BytesRefBlock rightValueBlock) { + public BooleanBlock eval(int positionCount, BytesRefBlock leftBlock, BytesRefBlock rightBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - BytesRef rightValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; + if (!rightBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (rightValueBlock.isNull(p)) { + if (allBlocksAreNulls) { result.appendNull(); continue position; } - if (rightValueBlock.getValueCount(p) != 1) { - if (rightValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; - } - try { - result.appendBoolean(SpatialWithin.processCartesianSourceAndSource(leftValueBlock.getBytesRef(leftValueBlock.getFirstValueIndex(p), leftValueScratch), rightValueBlock.getBytesRef(rightValueBlock.getFirstValueIndex(p), rightValueScratch))); - } catch (IllegalArgumentException | IOException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector, - BytesRefVector rightValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - BytesRef rightValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { try { - result.appendBoolean(SpatialWithin.processCartesianSourceAndSource(leftValueVector.getBytesRef(p, leftValueScratch), rightValueVector.getBytesRef(p, rightValueScratch))); + SpatialWithin.processCartesianSourceAndSource(result, p, leftBlock, rightBlock); } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); @@ -117,36 +76,36 @@ public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector, @Override public String toString() { - return "SpatialWithinCartesianSourceAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialWithinCartesianSourceAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue, rightValue); + Releasables.closeExpectNoException(left, right); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final EvalOperator.ExpressionEvaluator.Factory rightValue; + private final EvalOperator.ExpressionEvaluator.Factory right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - EvalOperator.ExpressionEvaluator.Factory rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + EvalOperator.ExpressionEvaluator.Factory right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialWithinCartesianSourceAndSourceEvaluator get(DriverContext context) { - return new SpatialWithinCartesianSourceAndSourceEvaluator(source, leftValue.get(context), rightValue.get(context), context); + return new SpatialWithinCartesianSourceAndSourceEvaluator(source, left.get(context), right.get(context), context); } @Override public String toString() { - return "SpatialWithinCartesianSourceAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialWithinCartesianSourceAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoPointDocValuesAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoPointDocValuesAndConstantEvaluator.java index b686e1aec1f4c..b9676f2a5a367 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoPointDocValuesAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoPointDocValuesAndConstantEvaluator.java @@ -4,6 +4,7 @@ // 2.0. package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; +import java.io.IOException; import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; @@ -11,7 +12,6 @@ import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.LongBlock; -import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -26,63 +26,41 @@ public final class SpatialWithinGeoPointDocValuesAndConstantEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final Component2D rightValue; + private final Component2D right; private final DriverContext driverContext; public SpatialWithinGeoPointDocValuesAndConstantEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, Component2D rightValue, - DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + EvalOperator.ExpressionEvaluator left, Component2D right, DriverContext driverContext) { + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (LongBlock leftValueBlock = (LongBlock) leftValue.eval(page)) { - LongVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock); - } - return eval(page.getPositionCount(), leftValueVector); + try (LongBlock leftBlock = (LongBlock) left.eval(page)) { + return eval(page.getPositionCount(), leftBlock); } } - public BooleanBlock eval(int positionCount, LongBlock leftValueBlock) { + public BooleanBlock eval(int positionCount, LongBlock leftBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + if (allBlocksAreNulls) { result.appendNull(); continue position; } try { - result.appendBoolean(SpatialWithin.processGeoPointDocValuesAndConstant(leftValueBlock.getLong(leftValueBlock.getFirstValueIndex(p)), this.rightValue)); - } catch (IllegalArgumentException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, LongVector leftValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - position: for (int p = 0; p < positionCount; p++) { - try { - result.appendBoolean(SpatialWithin.processGeoPointDocValuesAndConstant(leftValueVector.getLong(p), this.rightValue)); - } catch (IllegalArgumentException e) { + SpatialWithin.processGeoPointDocValuesAndConstant(result, p, leftBlock, this.right); + } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); } @@ -93,36 +71,36 @@ public BooleanBlock eval(int positionCount, LongVector leftValueVector) { @Override public String toString() { - return "SpatialWithinGeoPointDocValuesAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialWithinGeoPointDocValuesAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue); + Releasables.closeExpectNoException(left); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final Component2D rightValue; + private final Component2D right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - Component2D rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + Component2D right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialWithinGeoPointDocValuesAndConstantEvaluator get(DriverContext context) { - return new SpatialWithinGeoPointDocValuesAndConstantEvaluator(source, leftValue.get(context), rightValue, context); + return new SpatialWithinGeoPointDocValuesAndConstantEvaluator(source, left.get(context), right, context); } @Override public String toString() { - return "SpatialWithinGeoPointDocValuesAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialWithinGeoPointDocValuesAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoPointDocValuesAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoPointDocValuesAndSourceEvaluator.java index 761e0f2019cec..4d56cd8ecdde4 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoPointDocValuesAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoPointDocValuesAndSourceEvaluator.java @@ -4,16 +4,14 @@ // 2.0. package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; +import java.io.IOException; import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.LongBlock; -import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -28,84 +26,47 @@ public final class SpatialWithinGeoPointDocValuesAndSourceEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final EvalOperator.ExpressionEvaluator rightValue; + private final EvalOperator.ExpressionEvaluator right; private final DriverContext driverContext; public SpatialWithinGeoPointDocValuesAndSourceEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, EvalOperator.ExpressionEvaluator rightValue, + EvalOperator.ExpressionEvaluator left, EvalOperator.ExpressionEvaluator right, DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (LongBlock leftValueBlock = (LongBlock) leftValue.eval(page)) { - try (BytesRefBlock rightValueBlock = (BytesRefBlock) rightValue.eval(page)) { - LongVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - BytesRefVector rightValueVector = rightValueBlock.asVector(); - if (rightValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - return eval(page.getPositionCount(), leftValueVector, rightValueVector); + try (LongBlock leftBlock = (LongBlock) left.eval(page)) { + try (BytesRefBlock rightBlock = (BytesRefBlock) right.eval(page)) { + return eval(page.getPositionCount(), leftBlock, rightBlock); } } } - public BooleanBlock eval(int positionCount, LongBlock leftValueBlock, - BytesRefBlock rightValueBlock) { + public BooleanBlock eval(int positionCount, LongBlock leftBlock, BytesRefBlock rightBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef rightValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; - } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (rightValueBlock.isNull(p)) { - result.appendNull(); - continue position; + if (!rightBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (rightValueBlock.getValueCount(p) != 1) { - if (rightValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + if (allBlocksAreNulls) { result.appendNull(); continue position; } try { - result.appendBoolean(SpatialWithin.processGeoPointDocValuesAndSource(leftValueBlock.getLong(leftValueBlock.getFirstValueIndex(p)), rightValueBlock.getBytesRef(rightValueBlock.getFirstValueIndex(p), rightValueScratch))); - } catch (IllegalArgumentException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, LongVector leftValueVector, - BytesRefVector rightValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef rightValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { - try { - result.appendBoolean(SpatialWithin.processGeoPointDocValuesAndSource(leftValueVector.getLong(p), rightValueVector.getBytesRef(p, rightValueScratch))); - } catch (IllegalArgumentException e) { + SpatialWithin.processGeoPointDocValuesAndSource(result, p, leftBlock, rightBlock); + } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); } @@ -116,36 +77,36 @@ public BooleanBlock eval(int positionCount, LongVector leftValueVector, @Override public String toString() { - return "SpatialWithinGeoPointDocValuesAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialWithinGeoPointDocValuesAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue, rightValue); + Releasables.closeExpectNoException(left, right); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final EvalOperator.ExpressionEvaluator.Factory rightValue; + private final EvalOperator.ExpressionEvaluator.Factory right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - EvalOperator.ExpressionEvaluator.Factory rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + EvalOperator.ExpressionEvaluator.Factory right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialWithinGeoPointDocValuesAndSourceEvaluator get(DriverContext context) { - return new SpatialWithinGeoPointDocValuesAndSourceEvaluator(source, leftValue.get(context), rightValue.get(context), context); + return new SpatialWithinGeoPointDocValuesAndSourceEvaluator(source, left.get(context), right.get(context), context); } @Override public String toString() { - return "SpatialWithinGeoPointDocValuesAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialWithinGeoPointDocValuesAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoSourceAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoSourceAndConstantEvaluator.java index a5d3d48717531..a0535c9e8db78 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoSourceAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoSourceAndConstantEvaluator.java @@ -9,11 +9,9 @@ import java.lang.Override; import java.lang.String; import org.apache.lucene.geo.Component2D; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -28,64 +26,40 @@ public final class SpatialWithinGeoSourceAndConstantEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final Component2D rightValue; + private final Component2D right; private final DriverContext driverContext; public SpatialWithinGeoSourceAndConstantEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, Component2D rightValue, - DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + EvalOperator.ExpressionEvaluator left, Component2D right, DriverContext driverContext) { + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (BytesRefBlock leftValueBlock = (BytesRefBlock) leftValue.eval(page)) { - BytesRefVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock); - } - return eval(page.getPositionCount(), leftValueVector); + try (BytesRefBlock leftBlock = (BytesRefBlock) left.eval(page)) { + return eval(page.getPositionCount(), leftBlock); } } - public BooleanBlock eval(int positionCount, BytesRefBlock leftValueBlock) { + public BooleanBlock eval(int positionCount, BytesRefBlock leftBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } + if (allBlocksAreNulls) { result.appendNull(); continue position; } try { - result.appendBoolean(SpatialWithin.processGeoSourceAndConstant(leftValueBlock.getBytesRef(leftValueBlock.getFirstValueIndex(p), leftValueScratch), this.rightValue)); - } catch (IllegalArgumentException | IOException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { - try { - result.appendBoolean(SpatialWithin.processGeoSourceAndConstant(leftValueVector.getBytesRef(p, leftValueScratch), this.rightValue)); + SpatialWithin.processGeoSourceAndConstant(result, p, leftBlock, this.right); } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); @@ -97,36 +71,36 @@ public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector) { @Override public String toString() { - return "SpatialWithinGeoSourceAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialWithinGeoSourceAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue); + Releasables.closeExpectNoException(left); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final Component2D rightValue; + private final Component2D right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - Component2D rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + Component2D right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialWithinGeoSourceAndConstantEvaluator get(DriverContext context) { - return new SpatialWithinGeoSourceAndConstantEvaluator(source, leftValue.get(context), rightValue, context); + return new SpatialWithinGeoSourceAndConstantEvaluator(source, left.get(context), right, context); } @Override public String toString() { - return "SpatialWithinGeoSourceAndConstantEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialWithinGeoSourceAndConstantEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoSourceAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoSourceAndSourceEvaluator.java index bbeb07f6eefc5..9305b31e5582f 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoSourceAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoSourceAndSourceEvaluator.java @@ -8,11 +8,9 @@ import java.lang.IllegalArgumentException; import java.lang.Override; import java.lang.String; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.data.BytesRefBlock; -import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; @@ -27,85 +25,46 @@ public final class SpatialWithinGeoSourceAndSourceEvaluator implements EvalOperator.ExpressionEvaluator { private final Warnings warnings; - private final EvalOperator.ExpressionEvaluator leftValue; + private final EvalOperator.ExpressionEvaluator left; - private final EvalOperator.ExpressionEvaluator rightValue; + private final EvalOperator.ExpressionEvaluator right; private final DriverContext driverContext; public SpatialWithinGeoSourceAndSourceEvaluator(Source source, - EvalOperator.ExpressionEvaluator leftValue, EvalOperator.ExpressionEvaluator rightValue, + EvalOperator.ExpressionEvaluator left, EvalOperator.ExpressionEvaluator right, DriverContext driverContext) { - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; this.driverContext = driverContext; this.warnings = Warnings.createWarnings(driverContext.warningsMode(), source); } @Override public Block eval(Page page) { - try (BytesRefBlock leftValueBlock = (BytesRefBlock) leftValue.eval(page)) { - try (BytesRefBlock rightValueBlock = (BytesRefBlock) rightValue.eval(page)) { - BytesRefVector leftValueVector = leftValueBlock.asVector(); - if (leftValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - BytesRefVector rightValueVector = rightValueBlock.asVector(); - if (rightValueVector == null) { - return eval(page.getPositionCount(), leftValueBlock, rightValueBlock); - } - return eval(page.getPositionCount(), leftValueVector, rightValueVector); + try (BytesRefBlock leftBlock = (BytesRefBlock) left.eval(page)) { + try (BytesRefBlock rightBlock = (BytesRefBlock) right.eval(page)) { + return eval(page.getPositionCount(), leftBlock, rightBlock); } } } - public BooleanBlock eval(int positionCount, BytesRefBlock leftValueBlock, - BytesRefBlock rightValueBlock) { + public BooleanBlock eval(int positionCount, BytesRefBlock leftBlock, BytesRefBlock rightBlock) { try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - BytesRef rightValueScratch = new BytesRef(); position: for (int p = 0; p < positionCount; p++) { - if (leftValueBlock.isNull(p)) { - result.appendNull(); - continue position; + boolean allBlocksAreNulls = true; + if (!leftBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (leftValueBlock.getValueCount(p) != 1) { - if (leftValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; + if (!rightBlock.isNull(p)) { + allBlocksAreNulls = false; } - if (rightValueBlock.isNull(p)) { + if (allBlocksAreNulls) { result.appendNull(); continue position; } - if (rightValueBlock.getValueCount(p) != 1) { - if (rightValueBlock.getValueCount(p) > 1) { - warnings.registerException(new IllegalArgumentException("single-value function encountered multi-value")); - } - result.appendNull(); - continue position; - } - try { - result.appendBoolean(SpatialWithin.processGeoSourceAndSource(leftValueBlock.getBytesRef(leftValueBlock.getFirstValueIndex(p), leftValueScratch), rightValueBlock.getBytesRef(rightValueBlock.getFirstValueIndex(p), rightValueScratch))); - } catch (IllegalArgumentException | IOException e) { - warnings.registerException(e); - result.appendNull(); - } - } - return result.build(); - } - } - - public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector, - BytesRefVector rightValueVector) { - try(BooleanBlock.Builder result = driverContext.blockFactory().newBooleanBlockBuilder(positionCount)) { - BytesRef leftValueScratch = new BytesRef(); - BytesRef rightValueScratch = new BytesRef(); - position: for (int p = 0; p < positionCount; p++) { try { - result.appendBoolean(SpatialWithin.processGeoSourceAndSource(leftValueVector.getBytesRef(p, leftValueScratch), rightValueVector.getBytesRef(p, rightValueScratch))); + SpatialWithin.processGeoSourceAndSource(result, p, leftBlock, rightBlock); } catch (IllegalArgumentException | IOException e) { warnings.registerException(e); result.appendNull(); @@ -117,36 +76,36 @@ public BooleanBlock eval(int positionCount, BytesRefVector leftValueVector, @Override public String toString() { - return "SpatialWithinGeoSourceAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialWithinGeoSourceAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } @Override public void close() { - Releasables.closeExpectNoException(leftValue, rightValue); + Releasables.closeExpectNoException(left, right); } static class Factory implements EvalOperator.ExpressionEvaluator.Factory { private final Source source; - private final EvalOperator.ExpressionEvaluator.Factory leftValue; + private final EvalOperator.ExpressionEvaluator.Factory left; - private final EvalOperator.ExpressionEvaluator.Factory rightValue; + private final EvalOperator.ExpressionEvaluator.Factory right; - public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory leftValue, - EvalOperator.ExpressionEvaluator.Factory rightValue) { + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory left, + EvalOperator.ExpressionEvaluator.Factory right) { this.source = source; - this.leftValue = leftValue; - this.rightValue = rightValue; + this.left = left; + this.right = right; } @Override public SpatialWithinGeoSourceAndSourceEvaluator get(DriverContext context) { - return new SpatialWithinGeoSourceAndSourceEvaluator(source, leftValue.get(context), rightValue.get(context), context); + return new SpatialWithinGeoSourceAndSourceEvaluator(source, left.get(context), right.get(context), context); } @Override public String toString() { - return "SpatialWithinGeoSourceAndSourceEvaluator[" + "leftValue=" + leftValue + ", rightValue=" + rightValue + "]"; + return "SpatialWithinGeoSourceAndSourceEvaluator[" + "left=" + left + ", right=" + right + "]"; } } } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java index 475e63733022d..4cb3ced2c86a1 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java @@ -150,6 +150,11 @@ public enum Cap { */ SPATIAL_FUNCTIONS_FIX_CRSTYPE_FOLDING, + /** + * Enable spatial predicate functions to support multi-values. Done in #112063. + */ + SPATIAL_PREDICATES_SUPPORT_MULTIVALUES, + /** * Fix to GROK and DISSECT that allows extracting attributes with the same name as the input * https://github.com/elastic/elasticsearch/issues/110184 diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContains.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContains.java index 6788d13cf345e..24519ae28721f 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContains.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContains.java @@ -16,8 +16,10 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; +import org.elasticsearch.compute.data.BooleanBlock; +import org.elasticsearch.compute.data.BytesRefBlock; +import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.geometry.Geometry; -import org.elasticsearch.geometry.Point; import org.elasticsearch.index.mapper.GeoShapeIndexer; import org.elasticsearch.index.mapper.ShapeIndexer; import org.elasticsearch.lucene.spatial.CartesianShapeIndexer; @@ -77,6 +79,7 @@ public class SpatialContains extends SpatialRelatesFunction { * This applies to multi-component geometries (MultiPolygon, etc.) as well as polygons that cross the dateline. */ static final class SpatialRelationsContains extends SpatialRelations { + SpatialRelationsContains(SpatialCoordinateTypes spatialCoordinateType, CoordinateEncoder encoder, ShapeIndexer shapeIndexer) { super(ShapeField.QueryRelation.CONTAINS, spatialCoordinateType, encoder, shapeIndexer); } @@ -87,12 +90,23 @@ protected boolean geometryRelatesGeometry(BytesRef left, BytesRef right) throws return geometryRelatesGeometries(left, rightComponent2Ds); } + @Override + protected boolean geometryRelatesGeometries(MultiValuesCombiner left, MultiValuesCombiner right) throws IOException { + Component2D[] rightComponent2Ds = asLuceneComponent2Ds(crsType, right.combined()); + return geometryRelatesGeometries(left, rightComponent2Ds); + } + private boolean geometryRelatesGeometries(BytesRef left, Component2D[] rightComponent2Ds) throws IOException { Geometry leftGeom = fromBytesRef(left); GeometryDocValueReader leftDocValueReader = asGeometryDocValueReader(coordinateEncoder, shapeIndexer, leftGeom); return geometryRelatesGeometries(leftDocValueReader, rightComponent2Ds); } + private boolean geometryRelatesGeometries(MultiValuesCombiner left, Component2D[] rightComponent2Ds) throws IOException { + GeometryDocValueReader leftDocValueReader = asGeometryDocValueReader(coordinateEncoder, shapeIndexer, left.combined()); + return geometryRelatesGeometries(leftDocValueReader, rightComponent2Ds); + } + private boolean geometryRelatesGeometries(GeometryDocValueReader leftDocValueReader, Component2D[] rightComponent2Ds) throws IOException { for (Component2D rightComponent2D : rightComponent2Ds) { @@ -104,16 +118,24 @@ private boolean geometryRelatesGeometries(GeometryDocValueReader leftDocValueRea return true; } - private boolean pointRelatesGeometries(long encoded, Component2D[] rightComponent2Ds) { - // This code path exists for doc-values points, and we could consider re-using the point class to reduce garbage creation - Point point = spatialCoordinateType.longAsPoint(encoded); - for (Component2D rightComponent2D : rightComponent2Ds) { - // Every component of the right geometry must be contained within the left geometry for this to pass - if (pointRelatesGeometry(point, rightComponent2D) == false) { - return false; - } + private void processSourceAndConstant(BooleanBlock.Builder builder, int position, BytesRefBlock left, @Fixed Component2D[] right) + throws IOException { + if (left.getValueCount(position) < 1) { + builder.appendNull(); + } else { + MultiValuesBytesRef leftValues = new MultiValuesBytesRef(left, position); + builder.appendBoolean(geometryRelatesGeometries(leftValues, right)); + } + } + + private void processPointDocValuesAndConstant(BooleanBlock.Builder builder, int p, LongBlock left, @Fixed Component2D[] right) + throws IOException { + if (left.getValueCount(p) < 1) { + builder.appendNull(); + } else { + MultiValuesLong leftValues = new MultiValuesLong(left, p, spatialCoordinateType::longAsPoint); + builder.appendBoolean(geometryRelatesGeometries(leftValues, right)); } - return true; } } @@ -272,44 +294,49 @@ public SpatialRelatesFunction surrogate() { } @Evaluator(extraName = "GeoSourceAndConstant", warnExceptions = { IllegalArgumentException.class, IOException.class }) - static boolean processGeoSourceAndConstant(BytesRef leftValue, @Fixed Component2D[] rightValue) throws IOException { - return GEO.geometryRelatesGeometries(leftValue, rightValue); + static void processGeoSourceAndConstant(BooleanBlock.Builder results, int p, BytesRefBlock left, @Fixed Component2D[] right) + throws IOException { + GEO.processSourceAndConstant(results, p, left, right); } @Evaluator(extraName = "GeoSourceAndSource", warnExceptions = { IllegalArgumentException.class, IOException.class }) - static boolean processGeoSourceAndSource(BytesRef leftValue, BytesRef rightValue) throws IOException { - return GEO.geometryRelatesGeometry(leftValue, rightValue); + static void processGeoSourceAndSource(BooleanBlock.Builder builder, int p, BytesRefBlock left, BytesRefBlock right) throws IOException { + GEO.processSourceAndSource(builder, p, left, right); } - @Evaluator(extraName = "GeoPointDocValuesAndConstant", warnExceptions = { IllegalArgumentException.class }) - static boolean processGeoPointDocValuesAndConstant(long leftValue, @Fixed Component2D[] rightValue) { - return GEO.pointRelatesGeometries(leftValue, rightValue); + @Evaluator(extraName = "GeoPointDocValuesAndConstant", warnExceptions = { IllegalArgumentException.class, IOException.class }) + static void processGeoPointDocValuesAndConstant(BooleanBlock.Builder builder, int p, LongBlock left, @Fixed Component2D[] right) + throws IOException { + GEO.processPointDocValuesAndConstant(builder, p, left, right); } - @Evaluator(extraName = "GeoPointDocValuesAndSource", warnExceptions = { IllegalArgumentException.class }) - static boolean processGeoPointDocValuesAndSource(long leftValue, BytesRef rightValue) { - Geometry geometry = SpatialCoordinateTypes.UNSPECIFIED.wkbToGeometry(rightValue); - return GEO.pointRelatesGeometry(leftValue, geometry); + @Evaluator(extraName = "GeoPointDocValuesAndSource", warnExceptions = { IllegalArgumentException.class, IOException.class }) + static void processGeoPointDocValuesAndSource(BooleanBlock.Builder builder, int p, LongBlock left, BytesRefBlock right) + throws IOException { + GEO.processPointDocValuesAndSource(builder, p, left, right); } @Evaluator(extraName = "CartesianSourceAndConstant", warnExceptions = { IllegalArgumentException.class, IOException.class }) - static boolean processCartesianSourceAndConstant(BytesRef leftValue, @Fixed Component2D[] rightValue) throws IOException { - return CARTESIAN.geometryRelatesGeometries(leftValue, rightValue); + static void processCartesianSourceAndConstant(BooleanBlock.Builder builder, int p, BytesRefBlock left, @Fixed Component2D[] right) + throws IOException { + CARTESIAN.processSourceAndConstant(builder, p, left, right); } @Evaluator(extraName = "CartesianSourceAndSource", warnExceptions = { IllegalArgumentException.class, IOException.class }) - static boolean processCartesianSourceAndSource(BytesRef leftValue, BytesRef rightValue) throws IOException { - return CARTESIAN.geometryRelatesGeometry(leftValue, rightValue); + static void processCartesianSourceAndSource(BooleanBlock.Builder builder, int p, BytesRefBlock left, BytesRefBlock right) + throws IOException { + CARTESIAN.processSourceAndSource(builder, p, left, right); } - @Evaluator(extraName = "CartesianPointDocValuesAndConstant", warnExceptions = { IllegalArgumentException.class }) - static boolean processCartesianPointDocValuesAndConstant(long leftValue, @Fixed Component2D[] rightValue) { - return CARTESIAN.pointRelatesGeometries(leftValue, rightValue); + @Evaluator(extraName = "CartesianPointDocValuesAndConstant", warnExceptions = { IllegalArgumentException.class, IOException.class }) + static void processCartesianPointDocValuesAndConstant(BooleanBlock.Builder builder, int p, LongBlock left, @Fixed Component2D[] right) + throws IOException { + CARTESIAN.processPointDocValuesAndConstant(builder, p, left, right); } - @Evaluator(extraName = "CartesianPointDocValuesAndSource") - static boolean processCartesianPointDocValuesAndSource(long leftValue, BytesRef rightValue) { - Geometry geometry = SpatialCoordinateTypes.UNSPECIFIED.wkbToGeometry(rightValue); - return CARTESIAN.pointRelatesGeometry(leftValue, geometry); + @Evaluator(extraName = "CartesianPointDocValuesAndSource", warnExceptions = { IllegalArgumentException.class, IOException.class }) + static void processCartesianPointDocValuesAndSource(BooleanBlock.Builder builder, int p, LongBlock left, BytesRefBlock right) + throws IOException { + CARTESIAN.processPointDocValuesAndSource(builder, p, left, right); } } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjoint.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjoint.java index eac50f84bd12d..47d19ebae884b 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjoint.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjoint.java @@ -9,14 +9,15 @@ import org.apache.lucene.document.ShapeField; import org.apache.lucene.geo.Component2D; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.geo.Orientation; import org.elasticsearch.common.geo.ShapeRelation; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; -import org.elasticsearch.geometry.Geometry; +import org.elasticsearch.compute.data.BooleanBlock; +import org.elasticsearch.compute.data.BytesRefBlock; +import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.index.mapper.GeoShapeIndexer; import org.elasticsearch.lucene.spatial.CartesianShapeIndexer; import org.elasticsearch.lucene.spatial.CoordinateEncoder; @@ -214,44 +215,49 @@ public Object fold() { } @Evaluator(extraName = "GeoSourceAndConstant", warnExceptions = { IllegalArgumentException.class, IOException.class }) - static boolean processGeoSourceAndConstant(BytesRef leftValue, @Fixed Component2D rightValue) throws IOException { - return GEO.geometryRelatesGeometry(leftValue, rightValue); + static void processGeoSourceAndConstant(BooleanBlock.Builder results, int p, BytesRefBlock left, @Fixed Component2D right) + throws IOException { + GEO.processSourceAndConstant(results, p, left, right); } @Evaluator(extraName = "GeoSourceAndSource", warnExceptions = { IllegalArgumentException.class, IOException.class }) - static boolean processGeoSourceAndSource(BytesRef leftValue, BytesRef rightValue) throws IOException { - return GEO.geometryRelatesGeometry(leftValue, rightValue); + static void processGeoSourceAndSource(BooleanBlock.Builder builder, int p, BytesRefBlock left, BytesRefBlock right) throws IOException { + GEO.processSourceAndSource(builder, p, left, right); } - @Evaluator(extraName = "GeoPointDocValuesAndConstant", warnExceptions = { IllegalArgumentException.class }) - static boolean processGeoPointDocValuesAndConstant(long leftValue, @Fixed Component2D rightValue) { - return GEO.pointRelatesGeometry(leftValue, rightValue); + @Evaluator(extraName = "GeoPointDocValuesAndConstant", warnExceptions = { IllegalArgumentException.class, IOException.class }) + static void processGeoPointDocValuesAndConstant(BooleanBlock.Builder builder, int p, LongBlock left, @Fixed Component2D right) + throws IOException { + GEO.processPointDocValuesAndConstant(builder, p, left, right); } - @Evaluator(extraName = "GeoPointDocValuesAndSource", warnExceptions = { IllegalArgumentException.class }) - static boolean processGeoPointDocValuesAndSource(long leftValue, BytesRef rightValue) { - Geometry geometry = SpatialCoordinateTypes.UNSPECIFIED.wkbToGeometry(rightValue); - return GEO.pointRelatesGeometry(leftValue, geometry); + @Evaluator(extraName = "GeoPointDocValuesAndSource", warnExceptions = { IllegalArgumentException.class, IOException.class }) + static void processGeoPointDocValuesAndSource(BooleanBlock.Builder builder, int p, LongBlock left, BytesRefBlock right) + throws IOException { + GEO.processPointDocValuesAndSource(builder, p, left, right); } @Evaluator(extraName = "CartesianSourceAndConstant", warnExceptions = { IllegalArgumentException.class, IOException.class }) - static boolean processCartesianSourceAndConstant(BytesRef leftValue, @Fixed Component2D rightValue) throws IOException { - return CARTESIAN.geometryRelatesGeometry(leftValue, rightValue); + static void processCartesianSourceAndConstant(BooleanBlock.Builder builder, int p, BytesRefBlock left, @Fixed Component2D right) + throws IOException { + CARTESIAN.processSourceAndConstant(builder, p, left, right); } @Evaluator(extraName = "CartesianSourceAndSource", warnExceptions = { IllegalArgumentException.class, IOException.class }) - static boolean processCartesianSourceAndSource(BytesRef leftValue, BytesRef rightValue) throws IOException { - return CARTESIAN.geometryRelatesGeometry(leftValue, rightValue); + static void processCartesianSourceAndSource(BooleanBlock.Builder builder, int p, BytesRefBlock left, BytesRefBlock right) + throws IOException { + CARTESIAN.processSourceAndSource(builder, p, left, right); } - @Evaluator(extraName = "CartesianPointDocValuesAndConstant", warnExceptions = { IllegalArgumentException.class }) - static boolean processCartesianPointDocValuesAndConstant(long leftValue, @Fixed Component2D rightValue) { - return CARTESIAN.pointRelatesGeometry(leftValue, rightValue); + @Evaluator(extraName = "CartesianPointDocValuesAndConstant", warnExceptions = { IllegalArgumentException.class, IOException.class }) + static void processCartesianPointDocValuesAndConstant(BooleanBlock.Builder builder, int p, LongBlock left, @Fixed Component2D right) + throws IOException { + CARTESIAN.processPointDocValuesAndConstant(builder, p, left, right); } - @Evaluator(extraName = "CartesianPointDocValuesAndSource") - static boolean processCartesianPointDocValuesAndSource(long leftValue, BytesRef rightValue) { - Geometry geometry = SpatialCoordinateTypes.UNSPECIFIED.wkbToGeometry(rightValue); - return CARTESIAN.pointRelatesGeometry(leftValue, geometry); + @Evaluator(extraName = "CartesianPointDocValuesAndSource", warnExceptions = { IllegalArgumentException.class, IOException.class }) + static void processCartesianPointDocValuesAndSource(BooleanBlock.Builder builder, int p, LongBlock left, BytesRefBlock right) + throws IOException { + CARTESIAN.processPointDocValuesAndSource(builder, p, left, right); } } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersects.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersects.java index 886551d1f3154..8e287baeaa9b8 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersects.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersects.java @@ -9,14 +9,15 @@ import org.apache.lucene.document.ShapeField; import org.apache.lucene.geo.Component2D; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.geo.Orientation; import org.elasticsearch.common.geo.ShapeRelation; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; -import org.elasticsearch.geometry.Geometry; +import org.elasticsearch.compute.data.BooleanBlock; +import org.elasticsearch.compute.data.BytesRefBlock; +import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.index.mapper.GeoShapeIndexer; import org.elasticsearch.lucene.spatial.CartesianShapeIndexer; import org.elasticsearch.lucene.spatial.CoordinateEncoder; @@ -212,44 +213,49 @@ public Object fold() { } @Evaluator(extraName = "GeoSourceAndConstant", warnExceptions = { IllegalArgumentException.class, IOException.class }) - static boolean processGeoSourceAndConstant(BytesRef leftValue, @Fixed Component2D rightValue) throws IOException { - return GEO.geometryRelatesGeometry(leftValue, rightValue); + static void processGeoSourceAndConstant(BooleanBlock.Builder results, int p, BytesRefBlock left, @Fixed Component2D right) + throws IOException { + GEO.processSourceAndConstant(results, p, left, right); } @Evaluator(extraName = "GeoSourceAndSource", warnExceptions = { IllegalArgumentException.class, IOException.class }) - static boolean processGeoSourceAndSource(BytesRef leftValue, BytesRef rightValue) throws IOException { - return GEO.geometryRelatesGeometry(leftValue, rightValue); + static void processGeoSourceAndSource(BooleanBlock.Builder builder, int p, BytesRefBlock left, BytesRefBlock right) throws IOException { + GEO.processSourceAndSource(builder, p, left, right); } - @Evaluator(extraName = "GeoPointDocValuesAndConstant", warnExceptions = { IllegalArgumentException.class }) - static boolean processGeoPointDocValuesAndConstant(long leftValue, @Fixed Component2D rightValue) { - return GEO.pointRelatesGeometry(leftValue, rightValue); + @Evaluator(extraName = "GeoPointDocValuesAndConstant", warnExceptions = { IllegalArgumentException.class, IOException.class }) + static void processGeoPointDocValuesAndConstant(BooleanBlock.Builder builder, int p, LongBlock left, @Fixed Component2D right) + throws IOException { + GEO.processPointDocValuesAndConstant(builder, p, left, right); } - @Evaluator(extraName = "GeoPointDocValuesAndSource", warnExceptions = { IllegalArgumentException.class }) - static boolean processGeoPointDocValuesAndSource(long leftValue, BytesRef rightValue) { - Geometry geometry = SpatialCoordinateTypes.UNSPECIFIED.wkbToGeometry(rightValue); - return GEO.pointRelatesGeometry(leftValue, geometry); + @Evaluator(extraName = "GeoPointDocValuesAndSource", warnExceptions = { IllegalArgumentException.class, IOException.class }) + static void processGeoPointDocValuesAndSource(BooleanBlock.Builder builder, int p, LongBlock left, BytesRefBlock right) + throws IOException { + GEO.processPointDocValuesAndSource(builder, p, left, right); } @Evaluator(extraName = "CartesianSourceAndConstant", warnExceptions = { IllegalArgumentException.class, IOException.class }) - static boolean processCartesianSourceAndConstant(BytesRef leftValue, @Fixed Component2D rightValue) throws IOException { - return CARTESIAN.geometryRelatesGeometry(leftValue, rightValue); + static void processCartesianSourceAndConstant(BooleanBlock.Builder builder, int p, BytesRefBlock left, @Fixed Component2D right) + throws IOException { + CARTESIAN.processSourceAndConstant(builder, p, left, right); } @Evaluator(extraName = "CartesianSourceAndSource", warnExceptions = { IllegalArgumentException.class, IOException.class }) - static boolean processCartesianSourceAndSource(BytesRef leftValue, BytesRef rightValue) throws IOException { - return CARTESIAN.geometryRelatesGeometry(leftValue, rightValue); + static void processCartesianSourceAndSource(BooleanBlock.Builder builder, int p, BytesRefBlock left, BytesRefBlock right) + throws IOException { + CARTESIAN.processSourceAndSource(builder, p, left, right); } - @Evaluator(extraName = "CartesianPointDocValuesAndConstant", warnExceptions = { IllegalArgumentException.class }) - static boolean processCartesianPointDocValuesAndConstant(long leftValue, @Fixed Component2D rightValue) { - return CARTESIAN.pointRelatesGeometry(leftValue, rightValue); + @Evaluator(extraName = "CartesianPointDocValuesAndConstant", warnExceptions = { IllegalArgumentException.class, IOException.class }) + static void processCartesianPointDocValuesAndConstant(BooleanBlock.Builder builder, int p, LongBlock left, @Fixed Component2D right) + throws IOException { + CARTESIAN.processPointDocValuesAndConstant(builder, p, left, right); } - @Evaluator(extraName = "CartesianPointDocValuesAndSource") - static boolean processCartesianPointDocValuesAndSource(long leftValue, BytesRef rightValue) { - Geometry geometry = SpatialCoordinateTypes.UNSPECIFIED.wkbToGeometry(rightValue); - return CARTESIAN.pointRelatesGeometry(leftValue, geometry); + @Evaluator(extraName = "CartesianPointDocValuesAndSource", warnExceptions = { IllegalArgumentException.class, IOException.class }) + static void processCartesianPointDocValuesAndSource(BooleanBlock.Builder builder, int p, LongBlock left, BytesRefBlock right) + throws IOException { + CARTESIAN.processPointDocValuesAndSource(builder, p, left, right); } } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialRelatesFunction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialRelatesFunction.java index 36e98984d2303..a73f8d08c6397 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialRelatesFunction.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialRelatesFunction.java @@ -12,8 +12,14 @@ import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.geo.ShapeRelation; import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.compute.ann.Fixed; +import org.elasticsearch.compute.data.BooleanBlock; +import org.elasticsearch.compute.data.BytesRefBlock; +import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.geometry.Geometry; +import org.elasticsearch.geometry.GeometryCollection; +import org.elasticsearch.geometry.MultiPoint; import org.elasticsearch.geometry.Point; import org.elasticsearch.index.mapper.ShapeIndexer; import org.elasticsearch.lucene.spatial.Component2DVisitor; @@ -27,14 +33,14 @@ import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; -import static org.apache.lucene.document.ShapeField.QueryRelation.CONTAINS; -import static org.apache.lucene.document.ShapeField.QueryRelation.DISJOINT; import static org.elasticsearch.xpack.esql.expression.function.scalar.spatial.SpatialRelatesUtils.asGeometryDocValueReader; import static org.elasticsearch.xpack.esql.expression.function.scalar.spatial.SpatialRelatesUtils.asLuceneComponent2D; @@ -153,13 +159,8 @@ protected Boolean compare(BytesRef left, BytesRef right) throws IOException { protected boolean geometryRelatesGeometry(BytesRef left, BytesRef right) throws IOException { Component2D rightComponent2D = asLuceneComponent2D(crsType, fromBytesRef(right)); - return geometryRelatesGeometry(left, rightComponent2D); - } - - protected boolean geometryRelatesGeometry(BytesRef left, Component2D rightComponent2D) throws IOException { - Geometry leftGeom = fromBytesRef(left); // We already have a Component2D for the right geometry, so we need to convert the left geometry to a doc-values byte array - return geometryRelatesGeometry(asGeometryDocValueReader(coordinateEncoder, shapeIndexer, leftGeom), rightComponent2D); + return geometryRelatesGeometry(asGeometryDocValueReader(coordinateEncoder, shapeIndexer, fromBytesRef(left)), rightComponent2D); } protected boolean geometryRelatesGeometry(GeometryDocValueReader reader, Component2D rightComponent2D) throws IOException { @@ -168,24 +169,154 @@ protected boolean geometryRelatesGeometry(GeometryDocValueReader reader, Compone return visitor.matches(); } - protected boolean pointRelatesGeometry(long encoded, Geometry geometry) { - Component2D component2D = asLuceneComponent2D(crsType, geometry); - return pointRelatesGeometry(encoded, component2D); + protected boolean geometryRelatesGeometries(MultiValuesCombiner left, MultiValuesCombiner right) throws IOException { + Component2D rightComponent2D = asLuceneComponent2D(crsType, right.combined()); + return geometryRelatesGeometry(left, rightComponent2D); + } + + private boolean geometryRelatesGeometry(MultiValuesCombiner left, Component2D rightComponent2D) throws IOException { + GeometryDocValueReader leftDocValueReader = asGeometryDocValueReader(coordinateEncoder, shapeIndexer, left.combined()); + return geometryRelatesGeometry(leftDocValueReader, rightComponent2D); + } + + protected void processSourceAndConstant(BooleanBlock.Builder builder, int position, BytesRefBlock left, @Fixed Component2D right) + throws IOException { + if (left.getValueCount(position) < 1) { + builder.appendNull(); + } else { + MultiValuesBytesRef leftValues = new MultiValuesBytesRef(left, position); + builder.appendBoolean(geometryRelatesGeometry(leftValues, right)); + } + } + + protected void processSourceAndSource(BooleanBlock.Builder builder, int position, BytesRefBlock left, BytesRefBlock right) + throws IOException { + if (left.getValueCount(position) < 1 || right.getValueCount(position) < 1) { + builder.appendNull(); + } else { + MultiValuesBytesRef leftValues = new MultiValuesBytesRef(left, position); + MultiValuesBytesRef rightValues = new MultiValuesBytesRef(right, position); + builder.appendBoolean(geometryRelatesGeometries(leftValues, rightValues)); + } } - protected boolean pointRelatesGeometry(long encoded, Component2D component2D) { - // This code path exists for doc-values points, and we could consider re-using the point class to reduce garbage creation - Point point = spatialCoordinateType.longAsPoint(encoded); - return pointRelatesGeometry(point, component2D); + protected void processPointDocValuesAndConstant( + BooleanBlock.Builder builder, + int position, + LongBlock leftValue, + @Fixed Component2D rightValue + ) throws IOException { + if (leftValue.getValueCount(position) < 1) { + builder.appendNull(); + } else { + MultiValuesLong leftValues = new MultiValuesLong(leftValue, position, spatialCoordinateType::longAsPoint); + builder.appendBoolean(geometryRelatesGeometry(leftValues, rightValue)); + } } - protected boolean pointRelatesGeometry(Point point, Component2D component2D) { - if (queryRelation == CONTAINS) { - return component2D.withinPoint(point.getX(), point.getY()) == Component2D.WithinRelation.CANDIDATE; + protected void processPointDocValuesAndSource( + BooleanBlock.Builder builder, + int position, + LongBlock leftValue, + BytesRefBlock rightValue + ) throws IOException { + if (leftValue.getValueCount(position) < 1 || rightValue.getValueCount(position) < 1) { + builder.appendNull(); } else { - boolean contains = component2D.contains(point.getX(), point.getY()); - return queryRelation == DISJOINT ? contains == false : contains; + MultiValuesLong leftValues = new MultiValuesLong(leftValue, position, spatialCoordinateType::longAsPoint); + MultiValuesBytesRef rightValues = new MultiValuesBytesRef(rightValue, position); + builder.appendBoolean(geometryRelatesGeometries(leftValues, rightValues)); + } + } + } + + /** + * When dealing with ST_CONTAINS and ST_WITHIN we need to pre-combine the field geometries for multi-values in order + * to perform the relationship check. This means instead of relying on the generated evaluators to iterate over all + * values in a multi-value field, the entire block is passed into the spatial function, and we combine the values into + * a geometry collection or multipoint. + */ + protected interface MultiValuesCombiner { + Geometry combined(); + } + + /** + * Values read from source will be encoded as WKB in BytesRefBlock. The block contains multiple rows, and within + * each row multiple values, so we need to efficiently iterate over only the values required for the requested row. + * This class works for point and shape fields, because both are extracted into the same block encoding. + * However, we do detect if all values in the field are actually points and create a MultiPoint instead of a GeometryCollection. + */ + protected static class MultiValuesBytesRef implements MultiValuesCombiner { + private final BytesRefBlock valueBlock; + private final int valueCount; + private final BytesRef scratch = new BytesRef(); + private final int firstValue; + + MultiValuesBytesRef(BytesRefBlock valueBlock, int position) { + this.valueBlock = valueBlock; + this.firstValue = valueBlock.getFirstValueIndex(position); + this.valueCount = valueBlock.getValueCount(position); + } + + @Override + public Geometry combined() { + int valueIndex = firstValue; + boolean allPoints = true; + if (valueCount == 1) { + return fromBytesRef(valueBlock.getBytesRef(valueIndex, scratch)); + } + List geometries = new ArrayList<>(); + while (valueIndex < firstValue + valueCount) { + geometries.add(fromBytesRef(valueBlock.getBytesRef(valueIndex++, scratch))); + if (geometries.getLast() instanceof Point == false) { + allPoints = false; + } + } + return allPoints ? new MultiPoint(asPointList(geometries)) : new GeometryCollection<>(geometries); + } + + private List asPointList(List geometries) { + List points = new ArrayList<>(geometries.size()); + for (Geometry geometry : geometries) { + points.add((Point) geometry); + } + return points; + } + + protected Geometry fromBytesRef(BytesRef bytesRef) { + return SpatialCoordinateTypes.UNSPECIFIED.wkbToGeometry(bytesRef); + } + } + + /** + * Point values read from doc-values will be encoded as in LogBlock. The block contains multiple rows, and within + * each row multiple values, so we need to efficiently iterate over only the values required for the requested row. + * Since the encoding differs for GEO and CARTESIAN, we need the decoder function to be passed in the constructor. + */ + protected static class MultiValuesLong implements MultiValuesCombiner { + private final LongBlock valueBlock; + private final Function decoder; + private final int valueCount; + private final int firstValue; + + MultiValuesLong(LongBlock valueBlock, int position, Function decoder) { + this.valueBlock = valueBlock; + this.decoder = decoder; + this.firstValue = valueBlock.getFirstValueIndex(position); + this.valueCount = valueBlock.getValueCount(position); + } + + @Override + public Geometry combined() { + int valueIndex = firstValue; + if (valueCount == 1) { + return decoder.apply(valueBlock.getLong(valueIndex)); + } + List points = new ArrayList<>(); + while (valueIndex < firstValue + valueCount) { + points.add(decoder.apply(valueBlock.getLong(valueIndex++))); } + return new MultiPoint(points); } } } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialRelatesUtils.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialRelatesUtils.java index 64f991dd1a08f..6997eb7fa9528 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialRelatesUtils.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialRelatesUtils.java @@ -15,6 +15,7 @@ import org.elasticsearch.common.geo.Orientation; import org.elasticsearch.geometry.Circle; import org.elasticsearch.geometry.Geometry; +import org.elasticsearch.geometry.GeometryCollection; import org.elasticsearch.geometry.ShapeType; import org.elasticsearch.index.mapper.GeoShapeIndexer; import org.elasticsearch.index.mapper.ShapeIndexer; @@ -24,9 +25,12 @@ import org.elasticsearch.lucene.spatial.GeometryDocValueReader; import org.elasticsearch.lucene.spatial.GeometryDocValueWriter; import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import static org.elasticsearch.xpack.esql.core.expression.Foldables.valueOf; @@ -111,13 +115,23 @@ static GeometryDocValueReader asGeometryDocValueReader(CoordinateEncoder encoder * we do lucene-pushdown of spatial functions. */ public static Geometry makeGeometryFromLiteral(Expression expr) { - Object value = valueOf(expr); + return makeGeometryFromLiteralValue(valueOf(expr), expr.dataType()); + } + private static Geometry makeGeometryFromLiteralValue(Object value, DataType dataType) { if (value instanceof BytesRef bytesRef) { + // Single value expression return SpatialCoordinateTypes.UNSPECIFIED.wkbToGeometry(bytesRef); + } else if (value instanceof List bytesRefList) { + // Multi-value expression + ArrayList geometries = new ArrayList<>(); + for (Object obj : bytesRefList) { + geometries.add(makeGeometryFromLiteralValue(obj, dataType)); + } + return new GeometryCollection<>(geometries); } else { throw new IllegalArgumentException( - "Unsupported combination of literal [" + value.getClass().getSimpleName() + "] of type [" + expr.dataType() + "]" + "Unsupported combination of literal [" + value.getClass().getSimpleName() + "] of type [" + dataType + "]" ); } } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithin.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithin.java index 0b210f07a02f4..84ea5b86f1d40 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithin.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithin.java @@ -9,14 +9,15 @@ import org.apache.lucene.document.ShapeField; import org.apache.lucene.geo.Component2D; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.geo.Orientation; import org.elasticsearch.common.geo.ShapeRelation; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; -import org.elasticsearch.geometry.Geometry; +import org.elasticsearch.compute.data.BooleanBlock; +import org.elasticsearch.compute.data.BytesRefBlock; +import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.index.mapper.GeoShapeIndexer; import org.elasticsearch.lucene.spatial.CartesianShapeIndexer; import org.elasticsearch.lucene.spatial.CoordinateEncoder; @@ -224,44 +225,49 @@ public SpatialRelatesFunction surrogate() { } @Evaluator(extraName = "GeoSourceAndConstant", warnExceptions = { IllegalArgumentException.class, IOException.class }) - static boolean processGeoSourceAndConstant(BytesRef leftValue, @Fixed Component2D rightValue) throws IOException { - return GEO.geometryRelatesGeometry(leftValue, rightValue); + static void processGeoSourceAndConstant(BooleanBlock.Builder results, int p, BytesRefBlock left, @Fixed Component2D right) + throws IOException { + GEO.processSourceAndConstant(results, p, left, right); } @Evaluator(extraName = "GeoSourceAndSource", warnExceptions = { IllegalArgumentException.class, IOException.class }) - static boolean processGeoSourceAndSource(BytesRef leftValue, BytesRef rightValue) throws IOException { - return GEO.geometryRelatesGeometry(leftValue, rightValue); + static void processGeoSourceAndSource(BooleanBlock.Builder builder, int p, BytesRefBlock left, BytesRefBlock right) throws IOException { + GEO.processSourceAndSource(builder, p, left, right); } - @Evaluator(extraName = "GeoPointDocValuesAndConstant", warnExceptions = { IllegalArgumentException.class }) - static boolean processGeoPointDocValuesAndConstant(long leftValue, @Fixed Component2D rightValue) { - return GEO.pointRelatesGeometry(leftValue, rightValue); + @Evaluator(extraName = "GeoPointDocValuesAndConstant", warnExceptions = { IllegalArgumentException.class, IOException.class }) + static void processGeoPointDocValuesAndConstant(BooleanBlock.Builder builder, int p, LongBlock left, @Fixed Component2D right) + throws IOException { + GEO.processPointDocValuesAndConstant(builder, p, left, right); } - @Evaluator(extraName = "GeoPointDocValuesAndSource", warnExceptions = { IllegalArgumentException.class }) - static boolean processGeoPointDocValuesAndSource(long leftValue, BytesRef rightValue) { - Geometry geometry = SpatialCoordinateTypes.UNSPECIFIED.wkbToGeometry(rightValue); - return GEO.pointRelatesGeometry(leftValue, geometry); + @Evaluator(extraName = "GeoPointDocValuesAndSource", warnExceptions = { IllegalArgumentException.class, IOException.class }) + static void processGeoPointDocValuesAndSource(BooleanBlock.Builder builder, int p, LongBlock left, BytesRefBlock right) + throws IOException { + GEO.processPointDocValuesAndSource(builder, p, left, right); } @Evaluator(extraName = "CartesianSourceAndConstant", warnExceptions = { IllegalArgumentException.class, IOException.class }) - static boolean processCartesianSourceAndConstant(BytesRef leftValue, @Fixed Component2D rightValue) throws IOException { - return CARTESIAN.geometryRelatesGeometry(leftValue, rightValue); + static void processCartesianSourceAndConstant(BooleanBlock.Builder builder, int p, BytesRefBlock left, @Fixed Component2D right) + throws IOException { + CARTESIAN.processSourceAndConstant(builder, p, left, right); } @Evaluator(extraName = "CartesianSourceAndSource", warnExceptions = { IllegalArgumentException.class, IOException.class }) - static boolean processCartesianSourceAndSource(BytesRef leftValue, BytesRef rightValue) throws IOException { - return CARTESIAN.geometryRelatesGeometry(leftValue, rightValue); + static void processCartesianSourceAndSource(BooleanBlock.Builder builder, int p, BytesRefBlock left, BytesRefBlock right) + throws IOException { + CARTESIAN.processSourceAndSource(builder, p, left, right); } - @Evaluator(extraName = "CartesianPointDocValuesAndConstant", warnExceptions = { IllegalArgumentException.class }) - static boolean processCartesianPointDocValuesAndConstant(long leftValue, @Fixed Component2D rightValue) { - return CARTESIAN.pointRelatesGeometry(leftValue, rightValue); + @Evaluator(extraName = "CartesianPointDocValuesAndConstant", warnExceptions = { IllegalArgumentException.class, IOException.class }) + static void processCartesianPointDocValuesAndConstant(BooleanBlock.Builder builder, int p, LongBlock left, @Fixed Component2D right) + throws IOException { + CARTESIAN.processPointDocValuesAndConstant(builder, p, left, right); } - @Evaluator(extraName = "CartesianPointDocValuesAndSource") - static boolean processCartesianPointDocValuesAndSource(long leftValue, BytesRef rightValue) { - Geometry geometry = SpatialCoordinateTypes.UNSPECIFIED.wkbToGeometry(rightValue); - return CARTESIAN.pointRelatesGeometry(leftValue, geometry); + @Evaluator(extraName = "CartesianPointDocValuesAndSource", warnExceptions = { IllegalArgumentException.class, IOException.class }) + static void processCartesianPointDocValuesAndSource(BooleanBlock.Builder builder, int p, LongBlock left, BytesRefBlock right) + throws IOException { + CARTESIAN.processPointDocValuesAndSource(builder, p, left, right); } } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/SpatialDocValuesExtraction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/SpatialDocValuesExtraction.java index 42dbc5f1a6fd5..ea6541326458e 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/SpatialDocValuesExtraction.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/SpatialDocValuesExtraction.java @@ -115,6 +115,9 @@ && allowedForDocValues(fieldAttribute, agg, foundAttributes)) { * This is because comparing two doc-values fields is not supported in the current implementation. */ private boolean allowedForDocValues(FieldAttribute fieldAttribute, AggregateExec agg, Set foundAttributes) { + if (fieldAttribute.field().isAggregatable() == false) { + return false; + } var candidateDocValuesAttributes = new HashSet<>(foundAttributes); candidateDocValuesAttributes.add(fieldAttribute); var spatialRelatesAttributes = new HashSet(); diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/BinarySpatialFunctionTestCase.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/BinarySpatialFunctionTestCase.java index 0729d4854f65f..6794de80f7433 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/BinarySpatialFunctionTestCase.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/BinarySpatialFunctionTestCase.java @@ -267,14 +267,17 @@ private static DataType pickSpatialType(DataType leftType, DataType rightType) { private static Matcher spatialEvaluatorString(DataType leftType, DataType rightType) { String crsType = isSpatialGeo(pickSpatialType(leftType, rightType)) ? "Geo" : "Cartesian"; - String channels = channelsText("leftValue", "rightValue"); + String paramSuffix = paramSuffix(); + String channels = channelsText("left" + paramSuffix, "right" + paramSuffix); return equalTo(getFunctionClassName() + crsType + "SourceAndSourceEvaluator[" + channels + "]"); } - private static Matcher spatialEvaluatorString(DataType leftType, DataType rightType, DataType argType) { - String crsType = isSpatialGeo(pickSpatialType(leftType, rightType)) ? "Geo" : "Cartesian"; - String channels = channelsText("leftValue", "rightValue", "argValue"); - return equalTo(getFunctionClassName() + crsType + "FieldAndFieldAndFieldEvaluator[" + channels + "]"); + private static String paramSuffix() { + try { + return getSpatialRelatesFunctionClass().getSimpleName().contains("Distance") ? "Value" : ""; + } catch (ClassNotFoundException e) { + return ""; + } } private static String channelsText(String... args) { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java index 96e8cd68ae9d2..be7bf7f53734d 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java @@ -109,6 +109,7 @@ import org.elasticsearch.xpack.esql.plan.physical.ProjectExec; import org.elasticsearch.xpack.esql.plan.physical.RowExec; import org.elasticsearch.xpack.esql.plan.physical.TopNExec; +import org.elasticsearch.xpack.esql.plan.physical.UnaryExec; import org.elasticsearch.xpack.esql.planner.Mapper; import org.elasticsearch.xpack.esql.planner.PlannerUtils; import org.elasticsearch.xpack.esql.plugin.QueryPragmas; @@ -180,6 +181,7 @@ public class PhysicalPlanOptimizerTests extends ESTestCase { private TestDataSource testData; private int allFieldRowSize; // TODO: Move this into testDataSource so tests that load other indexes can also assert on this private TestDataSource airports; + private TestDataSource airportsNoDocValues; private TestDataSource airportsWeb; private TestDataSource countriesBbox; private TestDataSource countriesBboxWeb; @@ -228,6 +230,12 @@ public void init() { // Some tests use data from the airports and countries indexes, so we load that here, and use it in the plan(q, airports) function. this.airports = makeTestDataSource("airports", "mapping-airports.json", functionRegistry, enrichResolution); + this.airportsNoDocValues = makeTestDataSource( + "airports-no-doc-values", + "mapping-airports-no-doc-values.json", + functionRegistry, + enrichResolution + ); this.airportsWeb = makeTestDataSource("airports_web", "mapping-airports_web.json", functionRegistry, enrichResolution); this.countriesBbox = makeTestDataSource("countriesBbox", "mapping-countries_bbox.json", functionRegistry, enrichResolution); this.countriesBboxWeb = makeTestDataSource( @@ -2376,6 +2384,7 @@ public boolean exists(String field) { /** * Expects * intermediate plan + * * LimitExec[1000[INTEGER]] * \_AggregateExec[[],[COUNT(emp_no{f}#6) AS c],FINAL,null] * \_ExchangeExec[[count{r}#16, seen{r}#17],true] @@ -2383,12 +2392,14 @@ public boolean exists(String field) { * Aggregate[[],[COUNT(emp_no{f}#6) AS c]] * \_Filter[emp_no{f}#6 > 10[INTEGER]] * \_EsRelation[test][_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, ge..]]] - * + * * and final plan is + * * LimitExec[1000[INTEGER]] * \_AggregateExec[[],[COUNT(emp_no{f}#6) AS c],FINAL,8] * \_ExchangeExec[[count{r}#16, seen{r}#17],true] * \_LocalSourceExec[[count{r}#16, seen{r}#17],[LongVectorBlock[vector=ConstantLongVector[positions=1, value=0]]]] + * */ public void testPartialAggFoldingOutput() { var plan = physicalPlan(""" @@ -2411,7 +2422,7 @@ public void testPartialAggFoldingOutput() { /** * Checks that when the folding happens on the coordinator, the intermediate agg state * are not used anymore. - * + * * Expects * LimitExec[10000[INTEGER]] * \_AggregateExec[[],[COUNT(emp_no{f}#5) AS c],FINAL,8] @@ -2421,6 +2432,7 @@ public void testPartialAggFoldingOutput() { * \_ProjectExec[[emp_no{r}#5]] * \_EvalExec[[null[INTEGER] AS emp_no]] * \_EsQueryExec[test], query[][_doc{f}#26], limit[10], sort[] estimatedRowSize[8] + * */ public void testGlobalAggFoldingOutput() { var plan = physicalPlan(""" @@ -2444,7 +2456,7 @@ public void testGlobalAggFoldingOutput() { /** * Checks the folded aggregation preserves the intermediate output. - * + * * Expects * ProjectExec[[a{r}#5]] * \_EvalExec[[__a_SUM@734e2841{r}#16 / __a_COUNT@12536eab{r}#17 AS a]] @@ -2456,6 +2468,7 @@ public void testGlobalAggFoldingOutput() { * 0]], BooleanVectorBlock[vector=ConstantBooleanVector[positions=1, value=true]], * LongVectorBlock[vector=ConstantLongVector[positions=1, value=0]], * BooleanVectorBlock[vector=ConstantBooleanVector[positions=1, value=true]]]] + * */ public void testPartialAggFoldingOutputForSyntheticAgg() { var plan = physicalPlan(""" @@ -2480,16 +2493,16 @@ public void testPartialAggFoldingOutputForSyntheticAgg() { /** * Before local optimizations: - * + * * LimitExec[1000[INTEGER]] * \_AggregateExec[[],[SPATIALCENTROID(location{f}#9) AS centroid],FINAL,null] * \_ExchangeExec[[xVal{r}#10, xDel{r}#11, yVal{r}#12, yDel{r}#13, count{r}#14],true] * \_FragmentExec[filter=null, estimatedRowSize=0, fragment=[ * Aggregate[[],[SPATIALCENTROID(location{f}#9) AS centroid]] * \_EsRelation[airports][abbrev{f}#5, location{f}#9, name{f}#6, scalerank{f}..]]] - * + * * After local optimizations: - * + * * LimitExec[1000[INTEGER]] * \_AggregateExec[[],[SPATIALCENTROID(location{f}#9) AS centroid],FINAL,50] * \_ExchangeExec[[xVal{r}#10, xDel{r}#11, yVal{r}#12, yDel{r}#13, count{r}#14],true] @@ -2497,9 +2510,9 @@ public void testPartialAggFoldingOutputForSyntheticAgg() { * \_FilterExec[ISNOTNULL(location{f}#9)] * \_FieldExtractExec[location{f}#9][location{f}#9] * \_EsQueryExec[airports], query[][_doc{f}#26], limit[], sort[] estimatedRowSize[54] - * + * * Note the FieldExtractExec has 'location' set for stats: FieldExtractExec[location{f}#9][location{f}#9] - * + *

* Also note that the type converting function is removed when it does not actually convert the type, * ensuring that ReferenceAttributes are not created for the same field, and the optimization can still work. */ @@ -2508,57 +2521,54 @@ public void testSpatialTypesAndStatsUseDocValues() { "from airports | stats centroid = st_centroid_agg(location)", "from airports | stats centroid = st_centroid_agg(to_geopoint(location))", "from airports | eval location = to_geopoint(location) | stats centroid = st_centroid_agg(location)" }) { - var plan = this.physicalPlan(query, airports); - - var limit = as(plan, LimitExec.class); - var agg = as(limit.child(), AggregateExec.class); - // Before optimization the aggregation does not use doc-values - assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, false); - - var exchange = as(agg.child(), ExchangeExec.class); - var fragment = as(exchange.child(), FragmentExec.class); - var fAgg = as(fragment.fragment(), Aggregate.class); - as(fAgg.child(), EsRelation.class); - - // Now optimize the plan and assert the aggregation uses doc-values - var optimized = optimizedPlan(plan); - limit = as(optimized, LimitExec.class); - agg = as(limit.child(), AggregateExec.class); - // Above the exchange (in coordinator) the aggregation is not using doc-values - assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, false); - exchange = as(agg.child(), ExchangeExec.class); - agg = as(exchange.child(), AggregateExec.class); - // below the exchange (in data node) the aggregation is using doc-values - assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, true); - var extract = as(agg.child(), FieldExtractExec.class); - source(extract.child()); - assertTrue( - "Expect field attribute to be extracted as doc-values", - extract.attributesToExtract().stream().allMatch(attr -> extract.hasDocValuesAttribute(attr) && attr.dataType() == GEO_POINT) - ); + for (boolean withDocValues : new boolean[] { false, true }) { + var plan = withDocValues ? physicalPlan(query, airports) : physicalPlan(query, airportsNoDocValues); + + var limit = as(plan, LimitExec.class); + var agg = as(limit.child(), AggregateExec.class); + // Before optimization the aggregation does not use doc-values + assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, false); + + var exchange = as(agg.child(), ExchangeExec.class); + var fragment = as(exchange.child(), FragmentExec.class); + var fAgg = as(fragment.fragment(), Aggregate.class); + as(fAgg.child(), EsRelation.class); + + // Now optimize the plan and assert the aggregation uses doc-values + var optimized = optimizedPlan(plan); + limit = as(optimized, LimitExec.class); + agg = as(limit.child(), AggregateExec.class); + // Above the exchange (in coordinator) the aggregation is not using doc-values + assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, false); + exchange = as(agg.child(), ExchangeExec.class); + agg = as(exchange.child(), AggregateExec.class); + // below the exchange (in data node) the aggregation is using doc-values + assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, withDocValues); + assertChildIsGeoPointExtract(withDocValues ? agg : as(agg.child(), FilterExec.class), withDocValues); + } } } /** * This test does not have real index fields, and therefor asserts that doc-values field extraction does NOT occur. - * * Before local optimizations: - * + * * LimitExec[1000[INTEGER]] * \_AggregateExec[[],[SPATIALCENTROID(__centroid_SPATIALCENTROID@ec8dd77e{r}#7) AS centroid],FINAL,null] * \_AggregateExec[[],[SPATIALCENTROID(__centroid_SPATIALCENTROID@ec8dd77e{r}#7) AS centroid],PARTIAL,null] * \_EvalExec[[[1 1 0 0 0 0 0 30 e2 4c 7c 45 40 0 0 e0 92 b0 82 2d 40][GEO_POINT] AS __centroid_SPATIALCENTROID@ec8dd77e]] * \_RowExec[[[50 4f 49 4e 54 28 34 32 2e 39 37 31 30 39 36 32 39 39 35 38 38 36 38 20 31 34 2e 37 35 35 32 35 33 34 30 30 * 36 35 33 36 29][KEYWORD] AS wkt]] - * + * * After local optimizations we expect no changes because field is extracted: - * + * * LimitExec[1000[INTEGER]] * \_AggregateExec[[],[SPATIALCENTROID(__centroid_SPATIALCENTROID@7ff910a{r}#7) AS centroid],FINAL,50] * \_AggregateExec[[],[SPATIALCENTROID(__centroid_SPATIALCENTROID@7ff910a{r}#7) AS centroid],PARTIAL,50] * \_EvalExec[[[1 1 0 0 0 0 0 30 e2 4c 7c 45 40 0 0 e0 92 b0 82 2d 40][GEO_POINT] AS __centroid_SPATIALCENTROID@7ff910a]] * \_RowExec[[[50 4f 49 4e 54 28 34 32 2e 39 37 31 30 39 36 32 39 39 35 38 38 36 38 20 31 34 2e 37 35 35 32 35 33 34 30 30 * 36 35 33 36 29][KEYWORD] AS wkt]] + * */ public void testSpatialTypesAndStatsUseDocValuesNestedLiteral() { var plan = this.physicalPlan(""" @@ -2595,23 +2605,23 @@ public void testSpatialTypesAndStatsUseDocValuesNestedLiteral() { /** * Before local optimizations: - * + * * LimitExec[1000[INTEGER]] * \_AggregateExec[[],[SPATIALCENTROID(location{f}#11) AS centroid, COUNT([2a][KEYWORD]) AS count],FINAL,null] * \_ExchangeExec[[xVal{r}#12, xDel{r}#13, yVal{r}#14, yDel{r}#15, count{r}#16, count{r}#17, seen{r}#18],true] * \_FragmentExec[filter=null, estimatedRowSize=0, fragment=[ * Aggregate[[],[SPATIALCENTROID(location{f}#11) AS centroid, COUNT([2a][KEYWORD]) AS count]] * \_EsRelation[airports][abbrev{f}#7, location{f}#11, name{f}#8, scalerank{f..]]] - * + * * After local optimizations: - * + * * LimitExec[1000[INTEGER]] * \_AggregateExec[[],[SPATIALCENTROID(location{f}#11) AS centroid, COUNT([2a][KEYWORD]) AS count],FINAL,58] * \_ExchangeExec[[xVal{r}#12, xDel{r}#13, yVal{r}#14, yDel{r}#15, count{r}#16, count{r}#17, seen{r}#18],true] * \_AggregateExec[[],[COUNT([2a][KEYWORD]) AS count, SPATIALCENTROID(location{f}#11) AS centroid],PARTIAL,58] * \_FieldExtractExec[location{f}#11][location{f}#11] * \_EsQueryExec[airports], query[][_doc{f}#33], limit[], sort[] estimatedRowSize[54] - * + * * Note the FieldExtractExec has 'location' set for stats: FieldExtractExec[location{f}#9][location{f}#9] */ public void testSpatialTypesAndStatsUseDocValuesMultiAggregations() { @@ -2645,17 +2655,12 @@ public void testSpatialTypesAndStatsUseDocValuesMultiAggregations() { // below the exchange (in data node) the aggregation is using doc-values assertAggregation(agg, "count", Count.class); assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, true); - var extract = as(agg.child(), FieldExtractExec.class); - source(extract.child()); - assertTrue( - "Expect field attribute to be extracted as doc-values", - extract.attributesToExtract().stream().allMatch(attr -> extract.hasDocValuesAttribute(attr) && attr.dataType() == GEO_POINT) - ); + assertChildIsGeoPointExtract(agg, true); } /** * Before local optimizations: - * + * * LimitExec[1000[INTEGER]] * \_AggregateExec[[],[SPATIALCENTROID(location{f}#14) AS airports, SPATIALCENTROID(city_location{f}#17) AS cities, COUNT([2a][KEY * WORD]) AS count],FINAL,null] @@ -2665,9 +2670,9 @@ public void testSpatialTypesAndStatsUseDocValuesMultiAggregations() { * Aggregate[[],[SPATIALCENTROID(location{f}#14) AS airports, SPATIALCENTROID(city_location{f}#17) AS cities, COUNT([2a][KEY * WORD]) AS count]] * \_EsRelation[airports][abbrev{f}#10, city{f}#16, city_location{f}#17, coun..]]] - * + * * After local optimizations: - * + * * LimitExec[1000[INTEGER]] * \_AggregateExec[[],[SPATIALCENTROID(location{f}#14) AS airports, SPATIALCENTROID(city_location{f}#17) AS cities, COUNT([2a][KEY * WORD]) AS count],FINAL,108] @@ -2677,7 +2682,7 @@ public void testSpatialTypesAndStatsUseDocValuesMultiAggregations() { * WORD]) AS count],PARTIAL,108] * \_FieldExtractExec[location{f}#14, city_location{f}#17][location{f}#14, city_location{f}#17] * \_EsQueryExec[airports], query[][_doc{f}#53], limit[], sort[] estimatedRowSize[104] - * + * * Note the FieldExtractExec has 'location' set for stats: FieldExtractExec[location{f}#9][location{f}#9] */ public void testSpatialTypesAndStatsUseDocValuesMultiSpatialAggregations() { @@ -2714,17 +2719,12 @@ public void testSpatialTypesAndStatsUseDocValuesMultiSpatialAggregations() { assertAggregation(agg, "count", Count.class); assertAggregation(agg, "airports", SpatialCentroid.class, GEO_POINT, true); assertAggregation(agg, "cities", SpatialCentroid.class, GEO_POINT, true); - var extract = as(agg.child(), FieldExtractExec.class); - source(extract.child()); - assertTrue( - "Expect field attribute to be extracted as doc-values", - extract.attributesToExtract().stream().allMatch(attr -> extract.hasDocValuesAttribute(attr) && attr.dataType() == GEO_POINT) - ); + assertChildIsGeoPointExtract(agg, true); } /** * Before local optimizations: - * + * * LimitExec[1000[INTEGER]] * \_AggregateExec[[],[SPATIALCENTROID(location{f}#12) AS centroid, COUNT([2a][KEYWORD]) AS count],FINAL,null] * \_ExchangeExec[[xVal{r}#13, xDel{r}#14, yVal{r}#15, yDel{r}#16, count{r}#17, count{r}#18, seen{r}#19],true] @@ -2732,9 +2732,9 @@ public void testSpatialTypesAndStatsUseDocValuesMultiSpatialAggregations() { * Aggregate[[],[SPATIALCENTROID(location{f}#12) AS centroid, COUNT([2a][KEYWORD]) AS count]] * \_Filter[scalerank{f}#10 == 9[INTEGER]] * \_EsRelation[airports][abbrev{f}#8, location{f}#12, name{f}#9, scalerank{f..]]] - * + * * After local optimizations: - * + * * LimitExec[1000[INTEGER]] * \_AggregateExec[[],[SPATIALCENTROID(location{f}#11) AS centroid, COUNT([2a][KEYWORD]) AS count],FINAL,58] * \_ExchangeExec[[xVal{r}#12, xDel{r}#13, yVal{r}#14, yDel{r}#15, count{r}#16, count{r}#17, seen{r}#18],true] @@ -2742,7 +2742,7 @@ public void testSpatialTypesAndStatsUseDocValuesMultiSpatialAggregations() { * \_FieldExtractExec[location{f}#11][location{f}#11] * \_EsQueryExec[airports], query[{"esql_single_value":{"field":"scalerank","next":{"term":{"scalerank":{"value":9}}}, * "source":"scalerank == 9@2:9"}}][_doc{f}#34], limit[], sort[] estimatedRowSize[54] - * + * * Note the FieldExtractExec has 'location' set for stats: FieldExtractExec[location{f}#9][location{f}#9] */ public void testSpatialTypesAndStatsUseDocValuesMultiAggregationsFiltered() { @@ -2779,19 +2779,14 @@ public void testSpatialTypesAndStatsUseDocValuesMultiAggregationsFiltered() { // below the exchange (in data node) the aggregation is using doc-values assertAggregation(agg, "count", Count.class); assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, true); - var extract = as(agg.child(), FieldExtractExec.class); - assertTrue( - "Expect field attribute to be extracted as doc-values", - extract.attributesToExtract().stream().allMatch(attr -> extract.hasDocValuesAttribute(attr) && attr.dataType() == GEO_POINT) - ); - var source = source(extract.child()); + var source = assertChildIsGeoPointExtract(agg, true); var qb = as(source.query(), SingleValueQuery.Builder.class); assertThat("Expected predicate to be passed to Lucene query", qb.source().text(), equalTo("scalerank == 9")); } /** * Before local optimizations: - * + * * LimitExec[1000[INTEGER]] * \_AggregateExec[[scalerank{f}#10],[SPATIALCENTROID(location{f}#12) AS centroid, COUNT([2a][KEYWORD]) AS count, scalerank{f}#10], * FINAL,null] @@ -2799,9 +2794,9 @@ public void testSpatialTypesAndStatsUseDocValuesMultiAggregationsFiltered() { * \_FragmentExec[filter=null, estimatedRowSize=0, fragment=[ * Aggregate[[scalerank{f}#10],[SPATIALCENTROID(location{f}#12) AS centroid, COUNT([2a][KEYWORD]) AS count, scalerank{f}#10]] * \_EsRelation[airports][abbrev{f}#8, location{f}#12, name{f}#9, scalerank{f..]]] - * + * * After local optimizations: - * + * * LimitExec[1000[INTEGER]] * \_AggregateExec[[scalerank{f}#10],[SPATIALCENTROID(location{f}#12) AS centroid, COUNT([2a][KEYWORD]) AS count, scalerank{f}#10], * FINAL,62] @@ -2810,57 +2805,54 @@ public void testSpatialTypesAndStatsUseDocValuesMultiAggregationsFiltered() { * PARTIAL,62] * \_FieldExtractExec[location{f}#12][location{f}#12] * \_EsQueryExec[airports], query[][_doc{f}#34], limit[], sort[] estimatedRowSize[54] - * + * * Note the FieldExtractExec has 'location' set for stats: FieldExtractExec[location{f}#9][location{f}#9] */ public void testSpatialTypesAndStatsUseDocValuesMultiAggregationsGrouped() { - var plan = this.physicalPlan(""" - FROM airports - | STATS centroid=ST_CENTROID_AGG(location), count=COUNT() BY scalerank - """, airports); + for (boolean useDocValues : new boolean[] { true, false }) { + var plan = this.physicalPlan(""" + FROM airports + | STATS centroid=ST_CENTROID_AGG(location), count=COUNT() BY scalerank + """, useDocValues ? airports : airportsNoDocValues); - var limit = as(plan, LimitExec.class); - var agg = as(limit.child(), AggregateExec.class); - assertThat("One grouping in aggregation", agg.groupings().size(), equalTo(1)); - var att = as(agg.groupings().get(0), Attribute.class); - assertThat(att.name(), equalTo("scalerank")); - // Before optimization the aggregation does not use doc-values - assertAggregation(agg, "count", Count.class); - assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, false); + var limit = as(plan, LimitExec.class); + var agg = as(limit.child(), AggregateExec.class); + assertThat("One grouping in aggregation", agg.groupings().size(), equalTo(1)); + var att = as(agg.groupings().get(0), Attribute.class); + assertThat(att.name(), equalTo("scalerank")); + // Before optimization the aggregation does not use doc-values + assertAggregation(agg, "count", Count.class); + assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, false); - var exchange = as(agg.child(), ExchangeExec.class); - var fragment = as(exchange.child(), FragmentExec.class); - var fAgg = as(fragment.fragment(), Aggregate.class); - as(fAgg.child(), EsRelation.class); + var exchange = as(agg.child(), ExchangeExec.class); + var fragment = as(exchange.child(), FragmentExec.class); + var fAgg = as(fragment.fragment(), Aggregate.class); + as(fAgg.child(), EsRelation.class); - // Now optimize the plan and assert the aggregation uses doc-values - var optimized = optimizedPlan(plan); - limit = as(optimized, LimitExec.class); - agg = as(limit.child(), AggregateExec.class); - att = as(agg.groupings().get(0), Attribute.class); - assertThat(att.name(), equalTo("scalerank")); - // Above the exchange (in coordinator) the aggregation is not using doc-values - assertAggregation(agg, "count", Count.class); - assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, false); - exchange = as(agg.child(), ExchangeExec.class); - agg = as(exchange.child(), AggregateExec.class); - assertThat("Aggregation is PARTIAL", agg.getMode(), equalTo(INITIAL)); - att = as(agg.groupings().get(0), Attribute.class); - assertThat(att.name(), equalTo("scalerank")); - // below the exchange (in data node) the aggregation is using doc-values - assertAggregation(agg, "count", Count.class); - assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, true); - var extract = as(agg.child(), FieldExtractExec.class); - assertTrue( - "Expect field attribute to be extracted as doc-values", - extract.attributesToExtract().stream().allMatch(attr -> extract.hasDocValuesAttribute(attr) && attr.dataType() == GEO_POINT) - ); - source(extract.child()); + // Now optimize the plan and assert the aggregation uses doc-values + var optimized = optimizedPlan(plan); + limit = as(optimized, LimitExec.class); + agg = as(limit.child(), AggregateExec.class); + att = as(agg.groupings().get(0), Attribute.class); + assertThat(att.name(), equalTo("scalerank")); + // Above the exchange (in coordinator) the aggregation is not using doc-values + assertAggregation(agg, "count", Count.class); + assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, false); + exchange = as(agg.child(), ExchangeExec.class); + agg = as(exchange.child(), AggregateExec.class); + assertThat("Aggregation is PARTIAL", agg.getMode(), equalTo(INITIAL)); + att = as(agg.groupings().get(0), Attribute.class); + assertThat(att.name(), equalTo("scalerank")); + // below the exchange (in data node) the aggregation is using doc-values + assertAggregation(agg, "count", Count.class); + assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, useDocValues); + assertChildIsGeoPointExtract(agg, useDocValues); + } } /** * Before local optimizations: - * + * * LimitExec[1000[INTEGER]] * \_AggregateExec[[],[SPATIALCENTROID(centroid{r}#4) AS centroid, SUM(count{r}#6) AS count],FINAL,null] * \_AggregateExec[[],[SPATIALCENTROID(centroid{r}#4) AS centroid, SUM(count{r}#6) AS count],PARTIAL,null] @@ -2869,9 +2861,9 @@ public void testSpatialTypesAndStatsUseDocValuesMultiAggregationsGrouped() { * \_FragmentExec[filter=null, estimatedRowSize=0, fragment=[ * Aggregate[[scalerank{f}#16],[SPATIALCENTROID(location{f}#18) AS centroid, COUNT([2a][KEYWORD]) AS count]] * \_EsRelation[airports][abbrev{f}#14, location{f}#18, name{f}#15, scalerank..]]] - * + * * After local optimizations: - * + * * LimitExec[1000[INTEGER]] * \_AggregateExec[[],[SPATIALCENTROID(centroid{r}#4) AS centroid, SUM(count{r}#6) AS count],FINAL,58] * \_AggregateExec[[],[SPATIALCENTROID(centroid{r}#4) AS centroid, SUM(count{r}#6) AS count],PARTIAL,58] @@ -2880,7 +2872,7 @@ public void testSpatialTypesAndStatsUseDocValuesMultiAggregationsGrouped() { * \_AggregateExec[[scalerank{f}#16],[SPATIALCENTROID(location{f}#18) AS centroid, COUNT([2a][KEYWORD]) AS count],PARTIAL,58] * \_FieldExtractExec[location{f}#18][location{f}#18] * \_EsQueryExec[airports], query[][_doc{f}#42], limit[], sort[] estimatedRowSize[54] - * + * * Note the FieldExtractExec has 'location' set for stats: FieldExtractExec[location{f}#9][location{f}#9] */ public void testSpatialTypesAndStatsUseDocValuesMultiAggregationsGroupedAggregated() { @@ -2943,16 +2935,12 @@ public void testSpatialTypesAndStatsUseDocValuesMultiAggregationsGroupedAggregat assertThat("Aggregation is PARTIAL", agg.getMode(), equalTo(INITIAL)); assertAggregation(agg, "count", Count.class); assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, true); - var extract = as(agg.child(), FieldExtractExec.class); - assertTrue( - "Expect field attribute to be extracted as doc-values", - extract.attributesToExtract().stream().allMatch(attr -> extract.hasDocValuesAttribute(attr) && attr.dataType() == GEO_POINT) - ); - source(extract.child()); + assertChildIsGeoPointExtract(agg, true); } /** * Plan: + * * LimitExec[1000[INTEGER]] * \_AggregateExec[[],[SPATIALCENTROID(city_location{f}#16) AS centroid],FINAL,null] * \_ExchangeExec[[xVal{r}#24, xDel{r}#25, yVal{r}#26, yDel{r}#27, count{r}#28],true] @@ -2962,8 +2950,9 @@ public void testSpatialTypesAndStatsUseDocValuesMultiAggregationsGroupedAggregat * _field":"city_boundary","enrich_fields":["city","airport","region","city_boundary"]}},{=airport_city_boundaries * },[airport{r}#21, region{r}#22, city_boundary{r}#23]] * \_EsRelation[airports][abbrev{f}#9, city{f}#15, city_location{f}#16, count..]]] - * + * * Optimized: + * * LimitExec[1000[INTEGER]] * \_AggregateExec[[],[SPATIALCENTROID(city_location{f}#16) AS centroid],FINAL,50] * \_ExchangeExec[[xVal{r}#24, xDel{r}#25, yVal{r}#26, yDel{r}#27, count{r}#28],true] @@ -2973,7 +2962,7 @@ public void testSpatialTypesAndStatsUseDocValuesMultiAggregationsGroupedAggregat * \_FieldExtractExec[city_location{f}#16][city_location{f}#16] * \_EsQueryExec[airports], query[{"exists":{"field":"city_location","boost":1.0}}][_doc{f}#46], limit[], sort[] * estimatedRowSize[204] - * + * * Note the FieldExtractExec has 'city_location' set for doc-values: FieldExtractExec[city_location{f}#16][city_location{f}#16] */ public void testEnrichBeforeSpatialAggregationSupportsDocValues() { @@ -3011,24 +3000,21 @@ public void testEnrichBeforeSpatialAggregationSupportsDocValues() { assertThat(enrichExec.mode(), equalTo(Enrich.Mode.ANY)); assertThat(enrichExec.concreteIndices(), equalTo(Map.of("", "airport_city_boundaries"))); assertThat(enrichExec.enrichFields().size(), equalTo(3)); - var extract = as(enrichExec.child(), FieldExtractExec.class); - source(extract.child()); - assertTrue( - "Expect field attribute to be extracted as doc-values", - extract.attributesToExtract().stream().allMatch(attr -> extract.hasDocValuesAttribute(attr) && attr.dataType() == GEO_POINT) - ); + assertChildIsGeoPointExtract(enrichExec, true); } /** * Plan: + * * LimitExec[500[INTEGER]] * \_ExchangeExec[[],false] * \_FragmentExec[filter=null, estimatedRowSize=0, fragment=[ * Limit[500[INTEGER]] * \_Filter[SPATIALINTERSECTS(location{f}#7,[50 4f 4c 59 47 4f 4e 28 29][KEYWORD])] * \_EsRelation[airports][abbrev{f}#3, city{f}#9, city_location{f}#10, countr..]]] - * + * * Optimized: + * * LimitExec[500[INTEGER]] * \_ExchangeExec[[],false] * \_ProjectExec[[abbrev{f}#3, city{f}#9, city_location{f}#10, country{f}#8, location{f}#7, name{f}#4, scalerank{f}#5, type{f}# @@ -3053,6 +3039,7 @@ public void testEnrichBeforeSpatialAggregationSupportsDocValues() { * "source":"ST_INTERSECTS(location, \"POLYGON((42 14, 43 14, 43 15, 42 15, 42 14))\")@2:9" * } * }][_doc{f}#19], limit[500], sort[] estimatedRowSize[358] + * */ public void testPushSpatialIntersectsStringToSource() { for (String query : new String[] { """ @@ -3077,8 +3064,6 @@ public void testPushSpatialIntersectsStringToSource() { var project = as(exchange.child(), ProjectExec.class); var fieldExtract = as(project.child(), FieldExtractExec.class); var source = source(fieldExtract.child()); - // TODO: bring back SingleValueQuery once it can handle LeafShapeFieldData - // var condition = as(sv(source.query(), "location"), AbstractGeometryQueryBuilder.class); var condition = as(source.query(), SpatialRelatesQuery.ShapeQueryBuilder.class); assertThat("Geometry field name", condition.fieldName(), equalTo("location")); assertThat("Spatial relationship", condition.relation(), equalTo(ShapeRelation.INTERSECTS)); @@ -3167,8 +3152,6 @@ public void testPushDownSpatialRelatesStringToSource() { var fieldExtract = as(project.child(), FieldExtractExec.class); if (test.canPushToSource) { var source = source(fieldExtract.child()); - // TODO: bring back SingleValueQuery once it can handle LeafShapeFieldData - // var condition = as(sv(source.query(), "location"), AbstractGeometryQueryBuilder.class); var condition = as(source.query(), SpatialRelatesQuery.ShapeQueryBuilder.class); assertThat("Geometry field name: " + test.predicate(), condition.fieldName(), equalTo("location")); assertThat("Spatial relationship: " + test.predicate(), condition.relation(), equalTo(test.relationship())); @@ -3239,16 +3222,7 @@ public void testPushDownSpatialRelatesStringToSourceAndUseDocValuesForCentroid() assertAggregation(agg, "count", Count.class); assertAggregation(agg, "centroid", SpatialCentroid.class, test.locationType(), true); if (test.canPushToSource) { - var extract = as(agg.child(), FieldExtractExec.class); - assertTrue( - "Expect field attribute to be extracted as doc-values", - extract.attributesToExtract() - .stream() - .allMatch(attr -> extract.hasDocValuesAttribute(attr) && attr.dataType() == test.locationType()) - ); - var source = source(extract.child()); - // TODO: bring back SingleValueQuery once it can handle LeafShapeFieldData - // var condition = as(sv(source.query(), "location"), AbstractGeometryQueryBuilder.class); + var source = assertChildIsExtractedAsDocValues(agg, true, test.locationType()); var condition = as(source.query(), SpatialRelatesQuery.ShapeQueryBuilder.class); assertThat("Geometry field name: " + test.predicate(), condition.fieldName(), equalTo("location")); assertThat("Spatial relationship: " + test.predicate(), condition.relation(), equalTo(test.relationship())); @@ -3271,7 +3245,7 @@ public void testPushDownSpatialRelatesStringToSourceAndUseDocValuesForCentroid() /** * Plan: - * Plan: + * * LimitExec[500[INTEGER]] * \_AggregateExec[[],[SPATIALCENTROID(location{f}#12) AS centroid, COUNT([2a][KEYWORD]) AS count],FINAL,null] * \_ExchangeExec[[xVal{r}#16, xDel{r}#17, yVal{r}#18, yDel{r}#19, count{r}#20, count{r}#21, seen{r}#22],true] @@ -3280,8 +3254,9 @@ public void testPushDownSpatialRelatesStringToSourceAndUseDocValuesForCentroid() * \_Filter[SPATIALINTERSECTS(location{f}#12,[50 4f 4c 59 47 4f 4e 28 28 34 32 20 31 34 2c 20 34 33 20 31 34 2c 20 34 33 2 * 0 31 35 2c 20 34 32 20 31 35 2c 20 34 32 20 31 34 29 29][KEYWORD])] * \_EsRelation[airports][abbrev{f}#8, city{f}#14, city_location{f}#15, count..]]] - * + * * Optimized: + * * LimitExec[500[INTEGER]] * \_AggregateExec[[],[SPATIALCENTROID(location{f}#12) AS centroid, COUNT([2a][KEYWORD]) AS count],FINAL,58] * \_ExchangeExec[[xVal{r}#16, xDel{r}#17, yVal{r}#18, yDel{r}#19, count{r}#20, count{r}#21, seen{r}#22],true] @@ -3306,6 +3281,7 @@ public void testPushDownSpatialRelatesStringToSourceAndUseDocValuesForCentroid() * "source":"ST_INTERSECTS(location, \"POLYGON((42 14, 43 14, 43 15, 42 15, 42 14))\")@2:9" * } * }][_doc{f}#140, limit[], sort[] estimatedRowSize[54] + * */ public void testPushSpatialIntersectsStringToSourceAndUseDocValuesForCentroid() { for (String query : new String[] { """ @@ -3318,48 +3294,46 @@ public void testPushSpatialIntersectsStringToSourceAndUseDocValuesForCentroid() | STATS centroid=ST_CENTROID_AGG(location), count=COUNT() """ }) { - var plan = this.physicalPlan(query, airports); - var limit = as(plan, LimitExec.class); - var agg = as(limit.child(), AggregateExec.class); - assertThat("No groupings in aggregation", agg.groupings().size(), equalTo(0)); - // Before optimization the aggregation does not use doc-values - assertAggregation(agg, "count", Count.class); - assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, false); - - var exchange = as(agg.child(), ExchangeExec.class); - var fragment = as(exchange.child(), FragmentExec.class); - var fAgg = as(fragment.fragment(), Aggregate.class); - var filter = as(fAgg.child(), Filter.class); - assertThat("filter contains ST_INTERSECTS", filter.condition(), instanceOf(SpatialIntersects.class)); - - // Now verify that optimization re-writes the ExchangeExec and pushed down the filter into the Lucene query - var optimized = optimizedPlan(plan); - limit = as(optimized, LimitExec.class); - agg = as(limit.child(), AggregateExec.class); - // Above the exchange (in coordinator) the aggregation is not using doc-values - assertAggregation(agg, "count", Count.class); - assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, false); - exchange = as(agg.child(), ExchangeExec.class); - agg = as(exchange.child(), AggregateExec.class); - assertThat("Aggregation is PARTIAL", agg.getMode(), equalTo(INITIAL)); - // below the exchange (in data node) the aggregation is using doc-values - assertAggregation(agg, "count", Count.class); - assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, true); - var extract = as(agg.child(), FieldExtractExec.class); - assertTrue( - "Expect field attribute to be extracted as doc-values", - extract.attributesToExtract().stream().allMatch(attr -> extract.hasDocValuesAttribute(attr) && attr.dataType() == GEO_POINT) - ); - var source = source(extract.child()); - // TODO: bring back SingleValueQuery once it can handle LeafShapeFieldData - // var condition = as(sv(source.query(), "location"), AbstractGeometryQueryBuilder.class); - var condition = as(source.query(), SpatialRelatesQuery.ShapeQueryBuilder.class); - assertThat("Geometry field name", condition.fieldName(), equalTo("location")); - assertThat("Spatial relationship", condition.relation(), equalTo(ShapeRelation.INTERSECTS)); - assertThat("Geometry is Polygon", condition.shape().type(), equalTo(ShapeType.POLYGON)); - var polygon = as(condition.shape(), Polygon.class); - assertThat("Polygon shell length", polygon.getPolygon().length(), equalTo(5)); - assertThat("Polygon holes", polygon.getNumberOfHoles(), equalTo(0)); + for (boolean useDocValues : new boolean[] { true, false }) { + var plan = this.physicalPlan(query, useDocValues ? airports : airportsNoDocValues); + var limit = as(plan, LimitExec.class); + var agg = as(limit.child(), AggregateExec.class); + assertThat("No groupings in aggregation", agg.groupings().size(), equalTo(0)); + // Before optimization the aggregation does not use doc-values + assertAggregation(agg, "count", Count.class); + assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, false); + + var exchange = as(agg.child(), ExchangeExec.class); + var fragment = as(exchange.child(), FragmentExec.class); + var fAgg = as(fragment.fragment(), Aggregate.class); + var filter = as(fAgg.child(), Filter.class); + assertThat("filter contains ST_INTERSECTS", filter.condition(), instanceOf(SpatialIntersects.class)); + + // Now verify that optimization re-writes the ExchangeExec and pushed down the filter into the Lucene query + var optimized = optimizedPlan(plan); + limit = as(optimized, LimitExec.class); + agg = as(limit.child(), AggregateExec.class); + // Above the exchange (in coordinator) the aggregation is not using doc-values + assertAggregation(agg, "count", Count.class); + assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, false); + exchange = as(agg.child(), ExchangeExec.class); + agg = as(exchange.child(), AggregateExec.class); + assertThat("Aggregation is PARTIAL", agg.getMode(), equalTo(INITIAL)); + // below the exchange (in data node) the aggregation is using doc-values + assertAggregation(agg, "count", Count.class); + assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, useDocValues); + var source = assertChildIsGeoPointExtract(useDocValues ? agg : as(agg.child(), FilterExec.class), useDocValues); + if (useDocValues) { + // Query is only pushed to lucene if indexing/doc-values are enabled + var condition = as(source.query(), SpatialRelatesQuery.ShapeQueryBuilder.class); + assertThat("Geometry field name", condition.fieldName(), equalTo("location")); + assertThat("Spatial relationship", condition.relation(), equalTo(ShapeRelation.INTERSECTS)); + assertThat("Geometry is Polygon", condition.shape().type(), equalTo(ShapeType.POLYGON)); + var polygon = as(condition.shape(), Polygon.class); + assertThat("Polygon shell length", polygon.getPolygon().length(), equalTo(5)); + assertThat("Polygon holes", polygon.getNumberOfHoles(), equalTo(0)); + } + } } } @@ -3392,8 +3366,6 @@ AND ST_INTERSECTS(TO_GEOSHAPE("POLYGON((42 14, 43 14, 43 15, 42 15, 42 14))"), l var project = as(exchange.child(), ProjectExec.class); var fieldExtract = as(project.child(), FieldExtractExec.class); var source = source(fieldExtract.child()); - // TODO: bring back SingleValueQuery once it can handle LeafShapeFieldData - // var condition = as(sv(source.query(), "location"), AbstractGeometryQueryBuilder.class); var booleanQuery = as(source.query(), BoolQueryBuilder.class); assertThat("Expected boolean query of three predicates", booleanQuery.must().size(), equalTo(3)); var condition = as(booleanQuery.must().get(1), SpatialRelatesQuery.ShapeQueryBuilder.class); @@ -3450,14 +3422,7 @@ AND ST_INTERSECTS(TO_GEOSHAPE("POLYGON((42 14, 43 14, 43 15, 42 15, 42 14))"), l // below the exchange (in data node) the aggregation is using doc-values assertAggregation(agg, "count", Count.class); assertAggregation(agg, "centroid", SpatialCentroid.class, GEO_POINT, true); - var extract = as(agg.child(), FieldExtractExec.class); - assertTrue( - "Expect field attribute to be extracted as doc-values", - extract.attributesToExtract().stream().allMatch(attr -> extract.hasDocValuesAttribute(attr) && attr.dataType() == GEO_POINT) - ); - var source = source(extract.child()); - // TODO: bring back SingleValueQuery once it can handle LeafShapeFieldData - // var condition = as(sv(source.query(), "location"), AbstractGeometryQueryBuilder.class); + var source = assertChildIsGeoPointExtract(agg, true); var booleanQuery = as(source.query(), BoolQueryBuilder.class); assertThat("Expected boolean query of three predicates", booleanQuery.must().size(), equalTo(3)); var condition = as(booleanQuery.must().get(1), SpatialRelatesQuery.ShapeQueryBuilder.class); @@ -3627,8 +3592,6 @@ AND ST_INTERSECTS(city_location, TO_GEOSHAPE("POLYGON((42 14, 43 14, 43 15, 42 1 var extract = as(agg.child(), FieldExtractExec.class); assertFieldExtractionWithDocValues(extract, GEO_POINT, "location", "city_location"); var source = source(extract.child()); - // TODO: bring back SingleValueQuery once it can handle LeafShapeFieldData - // var condition = as(sv(source.query(), "location"), AbstractGeometryQueryBuilder.class); var booleanQuery = as(source.query(), BoolQueryBuilder.class); assertThat("Expected boolean query of two predicates", booleanQuery.must().size(), equalTo(2)); String[] fieldNames = new String[] { "location", "city_location" }; @@ -3666,8 +3629,6 @@ public void testPushSpatialIntersectsShapeToSource() { var project = as(exchange.child(), ProjectExec.class); var fieldExtract = as(project.child(), FieldExtractExec.class); var source = source(fieldExtract.child()); - // TODO: bring back SingleValueQuery once it can handle LeafShapeFieldData - // var condition = as(sv(source.query(), "location"), AbstractGeometryQueryBuilder.class); var condition = as(source.query(), SpatialRelatesQuery.ShapeQueryBuilder.class); assertThat("Geometry field name", condition.fieldName(), equalTo("shape")); assertThat("Spatial relationship", condition.relation(), equalTo(ShapeRelation.INTERSECTS)); @@ -3935,8 +3896,6 @@ public void testPushCartesianSpatialIntersectsToSource() { var project = as(exchange.child(), ProjectExec.class); var fieldExtract = as(project.child(), FieldExtractExec.class); var source = source(fieldExtract.child()); - // TODO: bring back SingleValueQuery once it can handle LeafShapeFieldData - // var condition = as(sv(source.query(), "location"), AbstractGeometryQueryBuilder.class); var condition = as(source.query(), SpatialRelatesQuery.ShapeQueryBuilder.class); assertThat("Geometry field name", condition.fieldName(), equalTo("location")); assertThat("Spatial relationship", condition.relation(), equalTo(ShapeRelation.INTERSECTS)); @@ -3981,8 +3940,6 @@ public void testPushCartesianSpatialIntersectsShapeToSource() { var project = as(exchange.child(), ProjectExec.class); var fieldExtract = as(project.child(), FieldExtractExec.class); var source = source(fieldExtract.child()); - // TODO: bring back SingleValueQuery once it can handle LeafShapeFieldData - // var condition = as(sv(source.query(), "location"), AbstractGeometryQueryBuilder.class); var condition = as(source.query(), SpatialRelatesQuery.ShapeQueryBuilder.class); assertThat("Geometry field name", condition.fieldName(), equalTo("shape")); assertThat("Spatial relationship", condition.relation(), equalTo(ShapeRelation.INTERSECTS)); @@ -4692,6 +4649,21 @@ private static void assertFilterCondition( assertThat("Expected filter value", value.value(), equalTo(expected)); } + private EsQueryExec assertChildIsGeoPointExtract(UnaryExec parent, boolean useDocValues) { + return assertChildIsExtractedAsDocValues(parent, useDocValues, GEO_POINT); + } + + private EsQueryExec assertChildIsExtractedAsDocValues(UnaryExec parent, boolean useDocValues, DataType dataType) { + var extract = as(parent.child(), FieldExtractExec.class); + assertTrue( + "Expect field attribute to be extracted as " + (useDocValues ? "doc-values" : "source"), + extract.attributesToExtract() + .stream() + .allMatch(attr -> extract.hasDocValuesAttribute(attr) == useDocValues && attr.dataType() == dataType) + ); + return source(extract.child()); + } + private static void assertAggregation( PhysicalPlan plan, String aliasName, diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/TestPhysicalOperationProviders.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/TestPhysicalOperationProviders.java index 0cd1fa11a7499..c811643c8daea 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/TestPhysicalOperationProviders.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/TestPhysicalOperationProviders.java @@ -372,8 +372,14 @@ protected Block copyBlock(Block originalData) { if (count == 0) { builder.appendNull(); } else { + if (count > 1) { + builder.beginPositionEntry(); + } for (int v = 0; v < count; v++) { - builder.appendLong(encode(bytesRefBlock.getBytesRef(i, scratch))); + builder.appendLong(encode(bytesRefBlock.getBytesRef(i + v, scratch))); + } + if (count > 1) { + builder.endPositionEntry(); } } }