Skip to content

Commit e2b410e

Browse files
authored
Add support for multipoint geoshape queries (#52133)
Currently multi-point queries are not supported when indexing your data using BKD-backed geoshape strategy. This commit removes this limitation.
1 parent c7efab9 commit e2b410e

File tree

4 files changed

+35
-59
lines changed

4 files changed

+35
-59
lines changed

docs/reference/mapping/types/geo-shape.asciidoc

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -134,16 +134,10 @@ and will be removed in a future version.
134134

135135
*IMPORTANT NOTES*
136136

137-
The following features are not yet supported with the new indexing approach:
137+
`CONTAINS` relation query - when using the new default vector indexing strategy, `geo_shape`
138+
queries with `relation` defined as `contains` are supported for indices created with
139+
ElasticSearch 7.5.0 or higher.
138140

139-
* `geo_shape` query with `MultiPoint` geometry types - Elasticsearch currently prevents searching
140-
geo_shape fields with a MultiPoint geometry type to avoid a brute force linear search
141-
over each individual point. For now, if this is absolutely needed, this can be achieved
142-
using a `bool` query with each individual point.
143-
144-
* `CONTAINS` relation query - when using the new default vector indexing strategy, `geo_shape`
145-
queries with `relation` defined as `contains` are supported for indices created with
146-
ElasticSearch 7.5.0 or higher.
147141

148142
[[prefix-trees]]
149143
[float]

server/src/main/java/org/elasticsearch/index/query/VectorGeoShapeQueryProcessor.java

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import org.apache.lucene.search.MatchNoDocsQuery;
2929
import org.apache.lucene.search.Query;
3030
import org.elasticsearch.Version;
31-
import org.elasticsearch.common.geo.GeoShapeType;
3231
import org.elasticsearch.common.geo.ShapeRelation;
3332
import org.elasticsearch.geometry.Circle;
3433
import org.elasticsearch.geometry.Geometry;
@@ -106,13 +105,7 @@ private void visit(BooleanQuery.Builder bqb, GeometryCollection<?> collection) {
106105
occur = BooleanClause.Occur.SHOULD;
107106
}
108107
for (Geometry shape : collection) {
109-
if (shape instanceof MultiPoint) {
110-
// Flatten multi-points
111-
// We do not support multi-point queries?
112-
visit(bqb, (GeometryCollection<?>) shape);
113-
} else {
114-
bqb.add(shape.visit(this), occur);
115-
}
108+
bqb.add(shape.visit(this), occur);
116109
}
117110
}
118111

@@ -139,8 +132,11 @@ public Query visit(MultiLine multiLine) {
139132

140133
@Override
141134
public Query visit(MultiPoint multiPoint) {
142-
throw new QueryShardException(context, "Field [" + fieldName + "] does not support " + GeoShapeType.MULTIPOINT +
143-
" queries");
135+
double[][] points = new double[multiPoint.size()][2];
136+
for (int i = 0; i < multiPoint.size(); i++) {
137+
points[i] = new double[] {multiPoint.get(i).getLat(), multiPoint.get(i).getLon()};
138+
}
139+
return LatLonShape.newPointQuery(fieldName, relation.getLuceneRelation(), points);
144140
}
145141

146142
@Override
@@ -161,8 +157,8 @@ public Query visit(Point point) {
161157
// intersects is more efficient.
162158
luceneRelation = ShapeField.QueryRelation.INTERSECTS;
163159
}
164-
return LatLonShape.newBoxQuery(fieldName, luceneRelation,
165-
point.getY(), point.getY(), point.getX(), point.getX());
160+
return LatLonShape.newPointQuery(fieldName, luceneRelation,
161+
new double[] {point.getY(), point.getX()});
166162
}
167163

168164
@Override

server/src/test/java/org/elasticsearch/index/query/GeoShapeQueryBuilderTests.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,8 @@ protected GeoShapeQueryBuilder doCreateTestQueryBuilder() {
8282
}
8383

8484
protected GeoShapeQueryBuilder doCreateTestQueryBuilder(boolean indexedShape) {
85-
// LatLonShape does not support MultiPoint queries
8685
RandomShapeGenerator.ShapeType shapeType =
87-
randomFrom(ShapeType.POINT, ShapeType.LINESTRING, ShapeType.MULTILINESTRING, ShapeType.POLYGON);
86+
randomFrom(ShapeType.POINT, ShapeType.MULTIPOINT, ShapeType.LINESTRING, ShapeType.MULTILINESTRING, ShapeType.POLYGON);
8887
ShapeBuilder<?, ?, ?> shape = RandomShapeGenerator.createShapeWithin(random(), null, shapeType);
8988
GeoShapeQueryBuilder builder;
9089
clearShapeFields();
@@ -108,11 +107,20 @@ protected GeoShapeQueryBuilder doCreateTestQueryBuilder(boolean indexedShape) {
108107
}
109108
}
110109
if (randomBoolean()) {
111-
if (shapeType == ShapeType.LINESTRING || shapeType == ShapeType.MULTILINESTRING) {
112-
builder.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.INTERSECTS));
110+
QueryShardContext context = createShardContext();
111+
if (context.indexVersionCreated().onOrAfter(Version.V_7_5_0)) { // CONTAINS is only supported from version 7.5
112+
if (shapeType == ShapeType.LINESTRING || shapeType == ShapeType.MULTILINESTRING) {
113+
builder.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.INTERSECTS, ShapeRelation.CONTAINS));
114+
} else {
115+
builder.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.INTERSECTS,
116+
ShapeRelation.WITHIN, ShapeRelation.CONTAINS));
117+
}
113118
} else {
114-
// LatLonShape does not support CONTAINS:
115-
builder.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.INTERSECTS, ShapeRelation.WITHIN));
119+
if (shapeType == ShapeType.LINESTRING || shapeType == ShapeType.MULTILINESTRING) {
120+
builder.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.INTERSECTS));
121+
} else {
122+
builder.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.INTERSECTS, ShapeRelation.WITHIN));
123+
}
116124
}
117125
}
118126

server/src/test/java/org/elasticsearch/search/geo/GeoShapeQueryTests.java

Lines changed: 10 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -196,23 +196,9 @@ public void testShapeFetchingPath() throws Exception {
196196
}
197197

198198
public void testRandomGeoCollectionQuery() throws Exception {
199-
boolean usePrefixTrees = randomBoolean();
200199
// Create a random geometry collection to index.
201-
GeometryCollectionBuilder gcb;
202-
if (usePrefixTrees) {
203-
gcb = RandomShapeGenerator.createGeometryCollection(random());
204-
} else {
205-
// vector strategy does not yet support multipoint queries
206-
gcb = new GeometryCollectionBuilder();
207-
int numShapes = RandomNumbers.randomIntBetween(random(), 1, 4);
208-
for (int i = 0; i < numShapes; ++i) {
209-
ShapeBuilder shape;
210-
do {
211-
shape = RandomShapeGenerator.createShape(random());
212-
} while (shape instanceof MultiPointBuilder);
213-
gcb.shape(shape);
214-
}
215-
}
200+
GeometryCollectionBuilder gcb = RandomShapeGenerator.createGeometryCollection(random());;
201+
216202
org.apache.lucene.geo.Polygon randomPoly = GeoTestUtil.nextPolygon();
217203

218204
assumeTrue("Skipping the check for the polygon with a degenerated dimension",
@@ -224,10 +210,9 @@ public void testRandomGeoCollectionQuery() throws Exception {
224210
}
225211
gcb.shape(new PolygonBuilder(cb));
226212

227-
logger.info("Created Random GeometryCollection containing {} shapes using {} tree", gcb.numShapes(),
228-
usePrefixTrees ? "geohash" : "quadtree");
213+
logger.info("Created Random GeometryCollection containing {} shapes", gcb.numShapes());
229214

230-
XContentBuilder mapping = createPrefixTreeMapping(usePrefixTrees ? "geohash" : "quadtree");
215+
XContentBuilder mapping = createRandomMapping();
231216
Settings settings = Settings.builder().put("index.number_of_shards", 1).build();
232217
client().admin().indices().prepareCreate("test").setMapping(mapping).setSettings(settings).get();
233218
ensureGreen();
@@ -457,11 +442,8 @@ public void testPointQuery() throws Exception {
457442
PointBuilder pb = new PointBuilder(pt[0], pt[1]);
458443
gcb.shape(pb);
459444

460-
// don't use random as permits quadtree
461-
String mapping = Strings.toString(
462-
randomBoolean() ?
463-
createDefaultMapping() :
464-
createPrefixTreeMapping(LegacyGeoShapeFieldMapper.DeprecatedParameters.PrefixTrees.QUADTREE));
445+
// create mapping
446+
String mapping = Strings.toString(createRandomMapping());
465447
client().admin().indices().prepareCreate("test").setMapping(mapping).get();
466448
ensureGreen();
467449

@@ -527,10 +509,8 @@ public void testExistsQuery() throws Exception {
527509
GeometryCollectionBuilder gcb = RandomShapeGenerator.createGeometryCollection(random());
528510
logger.info("Created Random GeometryCollection containing {} shapes", gcb.numShapes());
529511

530-
String mapping = Strings.toString(
531-
randomBoolean() ?
532-
createDefaultMapping() :
533-
createPrefixTreeMapping(LegacyGeoShapeFieldMapper.DeprecatedParameters.PrefixTrees.QUADTREE));
512+
String mapping = Strings.toString(createRandomMapping());
513+
534514
client().admin().indices().prepareCreate("test").setMapping(mapping).get();
535515
ensureGreen();
536516

@@ -677,8 +657,7 @@ public void testFieldAlias() throws IOException {
677657

678658
public void testQueryRandomGeoCollection() throws Exception {
679659
// Create a random geometry collection.
680-
String mapping = Strings.toString(randomBoolean() ? createDefaultMapping() : createPrefixTreeMapping(
681-
LegacyGeoShapeFieldMapper.DeprecatedParameters.PrefixTrees.QUADTREE));
660+
String mapping = Strings.toString(createRandomMapping());
682661
GeometryCollectionBuilder gcb = RandomShapeGenerator.createGeometryCollection(random());
683662
org.apache.lucene.geo.Polygon randomPoly = GeoTestUtil.nextPolygon();
684663
CoordinatesBuilder cb = new CoordinatesBuilder();
@@ -708,8 +687,7 @@ public void testQueryRandomGeoCollection() throws Exception {
708687
}
709688

710689
public void testShapeFilterWithDefinedGeoCollection() throws Exception {
711-
String mapping = Strings.toString(
712-
createPrefixTreeMapping(LegacyGeoShapeFieldMapper.DeprecatedParameters.PrefixTrees.QUADTREE));
690+
String mapping = Strings.toString(createRandomMapping());
713691
client().admin().indices().prepareCreate("test").setMapping(mapping).get();
714692
ensureGreen();
715693

0 commit comments

Comments
 (0)