mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-22 12:56:53 +00:00
Geo shape query vs geo point backport (#53774)
Backport to 7x Enable geo_shape query to work on geo_point fields for shapes: circle, polygon, multipolygon, rectangle see: #48928 Co-Authored-By: @iverase
This commit is contained in:
parent
8f4a3eb07f
commit
b0884baf46
@ -18,9 +18,11 @@ Finds documents with geo-points within the specified distance of a central point
|
||||
Find documents with geo-points within the specified polygon.
|
||||
|
||||
<<query-dsl-geo-shape-query,`geo_shape`>> query::
|
||||
Finds documents with geo-shapes which either intersect, are contained by, or do not intersect with the specified
|
||||
geo-shape.
|
||||
|
||||
Finds documents with:
|
||||
* `geo-shapes` which either intersect, are contained by, or do not intersect
|
||||
with the specified geo-shape
|
||||
* `geo-points` which intersect the specified
|
||||
geo-shape
|
||||
|
||||
include::geo-bounding-box-query.asciidoc[]
|
||||
|
||||
|
@ -4,9 +4,9 @@
|
||||
<titleabbrev>Geo-shape</titleabbrev>
|
||||
++++
|
||||
|
||||
Filter documents indexed using the `geo_shape` type.
|
||||
Filter documents indexed using the `geo_shape` or `geo_point` type.
|
||||
|
||||
Requires the <<geo-shape,`geo_shape` Mapping>>.
|
||||
Requires the <<geo-shape,`geo_shape` Mapping>> or the <<geo-point,`geo_point` Mapping>>.
|
||||
|
||||
The `geo_shape` query uses the same grid square representation as the
|
||||
`geo_shape` mapping to find documents that have a shape that intersects
|
||||
@ -142,7 +142,7 @@ GET /example/_search
|
||||
The <<spatial-strategy, geo_shape strategy>> mapping parameter determines
|
||||
which spatial relation operators may be used at search time.
|
||||
|
||||
The following is a complete list of spatial relation operators available:
|
||||
The following is a complete list of spatial relation operators available when searching a field of type `geo_shape`:
|
||||
|
||||
* `INTERSECTS` - (default) Return all documents whose `geo_shape` field
|
||||
intersects the query geometry.
|
||||
@ -153,6 +153,11 @@ is within the query geometry.
|
||||
* `CONTAINS` - Return all documents whose `geo_shape` field
|
||||
contains the query geometry.
|
||||
|
||||
When searching a field of type `geo_point` there is a single supported spatial relation operator:
|
||||
|
||||
* `INTERSECTS` - (default) Return all documents whose `geo_point` field
|
||||
intersects the query geometry.
|
||||
|
||||
[float]
|
||||
==== Ignore Unmapped
|
||||
|
||||
@ -162,6 +167,15 @@ querying multiple indexes which might have different mappings. When set to
|
||||
`false` (the default value) the query will throw an exception if the field
|
||||
is not mapped.
|
||||
|
||||
==== Shape Types supported for Geo-Point
|
||||
|
||||
When searching a field of type `geo_point` the following shape types are not supported:
|
||||
|
||||
* `POINT`
|
||||
* `LINE`
|
||||
* `MULTIPOINT`
|
||||
* `MULTILINE`
|
||||
|
||||
==== Notes
|
||||
Geo-shape queries on geo-shapes implemented with <<prefix-trees, `PrefixTrees`>> will not be executed if
|
||||
<<query-dsl-allow-expensive-queries, `search.allow_expensive_queries`>> is set to false.
|
||||
|
@ -64,6 +64,6 @@ public class LinearRing extends Line {
|
||||
public String toString() {
|
||||
return "linearring(x=" + Arrays.toString(getX()) +
|
||||
", y=" + Arrays.toString(getY()) +
|
||||
(hasZ() ? ", z=" + Arrays.toString(getZ()) : "");
|
||||
(hasZ() ? ", z=" + Arrays.toString(getZ()) : "") + ")";
|
||||
}
|
||||
}
|
||||
|
@ -26,8 +26,6 @@ import org.apache.lucene.search.TermQuery;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.Explicit;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.geo.ShapeRelation;
|
||||
import org.elasticsearch.common.geo.SpatialStrategy;
|
||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
||||
import org.elasticsearch.common.geo.builders.ShapeBuilder.Orientation;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
@ -35,7 +33,6 @@ import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
||||
import org.elasticsearch.geometry.Geometry;
|
||||
import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper.DeprecatedParameters;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.index.query.QueryShardException;
|
||||
@ -91,19 +88,6 @@ public abstract class AbstractGeometryFieldMapper<Parsed, Processed> extends Fie
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* interface representing a query builder that generates a query from the given shape
|
||||
*/
|
||||
public interface QueryProcessor {
|
||||
Query process(Geometry shape, String fieldName, ShapeRelation relation, QueryShardContext context);
|
||||
|
||||
@Deprecated
|
||||
default Query process(Geometry shape, String fieldName, SpatialStrategy strategy, ShapeRelation relation,
|
||||
QueryShardContext context) {
|
||||
return process(shape, fieldName, relation, context);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class Builder<T extends Builder, Y extends AbstractGeometryFieldMapper>
|
||||
extends FieldMapper.Builder<T, Y> {
|
||||
protected Boolean coerce;
|
||||
@ -272,14 +256,14 @@ public abstract class AbstractGeometryFieldMapper<Parsed, Processed> extends Fie
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class AbstractGeometryFieldType<Parsed, Processed> extends MappedFieldType {
|
||||
public abstract static class AbstractGeometryFieldType<Parsed, Processed> extends AbstractSearchableGeometryFieldType {
|
||||
protected Orientation orientation = Defaults.ORIENTATION.value();
|
||||
|
||||
protected Indexer<Parsed, Processed> geometryIndexer;
|
||||
|
||||
protected Parser<Parsed> geometryParser;
|
||||
|
||||
protected QueryProcessor geometryQueryBuilder;
|
||||
|
||||
|
||||
protected AbstractGeometryFieldType() {
|
||||
setIndexOptions(IndexOptions.DOCS);
|
||||
@ -339,14 +323,6 @@ public abstract class AbstractGeometryFieldMapper<Parsed, Processed> extends Fie
|
||||
protected Parser<Parsed> geometryParser() {
|
||||
return geometryParser;
|
||||
}
|
||||
|
||||
public void setGeometryQueryBuilder(QueryProcessor geometryQueryBuilder) {
|
||||
this.geometryQueryBuilder = geometryQueryBuilder;
|
||||
}
|
||||
|
||||
public QueryProcessor geometryQueryBuilder() {
|
||||
return geometryQueryBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
protected Explicit<Boolean> coerce;
|
||||
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.index.mapper;
|
||||
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.common.geo.ShapeRelation;
|
||||
import org.elasticsearch.common.geo.SpatialStrategy;
|
||||
import org.elasticsearch.geometry.Geometry;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
|
||||
/**
|
||||
* a base class for geometry types that support shape query builder
|
||||
*/
|
||||
public abstract class AbstractSearchableGeometryFieldType extends MappedFieldType {
|
||||
|
||||
protected QueryProcessor geometryQueryBuilder;
|
||||
|
||||
protected AbstractSearchableGeometryFieldType() {
|
||||
}
|
||||
|
||||
protected AbstractSearchableGeometryFieldType(AbstractSearchableGeometryFieldType ref) {
|
||||
super(ref);
|
||||
}
|
||||
|
||||
public void setGeometryQueryBuilder(QueryProcessor geometryQueryBuilder) {
|
||||
this.geometryQueryBuilder = geometryQueryBuilder;
|
||||
}
|
||||
|
||||
public QueryProcessor geometryQueryBuilder() {
|
||||
return geometryQueryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* interface representing a query builder that generates a query from the given shape
|
||||
*/
|
||||
public interface QueryProcessor {
|
||||
Query process(Geometry shape, String fieldName, ShapeRelation relation, QueryShardContext context);
|
||||
|
||||
@Deprecated
|
||||
default Query process(Geometry shape, String fieldName, SpatialStrategy strategy, ShapeRelation relation,
|
||||
QueryShardContext context) {
|
||||
return process(shape, fieldName, relation, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||
import org.elasticsearch.index.fielddata.plain.AbstractLatLonPointDVIndexFieldData;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.index.query.QueryShardException;
|
||||
import org.elasticsearch.index.query.VectorGeoPointShapeQueryProcessor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@ -121,6 +122,14 @@ public class GeoPointFieldMapper extends FieldMapper implements ArrayValueMapper
|
||||
ignoreMalformed, ignoreZValue, copyTo);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupFieldType(BuilderContext context) {
|
||||
super.setupFieldType(context);
|
||||
|
||||
GeoPointFieldType fieldType = (GeoPointFieldType)fieldType();
|
||||
fieldType.setGeometryQueryBuilder(new VectorGeoPointShapeQueryProcessor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeoPointFieldMapper build(BuilderContext context) {
|
||||
return build(context, name, fieldType, defaultFieldType, context.indexSettings(),
|
||||
@ -210,7 +219,7 @@ public class GeoPointFieldMapper extends FieldMapper implements ArrayValueMapper
|
||||
throw new UnsupportedOperationException("Parsing is implemented in parse(), this method should NEVER be called");
|
||||
}
|
||||
|
||||
public static class GeoPointFieldType extends MappedFieldType {
|
||||
public static class GeoPointFieldType extends AbstractSearchableGeometryFieldType {
|
||||
public GeoPointFieldType() {
|
||||
}
|
||||
|
||||
@ -245,7 +254,8 @@ public class GeoPointFieldMapper extends FieldMapper implements ArrayValueMapper
|
||||
|
||||
@Override
|
||||
public Query termQuery(Object value, QueryShardContext context) {
|
||||
throw new QueryShardException(context, "Geo fields do not support exact searching, use dedicated geo queries instead: ["
|
||||
throw new QueryShardException(context,
|
||||
"Geo fields do not support exact searching, use dedicated geo queries instead: ["
|
||||
+ name() + "]");
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import org.apache.lucene.document.LatLonShape;
|
||||
import org.apache.lucene.index.IndexableField;
|
||||
import org.elasticsearch.common.geo.GeoLineDecomposer;
|
||||
import org.elasticsearch.common.geo.GeoPolygonDecomposer;
|
||||
import org.elasticsearch.common.geo.GeoShapeType;
|
||||
import org.elasticsearch.geometry.Circle;
|
||||
import org.elasticsearch.geometry.Geometry;
|
||||
import org.elasticsearch.geometry.GeometryCollection;
|
||||
@ -64,7 +65,7 @@ public final class GeoShapeIndexer implements AbstractGeometryFieldMapper.Indexe
|
||||
return geometry.visit(new GeometryVisitor<Geometry, RuntimeException>() {
|
||||
@Override
|
||||
public Geometry visit(Circle circle) {
|
||||
throw new UnsupportedOperationException("CIRCLE geometry is not supported");
|
||||
throw new UnsupportedOperationException(GeoShapeType.CIRCLE + " geometry is not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -372,11 +372,9 @@ public abstract class AbstractGeometryQueryBuilder<QB extends AbstractGeometryQu
|
||||
}
|
||||
|
||||
/** list of content types this shape query is compatible with */
|
||||
protected abstract List validContentTypes();
|
||||
protected abstract List<String> validContentTypes();
|
||||
/** builds the appropriate lucene shape query */
|
||||
protected abstract Query buildShapeQuery(QueryShardContext context, MappedFieldType fieldType);
|
||||
/** returns expected content type for this query */
|
||||
protected abstract String queryFieldType();
|
||||
/** writes the xcontent specific to this shape query */
|
||||
protected abstract void doShapeQueryXContent(XContentBuilder builder, Params params) throws IOException;
|
||||
/** creates a new ShapeQueryBuilder from the provided field name and shape builder */
|
||||
@ -400,7 +398,9 @@ public abstract class AbstractGeometryQueryBuilder<QB extends AbstractGeometryQu
|
||||
if (ignoreUnmapped) {
|
||||
return new MatchNoDocsQuery();
|
||||
} else {
|
||||
throw new QueryShardException(context, "failed to find " + queryFieldType() + " field [" + fieldName + "]");
|
||||
throw new QueryShardException(context, "failed to find "
|
||||
+ String.join(" or ", validContentTypes())
|
||||
+ " field [" + fieldName + "]");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,12 +35,14 @@ import org.elasticsearch.common.logging.DeprecationLogger;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.geometry.Geometry;
|
||||
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper;
|
||||
import org.elasticsearch.index.mapper.AbstractSearchableGeometryFieldType;
|
||||
import org.elasticsearch.index.mapper.GeoPointFieldMapper;
|
||||
import org.elasticsearch.index.mapper.GeoShapeFieldMapper;
|
||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
@ -57,6 +59,12 @@ public class GeoShapeQueryBuilder extends AbstractGeometryQueryBuilder<GeoShapeQ
|
||||
|
||||
private SpatialStrategy strategy;
|
||||
|
||||
protected static final List<String> validContentTypes =
|
||||
Collections.unmodifiableList(
|
||||
Arrays.asList(
|
||||
GeoShapeFieldMapper.CONTENT_TYPE,
|
||||
GeoPointFieldMapper.CONTENT_TYPE));
|
||||
|
||||
/**
|
||||
* Creates a new GeoShapeQueryBuilder whose Query will be against the given
|
||||
* field name using the given Shape
|
||||
@ -181,13 +189,8 @@ public class GeoShapeQueryBuilder extends AbstractGeometryQueryBuilder<GeoShapeQ
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List validContentTypes() {
|
||||
return Arrays.asList(GeoShapeFieldMapper.CONTENT_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String queryFieldType() {
|
||||
return GeoShapeFieldMapper.CONTENT_TYPE;
|
||||
protected List<String> validContentTypes() {
|
||||
return validContentTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -210,12 +213,15 @@ public class GeoShapeQueryBuilder extends AbstractGeometryQueryBuilder<GeoShapeQ
|
||||
|
||||
@Override
|
||||
public Query buildShapeQuery(QueryShardContext context, MappedFieldType fieldType) {
|
||||
if (fieldType.typeName().equals(GeoShapeFieldMapper.CONTENT_TYPE) == false) {
|
||||
if (validContentTypes().contains(fieldType.typeName()) == false) {
|
||||
throw new QueryShardException(context,
|
||||
"Field [" + fieldName + "] is not of type [" + queryFieldType() + "] but of type [" + fieldType.typeName() + "]");
|
||||
"Field [" + fieldName + "] is of unsupported type [" + fieldType.typeName() + "]. ["
|
||||
+ NAME + "] query supports the following types ["
|
||||
+ String.join(",", validContentTypes()) + "]");
|
||||
}
|
||||
|
||||
final AbstractGeometryFieldMapper.AbstractGeometryFieldType ft = (AbstractGeometryFieldMapper.AbstractGeometryFieldType) fieldType;
|
||||
final AbstractSearchableGeometryFieldType ft =
|
||||
(AbstractSearchableGeometryFieldType) fieldType;
|
||||
return new ConstantScoreQuery(ft.geometryQueryBuilder().process(shape, fieldName, strategy, relation, context));
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,7 @@ import org.elasticsearch.geometry.Point;
|
||||
import org.elasticsearch.geometry.Polygon;
|
||||
import org.elasticsearch.geometry.Rectangle;
|
||||
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper;
|
||||
import org.elasticsearch.index.mapper.AbstractSearchableGeometryFieldType;
|
||||
import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper;
|
||||
import org.locationtech.jts.geom.Coordinate;
|
||||
import org.locationtech.spatial4j.shape.Shape;
|
||||
@ -62,7 +63,7 @@ import java.util.List;
|
||||
|
||||
import static org.elasticsearch.search.SearchService.ALLOW_EXPENSIVE_QUERIES;
|
||||
|
||||
public class LegacyGeoShapeQueryProcessor implements AbstractGeometryFieldMapper.QueryProcessor {
|
||||
public class LegacyGeoShapeQueryProcessor implements AbstractSearchableGeometryFieldType.QueryProcessor {
|
||||
|
||||
private AbstractGeometryFieldMapper.AbstractGeometryFieldType ft;
|
||||
|
||||
|
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.apache.lucene.document.LatLonDocValuesField;
|
||||
import org.apache.lucene.document.LatLonPoint;
|
||||
import org.apache.lucene.search.BooleanClause;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.search.IndexOrDocValuesQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.common.geo.GeoPolygonDecomposer;
|
||||
import org.elasticsearch.common.geo.GeoShapeType;
|
||||
import org.elasticsearch.common.geo.ShapeRelation;
|
||||
import org.elasticsearch.geometry.Circle;
|
||||
import org.elasticsearch.geometry.Geometry;
|
||||
import org.elasticsearch.geometry.GeometryCollection;
|
||||
import org.elasticsearch.geometry.GeometryVisitor;
|
||||
import org.elasticsearch.geometry.LinearRing;
|
||||
import org.elasticsearch.geometry.MultiLine;
|
||||
import org.elasticsearch.geometry.MultiPoint;
|
||||
import org.elasticsearch.geometry.MultiPolygon;
|
||||
import org.elasticsearch.geometry.Point;
|
||||
import org.elasticsearch.geometry.Polygon;
|
||||
import org.elasticsearch.geometry.Rectangle;
|
||||
import org.elasticsearch.geometry.ShapeType;
|
||||
import org.elasticsearch.index.mapper.AbstractSearchableGeometryFieldType;
|
||||
import org.elasticsearch.index.mapper.GeoPointFieldMapper;
|
||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static org.elasticsearch.index.mapper.GeoShapeIndexer.toLucenePolygon;
|
||||
|
||||
public class VectorGeoPointShapeQueryProcessor implements AbstractSearchableGeometryFieldType.QueryProcessor {
|
||||
|
||||
@Override
|
||||
public Query process(Geometry shape, String fieldName, ShapeRelation relation, QueryShardContext context) {
|
||||
validateIsGeoPointFieldType(fieldName, context);
|
||||
// geo points only support intersects
|
||||
if (relation != ShapeRelation.INTERSECTS) {
|
||||
throw new QueryShardException(context,
|
||||
relation+ " query relation not supported for Field [" + fieldName + "].");
|
||||
}
|
||||
// wrap geoQuery as a ConstantScoreQuery
|
||||
return getVectorQueryFromShape(shape, fieldName, relation, context);
|
||||
}
|
||||
|
||||
private void validateIsGeoPointFieldType(String fieldName, QueryShardContext context) {
|
||||
MappedFieldType fieldType = context.fieldMapper(fieldName);
|
||||
if (fieldType instanceof GeoPointFieldMapper.GeoPointFieldType == false) {
|
||||
throw new QueryShardException(context, "Expected " + GeoPointFieldMapper.CONTENT_TYPE
|
||||
+ " field type for Field [" + fieldName + "] but found " + fieldType.typeName());
|
||||
}
|
||||
}
|
||||
|
||||
protected Query getVectorQueryFromShape(
|
||||
Geometry queryShape, String fieldName, ShapeRelation relation, QueryShardContext context) {
|
||||
ShapeVisitor shapeVisitor = new ShapeVisitor(context, fieldName, relation);
|
||||
return queryShape.visit(shapeVisitor);
|
||||
}
|
||||
|
||||
private class ShapeVisitor implements GeometryVisitor<Query, RuntimeException> {
|
||||
QueryShardContext context;
|
||||
MappedFieldType fieldType;
|
||||
String fieldName;
|
||||
ShapeRelation relation;
|
||||
|
||||
ShapeVisitor(QueryShardContext context, String fieldName, ShapeRelation relation) {
|
||||
this.context = context;
|
||||
this.fieldType = context.fieldMapper(fieldName);
|
||||
this.fieldName = fieldName;
|
||||
this.relation = relation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query visit(Circle circle) {
|
||||
Query query = LatLonPoint.newDistanceQuery(
|
||||
fieldName, circle.getLat(), circle.getLon(), circle.getRadiusMeters());
|
||||
if (fieldType.hasDocValues()) {
|
||||
Query dvQuery = LatLonDocValuesField.newSlowDistanceQuery(
|
||||
fieldName, circle.getLat(), circle.getLon(), circle.getRadiusMeters());
|
||||
query = new IndexOrDocValuesQuery(query, dvQuery);
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query visit(GeometryCollection<?> collection) {
|
||||
BooleanQuery.Builder bqb = new BooleanQuery.Builder();
|
||||
visit(bqb, collection);
|
||||
return bqb.build();
|
||||
}
|
||||
|
||||
private void visit(BooleanQuery.Builder bqb, GeometryCollection<?> collection) {
|
||||
BooleanClause.Occur occur = BooleanClause.Occur.FILTER;
|
||||
for (Geometry shape : collection) {
|
||||
bqb.add(shape.visit(this), occur);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query visit(org.elasticsearch.geometry.Line line) {
|
||||
throw new QueryShardException(context, "Field [" + fieldName + "] does not support "
|
||||
+ GeoShapeType.LINESTRING + " queries");
|
||||
}
|
||||
|
||||
@Override
|
||||
// don't think this is called directly
|
||||
public Query visit(LinearRing ring) {
|
||||
throw new QueryShardException(context, "Field [" + fieldName + "] does not support "
|
||||
+ ShapeType.LINEARRING + " queries");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query visit(MultiLine multiLine) {
|
||||
throw new QueryShardException(context, "Field [" + fieldName + "] does not support "
|
||||
+ GeoShapeType.MULTILINESTRING + " queries");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query visit(MultiPoint multiPoint) {
|
||||
throw new QueryShardException(context, "Field [" + fieldName + "] does not support "
|
||||
+ GeoShapeType.MULTIPOINT + " queries");
|
||||
}
|
||||
|
||||
// helper for visit(MultiPolygon multiPolygon) and visit(Polygon polygon)
|
||||
private Query visit(ArrayList<Polygon> collector) {
|
||||
org.apache.lucene.geo.Polygon[] lucenePolygons =
|
||||
new org.apache.lucene.geo.Polygon[collector.size()];
|
||||
for (int i = 0; i < collector.size(); i++) {
|
||||
lucenePolygons[i] = toLucenePolygon(collector.get(i));
|
||||
}
|
||||
Query query = LatLonPoint.newPolygonQuery(fieldName, lucenePolygons);
|
||||
if (fieldType.hasDocValues()) {
|
||||
Query dvQuery = LatLonDocValuesField.newSlowPolygonQuery(fieldName, lucenePolygons);
|
||||
query = new IndexOrDocValuesQuery(query, dvQuery);
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query visit(MultiPolygon multiPolygon) {
|
||||
ArrayList<org.elasticsearch.geometry.Polygon> collector = new ArrayList<>();
|
||||
GeoPolygonDecomposer.decomposeMultiPolygon(multiPolygon, true, collector);
|
||||
return visit(collector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query visit(Point point) {
|
||||
// not currently supported
|
||||
throw new QueryShardException(context, "Field [" + fieldName + "] does not support " + GeoShapeType.POINT +
|
||||
" queries");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query visit(Polygon polygon) {
|
||||
ArrayList<org.elasticsearch.geometry.Polygon> collector = new ArrayList<>();
|
||||
GeoPolygonDecomposer.decomposePolygon(polygon, true, collector);
|
||||
return visit(collector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query visit(Rectangle r) {
|
||||
Query query = LatLonPoint.newBoxQuery(fieldName, r.getMinY(), r.getMaxY(), r.getMinX(), r.getMaxX());
|
||||
if (fieldType.hasDocValues()) {
|
||||
Query dvQuery = LatLonDocValuesField.newSlowBoxQuery(
|
||||
fieldName, r.getMinY(), r.getMaxY(), r.getMinX(), r.getMaxX());
|
||||
query = new IndexOrDocValuesQuery(query, dvQuery);
|
||||
}
|
||||
return query;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,14 +39,14 @@ import org.elasticsearch.geometry.MultiPoint;
|
||||
import org.elasticsearch.geometry.MultiPolygon;
|
||||
import org.elasticsearch.geometry.Point;
|
||||
import org.elasticsearch.geometry.Rectangle;
|
||||
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper;
|
||||
import org.elasticsearch.index.mapper.AbstractSearchableGeometryFieldType;
|
||||
import org.elasticsearch.index.mapper.GeoShapeFieldMapper;
|
||||
import org.elasticsearch.index.mapper.GeoShapeIndexer;
|
||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||
|
||||
import static org.elasticsearch.index.mapper.GeoShapeIndexer.toLucenePolygon;
|
||||
|
||||
public class VectorGeoShapeQueryProcessor implements AbstractGeometryFieldMapper.QueryProcessor {
|
||||
public class VectorGeoShapeQueryProcessor implements AbstractSearchableGeometryFieldType.QueryProcessor {
|
||||
|
||||
@Override
|
||||
public Query process(Geometry shape, String fieldName, ShapeRelation relation, QueryShardContext context) {
|
||||
@ -59,7 +59,8 @@ public class VectorGeoShapeQueryProcessor implements AbstractGeometryFieldMapper
|
||||
return getVectorQueryFromShape(shape, fieldName, relation, context);
|
||||
}
|
||||
|
||||
protected Query getVectorQueryFromShape(Geometry queryShape, String fieldName, ShapeRelation relation, QueryShardContext context) {
|
||||
protected Query getVectorQueryFromShape(
|
||||
Geometry queryShape, String fieldName, ShapeRelation relation, QueryShardContext context) {
|
||||
GeoShapeIndexer geometryIndexer = new GeoShapeIndexer(true, fieldName);
|
||||
|
||||
Geometry processedShape = geometryIndexer.prepareForIndexing(queryShape);
|
||||
@ -85,7 +86,7 @@ public class VectorGeoShapeQueryProcessor implements AbstractGeometryFieldMapper
|
||||
|
||||
@Override
|
||||
public Query visit(Circle circle) {
|
||||
throw new QueryShardException(context, "Field [" + fieldName + "] found and unknown shape Circle");
|
||||
throw new QueryShardException(context, "Field [" + fieldName + "] found an unknown shape Circle");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -117,7 +118,7 @@ public class VectorGeoShapeQueryProcessor implements AbstractGeometryFieldMapper
|
||||
|
||||
@Override
|
||||
public Query visit(LinearRing ring) {
|
||||
throw new QueryShardException(context, "Field [" + fieldName + "] found and unsupported shape LinearRing");
|
||||
throw new QueryShardException(context, "Field [" + fieldName + "] found an unsupported shape LinearRing");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -35,7 +35,6 @@ import org.elasticsearch.geometry.Point;
|
||||
import org.elasticsearch.geometry.Polygon;
|
||||
import org.elasticsearch.index.mapper.GeoShapeIndexer;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
@ -52,7 +51,7 @@ public class GeometryIndexerTests extends ESTestCase {
|
||||
public void testCircle() {
|
||||
UnsupportedOperationException ex =
|
||||
expectThrows(UnsupportedOperationException.class, () -> indexer.prepareForIndexing(new Circle(2, 1, 3)));
|
||||
assertEquals("CIRCLE geometry is not supported", ex.getMessage());
|
||||
assertEquals(GeoShapeType.CIRCLE + " geometry is not supported", ex.getMessage());
|
||||
}
|
||||
|
||||
public void testCollection() {
|
||||
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.elasticsearch.common.geo.ShapeRelation;
|
||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
||||
import org.elasticsearch.test.geo.RandomShapeGenerator;
|
||||
|
||||
public class GeoShapeQueryBuilderGeoPointTests extends GeoShapeQueryBuilderTests {
|
||||
|
||||
protected String fieldName() {
|
||||
return GEO_POINT_FIELD_NAME;
|
||||
}
|
||||
|
||||
protected GeoShapeQueryBuilder doCreateTestQueryBuilder(boolean indexedShape) {
|
||||
RandomShapeGenerator.ShapeType shapeType = RandomShapeGenerator.ShapeType.POLYGON;
|
||||
ShapeBuilder<?, ?, ?> shape = RandomShapeGenerator.createShapeWithin(random(), null, shapeType);
|
||||
GeoShapeQueryBuilder builder;
|
||||
clearShapeFields();
|
||||
if (indexedShape == false) {
|
||||
builder = new GeoShapeQueryBuilder(fieldName(), shape);
|
||||
} else {
|
||||
indexedShapeToReturn = shape;
|
||||
indexedShapeId = randomAlphaOfLengthBetween(3, 20);
|
||||
builder = new GeoShapeQueryBuilder(fieldName(), indexedShapeId);
|
||||
if (randomBoolean()) {
|
||||
indexedShapeIndex = randomAlphaOfLengthBetween(3, 20);
|
||||
builder.indexedShapeIndex(indexedShapeIndex);
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
indexedShapePath = randomAlphaOfLengthBetween(3, 20);
|
||||
builder.indexedShapePath(indexedShapePath);
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
indexedShapeRouting = randomAlphaOfLengthBetween(3, 20);
|
||||
builder.indexedShapeRouting(indexedShapeRouting);
|
||||
}
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
builder.relation(randomFrom(ShapeRelation.INTERSECTS));
|
||||
}
|
||||
|
||||
if (randomBoolean()) {
|
||||
builder.ignoreUnmapped(randomBoolean());
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.geo.ShapeRelation;
|
||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
||||
import org.elasticsearch.test.geo.RandomShapeGenerator;
|
||||
|
||||
public class GeoShapeQueryBuilderGeoShapeTests extends GeoShapeQueryBuilderTests {
|
||||
|
||||
protected String fieldName() {
|
||||
return GEO_SHAPE_FIELD_NAME;
|
||||
}
|
||||
|
||||
protected GeoShapeQueryBuilder doCreateTestQueryBuilder(boolean indexedShape) {
|
||||
RandomShapeGenerator.ShapeType shapeType = randomFrom(
|
||||
RandomShapeGenerator.ShapeType.POINT,
|
||||
RandomShapeGenerator.ShapeType.MULTIPOINT,
|
||||
RandomShapeGenerator.ShapeType.LINESTRING,
|
||||
RandomShapeGenerator.ShapeType.MULTILINESTRING,
|
||||
RandomShapeGenerator.ShapeType.POLYGON);
|
||||
ShapeBuilder<?, ?, ?> shape = RandomShapeGenerator.createShapeWithin(random(), null, shapeType);
|
||||
GeoShapeQueryBuilder builder;
|
||||
clearShapeFields();
|
||||
if (indexedShape == false) {
|
||||
builder = new GeoShapeQueryBuilder(fieldName(), shape);
|
||||
} else {
|
||||
indexedShapeToReturn = shape;
|
||||
indexedShapeId = randomAlphaOfLengthBetween(3, 20);
|
||||
builder = new GeoShapeQueryBuilder(fieldName(), indexedShapeId);
|
||||
if (randomBoolean()) {
|
||||
indexedShapeIndex = randomAlphaOfLengthBetween(3, 20);
|
||||
builder.indexedShapeIndex(indexedShapeIndex);
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
indexedShapePath = randomAlphaOfLengthBetween(3, 20);
|
||||
builder.indexedShapePath(indexedShapePath);
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
indexedShapeRouting = randomAlphaOfLengthBetween(3, 20);
|
||||
builder.indexedShapeRouting(indexedShapeRouting);
|
||||
}
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
QueryShardContext context = createShardContext();
|
||||
if (context.indexVersionCreated().onOrAfter(Version.V_7_5_0)) { // CONTAINS is only supported from version 7.5
|
||||
if (shapeType == RandomShapeGenerator.ShapeType.LINESTRING || shapeType == RandomShapeGenerator.ShapeType.MULTILINESTRING) {
|
||||
builder.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.INTERSECTS, ShapeRelation.CONTAINS));
|
||||
} else {
|
||||
builder.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.INTERSECTS,
|
||||
ShapeRelation.WITHIN, ShapeRelation.CONTAINS));
|
||||
}
|
||||
} else {
|
||||
if (shapeType == RandomShapeGenerator.ShapeType.LINESTRING || shapeType == RandomShapeGenerator.ShapeType.MULTILINESTRING) {
|
||||
builder.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.INTERSECTS));
|
||||
} else {
|
||||
builder.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.INTERSECTS, ShapeRelation.WITHIN));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (randomBoolean()) {
|
||||
builder.ignoreUnmapped(randomBoolean());
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
@ -29,7 +29,6 @@ import org.elasticsearch.action.get.GetResponse;
|
||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.bytes.BytesArray;
|
||||
import org.elasticsearch.common.geo.ShapeRelation;
|
||||
import org.elasticsearch.common.geo.builders.EnvelopeBuilder;
|
||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
||||
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
||||
@ -49,13 +48,15 @@ import org.locationtech.jts.geom.Coordinate;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.apache.lucene.util.LuceneTestCase.random;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.anyOf;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.matchesPattern;
|
||||
|
||||
public class GeoShapeQueryBuilderTests extends AbstractQueryTestCase<GeoShapeQueryBuilder> {
|
||||
public abstract class GeoShapeQueryBuilderTests extends AbstractQueryTestCase<GeoShapeQueryBuilder> {
|
||||
|
||||
protected static String indexedShapeId;
|
||||
protected static String indexedShapeType;
|
||||
@ -64,9 +65,7 @@ public class GeoShapeQueryBuilderTests extends AbstractQueryTestCase<GeoShapeQue
|
||||
protected static String indexedShapeRouting;
|
||||
protected static ShapeBuilder<?, ?, ?> indexedShapeToReturn;
|
||||
|
||||
protected String fieldName() {
|
||||
return GEO_SHAPE_FIELD_NAME;
|
||||
}
|
||||
protected abstract String fieldName();
|
||||
|
||||
@Override
|
||||
protected Settings createTestIndexSettings() {
|
||||
@ -83,55 +82,7 @@ public class GeoShapeQueryBuilderTests extends AbstractQueryTestCase<GeoShapeQue
|
||||
return doCreateTestQueryBuilder(randomBoolean());
|
||||
}
|
||||
|
||||
protected GeoShapeQueryBuilder doCreateTestQueryBuilder(boolean indexedShape) {
|
||||
RandomShapeGenerator.ShapeType shapeType =
|
||||
randomFrom(ShapeType.POINT, ShapeType.MULTIPOINT, ShapeType.LINESTRING, ShapeType.MULTILINESTRING, ShapeType.POLYGON);
|
||||
ShapeBuilder<?, ?, ?> shape = RandomShapeGenerator.createShapeWithin(random(), null, shapeType);
|
||||
GeoShapeQueryBuilder builder;
|
||||
clearShapeFields();
|
||||
if (indexedShape == false) {
|
||||
builder = new GeoShapeQueryBuilder(fieldName(), shape);
|
||||
} else {
|
||||
indexedShapeToReturn = shape;
|
||||
indexedShapeId = randomAlphaOfLengthBetween(3, 20);
|
||||
indexedShapeType = randomBoolean() ? randomAlphaOfLengthBetween(3, 20) : null;
|
||||
builder = new GeoShapeQueryBuilder(fieldName(), indexedShapeId, indexedShapeType);
|
||||
if (randomBoolean()) {
|
||||
indexedShapeIndex = randomAlphaOfLengthBetween(3, 20);
|
||||
builder.indexedShapeIndex(indexedShapeIndex);
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
indexedShapePath = randomAlphaOfLengthBetween(3, 20);
|
||||
builder.indexedShapePath(indexedShapePath);
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
indexedShapeRouting = randomAlphaOfLengthBetween(3, 20);
|
||||
builder.indexedShapeRouting(indexedShapeRouting);
|
||||
}
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
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 {
|
||||
if (shapeType == ShapeType.LINESTRING || shapeType == ShapeType.MULTILINESTRING) {
|
||||
builder.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.INTERSECTS));
|
||||
} else {
|
||||
builder.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.INTERSECTS, ShapeRelation.WITHIN));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (randomBoolean()) {
|
||||
builder.ignoreUnmapped(randomBoolean());
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
abstract GeoShapeQueryBuilder doCreateTestQueryBuilder(boolean indexedShape);
|
||||
|
||||
@Override
|
||||
protected GetResponse executeGet(GetRequest getRequest) {
|
||||
@ -282,7 +233,7 @@ public class GeoShapeQueryBuilderTests extends AbstractQueryTestCase<GeoShapeQue
|
||||
new GeoShapeQueryBuilder("unmapped", shape.buildGeometry());
|
||||
failingQueryBuilder.ignoreUnmapped(false);
|
||||
QueryShardException e = expectThrows(QueryShardException.class, () -> failingQueryBuilder.toQuery(createShardContext()));
|
||||
assertThat(e.getMessage(), containsString("failed to find geo_shape field [unmapped]"));
|
||||
assertThat(e.getMessage(), matchesPattern("failed to find .*geo_shape.* field \\[unmapped\\]"));
|
||||
}
|
||||
|
||||
public void testWrongFieldType() throws IOException {
|
||||
@ -292,7 +243,8 @@ public class GeoShapeQueryBuilderTests extends AbstractQueryTestCase<GeoShapeQue
|
||||
new GeoShapeQueryBuilder(STRING_FIELD_NAME, shape) :
|
||||
new GeoShapeQueryBuilder(STRING_FIELD_NAME, shape.buildGeometry());
|
||||
QueryShardException e = expectThrows(QueryShardException.class, () -> queryBuilder.toQuery(createShardContext()));
|
||||
assertThat(e.getMessage(), containsString("Field [mapped_string] is not of type [geo_shape] but of type [text]"));
|
||||
assertThat(e.getMessage(), matchesPattern("Field \\[mapped_string\\] is of unsupported type \\[text\\]." +
|
||||
" \\[geo_shape\\] query supports the following types \\[.*geo_shape.*\\]"));
|
||||
}
|
||||
|
||||
public void testSerializationFailsUnlessFetched() throws IOException {
|
||||
|
@ -19,8 +19,28 @@
|
||||
|
||||
package org.elasticsearch.search.geo;
|
||||
|
||||
import org.elasticsearch.action.search.SearchAction;
|
||||
import org.elasticsearch.action.search.SearchPhaseExecutionException;
|
||||
import org.elasticsearch.action.search.SearchRequestBuilder;
|
||||
import org.elasticsearch.common.geo.GeoShapeType;
|
||||
import org.elasticsearch.common.geo.ShapeRelation;
|
||||
import org.elasticsearch.common.geo.builders.CoordinatesBuilder;
|
||||
import org.elasticsearch.common.geo.builders.LineStringBuilder;
|
||||
import org.elasticsearch.common.geo.builders.MultiLineStringBuilder;
|
||||
import org.elasticsearch.common.geo.builders.MultiPointBuilder;
|
||||
import org.elasticsearch.common.geo.builders.PointBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.geometry.Line;
|
||||
import org.elasticsearch.geometry.LinearRing;
|
||||
import org.elasticsearch.geometry.MultiLine;
|
||||
import org.elasticsearch.geometry.MultiPoint;
|
||||
import org.elasticsearch.geometry.Point;
|
||||
import org.elasticsearch.geometry.Rectangle;
|
||||
import org.elasticsearch.index.query.GeoShapeQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
||||
public class GeoPointShapeQueryTests extends GeoQueryTests {
|
||||
|
||||
@ -37,16 +57,130 @@ public class GeoPointShapeQueryTests extends GeoQueryTests {
|
||||
@Override
|
||||
protected XContentBuilder createDefaultMapping() throws Exception {
|
||||
XContentBuilder xcb = XContentFactory.jsonBuilder().startObject()
|
||||
.startObject("properties").startObject("location")
|
||||
.startObject("properties").startObject(defaultGeoFieldName)
|
||||
.field("type", "geo_point")
|
||||
.endObject().endObject().endObject();
|
||||
|
||||
return xcb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testIndexPointsFilterRectangle(String mapping) throws Exception {
|
||||
//super.testIndexPointsFilterRectangle(Strings.toString(createDefaultMapping()));
|
||||
public void testProcessRelationSupport() throws Exception {
|
||||
XContentBuilder xcb = createDefaultMapping();
|
||||
client().admin().indices().prepareCreate("test").addMapping("_doc", xcb).get();
|
||||
ensureGreen();
|
||||
|
||||
Rectangle rectangle = new Rectangle(-35, -25, -25, -35);
|
||||
|
||||
for (ShapeRelation shapeRelation : ShapeRelation.values()) {
|
||||
if (shapeRelation.equals(ShapeRelation.INTERSECTS) == false) {
|
||||
try {
|
||||
client().prepareSearch("test")
|
||||
.setQuery(QueryBuilders.geoShapeQuery(defaultGeoFieldName, rectangle)
|
||||
.relation(shapeRelation))
|
||||
.get();
|
||||
} catch (SearchPhaseExecutionException e) {
|
||||
assertThat(e.getCause().getMessage(),
|
||||
containsString(shapeRelation
|
||||
+ " query relation not supported for Field [" + defaultGeoFieldName + "]"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testQueryLine() throws Exception {
|
||||
XContentBuilder xcb = createDefaultMapping();
|
||||
client().admin().indices().prepareCreate("test").addMapping("_doc", xcb).get();
|
||||
ensureGreen();
|
||||
|
||||
Line line = new Line(new double[]{-25, -25}, new double[]{-35, -35});
|
||||
|
||||
try {
|
||||
client().prepareSearch("test")
|
||||
.setQuery(QueryBuilders.geoShapeQuery(defaultGeoFieldName, line)).get();
|
||||
} catch (
|
||||
SearchPhaseExecutionException e) {
|
||||
assertThat(e.getCause().getMessage(),
|
||||
containsString("does not support " + GeoShapeType.LINESTRING + " queries"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testQueryLinearRing() throws Exception {
|
||||
XContentBuilder xcb = createDefaultMapping();
|
||||
client().admin().indices().prepareCreate("test").addMapping("_doc", xcb).get();
|
||||
ensureGreen();
|
||||
|
||||
LinearRing linearRing = new LinearRing(new double[]{-25,-35,-25}, new double[]{-25,-35,-25});
|
||||
|
||||
try {
|
||||
// LinearRing extends Line implements Geometry: expose the build process
|
||||
GeoShapeQueryBuilder queryBuilder = new GeoShapeQueryBuilder(defaultGeoFieldName, linearRing);
|
||||
SearchRequestBuilder searchRequestBuilder = new SearchRequestBuilder(client(), SearchAction.INSTANCE);
|
||||
searchRequestBuilder.setQuery(queryBuilder);
|
||||
searchRequestBuilder.setIndices("test");
|
||||
searchRequestBuilder.get();
|
||||
} catch (
|
||||
SearchPhaseExecutionException e) {
|
||||
assertThat(e.getCause().getMessage(),
|
||||
containsString("Field [" + defaultGeoFieldName + "] does not support LINEARRING queries"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testQueryMultiLine() throws Exception {
|
||||
XContentBuilder xcb = createDefaultMapping();
|
||||
client().admin().indices().prepareCreate("test").addMapping("_doc", xcb).get();
|
||||
ensureGreen();
|
||||
|
||||
CoordinatesBuilder coords1 = new CoordinatesBuilder()
|
||||
.coordinate(-35,-35)
|
||||
.coordinate(-25,-25);
|
||||
CoordinatesBuilder coords2 = new CoordinatesBuilder()
|
||||
.coordinate(-15,-15)
|
||||
.coordinate(-5,-5);
|
||||
LineStringBuilder lsb1 = new LineStringBuilder(coords1);
|
||||
LineStringBuilder lsb2 = new LineStringBuilder(coords2);
|
||||
MultiLineStringBuilder mlb = new MultiLineStringBuilder().linestring(lsb1).linestring(lsb2);
|
||||
MultiLine multiline = (MultiLine) mlb.buildGeometry();
|
||||
|
||||
try {
|
||||
client().prepareSearch("test")
|
||||
.setQuery(QueryBuilders.geoShapeQuery(defaultGeoFieldName, multiline)).get();
|
||||
} catch (Exception e) {
|
||||
assertThat(e.getCause().getMessage(),
|
||||
containsString("does not support " + GeoShapeType.MULTILINESTRING + " queries"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testQueryMultiPoint() throws Exception {
|
||||
XContentBuilder xcb = createDefaultMapping();
|
||||
client().admin().indices().prepareCreate("test").addMapping("_doc", xcb).get();
|
||||
ensureGreen();
|
||||
|
||||
MultiPointBuilder mpb = new MultiPointBuilder().coordinate(-35,-25).coordinate(-15,-5);
|
||||
MultiPoint multiPoint = mpb.buildGeometry();
|
||||
|
||||
try {
|
||||
client().prepareSearch("test")
|
||||
.setQuery(QueryBuilders.geoShapeQuery(defaultGeoFieldName, multiPoint)).get();
|
||||
} catch (Exception e) {
|
||||
assertThat(e.getCause().getMessage(),
|
||||
containsString("does not support " + GeoShapeType.MULTIPOINT + " queries"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testQueryPoint() throws Exception {
|
||||
XContentBuilder xcb = createDefaultMapping();
|
||||
client().admin().indices().prepareCreate("test").addMapping("_doc", xcb).get();
|
||||
ensureGreen();
|
||||
|
||||
PointBuilder pb = new PointBuilder().coordinate(-35, -25);
|
||||
Point point = pb.buildGeometry();
|
||||
|
||||
try {
|
||||
client().prepareSearch("test")
|
||||
.setQuery(QueryBuilders.geoShapeQuery(defaultGeoFieldName, point)).get();
|
||||
} catch (Exception e) {
|
||||
assertThat(e.getCause().getMessage(),
|
||||
containsString("does not support " + GeoShapeType.POINT + " queries"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,78 +21,421 @@ package org.elasticsearch.search.geo;
|
||||
|
||||
import org.elasticsearch.action.get.GetResponse;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.geo.GeoShapeType;
|
||||
import org.elasticsearch.common.geo.ShapeRelation;
|
||||
import org.elasticsearch.common.geo.builders.CircleBuilder;
|
||||
import org.elasticsearch.common.geo.builders.CoordinatesBuilder;
|
||||
import org.elasticsearch.common.geo.builders.EnvelopeBuilder;
|
||||
import org.elasticsearch.common.geo.builders.GeometryCollectionBuilder;
|
||||
import org.elasticsearch.common.geo.builders.MultiPolygonBuilder;
|
||||
import org.elasticsearch.common.geo.builders.PolygonBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.geometry.Geometry;
|
||||
import org.elasticsearch.geometry.Rectangle;
|
||||
import org.elasticsearch.index.query.GeoShapeQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.search.SearchHits;
|
||||
import org.elasticsearch.test.ESSingleNodeTestCase;
|
||||
import org.locationtech.jts.geom.Coordinate;
|
||||
|
||||
import static org.elasticsearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE;
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.geoIntersectionQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.geoShapeQuery;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
|
||||
public abstract class GeoQueryTests extends ESSingleNodeTestCase {
|
||||
|
||||
|
||||
protected abstract XContentBuilder createTypedMapping() throws Exception;
|
||||
|
||||
protected abstract XContentBuilder createDefaultMapping() throws Exception;
|
||||
|
||||
static String defaultGeoFieldName = "geo";
|
||||
static String defaultIndexName = "test";
|
||||
|
||||
public void testNullShape() throws Exception {
|
||||
String mapping = Strings.toString(createTypedMapping());
|
||||
client().admin().indices().prepareCreate("test").addMapping("type1", mapping, XContentType.JSON).get();
|
||||
XContentBuilder xcb = createDefaultMapping();
|
||||
client().admin().indices().prepareCreate(defaultIndexName).addMapping("_doc", xcb).get();
|
||||
ensureGreen();
|
||||
|
||||
client().prepareIndex("test", "type1", "aNullshape").setSource("{\"location\": null}", XContentType.JSON)
|
||||
client().prepareIndex(defaultIndexName,"_doc")
|
||||
.setId("aNullshape")
|
||||
.setSource("{\"geo\": null}", XContentType.JSON)
|
||||
.setRefreshPolicy(IMMEDIATE).get();
|
||||
GetResponse result = client().prepareGet("test", "type1", "aNullshape").get();
|
||||
GetResponse result = client().prepareGet(defaultIndexName,"_doc","aNullshape").get();
|
||||
assertThat(result.getField("location"), nullValue());
|
||||
}
|
||||
|
||||
public void testIndexPointsFilterRectangle(String mapping) throws Exception {
|
||||
client().admin().indices().prepareCreate("test").addMapping("type1", mapping, XContentType.JSON).get();
|
||||
public void testIndexPointsFilterRectangle() throws Exception {
|
||||
XContentBuilder xcb = createDefaultMapping();
|
||||
client().admin().indices().prepareCreate(defaultIndexName).addMapping("_doc", xcb).get();
|
||||
ensureGreen();
|
||||
|
||||
client().prepareIndex("test", "type1", "1").setSource(jsonBuilder().startObject()
|
||||
.field("name", "Document 1")
|
||||
.startObject("geo")
|
||||
.field("type", "point")
|
||||
.startArray("coordinates").value(-30).value(-30).endArray()
|
||||
.endObject()
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("1").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field("name", "Document 1")
|
||||
.field(defaultGeoFieldName, "POINT(-30 -30)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
client().prepareIndex("test", "type1", "2").setSource(jsonBuilder().startObject()
|
||||
.field("name", "Document 2")
|
||||
.startObject("geo")
|
||||
.field("type", "point")
|
||||
.startArray("coordinates").value(-45).value(-50).endArray()
|
||||
.endObject()
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("2").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field("name", "Document 2")
|
||||
.field(defaultGeoFieldName, "POINT(-45 -50)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
EnvelopeBuilder shape = new EnvelopeBuilder(new Coordinate(-45, 45), new Coordinate(45, -45));
|
||||
|
||||
SearchResponse searchResponse = client().prepareSearch("test")
|
||||
.setQuery(geoIntersectionQuery("geo", shape))
|
||||
GeometryCollectionBuilder builder = new GeometryCollectionBuilder().shape(shape);
|
||||
Geometry geometry = builder.buildGeometry().get(0);
|
||||
SearchResponse searchResponse = client().prepareSearch(defaultIndexName)
|
||||
.setQuery(QueryBuilders.geoShapeQuery(defaultGeoFieldName, geometry)
|
||||
.relation(ShapeRelation.INTERSECTS))
|
||||
.get();
|
||||
|
||||
assertSearchResponse(searchResponse);
|
||||
assertThat(searchResponse.getHits().getTotalHits().value, equalTo(1L));
|
||||
assertThat(searchResponse.getHits().getHits().length, equalTo(1));
|
||||
assertHitCount(searchResponse, 1);
|
||||
assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("1"));
|
||||
|
||||
searchResponse = client().prepareSearch("test")
|
||||
.setQuery(geoShapeQuery("geo", shape))
|
||||
// default query, without specifying relation (expect intersects)
|
||||
searchResponse = client().prepareSearch(defaultIndexName)
|
||||
.setQuery(QueryBuilders.geoShapeQuery(defaultGeoFieldName, geometry))
|
||||
.get();
|
||||
|
||||
assertSearchResponse(searchResponse);
|
||||
assertThat(searchResponse.getHits().getTotalHits().value, equalTo(1L));
|
||||
assertThat(searchResponse.getHits().getHits().length, equalTo(1));
|
||||
assertHitCount(searchResponse, 1);
|
||||
assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("1"));
|
||||
}
|
||||
|
||||
public void testIndexPointsCircle() throws Exception {
|
||||
XContentBuilder xcb = createDefaultMapping();
|
||||
client().admin().indices().prepareCreate(defaultIndexName).addMapping("_doc", xcb).get();
|
||||
ensureGreen();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("1").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field("name", "Document 1")
|
||||
.field(defaultGeoFieldName, "POINT(-30 -30)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("2").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field("name", "Document 2")
|
||||
.field(defaultGeoFieldName, "POINT(-45 -50)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
CircleBuilder shape = new CircleBuilder().center(new Coordinate(-30, -30)).radius("100m");
|
||||
GeometryCollectionBuilder builder = new GeometryCollectionBuilder().shape(shape);
|
||||
Geometry geometry = builder.buildGeometry().get(0);
|
||||
|
||||
try {
|
||||
client().prepareSearch(defaultIndexName)
|
||||
.setQuery(QueryBuilders.geoShapeQuery(defaultGeoFieldName, geometry)
|
||||
.relation(ShapeRelation.INTERSECTS))
|
||||
.get();
|
||||
} catch (
|
||||
Exception e) {
|
||||
assertThat(e.getCause().getMessage(),
|
||||
containsString("failed to create query: "
|
||||
+ GeoShapeType.CIRCLE + " geometry is not supported"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testIndexPointsPolygon() throws Exception {
|
||||
XContentBuilder xcb = createDefaultMapping();
|
||||
client().admin().indices().prepareCreate(defaultIndexName).addMapping("_doc", xcb).get();
|
||||
ensureGreen();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("1").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field(defaultGeoFieldName, "POINT(-30 -30)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("2").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field(defaultGeoFieldName, "POINT(-45 -50)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
CoordinatesBuilder cb = new CoordinatesBuilder();
|
||||
cb.coordinate(new Coordinate(-35, -35))
|
||||
.coordinate(new Coordinate(-35, -25))
|
||||
.coordinate(new Coordinate(-25, -25))
|
||||
.coordinate(new Coordinate(-25, -35))
|
||||
.coordinate(new Coordinate(-35, -35));
|
||||
PolygonBuilder shape = new PolygonBuilder(cb);
|
||||
GeometryCollectionBuilder builder = new GeometryCollectionBuilder().shape(shape);
|
||||
Geometry geometry = builder.buildGeometry();
|
||||
SearchResponse searchResponse = client().prepareSearch(defaultIndexName)
|
||||
.setQuery(QueryBuilders.geoShapeQuery(defaultGeoFieldName, geometry)
|
||||
.relation(ShapeRelation.INTERSECTS))
|
||||
.get();
|
||||
|
||||
assertSearchResponse(searchResponse);
|
||||
assertHitCount(searchResponse, 1);
|
||||
SearchHits searchHits = searchResponse.getHits();
|
||||
assertThat(searchHits.getAt(0).getId(), equalTo("1"));
|
||||
}
|
||||
|
||||
public void testIndexPointsMultiPolygon() throws Exception {
|
||||
XContentBuilder xcb = createDefaultMapping();
|
||||
client().admin().indices().prepareCreate(defaultIndexName).addMapping("_doc", xcb).get();
|
||||
ensureGreen();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("1").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field("name", "Document 1")
|
||||
.field(defaultGeoFieldName, "POINT(-30 -30)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("2").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field("name", "Document 2")
|
||||
.field(defaultGeoFieldName, "POINT(-40 -40)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("3").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field("name", "Document 3")
|
||||
.field(defaultGeoFieldName, "POINT(-50 -50)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
CoordinatesBuilder encloseDocument1Cb = new CoordinatesBuilder();
|
||||
encloseDocument1Cb.coordinate(new Coordinate(-35, -35))
|
||||
.coordinate(new Coordinate(-35, -25))
|
||||
.coordinate(new Coordinate(-25, -25))
|
||||
.coordinate(new Coordinate(-25, -35))
|
||||
.coordinate(new Coordinate(-35, -35));
|
||||
PolygonBuilder encloseDocument1Shape = new PolygonBuilder(encloseDocument1Cb);
|
||||
|
||||
CoordinatesBuilder encloseDocument2Cb = new CoordinatesBuilder();
|
||||
encloseDocument2Cb.coordinate(new Coordinate(-55, -55))
|
||||
.coordinate(new Coordinate(-55, -45))
|
||||
.coordinate(new Coordinate(-45, -45))
|
||||
.coordinate(new Coordinate(-45, -55))
|
||||
.coordinate(new Coordinate(-55, -55));
|
||||
PolygonBuilder encloseDocument2Shape = new PolygonBuilder(encloseDocument2Cb);
|
||||
|
||||
MultiPolygonBuilder mp = new MultiPolygonBuilder();
|
||||
mp.polygon(encloseDocument1Shape).polygon(encloseDocument2Shape);
|
||||
|
||||
GeometryCollectionBuilder builder = new GeometryCollectionBuilder().shape(mp);
|
||||
Geometry geometry = builder.buildGeometry();
|
||||
SearchResponse searchResponse = client().prepareSearch(defaultIndexName)
|
||||
.setQuery(QueryBuilders.geoShapeQuery(defaultGeoFieldName, geometry)
|
||||
.relation(ShapeRelation.INTERSECTS))
|
||||
.get();
|
||||
|
||||
assertSearchResponse(searchResponse);
|
||||
assertHitCount(searchResponse, 2);
|
||||
assertThat(searchResponse.getHits().getAt(0).getId(), not(equalTo("2")));
|
||||
assertThat(searchResponse.getHits().getAt(1).getId(), not(equalTo("2")));
|
||||
}
|
||||
|
||||
public void testIndexPointsRectangle() throws Exception {
|
||||
XContentBuilder xcb = createDefaultMapping();
|
||||
client().admin().indices().prepareCreate(defaultIndexName).addMapping("_doc", xcb).get();
|
||||
ensureGreen();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("1").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field("name", "Document 1")
|
||||
.field(defaultGeoFieldName, "POINT(-30 -30)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("2").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field("name", "Document 2")
|
||||
.field(defaultGeoFieldName, "POINT(-45 -50)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
Rectangle rectangle = new Rectangle(-50, -40, -45, -55);
|
||||
|
||||
SearchResponse searchResponse = client().prepareSearch(defaultIndexName)
|
||||
.setQuery(QueryBuilders.geoShapeQuery(defaultGeoFieldName, rectangle)
|
||||
.relation(ShapeRelation.INTERSECTS))
|
||||
.get();
|
||||
|
||||
assertSearchResponse(searchResponse);
|
||||
assertHitCount(searchResponse, 1);
|
||||
assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("2"));
|
||||
}
|
||||
|
||||
public void testIndexPointsIndexedRectangle() throws Exception {
|
||||
XContentBuilder xcb = createDefaultMapping();
|
||||
client().admin().indices().prepareCreate(defaultIndexName).addMapping(defaultIndexName, xcb).get();
|
||||
ensureGreen();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("point1").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field(defaultGeoFieldName, "POINT(-30 -30)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("point2").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field(defaultGeoFieldName, "POINT(-45 -50)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
String indexedShapeIndex = "indexed_query_shapes";
|
||||
String indexedShapePath = "shape";
|
||||
xcb = XContentFactory.jsonBuilder().startObject()
|
||||
.startObject("properties").startObject(indexedShapePath)
|
||||
.field("type", "geo_shape")
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject();
|
||||
client().admin().indices().prepareCreate(indexedShapeIndex).addMapping(defaultIndexName, xcb).get();
|
||||
ensureGreen();
|
||||
|
||||
client().prepareIndex(indexedShapeIndex,"_doc").setId("shape1").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field(indexedShapePath, "BBOX(-50, -40, -45, -55)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
client().prepareIndex(indexedShapeIndex,"_doc").setId("shape2").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field(indexedShapePath, "BBOX(-60, -50, -50, -60)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
SearchResponse searchResponse = client().prepareSearch(defaultIndexName)
|
||||
.setQuery(QueryBuilders.geoShapeQuery(defaultGeoFieldName, "shape1")
|
||||
.relation(ShapeRelation.INTERSECTS)
|
||||
.indexedShapeIndex(indexedShapeIndex)
|
||||
.indexedShapePath(indexedShapePath))
|
||||
.get();
|
||||
|
||||
assertSearchResponse(searchResponse);
|
||||
assertHitCount(searchResponse, 1);
|
||||
assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("point2"));
|
||||
|
||||
searchResponse = client().prepareSearch(defaultIndexName)
|
||||
.setQuery(QueryBuilders.geoShapeQuery(defaultGeoFieldName, "shape2")
|
||||
.relation(ShapeRelation.INTERSECTS)
|
||||
.indexedShapeIndex(indexedShapeIndex)
|
||||
.indexedShapePath(indexedShapePath))
|
||||
.get();
|
||||
assertSearchResponse(searchResponse);
|
||||
assertHitCount(searchResponse, 0);
|
||||
}
|
||||
|
||||
public void testRectangleSpanningDateline() throws Exception {
|
||||
XContentBuilder xcb = createDefaultMapping();
|
||||
client().admin().indices().prepareCreate("test").addMapping("_doc", xcb).get();
|
||||
ensureGreen();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("1").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field(defaultGeoFieldName, "POINT(-169 0)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("2").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field(defaultGeoFieldName, "POINT(-179 0)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("3").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field(defaultGeoFieldName, "POINT(171 0)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
Rectangle rectangle = new Rectangle(
|
||||
169, -178, 1, -1);
|
||||
|
||||
GeoShapeQueryBuilder geoShapeQueryBuilder = QueryBuilders.geoShapeQuery("geo", rectangle);
|
||||
SearchResponse response = client().prepareSearch("test").setQuery(geoShapeQueryBuilder).get();
|
||||
assertHitCount(response, 2);
|
||||
SearchHits searchHits = response.getHits();
|
||||
assertThat(searchHits.getAt(0).getId(),not(equalTo("1")));
|
||||
assertThat(searchHits.getAt(1).getId(),not(equalTo("1")));
|
||||
}
|
||||
|
||||
public void testPolygonSpanningDateline() throws Exception {
|
||||
XContentBuilder xcb = createDefaultMapping();
|
||||
client().admin().indices().prepareCreate("test").addMapping("_doc", xcb).get();
|
||||
ensureGreen();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("1").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field(defaultGeoFieldName, "POINT(-169 7)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("2").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field(defaultGeoFieldName, "POINT(-179 7)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("3").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field(defaultGeoFieldName, "POINT(179 7)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("4").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field(defaultGeoFieldName, "POINT(171 7)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
PolygonBuilder polygon = new PolygonBuilder(new CoordinatesBuilder()
|
||||
.coordinate(-177, 10)
|
||||
.coordinate(177, 10)
|
||||
.coordinate(177, 5)
|
||||
.coordinate(-177, 5)
|
||||
.coordinate(-177, 10));
|
||||
|
||||
GeoShapeQueryBuilder geoShapeQueryBuilder = QueryBuilders.geoShapeQuery("geo", polygon.buildGeometry());
|
||||
geoShapeQueryBuilder.relation(ShapeRelation.INTERSECTS);
|
||||
SearchResponse response = client().prepareSearch("test").setQuery(geoShapeQueryBuilder).get();
|
||||
assertHitCount(response, 2);
|
||||
SearchHits searchHits = response.getHits();
|
||||
assertThat(searchHits.getAt(0).getId(),not(equalTo("1")));
|
||||
assertThat(searchHits.getAt(1).getId(),not(equalTo("1")));
|
||||
assertThat(searchHits.getAt(0).getId(),not(equalTo("4")));
|
||||
assertThat(searchHits.getAt(1).getId(),not(equalTo("4")));
|
||||
}
|
||||
|
||||
public void testMultiPolygonSpanningDateline() throws Exception {
|
||||
XContentBuilder xcb = createDefaultMapping();
|
||||
client().admin().indices().prepareCreate("test").addMapping("_doc", xcb).get();
|
||||
ensureGreen();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("1").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field(defaultGeoFieldName, "POINT(-169 7)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("2").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field(defaultGeoFieldName, "POINT(-179 7)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
client().prepareIndex(defaultIndexName,"_doc").setId("3").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field(defaultGeoFieldName, "POINT(171 7)")
|
||||
.endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
MultiPolygonBuilder multiPolygon = new MultiPolygonBuilder()
|
||||
.polygon(new PolygonBuilder(new CoordinatesBuilder()
|
||||
.coordinate(-167, 10)
|
||||
.coordinate(-171, 10)
|
||||
.coordinate(171, 5)
|
||||
.coordinate(-167, 5)
|
||||
.coordinate(-167, 10)))
|
||||
.polygon(new PolygonBuilder(new CoordinatesBuilder()
|
||||
.coordinate(-177, 10)
|
||||
.coordinate(177, 10)
|
||||
.coordinate(177, 5)
|
||||
.coordinate(-177, 5)
|
||||
.coordinate(-177, 10)));
|
||||
|
||||
GeoShapeQueryBuilder geoShapeQueryBuilder = QueryBuilders.geoShapeQuery(
|
||||
"geo",
|
||||
multiPolygon.buildGeometry());
|
||||
geoShapeQueryBuilder.relation(ShapeRelation.INTERSECTS);
|
||||
SearchResponse response = client().prepareSearch("test").setQuery(geoShapeQueryBuilder).get();
|
||||
assertHitCount(response, 2);
|
||||
SearchHits searchHits = response.getHits();
|
||||
assertThat(searchHits.getAt(0).getId(),not(equalTo("3")));
|
||||
assertThat(searchHits.getAt(1).getId(),not(equalTo("3")));
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,8 @@ import org.locationtech.spatial4j.shape.Rectangle;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
import static com.carrotsearch.randomizedtesting.RandomizedTest.assumeTrue;
|
||||
import static org.apache.lucene.util.LuceneTestCase.random;
|
||||
import static org.elasticsearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE;
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.geoIntersectionQuery;
|
||||
@ -62,9 +64,11 @@ import static org.elasticsearch.test.geo.RandomShapeGenerator.xRandomPoint;
|
||||
import static org.elasticsearch.test.geo.RandomShapeGenerator.xRandomRectangle;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
|
||||
public class GeoShapeQueryTests extends GeoQueryTests {
|
||||
protected static final String[] PREFIX_TREES = new String[] {
|
||||
@ -74,7 +78,7 @@ public class GeoShapeQueryTests extends GeoQueryTests {
|
||||
|
||||
@Override
|
||||
protected XContentBuilder createTypedMapping() throws Exception {
|
||||
XContentBuilder xcb = XContentFactory.jsonBuilder().startObject().startObject("type1")
|
||||
XContentBuilder xcb = XContentFactory.jsonBuilder().startObject()
|
||||
.startObject("properties").startObject("geo")
|
||||
.field("type", "geo_shape");
|
||||
if (randomBoolean()) {
|
||||
@ -121,10 +125,6 @@ public class GeoShapeQueryTests extends GeoQueryTests {
|
||||
return xcb;
|
||||
}
|
||||
|
||||
public void testIndexPointsFilterRectangle() throws Exception {
|
||||
super.testIndexPointsFilterRectangle(Strings.toString(createTypedMapping()));
|
||||
}
|
||||
|
||||
public void testShapeFetchingPath() throws Exception {
|
||||
createIndex("shapes");
|
||||
client().admin().indices().prepareCreate("test").addMapping("type", "geo", "type=geo_shape").get();
|
||||
@ -219,8 +219,6 @@ public class GeoShapeQueryTests extends GeoQueryTests {
|
||||
}
|
||||
gcb.shape(new PolygonBuilder(cb));
|
||||
|
||||
logger.info("Created Random GeometryCollection containing {} shapes", gcb.numShapes());
|
||||
|
||||
XContentBuilder mapping = createRandomMapping();
|
||||
Settings settings = Settings.builder().put("index.number_of_shards", 1).build();
|
||||
client().admin().indices().prepareCreate("test").addMapping("_doc",mapping).setSettings(settings).get();
|
||||
@ -237,8 +235,7 @@ public class GeoShapeQueryTests extends GeoQueryTests {
|
||||
geoShapeQueryBuilder.relation(ShapeRelation.INTERSECTS);
|
||||
SearchResponse result = client().prepareSearch("test").setQuery(geoShapeQueryBuilder).get();
|
||||
assertSearchResponse(result);
|
||||
assertTrue("query: " + geoShapeQueryBuilder.toString() + " doc: " + Strings.toString(docSource),
|
||||
result.getHits().getTotalHits().value > 0);
|
||||
assertThat(result.getHits().getHits().length, greaterThan(0));
|
||||
}
|
||||
|
||||
// Test for issue #34418
|
||||
@ -299,9 +296,9 @@ public class GeoShapeQueryTests extends GeoQueryTests {
|
||||
SearchResponse response = client().prepareSearch("test")
|
||||
.setQuery(querySupplier.get())
|
||||
.get();
|
||||
assertEquals(2, response.getHits().getTotalHits().value);
|
||||
assertNotEquals("1", response.getHits().getAt(0).getId());
|
||||
assertNotEquals("1", response.getHits().getAt(1).getId());
|
||||
assertHitCount(response, 2);
|
||||
assertThat(response.getHits().getAt(0).getId(), not(equalTo("1")));
|
||||
assertThat(response.getHits().getAt(1).getId(), not(equalTo("1")));
|
||||
}
|
||||
|
||||
public void testGeometryCollectionRelations() throws Exception {
|
||||
@ -322,15 +319,15 @@ public class GeoShapeQueryTests extends GeoQueryTests {
|
||||
SearchResponse response = client().prepareSearch("test")
|
||||
.setQuery(geoShapeQuery("geo", builder.buildGeometry()).relation(ShapeRelation.CONTAINS))
|
||||
.get();
|
||||
assertEquals(1, response.getHits().getTotalHits().value);
|
||||
assertHitCount(response, 1);
|
||||
response = client().prepareSearch("test")
|
||||
.setQuery(geoShapeQuery("geo", builder.buildGeometry()).relation(ShapeRelation.INTERSECTS))
|
||||
.get();
|
||||
assertEquals(1, response.getHits().getTotalHits().value);
|
||||
assertHitCount(response, 1);
|
||||
response = client().prepareSearch("test")
|
||||
.setQuery(geoShapeQuery("geo", builder.buildGeometry()).relation(ShapeRelation.DISJOINT))
|
||||
.get();
|
||||
assertEquals(0, response.getHits().getTotalHits().value);
|
||||
assertHitCount(response, 0);
|
||||
}
|
||||
// A geometry collection that is partially within the indexed shape
|
||||
{
|
||||
@ -340,15 +337,15 @@ public class GeoShapeQueryTests extends GeoQueryTests {
|
||||
SearchResponse response = client().prepareSearch("test")
|
||||
.setQuery(geoShapeQuery("geo", builder.buildGeometry()).relation(ShapeRelation.CONTAINS))
|
||||
.get();
|
||||
assertEquals(0, response.getHits().getTotalHits().value);
|
||||
assertHitCount(response, 0);
|
||||
response = client().prepareSearch("test")
|
||||
.setQuery(geoShapeQuery("geo", builder.buildGeometry()).relation(ShapeRelation.INTERSECTS))
|
||||
.get();
|
||||
assertEquals(1, response.getHits().getTotalHits().value);
|
||||
assertHitCount(response, 1);
|
||||
response = client().prepareSearch("test")
|
||||
.setQuery(geoShapeQuery("geo", builder.buildGeometry()).relation(ShapeRelation.DISJOINT))
|
||||
.get();
|
||||
assertEquals(0, response.getHits().getTotalHits().value);
|
||||
assertHitCount(response, 0);
|
||||
}
|
||||
{
|
||||
// A geometry collection that is disjoint with the indexed shape
|
||||
@ -358,15 +355,15 @@ public class GeoShapeQueryTests extends GeoQueryTests {
|
||||
SearchResponse response = client().prepareSearch("test")
|
||||
.setQuery(geoShapeQuery("geo", builder.buildGeometry()).relation(ShapeRelation.CONTAINS))
|
||||
.get();
|
||||
assertEquals(0, response.getHits().getTotalHits().value);
|
||||
assertHitCount(response, 0);
|
||||
response = client().prepareSearch("test")
|
||||
.setQuery(geoShapeQuery("geo", builder.buildGeometry()).relation(ShapeRelation.INTERSECTS))
|
||||
.get();
|
||||
assertEquals(0, response.getHits().getTotalHits().value);
|
||||
assertHitCount(response, 0);
|
||||
response = client().prepareSearch("test")
|
||||
.setQuery(geoShapeQuery("geo", builder.buildGeometry()).relation(ShapeRelation.DISJOINT))
|
||||
.get();
|
||||
assertEquals(1, response.getHits().getTotalHits().value);
|
||||
assertHitCount(response, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -401,13 +398,12 @@ public class GeoShapeQueryTests extends GeoQueryTests {
|
||||
.get();
|
||||
|
||||
assertSearchResponse(searchResponse);
|
||||
assertThat(searchResponse.getHits().getTotalHits().value, equalTo(1L));
|
||||
assertThat(searchResponse.getHits().getHits().length, equalTo(1));
|
||||
assertHitCount(searchResponse, 1);
|
||||
assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("blakely"));
|
||||
}
|
||||
|
||||
public void testIndexedShapeReferenceSourceDisabled() throws Exception {
|
||||
XContentBuilder mapping = createTypedMapping();
|
||||
XContentBuilder mapping = createDefaultMapping();
|
||||
client().admin().indices().prepareCreate("test").addMapping("type1", mapping).get();
|
||||
createIndex("shapes", Settings.EMPTY, "shape_type", "_source", "enabled=false");
|
||||
ensureGreen();
|
||||
@ -417,9 +413,13 @@ public class GeoShapeQueryTests extends GeoQueryTests {
|
||||
client().prepareIndex("shapes", "shape_type", "Big_Rectangle").setSource(jsonBuilder().startObject()
|
||||
.field("shape", shape).endObject()).setRefreshPolicy(IMMEDIATE).get();
|
||||
|
||||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> client().prepareSearch("test")
|
||||
.setQuery(geoIntersectionQuery("geo", "Big_Rectangle")).get());
|
||||
assertThat(e.getMessage(), containsString("source disabled"));
|
||||
try {
|
||||
client().prepareSearch("test")
|
||||
.setQuery(geoIntersectionQuery("geo", "Big_Rectangle")).get();
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage(),
|
||||
containsString("source disabled"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testReusableBuilder() throws IOException {
|
||||
@ -509,13 +509,12 @@ public class GeoShapeQueryTests extends GeoQueryTests {
|
||||
SearchResponse response = client().prepareSearch("test").setQuery(QueryBuilders.matchAllQuery())
|
||||
.setPostFilter(filter).get();
|
||||
assertSearchResponse(response);
|
||||
assertThat(response.getHits().getTotalHits().value, greaterThan(0L));
|
||||
assertThat(response.getHits().getHits().length, greaterThan(0));
|
||||
}
|
||||
|
||||
public void testExistsQuery() throws Exception {
|
||||
// Create a random geometry collection.
|
||||
GeometryCollectionBuilder gcb = RandomShapeGenerator.createGeometryCollection(random());
|
||||
logger.info("Created Random GeometryCollection containing {} shapes", gcb.numShapes());
|
||||
|
||||
XContentBuilder builder = createRandomMapping();
|
||||
client().admin().indices().prepareCreate("test").addMapping("type", builder)
|
||||
@ -560,7 +559,7 @@ public class GeoShapeQueryTests extends GeoQueryTests {
|
||||
.setQuery(geoIntersectionQuery("location", shape))
|
||||
.get();
|
||||
|
||||
assertEquals(1, response.getHits().getTotalHits().value);
|
||||
assertHitCount(response, 1);
|
||||
}
|
||||
|
||||
public void testPointsOnlyExplicit() throws Exception {
|
||||
@ -594,11 +593,11 @@ public class GeoShapeQueryTests extends GeoQueryTests {
|
||||
.setQuery(matchAllQuery())
|
||||
.get();
|
||||
|
||||
assertEquals(2, response.getHits().getTotalHits().value);
|
||||
assertHitCount(response, 2);
|
||||
}
|
||||
|
||||
public void testIndexedShapeReference() throws Exception {
|
||||
String mapping = Strings.toString(createTypedMapping());
|
||||
String mapping = Strings.toString(createDefaultMapping());
|
||||
client().admin().indices().prepareCreate("test").addMapping("type1", mapping, XContentType.JSON).get();
|
||||
createIndex("shapes");
|
||||
ensureGreen();
|
||||
@ -620,8 +619,7 @@ public class GeoShapeQueryTests extends GeoQueryTests {
|
||||
.get();
|
||||
|
||||
assertSearchResponse(searchResponse);
|
||||
assertThat(searchResponse.getHits().getTotalHits().value, equalTo(1L));
|
||||
assertThat(searchResponse.getHits().getHits().length, equalTo(1));
|
||||
assertHitCount(searchResponse, 1);
|
||||
assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("1"));
|
||||
|
||||
searchResponse = client().prepareSearch("test")
|
||||
@ -629,8 +627,7 @@ public class GeoShapeQueryTests extends GeoQueryTests {
|
||||
.get();
|
||||
|
||||
assertSearchResponse(searchResponse);
|
||||
assertThat(searchResponse.getHits().getTotalHits().value, equalTo(1L));
|
||||
assertThat(searchResponse.getHits().getHits().length, equalTo(1));
|
||||
assertHitCount(searchResponse, 1);
|
||||
assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("1"));
|
||||
}
|
||||
|
||||
@ -660,7 +657,7 @@ public class GeoShapeQueryTests extends GeoQueryTests {
|
||||
SearchResponse response = client().prepareSearch("test")
|
||||
.setQuery(geoShapeQuery("alias", shape))
|
||||
.get();
|
||||
assertEquals(1, response.getHits().getTotalHits().value);
|
||||
assertHitCount(response, 1);
|
||||
}
|
||||
|
||||
public void testQueryRandomGeoCollection() throws Exception {
|
||||
@ -673,8 +670,6 @@ public class GeoShapeQueryTests extends GeoQueryTests {
|
||||
}
|
||||
gcb.shape(new PolygonBuilder(cb));
|
||||
|
||||
logger.info("Created Random GeometryCollection containing {} shapes", gcb.numShapes());
|
||||
|
||||
XContentBuilder builder = createRandomMapping();
|
||||
client().admin().indices().prepareCreate("test")
|
||||
.addMapping("type", builder).get();
|
||||
|
@ -27,6 +27,7 @@ import org.elasticsearch.xpack.spatial.index.mapper.ShapeFieldMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
@ -45,6 +46,9 @@ public class ShapeQueryBuilder extends AbstractGeometryQueryBuilder<ShapeQueryBu
|
||||
static final String TYPES_DEPRECATION_MESSAGE = "[types removal] Types are deprecated in [geo_shape] queries. " +
|
||||
"The type should no longer be specified in the [indexed_shape] section.";
|
||||
|
||||
protected static final List<String> validContentTypes =
|
||||
Collections.unmodifiableList(Arrays.asList(ShapeFieldMapper.CONTENT_TYPE));
|
||||
|
||||
/**
|
||||
* Creates a new GeoShapeQueryBuilder whose Query will be against the given
|
||||
* field name using the given Shape
|
||||
@ -117,23 +121,20 @@ public class ShapeQueryBuilder extends AbstractGeometryQueryBuilder<ShapeQueryBu
|
||||
return new ShapeQueryBuilder(fieldName, shapeSupplier, indexedShapeId, indexedShapeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String queryFieldType() {
|
||||
return ShapeFieldMapper.CONTENT_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "rawtypes" })
|
||||
protected List validContentTypes() {
|
||||
return Arrays.asList(ShapeFieldMapper.CONTENT_TYPE);
|
||||
protected List<String> validContentTypes(){
|
||||
return validContentTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "rawtypes" })
|
||||
public Query buildShapeQuery(QueryShardContext context, MappedFieldType fieldType) {
|
||||
if (fieldType.typeName().equals(ShapeFieldMapper.CONTENT_TYPE) == false) {
|
||||
List<String> validContentTypes = validContentTypes();
|
||||
if (validContentTypes.contains(fieldType.typeName()) == false) {
|
||||
throw new QueryShardException(context,
|
||||
"Field [" + fieldName + "] is not of type [" + queryFieldType() + "] but of type [" + fieldType.typeName() + "]");
|
||||
"Field [" + fieldName + "] is not of type [" + String.join(" or ", validContentTypes())
|
||||
+ "] but of type [" + fieldType.typeName() + "]");
|
||||
}
|
||||
|
||||
final AbstractGeometryFieldMapper.AbstractGeometryFieldType ft = (AbstractGeometryFieldMapper.AbstractGeometryFieldType) fieldType;
|
||||
|
@ -28,7 +28,7 @@ import org.elasticsearch.geometry.MultiPolygon;
|
||||
import org.elasticsearch.geometry.Point;
|
||||
import org.elasticsearch.geometry.Polygon;
|
||||
import org.elasticsearch.geometry.Rectangle;
|
||||
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper;
|
||||
import org.elasticsearch.index.mapper.AbstractSearchableGeometryFieldType;
|
||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.index.query.QueryShardException;
|
||||
@ -36,7 +36,7 @@ import org.elasticsearch.xpack.spatial.index.mapper.ShapeFieldMapper;
|
||||
|
||||
import static org.elasticsearch.xpack.spatial.index.mapper.ShapeIndexer.toLucenePolygon;
|
||||
|
||||
public class ShapeQueryProcessor implements AbstractGeometryFieldMapper.QueryProcessor {
|
||||
public class ShapeQueryProcessor implements AbstractSearchableGeometryFieldType.QueryProcessor {
|
||||
|
||||
@Override
|
||||
public Query process(Geometry shape, String fieldName, ShapeRelation relation, QueryShardContext context) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user