Skip to content

Add support for multipoint geoshape queries #52133

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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