Skip to content

Commit

Permalink
Add support for multipoint geoshape queries (#52133)
Browse files Browse the repository at this point in the history
Currently multi-point queries are not supported when indexing your data using BKD-backed geoshape strategy. This commit removes this limitation.
  • Loading branch information
iverase committed Feb 20, 2020
1 parent c7efab9 commit e2b410e
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 59 deletions.
12 changes: 3 additions & 9 deletions docs/reference/mapping/types/geo-shape.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -134,16 +134,10 @@ and will be removed in a future version.

*IMPORTANT NOTES*

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

* `geo_shape` query with `MultiPoint` geometry types - Elasticsearch currently prevents searching
geo_shape fields with a MultiPoint geometry type to avoid a brute force linear search
over each individual point. For now, if this is absolutely needed, this can be achieved
using a `bool` query with each individual point.

* `CONTAINS` relation query - when using the new default vector indexing strategy, `geo_shape`
queries with `relation` defined as `contains` are supported for indices created with
ElasticSearch 7.5.0 or higher.

[[prefix-trees]]
[float]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query;
import org.elasticsearch.Version;
import org.elasticsearch.common.geo.GeoShapeType;
import org.elasticsearch.common.geo.ShapeRelation;
import org.elasticsearch.geometry.Circle;
import org.elasticsearch.geometry.Geometry;
Expand Down Expand Up @@ -106,13 +105,7 @@ private void visit(BooleanQuery.Builder bqb, GeometryCollection<?> collection) {
occur = BooleanClause.Occur.SHOULD;
}
for (Geometry shape : collection) {
if (shape instanceof MultiPoint) {
// Flatten multi-points
// We do not support multi-point queries?
visit(bqb, (GeometryCollection<?>) shape);
} else {
bqb.add(shape.visit(this), occur);
}
bqb.add(shape.visit(this), occur);
}
}

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

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

@Override
Expand All @@ -161,8 +157,8 @@ public Query visit(Point point) {
// intersects is more efficient.
luceneRelation = ShapeField.QueryRelation.INTERSECTS;
}
return LatLonShape.newBoxQuery(fieldName, luceneRelation,
point.getY(), point.getY(), point.getX(), point.getX());
return LatLonShape.newPointQuery(fieldName, luceneRelation,
new double[] {point.getY(), point.getX()});
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,8 @@ protected GeoShapeQueryBuilder doCreateTestQueryBuilder() {
}

protected GeoShapeQueryBuilder doCreateTestQueryBuilder(boolean indexedShape) {
// LatLonShape does not support MultiPoint queries
RandomShapeGenerator.ShapeType shapeType =
randomFrom(ShapeType.POINT, ShapeType.LINESTRING, ShapeType.MULTILINESTRING, ShapeType.POLYGON);
randomFrom(ShapeType.POINT, ShapeType.MULTIPOINT, ShapeType.LINESTRING, ShapeType.MULTILINESTRING, ShapeType.POLYGON);
ShapeBuilder<?, ?, ?> shape = RandomShapeGenerator.createShapeWithin(random(), null, shapeType);
GeoShapeQueryBuilder builder;
clearShapeFields();
Expand All @@ -108,11 +107,20 @@ protected GeoShapeQueryBuilder doCreateTestQueryBuilder(boolean indexedShape) {
}
}
if (randomBoolean()) {
if (shapeType == ShapeType.LINESTRING || shapeType == ShapeType.MULTILINESTRING) {
builder.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.INTERSECTS));
QueryShardContext context = createShardContext();
if (context.indexVersionCreated().onOrAfter(Version.V_7_5_0)) { // CONTAINS is only supported from version 7.5
if (shapeType == ShapeType.LINESTRING || shapeType == ShapeType.MULTILINESTRING) {
builder.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.INTERSECTS, ShapeRelation.CONTAINS));
} else {
builder.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.INTERSECTS,
ShapeRelation.WITHIN, ShapeRelation.CONTAINS));
}
} else {
// LatLonShape does not support CONTAINS:
builder.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.INTERSECTS, ShapeRelation.WITHIN));
if (shapeType == ShapeType.LINESTRING || shapeType == ShapeType.MULTILINESTRING) {
builder.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.INTERSECTS));
} else {
builder.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.INTERSECTS, ShapeRelation.WITHIN));
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,23 +196,9 @@ public void testShapeFetchingPath() throws Exception {
}

public void testRandomGeoCollectionQuery() throws Exception {
boolean usePrefixTrees = randomBoolean();
// Create a random geometry collection to index.
GeometryCollectionBuilder gcb;
if (usePrefixTrees) {
gcb = RandomShapeGenerator.createGeometryCollection(random());
} else {
// vector strategy does not yet support multipoint queries
gcb = new GeometryCollectionBuilder();
int numShapes = RandomNumbers.randomIntBetween(random(), 1, 4);
for (int i = 0; i < numShapes; ++i) {
ShapeBuilder shape;
do {
shape = RandomShapeGenerator.createShape(random());
} while (shape instanceof MultiPointBuilder);
gcb.shape(shape);
}
}
GeometryCollectionBuilder gcb = RandomShapeGenerator.createGeometryCollection(random());;

org.apache.lucene.geo.Polygon randomPoly = GeoTestUtil.nextPolygon();

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

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

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

// don't use random as permits quadtree
String mapping = Strings.toString(
randomBoolean() ?
createDefaultMapping() :
createPrefixTreeMapping(LegacyGeoShapeFieldMapper.DeprecatedParameters.PrefixTrees.QUADTREE));
// create mapping
String mapping = Strings.toString(createRandomMapping());
client().admin().indices().prepareCreate("test").setMapping(mapping).get();
ensureGreen();

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

String mapping = Strings.toString(
randomBoolean() ?
createDefaultMapping() :
createPrefixTreeMapping(LegacyGeoShapeFieldMapper.DeprecatedParameters.PrefixTrees.QUADTREE));
String mapping = Strings.toString(createRandomMapping());

client().admin().indices().prepareCreate("test").setMapping(mapping).get();
ensureGreen();

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

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

public void testShapeFilterWithDefinedGeoCollection() throws Exception {
String mapping = Strings.toString(
createPrefixTreeMapping(LegacyGeoShapeFieldMapper.DeprecatedParameters.PrefixTrees.QUADTREE));
String mapping = Strings.toString(createRandomMapping());
client().admin().indices().prepareCreate("test").setMapping(mapping).get();
ensureGreen();

Expand Down

0 comments on commit e2b410e

Please sign in to comment.