diff --git a/core/src/main/java/org/elasticsearch/common/geo/ShapeRelation.java b/core/src/main/java/org/elasticsearch/common/geo/ShapeRelation.java index 6ee16938d1e..67287b6cb30 100644 --- a/core/src/main/java/org/elasticsearch/common/geo/ShapeRelation.java +++ b/core/src/main/java/org/elasticsearch/common/geo/ShapeRelation.java @@ -19,13 +19,18 @@ package org.elasticsearch.common.geo; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Writeable; + +import java.io.IOException; import java.util.Locale; /** * Enum representing the relationship between a Query / Filter Shape and indexed Shapes * that will be used to determine if a Document should be matched or not */ -public enum ShapeRelation { +public enum ShapeRelation implements Writeable{ INTERSECTS("intersects"), DISJOINT("disjoint"), @@ -37,6 +42,20 @@ public enum ShapeRelation { this.relationName = relationName; } + @Override + public ShapeRelation readFrom(StreamInput in) throws IOException { + int ordinal = in.readVInt(); + if (ordinal < 0 || ordinal >= values().length) { + throw new IOException("Unknown ShapeRelation ordinal [" + ordinal + "]"); + } + return values()[ordinal]; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeVInt(ordinal()); + } + public static ShapeRelation getRelationByName(String name) { name = name.toLowerCase(Locale.ENGLISH); for (ShapeRelation relation : ShapeRelation.values()) { diff --git a/core/src/main/java/org/elasticsearch/common/geo/SpatialStrategy.java b/core/src/main/java/org/elasticsearch/common/geo/SpatialStrategy.java index a83f29156a1..23c1dbb43f1 100644 --- a/core/src/main/java/org/elasticsearch/common/geo/SpatialStrategy.java +++ b/core/src/main/java/org/elasticsearch/common/geo/SpatialStrategy.java @@ -18,11 +18,16 @@ */ package org.elasticsearch.common.geo; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Writeable; + +import java.io.IOException; /** * */ -public enum SpatialStrategy { +public enum SpatialStrategy implements Writeable { TERM("term"), RECURSIVE("recursive"); @@ -36,4 +41,27 @@ public enum SpatialStrategy { public String getStrategyName() { return strategyName; } + + @Override + public SpatialStrategy readFrom(StreamInput in) throws IOException { + int ordinal = in.readVInt(); + if (ordinal < 0 || ordinal >= values().length) { + throw new IOException("Unknown SpatialStrategy ordinal [" + ordinal + "]"); + } + return values()[ordinal]; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeVInt(ordinal()); + } + + public static SpatialStrategy fromString(String strategyName) { + for (SpatialStrategy strategy : values()) { + if (strategy.strategyName.equals(strategyName)) { + return strategy; + } + } + return null; + } } diff --git a/core/src/main/java/org/elasticsearch/index/mapper/geo/GeoShapeFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/geo/GeoShapeFieldMapper.java index 417950808ad..b99d20018cc 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/geo/GeoShapeFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/geo/GeoShapeFieldMapper.java @@ -125,6 +125,7 @@ public class GeoShapeFieldMapper extends FieldMapper { super(name, Defaults.FIELD_TYPE); } + @Override public GeoShapeFieldType fieldType() { return (GeoShapeFieldType)fieldType; } @@ -400,6 +401,10 @@ public class GeoShapeFieldMapper extends FieldMapper { return this.defaultStrategy; } + public PrefixTreeStrategy resolveStrategy(SpatialStrategy strategy) { + return resolveStrategy(strategy.getStrategyName()); + } + public PrefixTreeStrategy resolveStrategy(String strategyName) { if (SpatialStrategy.RECURSIVE.getStrategyName().equals(strategyName)) { recursiveStrategy.setPointsOnly(pointsOnly()); diff --git a/core/src/main/java/org/elasticsearch/index/query/GeoShapeQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/GeoShapeQueryBuilder.java index 9180d0e5911..52d30b41c3f 100644 --- a/core/src/main/java/org/elasticsearch/index/query/GeoShapeQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/GeoShapeQueryBuilder.java @@ -19,84 +19,161 @@ package org.elasticsearch.index.query; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.ConstantScoreQuery; +import org.apache.lucene.search.Filter; +import org.apache.lucene.search.Query; +import org.apache.lucene.spatial.prefix.PrefixTreeStrategy; +import org.apache.lucene.spatial.prefix.RecursivePrefixTreeStrategy; +import org.apache.lucene.spatial.query.SpatialArgs; +import org.apache.lucene.spatial.query.SpatialOperation; +import org.elasticsearch.action.get.GetRequest; +import org.elasticsearch.action.get.GetResponse; +import org.elasticsearch.client.Client; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.bytes.BytesArray; +import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.geo.ShapeRelation; +import org.elasticsearch.common.geo.ShapesAvailability; import org.elasticsearch.common.geo.SpatialStrategy; import org.elasticsearch.common.geo.builders.ShapeBuilder; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.index.mapper.MappedFieldType; +import org.elasticsearch.index.mapper.geo.GeoShapeFieldMapper; +import org.elasticsearch.search.internal.SearchContext; import java.io.IOException; +import java.util.Objects; /** - * {@link QueryBuilder} that builds a GeoShape Filter + * {@link QueryBuilder} that builds a GeoShape Query */ public class GeoShapeQueryBuilder extends AbstractQueryBuilder { public static final String NAME = "geo_shape"; + public static final String DEFAULT_SHAPE_INDEX_NAME = "shapes"; + public static final String DEFAULT_SHAPE_FIELD_NAME = "shape"; + public static final ShapeRelation DEFAULT_SHAPE_RELATION = ShapeRelation.INTERSECTS; - static final GeoShapeQueryBuilder PROTOTYPE = new GeoShapeQueryBuilder(null, null); + static final GeoShapeQueryBuilder PROTOTYPE = new GeoShapeQueryBuilder("", new BytesArray(new byte[0])); - private final String name; + private final String fieldName; - private final ShapeBuilder shape; + // TODO make the ShapeBuilder and subclasses Writable and implement hashCode + // and Equals so ShapeBuilder can be used here + private BytesReference shapeBytes; private SpatialStrategy strategy = null; private final String indexedShapeId; private final String indexedShapeType; - private String indexedShapeIndex; - private String indexedShapePath; + private String indexedShapeIndex = DEFAULT_SHAPE_INDEX_NAME; + private String indexedShapePath = DEFAULT_SHAPE_FIELD_NAME; - private ShapeRelation relation = null; + private ShapeRelation relation = DEFAULT_SHAPE_RELATION; /** - * Creates a new GeoShapeQueryBuilder whose Filter will be against the - * given field name using the given Shape + * Creates a new GeoShapeQueryBuilder whose Query will be against the given + * field name using the given Shape * - * @param name Name of the field that will be filtered - * @param shape Shape used in the filter + * @param name + * Name of the field that will be queried + * @param shape + * Shape used in the Query */ - public GeoShapeQueryBuilder(String name, ShapeBuilder shape) { - this(name, shape, null, null, null); + public GeoShapeQueryBuilder(String fieldName, ShapeBuilder shape) throws IOException { + this(fieldName, shape, null, null); } /** - * Creates a new GeoShapeQueryBuilder whose Filter will be against the - * given field name using the given Shape + * Creates a new GeoShapeQueryBuilder whose Query will be against the given + * field name and will use the Shape found with the given ID in the given + * type * - * @param name Name of the field that will be filtered - * @param relation {@link ShapeRelation} of query and indexed shape - * @param shape Shape used in the filter + * @param fieldName + * Name of the field that will be filtered + * @param indexedShapeId + * ID of the indexed Shape that will be used in the Query + * @param indexedShapeType + * Index type of the indexed Shapes */ - public GeoShapeQueryBuilder(String name, ShapeBuilder shape, ShapeRelation relation) { - this(name, shape, null, null, relation); + public GeoShapeQueryBuilder(String fieldName, String indexedShapeId, String indexedShapeType) { + this(fieldName, (BytesReference) null, indexedShapeId, indexedShapeType); } - /** - * Creates a new GeoShapeQueryBuilder whose Filter will be against the given field name - * and will use the Shape found with the given ID in the given type - * - * @param name Name of the field that will be filtered - * @param indexedShapeId ID of the indexed Shape that will be used in the Filter - * @param indexedShapeType Index type of the indexed Shapes - */ - public GeoShapeQueryBuilder(String name, String indexedShapeId, String indexedShapeType, ShapeRelation relation) { - this(name, null, indexedShapeId, indexedShapeType, relation); + GeoShapeQueryBuilder(String fieldName, BytesReference shapeBytes) { + this(fieldName, shapeBytes, null, null); } - private GeoShapeQueryBuilder(String name, ShapeBuilder shape, String indexedShapeId, String indexedShapeType, ShapeRelation relation) { - this.name = name; - this.shape = shape; + private GeoShapeQueryBuilder(String fieldName, ShapeBuilder shape, String indexedShapeId, String indexedShapeType) throws IOException { + this(fieldName, new BytesArray(new byte[0]), indexedShapeId, indexedShapeType); + if (shape != null) { + XContentBuilder builder = XContentFactory.jsonBuilder(); + shape.toXContent(builder, EMPTY_PARAMS); + this.shapeBytes = builder.bytes(); + } + } + + private GeoShapeQueryBuilder(String fieldName, BytesReference shapeBytes, String indexedShapeId, String indexedShapeType) { + if (fieldName == null) { + throw new IllegalArgumentException("fieldName is required"); + } + if (shapeBytes == null && indexedShapeId == null) { + throw new IllegalArgumentException("either shapeBytes or indexedShapeId and indexedShapeType are required"); + } + if (indexedShapeId != null && indexedShapeType == null) { + throw new IllegalArgumentException("indexedShapeType is required if indexedShapeId is specified"); + } + this.fieldName = fieldName; + this.shapeBytes = shapeBytes; this.indexedShapeId = indexedShapeId; - this.relation = relation; this.indexedShapeType = indexedShapeType; } /** - * Defines which spatial strategy will be used for building the geo shape filter. When not set, the strategy that - * will be used will be the one that is associated with the geo shape field in the mappings. + * @return the name of the field that will be queried + */ + public String fieldName() { + return fieldName; + } + + /** + * @return the JSON bytes for the shape used in the Query + */ + public BytesReference shapeBytes() { + return shapeBytes; + } + + /** + * @return the ID of the indexed Shape that will be used in the Query + */ + public String indexedShapeId() { + return indexedShapeId; + } + + /** + * @return the document type of the indexed Shape that will be used in the + * Query + */ + public String indexedShapeType() { + return indexedShapeType; + } + + /** + * Defines which spatial strategy will be used for building the geo shape + * Query. When not set, the strategy that will be used will be the one that + * is associated with the geo shape field in the mappings. * - * @param strategy The spatial strategy to use for building the geo shape filter + * @param strategy + * The spatial strategy to use for building the geo shape Query * @return this */ public GeoShapeQueryBuilder strategy(SpatialStrategy strategy) { @@ -104,6 +181,13 @@ public class GeoShapeQueryBuilder extends AbstractQueryBuilder { - public static class DEFAULTS { - public static final String INDEX_NAME = "shapes"; - public static final String SHAPE_FIELD_NAME = "shape"; - } + public static final ParseField SHAPE_FIELD = new ParseField("shape"); + public static final ParseField STRATEGY_FIELD = new ParseField("strategy"); + public static final ParseField RELATION_FIELD = new ParseField("relation"); + public static final ParseField INDEXED_SHAPE_FIELD = new ParseField("indexed_shape"); + public static final ParseField SHAPE_ID_FIELD = new ParseField("id"); + public static final ParseField SHAPE_TYPE_FIELD = new ParseField("type"); + public static final ParseField SHAPE_INDEX_FIELD = new ParseField("index"); + public static final ParseField SHAPE_PATH_FIELD = new ParseField("path"); @Override public String[] names() { @@ -52,23 +47,22 @@ public class GeoShapeQueryParser extends BaseQueryParserTemp { } @Override - public Query parse(QueryShardContext context) throws IOException, QueryParsingException { - QueryParseContext parseContext = context.parseContext(); + public GeoShapeQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, QueryParsingException { XContentParser parser = parseContext.parser(); String fieldName = null; - ShapeRelation shapeRelation = ShapeRelation.INTERSECTS; - String strategyName = null; - ShapeBuilder shape = null; + ShapeRelation shapeRelation = null; + SpatialStrategy strategy = null; + BytesReference shape = null; String id = null; String type = null; - String index = DEFAULTS.INDEX_NAME; - String shapePath = DEFAULTS.SHAPE_FIELD_NAME; + String index = null; + String shapePath = null; XContentParser.Token token; String currentFieldName = null; - float boost = 1f; + float boost = AbstractQueryBuilder.DEFAULT_BOOST; String queryName = null; while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { @@ -81,159 +75,78 @@ public class GeoShapeQueryParser extends BaseQueryParserTemp { if (token == XContentParser.Token.FIELD_NAME) { currentFieldName = parser.currentName(); token = parser.nextToken(); - if ("shape".equals(currentFieldName)) { - shape = ShapeBuilder.parse(parser); - } else if ("strategy".equals(currentFieldName)) { - strategyName = parser.text(); - } else if ("relation".equals(currentFieldName)) { + if (parseContext.parseFieldMatcher().match(currentFieldName, SHAPE_FIELD)) { + XContentBuilder builder = XContentFactory.contentBuilder(parser.contentType()).copyCurrentStructure(parser); + shape = builder.bytes(); + } else if (parseContext.parseFieldMatcher().match(currentFieldName, STRATEGY_FIELD)) { + String strategyName = parser.text(); + strategy = SpatialStrategy.fromString(strategyName); + if (strategy == null) { + throw new QueryParsingException(parseContext, "Unknown strategy [" + strategyName + " ]"); + } + } else if (parseContext.parseFieldMatcher().match(currentFieldName, RELATION_FIELD)) { shapeRelation = ShapeRelation.getRelationByName(parser.text()); if (shapeRelation == null) { throw new QueryParsingException(parseContext, "Unknown shape operation [" + parser.text() + " ]"); } - } else if ("indexed_shape".equals(currentFieldName) || "indexedShape".equals(currentFieldName)) { + } else if (parseContext.parseFieldMatcher().match(currentFieldName, INDEXED_SHAPE_FIELD)) { while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { currentFieldName = parser.currentName(); } else if (token.isValue()) { - if ("id".equals(currentFieldName)) { + if (parseContext.parseFieldMatcher().match(currentFieldName, SHAPE_ID_FIELD)) { id = parser.text(); - } else if ("type".equals(currentFieldName)) { + } else if (parseContext.parseFieldMatcher().match(currentFieldName, SHAPE_TYPE_FIELD)) { type = parser.text(); - } else if ("index".equals(currentFieldName)) { + } else if (parseContext.parseFieldMatcher().match(currentFieldName, SHAPE_INDEX_FIELD)) { index = parser.text(); - } else if ("path".equals(currentFieldName)) { + } else if (parseContext.parseFieldMatcher().match(currentFieldName, SHAPE_PATH_FIELD)) { shapePath = parser.text(); } } } - if (id == null) { - throw new QueryParsingException(parseContext, "ID for indexed shape not provided"); - } else if (type == null) { - throw new QueryParsingException(parseContext, "Type for indexed shape not provided"); - } - GetRequest getRequest = new GetRequest(index, type, id); - getRequest.copyContextAndHeadersFrom(SearchContext.current()); - shape = fetch(context.getClient(), getRequest, shapePath); } else { throw new QueryParsingException(parseContext, "[geo_shape] query does not support [" + currentFieldName + "]"); } } } } else if (token.isValue()) { - if ("boost".equals(currentFieldName)) { + if (parseContext.parseFieldMatcher().match(currentFieldName, AbstractQueryBuilder.BOOST_FIELD)) { boost = parser.floatValue(); - } else if ("_name".equals(currentFieldName)) { + } else if (parseContext.parseFieldMatcher().match(currentFieldName, AbstractQueryBuilder.NAME_FIELD)) { queryName = parser.text(); } else { throw new QueryParsingException(parseContext, "[geo_shape] query does not support [" + currentFieldName + "]"); } } } - - if (shape == null) { - throw new QueryParsingException(parseContext, "No Shape defined"); - } else if (shapeRelation == null) { - throw new QueryParsingException(parseContext, "No Shape Relation defined"); - } - - MappedFieldType fieldType = context.fieldMapper(fieldName); - if (fieldType == null) { - throw new QueryParsingException(parseContext, "Failed to find geo_shape field [" + fieldName + "]"); - } - - // TODO: This isn't the nicest way to check this - if (!(fieldType instanceof GeoShapeFieldMapper.GeoShapeFieldType)) { - throw new QueryParsingException(parseContext, "Field [" + fieldName + "] is not a geo_shape"); - } - - GeoShapeFieldMapper.GeoShapeFieldType shapeFieldType = (GeoShapeFieldMapper.GeoShapeFieldType) fieldType; - - PrefixTreeStrategy strategy = shapeFieldType.defaultStrategy(); - if (strategyName != null) { - strategy = shapeFieldType.resolveStrategy(strategyName); - } - Query query; - if (strategy instanceof RecursivePrefixTreeStrategy && shapeRelation == ShapeRelation.DISJOINT) { - // this strategy doesn't support disjoint anymore: but it did before, including creating lucene fieldcache (!) - // in this case, execute disjoint as exists && !intersects - BooleanQuery.Builder bool = new BooleanQuery.Builder(); - Query exists = ExistsQueryBuilder.newFilter(context, fieldName); - Filter intersects = strategy.makeFilter(getArgs(shape, ShapeRelation.INTERSECTS)); - bool.add(exists, BooleanClause.Occur.MUST); - bool.add(intersects, BooleanClause.Occur.MUST_NOT); - query = new ConstantScoreQuery(bool.build()); + GeoShapeQueryBuilder builder; + if (shape != null) { + builder = new GeoShapeQueryBuilder(fieldName, shape); } else { - query = strategy.makeQuery(getArgs(shape, shapeRelation)); + builder = new GeoShapeQueryBuilder(fieldName, id, type); + } + if (index != null) { + builder.indexedShapeIndex(index); + } + if (shapePath != null) { + builder.indexedShapePath(shapePath); + } + if (shapeRelation != null) { + builder.relation(shapeRelation); + } + if (strategy != null) { + builder.strategy(strategy); } - query.setBoost(boost); if (queryName != null) { - context.addNamedQuery(queryName, query); - } - return query; - } - - public static SpatialArgs getArgs(ShapeBuilder shape, ShapeRelation relation) { - switch(relation) { - case DISJOINT: - return new SpatialArgs(SpatialOperation.IsDisjointTo, shape.build()); - case INTERSECTS: - return new SpatialArgs(SpatialOperation.Intersects, shape.build()); - case WITHIN: - return new SpatialArgs(SpatialOperation.IsWithin, shape.build()); - default: - throw new IllegalArgumentException(""); + builder.queryName(queryName); } + builder.boost(boost); + return builder; } @Override public GeoShapeQueryBuilder getBuilderPrototype() { return GeoShapeQueryBuilder.PROTOTYPE; } - - /** - * Fetches the Shape with the given ID in the given type and index. - * - * @param getRequest GetRequest containing index, type and id - * @param path Name or path of the field in the Shape Document where the Shape itself is located - * @return Shape with the given ID - * @throws IOException Can be thrown while parsing the Shape Document and extracting the Shape - */ - private ShapeBuilder fetch(Client client, GetRequest getRequest, String path) throws IOException { - if (ShapesAvailability.JTS_AVAILABLE == false) { - throw new IllegalStateException("JTS not available"); - } - getRequest.preference("_local"); - getRequest.operationThreaded(false); - GetResponse response = client.get(getRequest).actionGet(); - if (!response.isExists()) { - throw new IllegalArgumentException("Shape with ID [" + getRequest.id() + "] in type [" + getRequest.type() + "] not found"); - } - - String[] pathElements = Strings.splitStringToArray(path, '.'); - int currentPathSlot = 0; - - XContentParser parser = null; - try { - parser = XContentHelper.createParser(response.getSourceAsBytesRef()); - XContentParser.Token currentToken; - while ((currentToken = parser.nextToken()) != XContentParser.Token.END_OBJECT) { - if (currentToken == XContentParser.Token.FIELD_NAME) { - if (pathElements[currentPathSlot].equals(parser.currentName())) { - parser.nextToken(); - if (++currentPathSlot == pathElements.length) { - return ShapeBuilder.parse(parser); - } - } else { - parser.nextToken(); - parser.skipChildren(); - } - } - } - throw new IllegalStateException("Shape with name [" + getRequest.id() + "] found but missing " + path + " field"); - } finally { - if (parser != null) { - parser.close(); - } - } - } } diff --git a/core/src/main/java/org/elasticsearch/index/query/QueryBuilders.java b/core/src/main/java/org/elasticsearch/index/query/QueryBuilders.java index 41545ee180f..7f3f1412725 100644 --- a/core/src/main/java/org/elasticsearch/index/query/QueryBuilders.java +++ b/core/src/main/java/org/elasticsearch/index/query/QueryBuilders.java @@ -31,6 +31,7 @@ import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.Template; +import java.io.IOException; import java.util.Collection; import java.util.Map; @@ -547,17 +548,6 @@ public abstract class QueryBuilders { return new WrapperQueryBuilder(source); } - /** - * Query that matches Documents based on the relationship between the given shape and - * indexed shapes - * - * @param name The shape field name - * @param shape Shape to use in the Query - */ - public static GeoShapeQueryBuilder geoShapeQuery(String name, ShapeBuilder shape) { - return new GeoShapeQueryBuilder(name, shape); - } - /** * Facilitates creating template query requests using an inline script */ @@ -694,16 +684,12 @@ public abstract class QueryBuilders { * @param shape Shape to use in the filter * @param relation relation of the shapes */ - public static GeoShapeQueryBuilder geoShapeQuery(String name, ShapeBuilder shape, ShapeRelation relation) { - return new GeoShapeQueryBuilder(name, shape, relation); - } - - public static GeoShapeQueryBuilder geoShapeQuery(String name, String indexedShapeId, String indexedShapeType, ShapeRelation relation) { - return new GeoShapeQueryBuilder(name, indexedShapeId, indexedShapeType, relation); + public static GeoShapeQueryBuilder geoShapeQuery(String name, ShapeBuilder shape) throws IOException { + return new GeoShapeQueryBuilder(name, shape); } public static GeoShapeQueryBuilder geoShapeQuery(String name, String indexedShapeId, String indexedShapeType) { - return geoShapeQuery(name, indexedShapeId, indexedShapeType, null); + return new GeoShapeQueryBuilder(name, indexedShapeId, indexedShapeType); } /** @@ -712,12 +698,16 @@ public abstract class QueryBuilders { * @param name The shape field name * @param shape Shape to use in the filter */ - public static GeoShapeQueryBuilder geoIntersectionQuery(String name, ShapeBuilder shape) { - return geoShapeQuery(name, shape, ShapeRelation.INTERSECTS); + public static GeoShapeQueryBuilder geoIntersectionQuery(String name, ShapeBuilder shape) throws IOException { + GeoShapeQueryBuilder builder = geoShapeQuery(name, shape); + builder.relation(ShapeRelation.INTERSECTS); + return builder; } public static GeoShapeQueryBuilder geoIntersectionQuery(String name, String indexedShapeId, String indexedShapeType) { - return geoShapeQuery(name, indexedShapeId, indexedShapeType, ShapeRelation.INTERSECTS); + GeoShapeQueryBuilder builder = geoShapeQuery(name, indexedShapeId, indexedShapeType); + builder.relation(ShapeRelation.INTERSECTS); + return builder; } /** @@ -726,12 +716,16 @@ public abstract class QueryBuilders { * @param name The shape field name * @param shape Shape to use in the filter */ - public static GeoShapeQueryBuilder geoWithinQuery(String name, ShapeBuilder shape) { - return geoShapeQuery(name, shape, ShapeRelation.WITHIN); + public static GeoShapeQueryBuilder geoWithinQuery(String name, ShapeBuilder shape) throws IOException { + GeoShapeQueryBuilder builder = geoShapeQuery(name, shape); + builder.relation(ShapeRelation.WITHIN); + return builder; } public static GeoShapeQueryBuilder geoWithinQuery(String name, String indexedShapeId, String indexedShapeType) { - return geoShapeQuery(name, indexedShapeId, indexedShapeType, ShapeRelation.WITHIN); + GeoShapeQueryBuilder builder = geoShapeQuery(name, indexedShapeId, indexedShapeType); + builder.relation(ShapeRelation.WITHIN); + return builder; } /** @@ -740,12 +734,16 @@ public abstract class QueryBuilders { * @param name The shape field name * @param shape Shape to use in the filter */ - public static GeoShapeQueryBuilder geoDisjointQuery(String name, ShapeBuilder shape) { - return geoShapeQuery(name, shape, ShapeRelation.DISJOINT); + public static GeoShapeQueryBuilder geoDisjointQuery(String name, ShapeBuilder shape) throws IOException { + GeoShapeQueryBuilder builder = geoShapeQuery(name, shape); + builder.relation(ShapeRelation.DISJOINT); + return builder; } public static GeoShapeQueryBuilder geoDisjointQuery(String name, String indexedShapeId, String indexedShapeType) { - return geoShapeQuery(name, indexedShapeId, indexedShapeType, ShapeRelation.DISJOINT); + GeoShapeQueryBuilder builder = geoShapeQuery(name, indexedShapeId, indexedShapeType); + builder.relation(ShapeRelation.DISJOINT); + return builder; } /** diff --git a/core/src/main/java/org/elasticsearch/index/query/QueryShardContext.java b/core/src/main/java/org/elasticsearch/index/query/QueryShardContext.java index 382cc1e06ab..8ce547ed45d 100644 --- a/core/src/main/java/org/elasticsearch/index/query/QueryShardContext.java +++ b/core/src/main/java/org/elasticsearch/index/query/QueryShardContext.java @@ -20,6 +20,7 @@ package org.elasticsearch.index.query; import com.google.common.collect.ImmutableMap; + import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.queryparser.classic.MapperQueryParser; import org.apache.lucene.queryparser.classic.QueryParserSettings; @@ -32,12 +33,17 @@ import org.elasticsearch.client.Client; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.common.ParseFieldMatcher; import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.geo.builders.ShapeBuilder; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.Index; import org.elasticsearch.index.analysis.AnalysisService; import org.elasticsearch.index.fielddata.IndexFieldData; -import org.elasticsearch.index.mapper.*; +import org.elasticsearch.index.mapper.ContentPath; +import org.elasticsearch.index.mapper.MappedFieldType; +import org.elasticsearch.index.mapper.Mapper; +import org.elasticsearch.index.mapper.MapperBuilders; +import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.core.StringFieldMapper; import org.elasticsearch.index.mapper.object.ObjectMapper; import org.elasticsearch.index.query.support.NestedScope; @@ -50,7 +56,12 @@ import org.elasticsearch.search.fetch.innerhits.InnerHitsContext; import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.search.lookup.SearchLookup; -import java.util.*; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * Context object used to create lucene queries on the shard level. diff --git a/core/src/test/java/org/elasticsearch/common/geo/ShapeRalationTests.java b/core/src/test/java/org/elasticsearch/common/geo/ShapeRalationTests.java new file mode 100644 index 00000000000..1c2ebb202b2 --- /dev/null +++ b/core/src/test/java/org/elasticsearch/common/geo/ShapeRalationTests.java @@ -0,0 +1,92 @@ +/* + * 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.common.geo; + +import org.elasticsearch.common.io.stream.BytesStreamOutput; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.test.ESTestCase; +import org.junit.Test; + +import java.io.IOException; + +import static org.hamcrest.Matchers.equalTo; + +public class ShapeRalationTests extends ESTestCase { + + public void testValidOrdinals() { + assertThat(ShapeRelation.INTERSECTS.ordinal(), equalTo(0)); + assertThat(ShapeRelation.DISJOINT.ordinal(), equalTo(1)); + assertThat(ShapeRelation.WITHIN.ordinal(), equalTo(2)); + } + + public void testwriteTo() throws Exception { + try (BytesStreamOutput out = new BytesStreamOutput()) { + ShapeRelation.INTERSECTS.writeTo(out); + try (StreamInput in = StreamInput.wrap(out.bytes())) { + assertThat(in.readVInt(), equalTo(0)); + } + } + + try (BytesStreamOutput out = new BytesStreamOutput()) { + ShapeRelation.DISJOINT.writeTo(out); + try (StreamInput in = StreamInput.wrap(out.bytes())) { + assertThat(in.readVInt(), equalTo(1)); + } + } + + try (BytesStreamOutput out = new BytesStreamOutput()) { + ShapeRelation.WITHIN.writeTo(out); + try (StreamInput in = StreamInput.wrap(out.bytes())) { + assertThat(in.readVInt(), equalTo(2)); + } + } + } + + public void testReadFrom() throws Exception { + try (BytesStreamOutput out = new BytesStreamOutput()) { + out.writeVInt(0); + try (StreamInput in = StreamInput.wrap(out.bytes())) { + assertThat(ShapeRelation.DISJOINT.readFrom(in), equalTo(ShapeRelation.INTERSECTS)); + } + } + try (BytesStreamOutput out = new BytesStreamOutput()) { + out.writeVInt(1); + try (StreamInput in = StreamInput.wrap(out.bytes())) { + assertThat(ShapeRelation.DISJOINT.readFrom(in), equalTo(ShapeRelation.DISJOINT)); + } + } + try (BytesStreamOutput out = new BytesStreamOutput()) { + out.writeVInt(2); + try (StreamInput in = StreamInput.wrap(out.bytes())) { + assertThat(ShapeRelation.DISJOINT.readFrom(in), equalTo(ShapeRelation.WITHIN)); + } + } + } + + @Test(expected = IOException.class) + public void testInvalidReadFrom() throws Exception { + try (BytesStreamOutput out = new BytesStreamOutput()) { + out.writeVInt(randomIntBetween(3, Integer.MAX_VALUE)); + try (StreamInput in = StreamInput.wrap(out.bytes())) { + ShapeRelation.DISJOINT.readFrom(in); + } + } + } +} diff --git a/core/src/test/java/org/elasticsearch/common/geo/SpatialStrategyTests.java b/core/src/test/java/org/elasticsearch/common/geo/SpatialStrategyTests.java new file mode 100644 index 00000000000..c53a3fb18cb --- /dev/null +++ b/core/src/test/java/org/elasticsearch/common/geo/SpatialStrategyTests.java @@ -0,0 +1,78 @@ +/* + * 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.common.geo; + +import org.elasticsearch.common.io.stream.BytesStreamOutput; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.test.ESTestCase; +import org.junit.Test; + +import java.io.IOException; + +import static org.hamcrest.Matchers.equalTo; + +public class SpatialStrategyTests extends ESTestCase { + + public void testValidOrdinals() { + assertThat(SpatialStrategy.TERM.ordinal(), equalTo(0)); + assertThat(SpatialStrategy.RECURSIVE.ordinal(), equalTo(1)); + } + + public void testwriteTo() throws Exception { + try (BytesStreamOutput out = new BytesStreamOutput()) { + SpatialStrategy.TERM.writeTo(out); + try (StreamInput in = StreamInput.wrap(out.bytes())) { + assertThat(in.readVInt(), equalTo(0)); + } + } + + try (BytesStreamOutput out = new BytesStreamOutput()) { + SpatialStrategy.RECURSIVE.writeTo(out); + try (StreamInput in = StreamInput.wrap(out.bytes())) { + assertThat(in.readVInt(), equalTo(1)); + } + } + } + + public void testReadFrom() throws Exception { + try (BytesStreamOutput out = new BytesStreamOutput()) { + out.writeVInt(0); + try (StreamInput in = StreamInput.wrap(out.bytes())) { + assertThat(SpatialStrategy.TERM.readFrom(in), equalTo(SpatialStrategy.TERM)); + } + } + try (BytesStreamOutput out = new BytesStreamOutput()) { + out.writeVInt(1); + try (StreamInput in = StreamInput.wrap(out.bytes())) { + assertThat(SpatialStrategy.TERM.readFrom(in), equalTo(SpatialStrategy.RECURSIVE)); + } + } + } + + @Test(expected = IOException.class) + public void testInvalidReadFrom() throws Exception { + try (BytesStreamOutput out = new BytesStreamOutput()) { + out.writeVInt(randomIntBetween(2, Integer.MAX_VALUE)); + try (StreamInput in = StreamInput.wrap(out.bytes())) { + SpatialStrategy.TERM.readFrom(in); + } + } + } +} diff --git a/core/src/test/java/org/elasticsearch/index/mapper/externalvalues/ExternalValuesMapperIntegrationIT.java b/core/src/test/java/org/elasticsearch/index/mapper/externalvalues/ExternalValuesMapperIntegrationIT.java index 42a9df6632e..35449d0faa3 100644 --- a/core/src/test/java/org/elasticsearch/index/mapper/externalvalues/ExternalValuesMapperIntegrationIT.java +++ b/core/src/test/java/org/elasticsearch/index/mapper/externalvalues/ExternalValuesMapperIntegrationIT.java @@ -22,14 +22,12 @@ package org.elasticsearch.index.mapper.externalvalues; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.common.geo.ShapeRelation; import org.elasticsearch.common.geo.builders.ShapeBuilder; -import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.test.ESIntegTestCase; import org.junit.Test; -import java.util.Arrays; import java.util.Collection; import static org.hamcrest.Matchers.equalTo; @@ -74,7 +72,7 @@ public class ExternalValuesMapperIntegrationIT extends ESIntegTestCase { assertThat(response.getHits().totalHits(), equalTo((long) 1)); response = client().prepareSearch("test-idx") - .setPostFilter(QueryBuilders.geoShapeQuery("field.shape", ShapeBuilder.newPoint(-100, 45), ShapeRelation.WITHIN)) + .setPostFilter(QueryBuilders.geoShapeQuery("field.shape", ShapeBuilder.newPoint(-100, 45)).relation(ShapeRelation.WITHIN)) .execute().actionGet(); assertThat(response.getHits().totalHits(), equalTo((long) 1)); diff --git a/core/src/test/java/org/elasticsearch/index/query/AbstractQueryTestCase.java b/core/src/test/java/org/elasticsearch/index/query/AbstractQueryTestCase.java index 6c63869aeac..23a729e7967 100644 --- a/core/src/test/java/org/elasticsearch/index/query/AbstractQueryTestCase.java +++ b/core/src/test/java/org/elasticsearch/index/query/AbstractQueryTestCase.java @@ -110,11 +110,12 @@ public abstract class AbstractQueryTestCase> protected static final String BOOLEAN_FIELD_NAME = "mapped_boolean"; protected static final String DATE_FIELD_NAME = "mapped_date"; protected static final String OBJECT_FIELD_NAME = "mapped_object"; - protected static final String GEO_FIELD_NAME = "mapped_geo"; - protected static final String[] MAPPED_FIELD_NAMES = new String[] { STRING_FIELD_NAME, INT_FIELD_NAME, - DOUBLE_FIELD_NAME, BOOLEAN_FIELD_NAME, DATE_FIELD_NAME, OBJECT_FIELD_NAME, GEO_FIELD_NAME }; - protected static final String[] MAPPED_LEAF_FIELD_NAMES = new String[] { STRING_FIELD_NAME, INT_FIELD_NAME, - DOUBLE_FIELD_NAME, BOOLEAN_FIELD_NAME, DATE_FIELD_NAME, GEO_FIELD_NAME }; + protected static final String GEO_POINT_FIELD_NAME = "mapped_geo_point"; + protected static final String GEO_SHAPE_FIELD_NAME = "mapped_geo_shape"; + protected static final String[] MAPPED_FIELD_NAMES = new String[] { STRING_FIELD_NAME, INT_FIELD_NAME, DOUBLE_FIELD_NAME, + BOOLEAN_FIELD_NAME, DATE_FIELD_NAME, OBJECT_FIELD_NAME, GEO_POINT_FIELD_NAME, GEO_SHAPE_FIELD_NAME }; + protected static final String[] MAPPED_LEAF_FIELD_NAMES = new String[] { STRING_FIELD_NAME, INT_FIELD_NAME, DOUBLE_FIELD_NAME, + BOOLEAN_FIELD_NAME, DATE_FIELD_NAME, GEO_POINT_FIELD_NAME }; private static Injector injector; private static IndexQueryParserService queryParserService; @@ -204,7 +205,8 @@ public abstract class AbstractQueryTestCase> BOOLEAN_FIELD_NAME, "type=boolean", DATE_FIELD_NAME, "type=date", OBJECT_FIELD_NAME, "type=object", - GEO_FIELD_NAME, "type=geo_point,lat_lon=true,geohash=true,geohash_prefix=true" + GEO_POINT_FIELD_NAME, "type=geo_point,lat_lon=true,geohash=true,geohash_prefix=true", + GEO_SHAPE_FIELD_NAME, "type=geo_shape" ).string()), false, false); // also add mappings for two inner field in the object field mapperService.merge(type, new CompressedXContent("{\"properties\":{\""+OBJECT_FIELD_NAME+"\":{\"type\":\"object\"," diff --git a/core/src/test/java/org/elasticsearch/index/query/GeoDistanceRangeQueryTests.java b/core/src/test/java/org/elasticsearch/index/query/GeoDistanceRangeQueryTests.java index 6fd1728e81f..f3da698d6dc 100644 --- a/core/src/test/java/org/elasticsearch/index/query/GeoDistanceRangeQueryTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/GeoDistanceRangeQueryTests.java @@ -38,7 +38,7 @@ public class GeoDistanceRangeQueryTests extends AbstractQueryTestCase polygon = randomPolygon(randomIntBetween(4, 50)); if (randomBoolean()) { - builder = new GeoPolygonQueryBuilder(GEO_FIELD_NAME, polygon); + builder = new GeoPolygonQueryBuilder(GEO_POINT_FIELD_NAME, polygon); } else { - builder = new GeoPolygonQueryBuilder(GEO_FIELD_NAME); + builder = new GeoPolygonQueryBuilder(GEO_POINT_FIELD_NAME); for (GeoPoint point : polygon) { int method = randomInt(2); switch (method) { @@ -128,7 +128,7 @@ public class GeoPolygonQueryBuilderTests extends AbstractQueryTestCase { + + private static String indexedShapeId; + private static String indexedShapeType; + private static String indexedShapePath; + private static String indexedShapeIndex; + private static ShapeBuilder indexedShapeToReturn; + + @Override + protected GeoShapeQueryBuilder doCreateTestQueryBuilder() { + ShapeBuilder shape = RandomShapeGenerator.createShapeWithin(getRandom(), null); + GeoShapeQueryBuilder builder; + if (randomBoolean()) { + try { + builder = new GeoShapeQueryBuilder(GEO_SHAPE_FIELD_NAME, shape); + } catch (IOException e) { + throw new RuntimeException(e); + } + } else { + indexedShapeToReturn = shape; + indexedShapeId = randomAsciiOfLengthBetween(3, 20); + indexedShapeType = randomAsciiOfLengthBetween(3, 20); + builder = new GeoShapeQueryBuilder(GEO_SHAPE_FIELD_NAME, indexedShapeId, indexedShapeType); + if (randomBoolean()) { + indexedShapeIndex = randomAsciiOfLengthBetween(3, 20); + builder.indexedShapeIndex(indexedShapeIndex); + } + if (randomBoolean()) { + indexedShapePath = randomAsciiOfLengthBetween(3, 20); + builder.indexedShapePath(indexedShapePath); + } + } + SpatialStrategy strategy = randomFrom(SpatialStrategy.values()); + builder.strategy(strategy); + if (strategy != SpatialStrategy.TERM) { + builder.relation(randomFrom(ShapeRelation.values())); + } + return builder; + } + + @Override + protected GetResponse executeGet(GetRequest getRequest) { + assertThat(indexedShapeToReturn, notNullValue()); + assertThat(indexedShapeId, notNullValue()); + assertThat(indexedShapeType, notNullValue()); + assertThat(getRequest.id(), equalTo(indexedShapeId)); + assertThat(getRequest.type(), equalTo(indexedShapeType)); + String expectedShapeIndex = indexedShapeIndex == null ? GeoShapeQueryBuilder.DEFAULT_SHAPE_INDEX_NAME : indexedShapeIndex; + assertThat(getRequest.index(), equalTo(expectedShapeIndex)); + String expectedShapePath = indexedShapePath == null ? GeoShapeQueryBuilder.DEFAULT_SHAPE_FIELD_NAME : indexedShapePath; + String json; + try { + XContentBuilder builder = XContentFactory.jsonBuilder().prettyPrint(); + builder.startObject(); + builder.field(expectedShapePath, indexedShapeToReturn); + builder.endObject(); + json = builder.string(); + } catch (IOException ex) { + throw new ElasticsearchException("boom", ex); + } + GetResponse response = new GetResponse(new GetResult(indexedShapeIndex, indexedShapeType, indexedShapeId, 0, true, new BytesArray( + json), null)); + return response; + } + + @After + public void clearShapeFields() { + indexedShapeToReturn = null; + indexedShapeId = null; + indexedShapeType = null; + indexedShapePath = null; + indexedShapeIndex = null; + } + + @Override + protected void doAssertLuceneQuery(GeoShapeQueryBuilder queryBuilder, Query query, QueryShardContext context) throws IOException { + // Logic for doToQuery is complex and is hard to test here. Need to rely + // on Integration tests to determine if created query is correct + // TODO improve GeoShapeQueryBuilder.doToQuery() method to make it + // easier to test here + assertThat(query, anyOf(instanceOf(BooleanQuery.class), instanceOf(ConstantScoreQuery.class))); + } + + /** + * Overridden here to ensure the test is only run if at least one type is + * present in the mappings. Geo queries do not execute if the field is not + * explicitly mapped + */ + @Override + public void testToQuery() throws IOException { + assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0); + super.testToQuery(); + } + + @Test(expected = IllegalArgumentException.class) + public void testNoFieldName() throws Exception { + ShapeBuilder shape = RandomShapeGenerator.createShapeWithin(getRandom(), null); + new GeoShapeQueryBuilder(null, shape); + } + + @Test + public void testNoShape() throws IOException { + try { + GeoShapeQueryBuilder builder = new GeoShapeQueryBuilder(GEO_SHAPE_FIELD_NAME, (ShapeBuilder) null); + QueryValidationException exception = builder.validate(); + assertThat(exception, notNullValue()); + assertThat(exception.validationErrors(), notNullValue()); + assertThat(exception.validationErrors().size(), equalTo(1)); + assertThat(exception.validationErrors().get(0), equalTo("[" + GeoShapeQueryBuilder.NAME + "] No Shape defined")); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Test(expected = IllegalArgumentException.class) + public void testNoIndexedShape() throws IOException { + new GeoShapeQueryBuilder(GEO_SHAPE_FIELD_NAME, (String) null, "type"); + } + + @Test(expected = IllegalArgumentException.class) + public void testNoIndexedShapeType() throws IOException { + new GeoShapeQueryBuilder(GEO_SHAPE_FIELD_NAME, "id", (String) null); + } + + @Test + public void testNoRelation() { + ShapeBuilder shape = RandomShapeGenerator.createShapeWithin(getRandom(), null); + try { + GeoShapeQueryBuilder builder = new GeoShapeQueryBuilder(GEO_SHAPE_FIELD_NAME, shape); + builder.relation(null); + QueryValidationException exception = builder.validate(); + assertThat(exception, notNullValue()); + assertThat(exception.validationErrors(), notNullValue()); + assertThat(exception.validationErrors().size(), equalTo(1)); + assertThat(exception.validationErrors().get(0), equalTo("[" + GeoShapeQueryBuilder.NAME + "] No Shape Relation defined")); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Test + public void testInvalidRelation() { + ShapeBuilder shape = RandomShapeGenerator.createShapeWithin(getRandom(), null); + try { + GeoShapeQueryBuilder builder = new GeoShapeQueryBuilder(GEO_SHAPE_FIELD_NAME, shape); + builder.strategy(SpatialStrategy.TERM); + ShapeRelation relation = randomFrom(ShapeRelation.DISJOINT, ShapeRelation.WITHIN); + builder.relation(relation); + QueryValidationException exception = builder.validate(); + assertThat(exception, notNullValue()); + assertThat(exception.validationErrors(), notNullValue()); + assertThat(exception.validationErrors().size(), equalTo(1)); + assertThat( + exception.validationErrors().get(0), + equalTo("[" + GeoShapeQueryBuilder.NAME + "] strategy [" + SpatialStrategy.TERM.getStrategyName() + + "] only supports relation [" + ShapeRelation.INTERSECTS.getRelationName() + "] found relation [" + + relation.getRelationName() + "]")); + } catch (IOException e) { + throw new RuntimeException(e); + } + } @Test // see #3878 public void testThatXContentSerializationInsideOfArrayWorks() throws Exception { diff --git a/core/src/test/java/org/elasticsearch/index/query/GeohashCellQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/GeohashCellQueryBuilderTests.java index 48faac3f1e1..020f82bd9be 100644 --- a/core/src/test/java/org/elasticsearch/index/query/GeohashCellQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/GeohashCellQueryBuilderTests.java @@ -38,7 +38,7 @@ public class GeohashCellQueryBuilderTests extends AbstractQueryTestCase @Override protected Builder doCreateTestQueryBuilder() { - GeohashCellQuery.Builder builder = new Builder(GEO_FIELD_NAME); + GeohashCellQuery.Builder builder = new Builder(GEO_POINT_FIELD_NAME); builder.geohash(randomGeohash(1, 12)); if (randomBoolean()) { builder.neighbors(randomBoolean()); @@ -95,7 +95,7 @@ public class GeohashCellQueryBuilderTests extends AbstractQueryTestCase @Test public void testNullGeohash() { - GeohashCellQuery.Builder builder = new Builder(GEO_FIELD_NAME); + GeohashCellQuery.Builder builder = new Builder(GEO_POINT_FIELD_NAME); QueryValidationException exception = builder.validate(); assertThat(exception, notNullValue()); assertThat(exception.validationErrors(), notNullValue()); @@ -105,7 +105,7 @@ public class GeohashCellQueryBuilderTests extends AbstractQueryTestCase @Test public void testInvalidPrecision() { - GeohashCellQuery.Builder builder = new Builder(GEO_FIELD_NAME); + GeohashCellQuery.Builder builder = new Builder(GEO_POINT_FIELD_NAME); builder.geohash(randomGeohash(1, 12)); builder.precision(-1); QueryValidationException exception = builder.validate(); diff --git a/core/src/test/java/org/elasticsearch/search/geo/GeoShapeIntegrationIT.java b/core/src/test/java/org/elasticsearch/search/geo/GeoShapeIntegrationIT.java index 5607266398b..33593e9ac06 100644 --- a/core/src/test/java/org/elasticsearch/search/geo/GeoShapeIntegrationIT.java +++ b/core/src/test/java/org/elasticsearch/search/geo/GeoShapeIntegrationIT.java @@ -49,7 +49,10 @@ import static org.elasticsearch.index.query.QueryBuilders.geoShapeQuery; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse; -import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.nullValue; public class GeoShapeIntegrationIT extends ESIntegTestCase { @@ -286,28 +289,28 @@ public class GeoShapeIntegrationIT extends ESIntegTestCase { .endObject().endObject())); ensureSearchable("test", "shapes"); - GeoShapeQueryBuilder filter = QueryBuilders.geoShapeQuery("location", "1", "type", ShapeRelation.INTERSECTS) + GeoShapeQueryBuilder filter = QueryBuilders.geoShapeQuery("location", "1", "type").relation(ShapeRelation.INTERSECTS) .indexedShapeIndex("shapes") .indexedShapePath("location"); SearchResponse result = client().prepareSearch("test").setQuery(QueryBuilders.matchAllQuery()) .setPostFilter(filter).get(); assertSearchResponse(result); assertHitCount(result, 1); - filter = QueryBuilders.geoShapeQuery("location", "1", "type", ShapeRelation.INTERSECTS) + filter = QueryBuilders.geoShapeQuery("location", "1", "type").relation(ShapeRelation.INTERSECTS) .indexedShapeIndex("shapes") .indexedShapePath("1.location"); result = client().prepareSearch("test").setQuery(QueryBuilders.matchAllQuery()) .setPostFilter(filter).get(); assertSearchResponse(result); assertHitCount(result, 1); - filter = QueryBuilders.geoShapeQuery("location", "1", "type", ShapeRelation.INTERSECTS) + filter = QueryBuilders.geoShapeQuery("location", "1", "type").relation(ShapeRelation.INTERSECTS) .indexedShapeIndex("shapes") .indexedShapePath("1.2.location"); result = client().prepareSearch("test").setQuery(QueryBuilders.matchAllQuery()) .setPostFilter(filter).get(); assertSearchResponse(result); assertHitCount(result, 1); - filter = QueryBuilders.geoShapeQuery("location", "1", "type", ShapeRelation.INTERSECTS) + filter = QueryBuilders.geoShapeQuery("location", "1", "type").relation(ShapeRelation.INTERSECTS) .indexedShapeIndex("shapes") .indexedShapePath("1.2.3.location"); result = client().prepareSearch("test").setQuery(QueryBuilders.matchAllQuery()) @@ -360,7 +363,8 @@ public class GeoShapeIntegrationIT extends ESIntegTestCase { ShapeBuilder filterShape = (gcb.getShapeAt(randomIntBetween(0, gcb.numShapes() - 1))); - GeoShapeQueryBuilder filter = QueryBuilders.geoShapeQuery("location", filterShape, ShapeRelation.INTERSECTS); + GeoShapeQueryBuilder filter = QueryBuilders.geoShapeQuery("location", filterShape); + filter.relation(ShapeRelation.INTERSECTS); SearchResponse result = client().prepareSearch("test").setQuery(QueryBuilders.matchAllQuery()) .setPostFilter(filter).get(); assertSearchResponse(result); @@ -399,19 +403,30 @@ public class GeoShapeIntegrationIT extends ESIntegTestCase { .setSource(docSource)); ensureSearchable("test"); - GeoShapeQueryBuilder filter = QueryBuilders.geoShapeQuery("location", ShapeBuilder.newGeometryCollection().polygon(ShapeBuilder.newPolygon().point(99.0, -1.0).point(99.0, 3.0).point(103.0, 3.0).point(103.0, -1.0).point(99.0, -1.0)), ShapeRelation.INTERSECTS); + GeoShapeQueryBuilder filter = QueryBuilders.geoShapeQuery( + "location", + ShapeBuilder.newGeometryCollection() + .polygon( + ShapeBuilder.newPolygon().point(99.0, -1.0).point(99.0, 3.0).point(103.0, 3.0).point(103.0, -1.0) + .point(99.0, -1.0))).relation(ShapeRelation.INTERSECTS); SearchResponse result = client().prepareSearch("test").setQuery(QueryBuilders.matchAllQuery()) .setPostFilter(filter).get(); assertSearchResponse(result); assertHitCount(result, 1); - filter = QueryBuilders.geoShapeQuery("location", ShapeBuilder.newGeometryCollection().polygon(ShapeBuilder.newPolygon().point(199.0, -11.0).point(199.0, 13.0).point(193.0, 13.0).point(193.0, -11.0).point(199.0, -11.0)), ShapeRelation.INTERSECTS); + filter = QueryBuilders.geoShapeQuery( + "location", + ShapeBuilder.newGeometryCollection().polygon( + ShapeBuilder.newPolygon().point(199.0, -11.0).point(199.0, 13.0).point(193.0, 13.0).point(193.0, -11.0) + .point(199.0, -11.0))).relation(ShapeRelation.INTERSECTS); result = client().prepareSearch("test").setQuery(QueryBuilders.matchAllQuery()) .setPostFilter(filter).get(); assertSearchResponse(result); assertHitCount(result, 0); filter = QueryBuilders.geoShapeQuery("location", ShapeBuilder.newGeometryCollection() .polygon(ShapeBuilder.newPolygon().point(99.0, -1.0).point(99.0, 3.0).point(103.0, 3.0).point(103.0, -1.0).point(99.0, -1.0)) - .polygon(ShapeBuilder.newPolygon().point(199.0, -11.0).point(199.0, 13.0).point(193.0, 13.0).point(193.0, -11.0).point(199.0, -11.0)), ShapeRelation.INTERSECTS); + .polygon( + ShapeBuilder.newPolygon().point(199.0, -11.0).point(199.0, 13.0).point(193.0, 13.0).point(193.0, -11.0) + .point(199.0, -11.0))).relation(ShapeRelation.INTERSECTS); result = client().prepareSearch("test").setQuery(QueryBuilders.matchAllQuery()) .setPostFilter(filter).get(); assertSearchResponse(result);