Merge pull request #15010 from cbuescher/refactor-shapebuilders

Make remaining ShapeBuilders implement Writeable
This commit is contained in:
Christoph Büscher 2015-12-18 11:11:34 +01:00
commit 2f97ff0925
30 changed files with 1101 additions and 232 deletions

View File

@ -25,26 +25,17 @@ import com.vividsolutions.jts.geom.Coordinate;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException;
import java.util.Locale;
import java.util.Objects;
public class EnvelopeBuilder extends ShapeBuilder {
public static final GeoShapeType TYPE = GeoShapeType.ENVELOPE;
public static final EnvelopeBuilder PROTOTYPE = new EnvelopeBuilder();
protected Coordinate topLeft;
protected Coordinate bottomRight;
public EnvelopeBuilder() {
this(Orientation.RIGHT);
}
public EnvelopeBuilder(Orientation orientation) {
super(orientation);
}
private Coordinate topLeft;
private Coordinate bottomRight;
public EnvelopeBuilder topLeft(Coordinate topLeft) {
this.topLeft = topLeft;
@ -55,6 +46,10 @@ public class EnvelopeBuilder extends ShapeBuilder {
return topLeft(coordinate(longitude, latitude));
}
public Coordinate topLeft() {
return this.topLeft;
}
public EnvelopeBuilder bottomRight(Coordinate bottomRight) {
this.bottomRight = bottomRight;
return this;
@ -64,11 +59,14 @@ public class EnvelopeBuilder extends ShapeBuilder {
return bottomRight(coordinate(longitude, latitude));
}
public Coordinate bottomRight() {
return this.bottomRight;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(FIELD_TYPE, TYPE.shapeName());
builder.field(FIELD_ORIENTATION, orientation.name().toLowerCase(Locale.ROOT));
builder.startArray(FIELD_COORDINATES);
toXContent(builder, topLeft);
toXContent(builder, bottomRight);
@ -88,7 +86,7 @@ public class EnvelopeBuilder extends ShapeBuilder {
@Override
public int hashCode() {
return Objects.hash(orientation, topLeft, bottomRight);
return Objects.hash(topLeft, bottomRight);
}
@Override
@ -100,22 +98,19 @@ public class EnvelopeBuilder extends ShapeBuilder {
return false;
}
EnvelopeBuilder other = (EnvelopeBuilder) obj;
return Objects.equals(orientation, other.orientation) &&
Objects.equals(topLeft, other.topLeft) &&
return Objects.equals(topLeft, other.topLeft) &&
Objects.equals(bottomRight, other.bottomRight);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeBoolean(orientation == Orientation.RIGHT);
writeCoordinateTo(topLeft, out);
writeCoordinateTo(bottomRight, out);
}
@Override
public EnvelopeBuilder readFrom(StreamInput in) throws IOException {
Orientation orientation = in.readBoolean() ? Orientation.RIGHT : Orientation.LEFT;
return new EnvelopeBuilder(orientation)
return new EnvelopeBuilder()
.topLeft(readCoordinateFrom(in))
.bottomRight(readCoordinateFrom(in));
}

View File

@ -20,28 +20,26 @@
package org.elasticsearch.common.geo.builders;
import com.spatial4j.core.shape.Shape;
import org.elasticsearch.common.geo.XShapeCollection;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class GeometryCollectionBuilder extends ShapeBuilder {
public static final GeoShapeType TYPE = GeoShapeType.GEOMETRYCOLLECTION;
public static final GeometryCollectionBuilder PROTOTYPE = new GeometryCollectionBuilder();
protected final ArrayList<ShapeBuilder> shapes = new ArrayList<>();
public GeometryCollectionBuilder() {
this(Orientation.RIGHT);
}
public GeometryCollectionBuilder(Orientation orientation) {
super(orientation);
}
public GeometryCollectionBuilder shape(ShapeBuilder shape) {
this.shapes.add(shape);
return this;
@ -132,4 +130,39 @@ public class GeometryCollectionBuilder extends ShapeBuilder {
//note: ShapeCollection is probably faster than a Multi* geom.
}
@Override
public int hashCode() {
return Objects.hash(shapes);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
GeometryCollectionBuilder other = (GeometryCollectionBuilder) obj;
return Objects.equals(shapes, other.shapes);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeVInt(shapes.size());
for (ShapeBuilder shape : shapes) {
out.writeShape(shape);
}
}
@Override
public GeometryCollectionBuilder readFrom(StreamInput in) throws IOException {
GeometryCollectionBuilder geometryCollectionBuilder = new GeometryCollectionBuilder();
int shapes = in.readVInt();
for (int i = 0; i < shapes; i++) {
geometryCollectionBuilder.shape(in.readShape());
}
return geometryCollectionBuilder;
}
}

View File

@ -22,8 +22,12 @@ package org.elasticsearch.common.geo.builders;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import com.spatial4j.core.shape.Shape;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
@ -34,6 +38,8 @@ public class LineStringBuilder extends PointCollection<LineStringBuilder> {
public static final GeoShapeType TYPE = GeoShapeType.LINESTRING;
public static final LineStringBuilder PROTOTYPE = new LineStringBuilder();
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
@ -139,4 +145,39 @@ public class LineStringBuilder extends PointCollection<LineStringBuilder> {
}
return coordinates;
}
@Override
public int hashCode() {
return Objects.hash(points);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
LineStringBuilder other = (LineStringBuilder) obj;
return Objects.equals(points, other.points);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeVInt(points.size());
for (Coordinate point : points) {
writeCoordinateTo(point, out);
}
}
@Override
public LineStringBuilder readFrom(StreamInput in) throws IOException {
LineStringBuilder lineStringBuilder = new LineStringBuilder();
int size = in.readVInt();
for (int i=0; i < size; i++) {
lineStringBuilder.point(readCoordinateFrom(in));
}
return lineStringBuilder;
}
}

View File

@ -19,6 +19,8 @@
package org.elasticsearch.common.geo.builders;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import com.spatial4j.core.shape.Shape;
@ -29,11 +31,14 @@ import com.vividsolutions.jts.geom.LineString;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Objects;
public class MultiLineStringBuilder extends ShapeBuilder {
public static final GeoShapeType TYPE = GeoShapeType.MULTILINESTRING;
public static final MultiLineStringBuilder PROTOTYPE = new MultiLineStringBuilder();
private final ArrayList<LineStringBuilder> lines = new ArrayList<>();
public MultiLineStringBuilder linestring(LineStringBuilder line) {
@ -41,6 +46,10 @@ public class MultiLineStringBuilder extends ShapeBuilder {
return this;
}
public MultiLineStringBuilder linestring(Coordinate[] coordinates) {
return this.linestring(new LineStringBuilder().points(coordinates));
}
public Coordinate[][] coordinates() {
Coordinate[][] result = new Coordinate[lines.size()][];
for (int i = 0; i < result.length; i++) {
@ -92,4 +101,39 @@ public class MultiLineStringBuilder extends ShapeBuilder {
}
return jtsGeometry(geometry);
}
@Override
public int hashCode() {
return Objects.hash(lines);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
MultiLineStringBuilder other = (MultiLineStringBuilder) obj;
return Objects.equals(lines, other.lines);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeVInt(lines.size());
for (LineStringBuilder line : lines) {
line.writeTo(out);
}
}
@Override
public MultiLineStringBuilder readFrom(StreamInput in) throws IOException {
MultiLineStringBuilder multiLineStringBuilder = new MultiLineStringBuilder();
int size = in.readVInt();
for (int i = 0; i < size; i++) {
multiLineStringBuilder.linestring(LineStringBuilder.PROTOTYPE.readFrom(in));
}
return multiLineStringBuilder;
}
}

View File

@ -22,18 +22,22 @@ package org.elasticsearch.common.geo.builders;
import com.spatial4j.core.shape.Point;
import com.spatial4j.core.shape.Shape;
import com.vividsolutions.jts.geom.Coordinate;
import org.elasticsearch.common.geo.XShapeCollection;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.geo.XShapeCollection;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class MultiPointBuilder extends PointCollection<MultiPointBuilder> {
public static final GeoShapeType TYPE = GeoShapeType.MULTIPOINT;
public final static MultiPointBuilder PROTOTYPE = new MultiPointBuilder();
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
@ -52,7 +56,7 @@ public class MultiPointBuilder extends PointCollection<MultiPointBuilder> {
for (Coordinate coord : points) {
shapes.add(SPATIAL_CONTEXT.makePoint(coord.x, coord.y));
}
XShapeCollection multiPoints = new XShapeCollection<>(shapes, SPATIAL_CONTEXT);
XShapeCollection<Point> multiPoints = new XShapeCollection<>(shapes, SPATIAL_CONTEXT);
multiPoints.setPointsOnly(true);
return multiPoints;
}
@ -61,4 +65,39 @@ public class MultiPointBuilder extends PointCollection<MultiPointBuilder> {
public GeoShapeType type() {
return TYPE;
}
@Override
public int hashCode() {
return Objects.hash(points);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
MultiPointBuilder other = (MultiPointBuilder) obj;
return Objects.equals(points, other.points);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeVInt(points.size());
for (Coordinate point : points) {
writeCoordinateTo(point, out);
}
}
@Override
public MultiPointBuilder readFrom(StreamInput in) throws IOException {
MultiPointBuilder multiPointBuilder = new MultiPointBuilder();
int size = in.readVInt();
for (int i=0; i < size; i++) {
multiPointBuilder.point(readCoordinateFrom(in));
}
return multiPointBuilder;
}
}

View File

@ -22,8 +22,12 @@ package org.elasticsearch.common.geo.builders;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import org.elasticsearch.common.geo.XShapeCollection;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import com.spatial4j.core.shape.Shape;
@ -32,26 +36,50 @@ import com.vividsolutions.jts.geom.Coordinate;
public class MultiPolygonBuilder extends ShapeBuilder {
public static final GeoShapeType TYPE = GeoShapeType.MULTIPOLYGON;
public static final MultiPolygonBuilder PROTOTYPE = new MultiPolygonBuilder();
protected final ArrayList<PolygonBuilder> polygons = new ArrayList<>();
private final ArrayList<PolygonBuilder> polygons = new ArrayList<>();
private Orientation orientation = Orientation.RIGHT;
public MultiPolygonBuilder() {
this(Orientation.RIGHT);
}
public MultiPolygonBuilder(Orientation orientation) {
super(orientation);
this.orientation = orientation;
}
public Orientation orientation() {
return this.orientation;
}
/**
* Add a shallow copy of the polygon to the multipolygon. This will apply the orientation of the
* {@link MultiPolygonBuilder} to the polygon if polygon has different orientation.
*/
public MultiPolygonBuilder polygon(PolygonBuilder polygon) {
this.polygons.add(polygon);
PolygonBuilder pb = new PolygonBuilder(this.orientation);
pb.points(polygon.shell().coordinates(false));
for (LineStringBuilder hole : polygon.holes()) {
pb.hole(hole);
}
this.polygons.add(pb);
return this;
}
/**
* get the list of polygons
*/
public ArrayList<PolygonBuilder> polygons() {
return polygons;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(FIELD_TYPE, TYPE.shapeName());
builder.field(FIELD_ORIENTATION, orientation.name().toLowerCase(Locale.ROOT));
builder.startArray(FIELD_COORDINATES);
for(PolygonBuilder polygon : polygons) {
builder.startArray();
@ -89,4 +117,41 @@ public class MultiPolygonBuilder extends ShapeBuilder {
return new XShapeCollection<>(shapes, SPATIAL_CONTEXT);
//note: ShapeCollection is probably faster than a Multi* geom.
}
@Override
public int hashCode() {
return Objects.hash(polygons, orientation);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
MultiPolygonBuilder other = (MultiPolygonBuilder) obj;
return Objects.equals(polygons, other.polygons) &&
Objects.equals(orientation, other.orientation);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
orientation.writeTo(out);
out.writeVInt(polygons.size());
for (PolygonBuilder polygon : polygons) {
polygon.writeTo(out);
}
}
@Override
public MultiPolygonBuilder readFrom(StreamInput in) throws IOException {
MultiPolygonBuilder polyBuilder = new MultiPolygonBuilder(Orientation.readFrom(in));
int holes = in.readVInt();
for (int i = 0; i < holes; i++) {
polyBuilder.polygon(PolygonBuilder.PROTOTYPE.readFrom(in));
}
return polyBuilder;
}
}

View File

@ -32,7 +32,6 @@ import com.vividsolutions.jts.geom.Coordinate;
public class PointBuilder extends ShapeBuilder {
public static final GeoShapeType TYPE = GeoShapeType.POINT;
public static final PointBuilder PROTOTYPE = new PointBuilder();
private Coordinate coordinate;

View File

@ -29,6 +29,8 @@ import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Polygon;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.common.xcontent.XContentBuilder;
@ -39,6 +41,9 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
/**
* The {@link PolygonBuilder} implements the groundwork to create polygons. This contains
@ -48,6 +53,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
public class PolygonBuilder extends ShapeBuilder {
public static final GeoShapeType TYPE = GeoShapeType.POLYGON;
public static final PolygonBuilder PROTOTYPE = new PolygonBuilder();
private static final Coordinate[][] EMPTY = new Coordinate[0][];
private Orientation orientation = Orientation.RIGHT;
// line string defining the shell of the polygon
private LineStringBuilder shell;
@ -56,7 +66,7 @@ public class PolygonBuilder extends ShapeBuilder {
private final ArrayList<LineStringBuilder> holes = new ArrayList<>();
public PolygonBuilder() {
this(new ArrayList<Coordinate>(), Orientation.RIGHT);
this(Orientation.RIGHT);
}
public PolygonBuilder(Orientation orientation) {
@ -64,10 +74,14 @@ public class PolygonBuilder extends ShapeBuilder {
}
public PolygonBuilder(ArrayList<Coordinate> points, Orientation orientation) {
super(orientation);
this.orientation = orientation;
this.shell = new LineStringBuilder().points(points);
}
public Orientation orientation() {
return this.orientation;
}
public PolygonBuilder point(double longitude, double latitude) {
shell.point(longitude, latitude);
return this;
@ -103,6 +117,20 @@ public class PolygonBuilder extends ShapeBuilder {
return this;
}
/**
* @return the list of holes defined for this polygon
*/
public List<LineStringBuilder> holes() {
return this.holes;
}
/**
* @return the list of points of the shell for this polygon
*/
public LineStringBuilder shell() {
return this.shell;
}
/**
* Close the shell of the polygon
*/
@ -175,6 +203,7 @@ public class PolygonBuilder extends ShapeBuilder {
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(FIELD_TYPE, TYPE.shapeName());
builder.field(FIELD_ORIENTATION, orientation.name().toLowerCase(Locale.ROOT));
builder.startArray(FIELD_COORDINATES);
coordinatesArray(builder, params);
builder.endArray();
@ -357,8 +386,6 @@ public class PolygonBuilder extends ShapeBuilder {
return result;
}
private static final Coordinate[][] EMPTY = new Coordinate[0][];
private static Coordinate[][] holes(Edge[] holes, int numHoles) {
if (numHoles == 0) {
return EMPTY;
@ -663,4 +690,44 @@ public class PolygonBuilder extends ShapeBuilder {
}
}
}
@Override
public int hashCode() {
return Objects.hash(shell, holes, orientation);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
PolygonBuilder other = (PolygonBuilder) obj;
return Objects.equals(shell, other.shell) &&
Objects.equals(holes, other.holes) &&
Objects.equals(orientation, other.orientation);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
orientation.writeTo(out);
shell.writeTo(out);
out.writeVInt(holes.size());
for (LineStringBuilder hole : holes) {
hole.writeTo(out);
}
}
@Override
public PolygonBuilder readFrom(StreamInput in) throws IOException {
PolygonBuilder polyBuilder = new PolygonBuilder(Orientation.readFrom(in));
polyBuilder.shell = LineStringBuilder.PROTOTYPE.readFrom(in);
int holes = in.readVInt();
for (int i = 0; i < holes; i++) {
polyBuilder.hole(LineStringBuilder.PROTOTYPE.readFrom(in));
}
return polyBuilder;
}
}

View File

@ -77,16 +77,10 @@ public abstract class ShapeBuilder extends ToXContentToBytes implements NamedWri
/** @see com.spatial4j.core.shape.jts.JtsGeometry#index() */
protected final boolean autoIndexJtsGeometry = true;//may want to turn off once SpatialStrategy impls do it.
protected Orientation orientation = Orientation.RIGHT;
protected ShapeBuilder() {
}
protected ShapeBuilder(Orientation orientation) {
this.orientation = orientation;
}
protected static Coordinate coordinate(double longitude, double latitude) {
return new Coordinate(longitude, latitude);
}
@ -186,22 +180,6 @@ public abstract class ShapeBuilder extends ToXContentToBytes implements NamedWri
return new Coordinate(in.readDouble(), in.readDouble());
}
public static Orientation orientationFromString(String orientation) {
orientation = orientation.toLowerCase(Locale.ROOT);
switch (orientation) {
case "right":
case "counterclockwise":
case "ccw":
return Orientation.RIGHT;
case "left":
case "clockwise":
case "cw":
return Orientation.LEFT;
default:
throw new IllegalArgumentException("Unknown orientation [" + orientation + "]");
}
}
protected static Coordinate shift(Coordinate coordinate, double dateline) {
if (dateline == 0) {
return coordinate;
@ -408,6 +386,30 @@ public abstract class ShapeBuilder extends ToXContentToBytes implements NamedWri
public static final Orientation COUNTER_CLOCKWISE = Orientation.RIGHT;
public static final Orientation CW = Orientation.LEFT;
public static final Orientation CCW = Orientation.RIGHT;
public void writeTo (StreamOutput out) throws IOException {
out.writeBoolean(this == Orientation.RIGHT);
}
public static Orientation readFrom (StreamInput in) throws IOException {
return in.readBoolean() ? Orientation.RIGHT : Orientation.LEFT;
}
public static Orientation fromString(String orientation) {
orientation = orientation.toLowerCase(Locale.ROOT);
switch (orientation) {
case "right":
case "counterclockwise":
case "ccw":
return Orientation.RIGHT;
case "left":
case "clockwise":
case "cw":
return Orientation.LEFT;
default:
throw new IllegalArgumentException("Unknown orientation [" + orientation + "]");
}
}
}
public static final String FIELD_TYPE = "type";
@ -498,7 +500,7 @@ public abstract class ShapeBuilder extends ToXContentToBytes implements NamedWri
radius = Distance.parseDistance(parser.text());
} else if (FIELD_ORIENTATION.equals(fieldName)) {
parser.nextToken();
requestedOrientation = orientationFromString(parser.text());
requestedOrientation = Orientation.fromString(parser.text());
} else {
parser.nextToken();
parser.skipChildren();
@ -524,7 +526,7 @@ public abstract class ShapeBuilder extends ToXContentToBytes implements NamedWri
case POLYGON: return parsePolygon(node, requestedOrientation, coerce);
case MULTIPOLYGON: return parseMultiPolygon(node, requestedOrientation, coerce);
case CIRCLE: return parseCircle(node, radius);
case ENVELOPE: return parseEnvelope(node, requestedOrientation);
case ENVELOPE: return parseEnvelope(node);
case GEOMETRYCOLLECTION: return geometryCollections;
default:
throw new ElasticsearchParseException("shape type [{}] not included", shapeType);
@ -550,7 +552,7 @@ public abstract class ShapeBuilder extends ToXContentToBytes implements NamedWri
return ShapeBuilders.newCircleBuilder().center(coordinates.coordinate).radius(radius);
}
protected static EnvelopeBuilder parseEnvelope(CoordinateNode coordinates, final Orientation orientation) {
protected static EnvelopeBuilder parseEnvelope(CoordinateNode coordinates) {
// validate the coordinate array for envelope type
if (coordinates.children.size() != 2) {
throw new ElasticsearchParseException("invalid number of points [{}] provided for " +
@ -564,7 +566,7 @@ public abstract class ShapeBuilder extends ToXContentToBytes implements NamedWri
uL = new Coordinate(Math.min(uL.x, lR.x), Math.max(uL.y, lR.y));
lR = new Coordinate(Math.max(uLtmp.x, lR.x), Math.min(uLtmp.y, lR.y));
}
return ShapeBuilders.newEnvelope(orientation).topLeft(uL).bottomRight(lR);
return ShapeBuilders.newEnvelope().topLeft(uL).bottomRight(lR);
}
protected static void validateMultiPointNode(CoordinateNode coordinates) {
@ -684,8 +686,7 @@ public abstract class ShapeBuilder extends ToXContentToBytes implements NamedWri
}
XContentParser.Token token = parser.nextToken();
GeometryCollectionBuilder geometryCollection = ShapeBuilders.newGeometryCollection( (mapper == null) ? Orientation.RIGHT : mapper
.fieldType().orientation());
GeometryCollectionBuilder geometryCollection = ShapeBuilders.newGeometryCollection();
while (token != XContentParser.Token.END_ARRAY) {
ShapeBuilder shapeBuilder = GeoShapeType.parse(parser);
geometryCollection.shape(shapeBuilder);
@ -700,15 +701,4 @@ public abstract class ShapeBuilder extends ToXContentToBytes implements NamedWri
public String getWriteableName() {
return type().shapeName();
}
// NORELEASE this should be deleted as soon as all shape builders implement writable
@Override
public void writeTo(StreamOutput out) throws IOException {
}
// NORELEASE this should be deleted as soon as all shape builders implement writable
@Override
public ShapeBuilder readFrom(StreamInput in) throws IOException {
return null;
}
}

View File

@ -0,0 +1,45 @@
/*
* 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.builders;
import org.elasticsearch.common.geo.ShapesAvailability;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
/**
* Register the shape builder prototypes with the {@link NamedWriteableRegistry}
*/
public class ShapeBuilderRegistry {
@Inject
public ShapeBuilderRegistry(NamedWriteableRegistry namedWriteableRegistry) {
if (ShapesAvailability.JTS_AVAILABLE && ShapesAvailability.SPATIAL4J_AVAILABLE) {
namedWriteableRegistry.registerPrototype(ShapeBuilder.class, PointBuilder.PROTOTYPE);
namedWriteableRegistry.registerPrototype(ShapeBuilder.class, CircleBuilder.PROTOTYPE);
namedWriteableRegistry.registerPrototype(ShapeBuilder.class, EnvelopeBuilder.PROTOTYPE);
namedWriteableRegistry.registerPrototype(ShapeBuilder.class, MultiPointBuilder.PROTOTYPE);
namedWriteableRegistry.registerPrototype(ShapeBuilder.class, LineStringBuilder.PROTOTYPE);
namedWriteableRegistry.registerPrototype(ShapeBuilder.class, MultiLineStringBuilder.PROTOTYPE);
namedWriteableRegistry.registerPrototype(ShapeBuilder.class, PolygonBuilder.PROTOTYPE);
namedWriteableRegistry.registerPrototype(ShapeBuilder.class, MultiPolygonBuilder.PROTOTYPE);
namedWriteableRegistry.registerPrototype(ShapeBuilder.class, GeometryCollectionBuilder.PROTOTYPE);
}
}
}

View File

@ -110,15 +110,6 @@ public class ShapeBuilders {
return new GeometryCollectionBuilder();
}
/**
* Create a new GeometryCollection
*
* @return a new {@link GeometryCollectionBuilder}
*/
public static GeometryCollectionBuilder newGeometryCollection(ShapeBuilder.Orientation orientation) {
return new GeometryCollectionBuilder(orientation);
}
/**
* create a new Circle
*
@ -136,13 +127,4 @@ public class ShapeBuilders {
public static EnvelopeBuilder newEnvelope() {
return new EnvelopeBuilder();
}
/**
* create a new rectangle
*
* @return a new {@link EnvelopeBuilder}
*/
public static EnvelopeBuilder newEnvelope(ShapeBuilder.Orientation orientation) {
return new EnvelopeBuilder(orientation);
}
}

View File

@ -33,7 +33,7 @@ import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.geo.builders.ShapeBuilder;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder;
@ -629,6 +629,13 @@ public abstract class StreamInput extends InputStream {
return readNamedWriteable(QueryBuilder.class);
}
/**
* Reads a {@link ShapeBuilder} from the current stream
*/
public ShapeBuilder readShape() throws IOException {
return readNamedWriteable(ShapeBuilder.class);
}
/**
* Reads a {@link org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder} from the current stream
*/

View File

@ -32,6 +32,7 @@ import org.elasticsearch.Version;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.geo.builders.ShapeBuilder;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder;
@ -618,6 +619,13 @@ public abstract class StreamOutput extends OutputStream {
writeNamedWriteable(queryBuilder);
}
/**
* Writes a {@link ShapeBuilder} to the current stream
*/
public void writeShape(ShapeBuilder shapeBuilder) throws IOException {
writeNamedWriteable(shapeBuilder);
}
/**
* Writes a {@link ScoreFunctionBuilder} to the current stream
*/

View File

@ -184,7 +184,7 @@ public class GeoShapeFieldMapper extends FieldMapper {
builder.fieldType().setDistanceErrorPct(Double.parseDouble(fieldNode.toString()));
iterator.remove();
} else if (Names.ORIENTATION.equals(fieldName)) {
builder.fieldType().setOrientation(ShapeBuilder.orientationFromString(fieldNode.toString()));
builder.fieldType().setOrientation(ShapeBuilder.Orientation.fromString(fieldNode.toString()));
iterator.remove();
} else if (Names.STRATEGY.equals(fieldName)) {
builder.fieldType().setStrategyName(fieldNode.toString());

View File

@ -31,19 +31,16 @@ 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.PointBuilder;
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;
@ -61,13 +58,11 @@ public class GeoShapeQueryBuilder extends AbstractQueryBuilder<GeoShapeQueryBuil
public static final String DEFAULT_SHAPE_FIELD_NAME = "shape";
public static final ShapeRelation DEFAULT_SHAPE_RELATION = ShapeRelation.INTERSECTS;
static final GeoShapeQueryBuilder PROTOTYPE = new GeoShapeQueryBuilder("field", new BytesArray(new byte[1]));
static final GeoShapeQueryBuilder PROTOTYPE = new GeoShapeQueryBuilder("field", new PointBuilder());
private final String fieldName;
// TODO make the ShapeBuilder and subclasses Writable and implement hashCode
// and Equals so ShapeBuilder can be used here
private BytesReference shapeBytes;
private ShapeBuilder shape;
private SpatialStrategy strategy;
@ -88,7 +83,7 @@ public class GeoShapeQueryBuilder extends AbstractQueryBuilder<GeoShapeQueryBuil
* @param shape
* Shape used in the Query
*/
public GeoShapeQueryBuilder(String fieldName, ShapeBuilder shape) throws IOException {
public GeoShapeQueryBuilder(String fieldName, ShapeBuilder shape) {
this(fieldName, shape, null, null);
}
@ -105,37 +100,21 @@ public class GeoShapeQueryBuilder extends AbstractQueryBuilder<GeoShapeQueryBuil
* Index type of the indexed Shapes
*/
public GeoShapeQueryBuilder(String fieldName, String indexedShapeId, String indexedShapeType) {
this(fieldName, (BytesReference) null, indexedShapeId, indexedShapeType);
this(fieldName, (ShapeBuilder) null, indexedShapeId, indexedShapeType);
}
GeoShapeQueryBuilder(String fieldName, BytesReference shapeBytes) {
this(fieldName, shapeBytes, null, null);
}
private GeoShapeQueryBuilder(String fieldName, ShapeBuilder shape, String indexedShapeId, String indexedShapeType) throws IOException {
this(fieldName, new BytesArray(new byte[1]), indexedShapeId, indexedShapeType);
if (shape != null) {
this.shapeBytes = shape.buildAsBytes(XContentType.JSON);
if (this.shapeBytes.length() == 0) {
throw new IllegalArgumentException("shape must not be empty");
}
} else {
throw new IllegalArgumentException("shape must not be null");
}
}
private GeoShapeQueryBuilder(String fieldName, BytesReference shapeBytes, String indexedShapeId, String indexedShapeType) {
private GeoShapeQueryBuilder(String fieldName, ShapeBuilder shape, String indexedShapeId, String indexedShapeType) {
if (fieldName == null) {
throw new IllegalArgumentException("fieldName is required");
}
if ((shapeBytes == null || shapeBytes.length() == 0) && indexedShapeId == null) {
if (shape == 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.shape = shape;
this.indexedShapeId = indexedShapeId;
this.indexedShapeType = indexedShapeType;
}
@ -148,10 +127,10 @@ public class GeoShapeQueryBuilder extends AbstractQueryBuilder<GeoShapeQueryBuil
}
/**
* @return the JSON bytes for the shape used in the Query
* @return the shape used in the Query
*/
public BytesReference shapeBytes() {
return shapeBytes;
public ShapeBuilder shape() {
return shape;
}
/**
@ -258,15 +237,11 @@ public class GeoShapeQueryBuilder extends AbstractQueryBuilder<GeoShapeQueryBuil
@Override
protected Query doToQuery(QueryShardContext context) throws IOException {
ShapeBuilder shape;
if (shapeBytes == null) {
ShapeBuilder shapeToQuery = shape;
if (shapeToQuery == null) {
GetRequest getRequest = new GetRequest(indexedShapeIndex, indexedShapeType, indexedShapeId);
getRequest.copyContextAndHeadersFrom(SearchContext.current());
shape = fetch(context.getClient(), getRequest, indexedShapePath);
} else {
XContentParser shapeParser = XContentHelper.createParser(shapeBytes);
shapeParser.nextToken();
shape = ShapeBuilder.parse(shapeParser);
shapeToQuery = fetch(context.getClient(), getRequest, indexedShapePath);
}
MappedFieldType fieldType = context.fieldMapper(fieldName);
if (fieldType == null) {
@ -291,12 +266,12 @@ public class GeoShapeQueryBuilder extends AbstractQueryBuilder<GeoShapeQueryBuil
// in this case, execute disjoint as exists && !intersects
BooleanQuery.Builder bool = new BooleanQuery.Builder();
Query exists = ExistsQueryBuilder.newFilter(context, fieldName);
Query intersects = strategy.makeQuery(getArgs(shape, ShapeRelation.INTERSECTS));
Query intersects = strategy.makeQuery(getArgs(shapeToQuery, ShapeRelation.INTERSECTS));
bool.add(exists, BooleanClause.Occur.MUST);
bool.add(intersects, BooleanClause.Occur.MUST_NOT);
query = new ConstantScoreQuery(bool.build());
} else {
query = new ConstantScoreQuery(strategy.makeQuery(getArgs(shape, relation)));
query = new ConstantScoreQuery(strategy.makeQuery(getArgs(shapeToQuery, relation)));
}
return query;
}
@ -378,11 +353,9 @@ public class GeoShapeQueryBuilder extends AbstractQueryBuilder<GeoShapeQueryBuil
builder.field(GeoShapeQueryParser.STRATEGY_FIELD.getPreferredName(), strategy.getStrategyName());
}
if (shapeBytes != null) {
if (shape != null) {
builder.field(GeoShapeQueryParser.SHAPE_FIELD.getPreferredName());
XContentParser parser = XContentFactory.xContent(XContentType.JSON).createParser(shapeBytes);
parser.nextToken();
builder.copyCurrentStructure(parser);
shape.toXContent(builder, params);
} else {
builder.startObject(GeoShapeQueryParser.INDEXED_SHAPE_FIELD.getPreferredName())
.field(GeoShapeQueryParser.SHAPE_ID_FIELD.getPreferredName(), indexedShapeId)
@ -412,8 +385,7 @@ public class GeoShapeQueryBuilder extends AbstractQueryBuilder<GeoShapeQueryBuil
String fieldName = in.readString();
GeoShapeQueryBuilder builder;
if (in.readBoolean()) {
BytesReference shapeBytes = in.readBytesReference();
builder = new GeoShapeQueryBuilder(fieldName, shapeBytes);
builder = new GeoShapeQueryBuilder(fieldName, in.readShape());
} else {
String indexedShapeId = in.readOptionalString();
String indexedShapeType = in.readOptionalString();
@ -437,10 +409,10 @@ public class GeoShapeQueryBuilder extends AbstractQueryBuilder<GeoShapeQueryBuil
@Override
protected void doWriteTo(StreamOutput out) throws IOException {
out.writeString(fieldName);
boolean hasShapeBytes = shapeBytes != null;
out.writeBoolean(hasShapeBytes);
if (hasShapeBytes) {
out.writeBytesReference(shapeBytes);
boolean hasShape = shape != null;
out.writeBoolean(hasShape);
if (hasShape) {
out.writeShape(shape);
} else {
out.writeOptionalString(indexedShapeId);
out.writeOptionalString(indexedShapeType);
@ -464,14 +436,14 @@ public class GeoShapeQueryBuilder extends AbstractQueryBuilder<GeoShapeQueryBuil
&& Objects.equals(indexedShapePath, other.indexedShapePath)
&& Objects.equals(indexedShapeType, other.indexedShapeType)
&& Objects.equals(relation, other.relation)
&& Objects.equals(shapeBytes, other.shapeBytes)
&& Objects.equals(shape, other.shape)
&& Objects.equals(strategy, other.strategy);
}
@Override
protected int doHashCode() {
return Objects.hash(fieldName, indexedShapeId, indexedShapeIndex,
indexedShapePath, indexedShapeType, relation, shapeBytes, strategy);
indexedShapePath, indexedShapeType, relation, shape, strategy);
}
@Override

View File

@ -22,11 +22,9 @@ package org.elasticsearch.index.query;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.geo.ShapeRelation;
import org.elasticsearch.common.geo.SpatialStrategy;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.geo.builders.ShapeBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException;
@ -54,7 +52,7 @@ public class GeoShapeQueryParser implements QueryParser<GeoShapeQueryBuilder> {
String fieldName = null;
ShapeRelation shapeRelation = null;
SpatialStrategy strategy = null;
BytesReference shape = null;
ShapeBuilder shape = null;
String id = null;
String type = null;
@ -79,8 +77,7 @@ public class GeoShapeQueryParser implements QueryParser<GeoShapeQueryBuilder> {
currentFieldName = parser.currentName();
token = parser.nextToken();
if (parseContext.parseFieldMatcher().match(currentFieldName, SHAPE_FIELD)) {
XContentBuilder builder = XContentFactory.jsonBuilder().copyCurrentStructure(parser);
shape = builder.bytes();
shape = ShapeBuilder.parse(parser);
} else if (parseContext.parseFieldMatcher().match(currentFieldName, STRATEGY_FIELD)) {
String strategyName = parser.text();
strategy = SpatialStrategy.fromString(strategyName);

View File

@ -22,18 +22,86 @@ package org.elasticsearch.indices;
import org.elasticsearch.action.update.UpdateHelper;
import org.elasticsearch.cluster.metadata.MetaDataIndexUpgradeService;
import org.elasticsearch.common.geo.ShapesAvailability;
import org.elasticsearch.common.geo.builders.ShapeBuilderRegistry;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.util.ExtensionPoint;
import org.elasticsearch.index.NodeServicesProvider;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MetadataFieldMapper;
import org.elasticsearch.index.mapper.core.*;
import org.elasticsearch.index.mapper.core.BinaryFieldMapper;
import org.elasticsearch.index.mapper.core.BooleanFieldMapper;
import org.elasticsearch.index.mapper.core.ByteFieldMapper;
import org.elasticsearch.index.mapper.core.CompletionFieldMapper;
import org.elasticsearch.index.mapper.core.DateFieldMapper;
import org.elasticsearch.index.mapper.core.DoubleFieldMapper;
import org.elasticsearch.index.mapper.core.FloatFieldMapper;
import org.elasticsearch.index.mapper.core.IntegerFieldMapper;
import org.elasticsearch.index.mapper.core.LongFieldMapper;
import org.elasticsearch.index.mapper.core.ShortFieldMapper;
import org.elasticsearch.index.mapper.core.StringFieldMapper;
import org.elasticsearch.index.mapper.core.TokenCountFieldMapper;
import org.elasticsearch.index.mapper.core.TypeParsers;
import org.elasticsearch.index.mapper.geo.GeoPointFieldMapper;
import org.elasticsearch.index.mapper.geo.GeoShapeFieldMapper;
import org.elasticsearch.index.mapper.internal.*;
import org.elasticsearch.index.mapper.internal.AllFieldMapper;
import org.elasticsearch.index.mapper.internal.FieldNamesFieldMapper;
import org.elasticsearch.index.mapper.internal.IdFieldMapper;
import org.elasticsearch.index.mapper.internal.IndexFieldMapper;
import org.elasticsearch.index.mapper.internal.ParentFieldMapper;
import org.elasticsearch.index.mapper.internal.RoutingFieldMapper;
import org.elasticsearch.index.mapper.internal.SourceFieldMapper;
import org.elasticsearch.index.mapper.internal.TTLFieldMapper;
import org.elasticsearch.index.mapper.internal.TimestampFieldMapper;
import org.elasticsearch.index.mapper.internal.TypeFieldMapper;
import org.elasticsearch.index.mapper.internal.UidFieldMapper;
import org.elasticsearch.index.mapper.internal.VersionFieldMapper;
import org.elasticsearch.index.mapper.ip.IpFieldMapper;
import org.elasticsearch.index.mapper.object.ObjectMapper;
import org.elasticsearch.index.query.*;
import org.elasticsearch.index.query.BoolQueryParser;
import org.elasticsearch.index.query.BoostingQueryParser;
import org.elasticsearch.index.query.CommonTermsQueryParser;
import org.elasticsearch.index.query.ConstantScoreQueryParser;
import org.elasticsearch.index.query.DisMaxQueryParser;
import org.elasticsearch.index.query.ExistsQueryParser;
import org.elasticsearch.index.query.FieldMaskingSpanQueryParser;
import org.elasticsearch.index.query.FuzzyQueryParser;
import org.elasticsearch.index.query.GeoBoundingBoxQueryParser;
import org.elasticsearch.index.query.GeoDistanceQueryParser;
import org.elasticsearch.index.query.GeoDistanceRangeQueryParser;
import org.elasticsearch.index.query.GeoPolygonQueryParser;
import org.elasticsearch.index.query.GeoShapeQueryParser;
import org.elasticsearch.index.query.GeohashCellQuery;
import org.elasticsearch.index.query.HasChildQueryParser;
import org.elasticsearch.index.query.HasParentQueryParser;
import org.elasticsearch.index.query.IdsQueryParser;
import org.elasticsearch.index.query.IndicesQueryParser;
import org.elasticsearch.index.query.MatchAllQueryParser;
import org.elasticsearch.index.query.MatchNoneQueryParser;
import org.elasticsearch.index.query.MatchQueryParser;
import org.elasticsearch.index.query.MoreLikeThisQueryParser;
import org.elasticsearch.index.query.MultiMatchQueryParser;
import org.elasticsearch.index.query.NestedQueryParser;
import org.elasticsearch.index.query.PrefixQueryParser;
import org.elasticsearch.index.query.QueryParser;
import org.elasticsearch.index.query.QueryStringQueryParser;
import org.elasticsearch.index.query.RangeQueryParser;
import org.elasticsearch.index.query.RegexpQueryParser;
import org.elasticsearch.index.query.ScriptQueryParser;
import org.elasticsearch.index.query.SimpleQueryStringParser;
import org.elasticsearch.index.query.SpanContainingQueryParser;
import org.elasticsearch.index.query.SpanFirstQueryParser;
import org.elasticsearch.index.query.SpanMultiTermQueryParser;
import org.elasticsearch.index.query.SpanNearQueryParser;
import org.elasticsearch.index.query.SpanNotQueryParser;
import org.elasticsearch.index.query.SpanOrQueryParser;
import org.elasticsearch.index.query.SpanTermQueryParser;
import org.elasticsearch.index.query.SpanWithinQueryParser;
import org.elasticsearch.index.query.TemplateQueryParser;
import org.elasticsearch.index.query.TermQueryParser;
import org.elasticsearch.index.query.TermsQueryParser;
import org.elasticsearch.index.query.TypeQueryParser;
import org.elasticsearch.index.query.WildcardQueryParser;
import org.elasticsearch.index.query.WrapperQueryParser;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryParser;
import org.elasticsearch.index.termvectors.TermVectorsService;
import org.elasticsearch.indices.cache.query.IndicesQueryCache;
@ -122,7 +190,7 @@ public class IndicesModule extends AbstractModule {
registerQueryParser(ExistsQueryParser.class);
registerQueryParser(MatchNoneQueryParser.class);
if (ShapesAvailability.JTS_AVAILABLE) {
if (ShapesAvailability.JTS_AVAILABLE && ShapesAvailability.SPATIAL4J_AVAILABLE) {
registerQueryParser(GeoShapeQueryParser.class);
}
}
@ -146,7 +214,7 @@ public class IndicesModule extends AbstractModule {
registerMapper(CompletionFieldMapper.CONTENT_TYPE, new CompletionFieldMapper.TypeParser());
registerMapper(GeoPointFieldMapper.CONTENT_TYPE, new GeoPointFieldMapper.TypeParser());
if (ShapesAvailability.JTS_AVAILABLE) {
if (ShapesAvailability.JTS_AVAILABLE && ShapesAvailability.SPATIAL4J_AVAILABLE) {
registerMapper(GeoShapeFieldMapper.CONTENT_TYPE, new GeoShapeFieldMapper.TypeParser());
}
}
@ -218,6 +286,7 @@ public class IndicesModule extends AbstractModule {
bind(IndicesFieldDataCacheListener.class).asEagerSingleton();
bind(TermVectorsService.class).asEagerSingleton();
bind(NodeServicesProvider.class).asEagerSingleton();
bind(ShapeBuilderRegistry.class).asEagerSingleton();
}
// public for testing

View File

@ -23,14 +23,20 @@ import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.xcontent.*;
import org.elasticsearch.common.xcontent.ToXContent;
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.test.ESTestCase;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import java.io.IOException;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
public abstract class AbstractShapeBuilderTestCase<SB extends ShapeBuilder> extends ESTestCase {
@ -47,6 +53,12 @@ public abstract class AbstractShapeBuilderTestCase<SB extends ShapeBuilder> exte
namedWriteableRegistry.registerPrototype(ShapeBuilder.class, PointBuilder.PROTOTYPE);
namedWriteableRegistry.registerPrototype(ShapeBuilder.class, CircleBuilder.PROTOTYPE);
namedWriteableRegistry.registerPrototype(ShapeBuilder.class, EnvelopeBuilder.PROTOTYPE);
namedWriteableRegistry.registerPrototype(ShapeBuilder.class, MultiPointBuilder.PROTOTYPE);
namedWriteableRegistry.registerPrototype(ShapeBuilder.class, LineStringBuilder.PROTOTYPE);
namedWriteableRegistry.registerPrototype(ShapeBuilder.class, MultiLineStringBuilder.PROTOTYPE);
namedWriteableRegistry.registerPrototype(ShapeBuilder.class, PolygonBuilder.PROTOTYPE);
namedWriteableRegistry.registerPrototype(ShapeBuilder.class, MultiPolygonBuilder.PROTOTYPE);
namedWriteableRegistry.registerPrototype(ShapeBuilder.class, GeometryCollectionBuilder.PROTOTYPE);
}
}
@ -63,7 +75,7 @@ public abstract class AbstractShapeBuilderTestCase<SB extends ShapeBuilder> exte
/**
* mutate the given shape so the returned shape is different
*/
protected abstract SB mutate(SB original) throws IOException;
protected abstract SB createMutation(SB original) throws IOException;
/**
* Test that creates new shape from a random test shape and checks both for equality
@ -89,19 +101,21 @@ public abstract class AbstractShapeBuilderTestCase<SB extends ShapeBuilder> exte
/**
* Test serialization and deserialization of the test shape.
*/
@SuppressWarnings("unchecked")
public void testSerialization() throws IOException {
for (int runs = 0; runs < NUMBER_OF_TESTBUILDERS; runs++) {
SB testShape = createTestShapeBuilder();
SB deserializedShape = copyShape(testShape);
assertEquals(deserializedShape, testShape);
assertEquals(deserializedShape.hashCode(), testShape.hashCode());
assertNotSame(deserializedShape, testShape);
SB deserializedShape = (SB) copyShape(testShape);
assertEquals(testShape, deserializedShape);
assertEquals(testShape.hashCode(), deserializedShape.hashCode());
assertNotSame(testShape, deserializedShape);
}
}
/**
* Test equality and hashCode properties
*/
@SuppressWarnings("unchecked")
public void testEqualsAndHashcode() throws IOException {
for (int runs = 0; runs < NUMBER_OF_TESTBUILDERS; runs++) {
SB firstShape = createTestShapeBuilder();
@ -110,15 +124,15 @@ public abstract class AbstractShapeBuilderTestCase<SB extends ShapeBuilder> exte
assertTrue("shape is not equal to self", firstShape.equals(firstShape));
assertThat("same shape's hashcode returns different values if called multiple times", firstShape.hashCode(),
equalTo(firstShape.hashCode()));
assertThat("different shapes should not be equal", mutate(firstShape), not(equalTo(firstShape)));
assertThat("different shapes should not be equal", createMutation(firstShape), not(equalTo(firstShape)));
SB secondShape = copyShape(firstShape);
SB secondShape = (SB) copyShape(firstShape);
assertTrue("shape is not equal to self", secondShape.equals(secondShape));
assertTrue("shape is not equal to its copy", firstShape.equals(secondShape));
assertTrue("equals is not symmetric", secondShape.equals(firstShape));
assertThat("shape copy's hashcode is different from original hashcode", secondShape.hashCode(), equalTo(firstShape.hashCode()));
SB thirdShape = copyShape(secondShape);
SB thirdShape = (SB) copyShape(secondShape);
assertTrue("shape is not equal to self", thirdShape.equals(thirdShape));
assertTrue("shape is not equal to its copy", secondShape.equals(thirdShape));
assertThat("shape copy's hashcode is different from original hashcode", secondShape.hashCode(), equalTo(thirdShape.hashCode()));
@ -129,14 +143,12 @@ public abstract class AbstractShapeBuilderTestCase<SB extends ShapeBuilder> exte
}
}
protected SB copyShape(SB original) throws IOException {
static ShapeBuilder copyShape(ShapeBuilder original) throws IOException {
try (BytesStreamOutput output = new BytesStreamOutput()) {
original.writeTo(output);
try (StreamInput in = new NamedWriteableAwareStreamInput(StreamInput.wrap(output.bytes()), namedWriteableRegistry)) {
ShapeBuilder prototype = (ShapeBuilder) namedWriteableRegistry.getPrototype(ShapeBuilder.class, original.getWriteableName());
@SuppressWarnings("unchecked")
SB copy = (SB) prototype.readFrom(in);
return copy;
return prototype.readFrom(in);
}
}
}

View File

@ -25,20 +25,20 @@ import org.elasticsearch.common.unit.DistanceUnit;
import java.io.IOException;
public class CirlceBuilderTests extends AbstractShapeBuilderTestCase<CircleBuilder> {
public class CircleBuilderTests extends AbstractShapeBuilderTestCase<CircleBuilder> {
@Override
protected CircleBuilder createTestShapeBuilder() {
double centerX = randomDoubleBetween(-180, 180, false);
double centerY = randomDoubleBetween(-90, 90, false);
return new CircleBuilder()
.center(new Coordinate(centerX, centerY))
.radius(randomDoubleBetween(0.1, 10.0, false), randomFrom(DistanceUnit.values()));
return createRandomShape();
}
@Override
protected CircleBuilder mutate(CircleBuilder original) throws IOException {
CircleBuilder mutation = copyShape(original);
protected CircleBuilder createMutation(CircleBuilder original) throws IOException {
return mutate(original);
}
static CircleBuilder mutate(CircleBuilder original) throws IOException {
CircleBuilder mutation = (CircleBuilder) copyShape(original);
double radius = original.radius();
DistanceUnit unit = original.unit();
@ -55,4 +55,12 @@ public class CirlceBuilderTests extends AbstractShapeBuilderTestCase<CircleBuild
}
return mutation.radius(radius, unit);
}
static CircleBuilder createRandomShape() {
double centerX = randomDoubleBetween(-180, 180, false);
double centerY = randomDoubleBetween(-90, 90, false);
return new CircleBuilder()
.center(new Coordinate(centerX, centerY))
.radius(randomDoubleBetween(0.1, 10.0, false), randomFrom(DistanceUnit.values()));
}
}

View File

@ -22,7 +22,6 @@ package org.elasticsearch.common.geo.builders;
import com.spatial4j.core.shape.Rectangle;
import com.vividsolutions.jts.geom.Coordinate;
import org.elasticsearch.common.geo.builders.ShapeBuilder.Orientation;
import org.elasticsearch.test.geo.RandomShapeGenerator;
import java.io.IOException;
@ -31,36 +30,39 @@ public class EnvelopeBuilderTests extends AbstractShapeBuilderTestCase<EnvelopeB
@Override
protected EnvelopeBuilder createTestShapeBuilder() {
EnvelopeBuilder envelope = new EnvelopeBuilder(randomFrom(Orientation.values()));
return createRandomShape();
}
@Override
protected EnvelopeBuilder createMutation(EnvelopeBuilder original) throws IOException {
return mutate(original);
}
static EnvelopeBuilder mutate(EnvelopeBuilder original) throws IOException {
EnvelopeBuilder mutation = (EnvelopeBuilder) copyShape(original);
// move one corner to the middle of original
switch (randomIntBetween(0, 3)) {
case 0:
mutation.topLeft(new Coordinate(randomDoubleBetween(-180.0, original.bottomRight().x, true), original.topLeft().y));
break;
case 1:
mutation.topLeft(new Coordinate(original.topLeft().x, randomDoubleBetween(original.bottomRight().y, 90.0, true)));
break;
case 2:
mutation.bottomRight(new Coordinate(randomDoubleBetween(original.topLeft().x, 180.0, true), original.bottomRight().y));
break;
case 3:
mutation.bottomRight(new Coordinate(original.bottomRight().x, randomDoubleBetween(-90.0, original.topLeft().y, true)));
break;
}
return mutation;
}
static EnvelopeBuilder createRandomShape() {
EnvelopeBuilder envelope = new EnvelopeBuilder();
Rectangle box = RandomShapeGenerator.xRandomRectangle(getRandom(), RandomShapeGenerator.xRandomPoint(getRandom()));
envelope.topLeft(box.getMinX(), box.getMaxY())
.bottomRight(box.getMaxX(), box.getMinY());
return envelope;
}
@Override
protected EnvelopeBuilder mutate(EnvelopeBuilder original) throws IOException {
EnvelopeBuilder mutation = copyShape(original);
if (randomBoolean()) {
// toggle orientation
mutation.orientation = (original.orientation == Orientation.LEFT ? Orientation.RIGHT : Orientation.LEFT);
} else {
// move one corner to the middle of original
switch (randomIntBetween(0, 3)) {
case 0:
mutation.topLeft(new Coordinate(randomDoubleBetween(-180.0, original.bottomRight.x, true), original.topLeft.y));
break;
case 1:
mutation.topLeft(new Coordinate(original.topLeft.x, randomDoubleBetween(original.bottomRight.y, 90.0, true)));
break;
case 2:
mutation.bottomRight(new Coordinate(randomDoubleBetween(original.topLeft.x, 180.0, true), original.bottomRight.y));
break;
case 3:
mutation.bottomRight(new Coordinate(original.bottomRight.x, randomDoubleBetween(-90.0, original.topLeft.y, true)));
break;
}
}
return mutation;
}
}

View File

@ -0,0 +1,107 @@
/*
* 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.builders;
import org.elasticsearch.test.geo.RandomShapeGenerator;
import java.io.IOException;
public class GeometryCollectionBuilderTests extends AbstractShapeBuilderTestCase<GeometryCollectionBuilder> {
@Override
protected GeometryCollectionBuilder createTestShapeBuilder() {
GeometryCollectionBuilder geometryCollection = new GeometryCollectionBuilder();
int shapes = randomIntBetween(0, 8);
for (int i = 0; i < shapes; i++) {
switch (randomIntBetween(0, 7)) {
case 0:
geometryCollection.shape(PointBuilderTests.createRandomShape());
break;
case 1:
geometryCollection.shape(CircleBuilderTests.createRandomShape());
break;
case 2:
geometryCollection.shape(EnvelopeBuilderTests.createRandomShape());
break;
case 3:
geometryCollection.shape(LineStringBuilderTests.createRandomShape());
break;
case 4:
geometryCollection.shape(MultiLineStringBuilderTests.createRandomShape());
break;
case 5:
geometryCollection.shape(MultiPolygonBuilderTests.createRandomShape());
break;
case 6:
geometryCollection.shape(MultiPointBuilderTests.createRandomShape());
break;
case 7:
geometryCollection.shape(PolygonBuilderTests.createRandomShape());
break;
}
}
return geometryCollection;
}
@Override
protected GeometryCollectionBuilder createMutation(GeometryCollectionBuilder original) throws IOException {
return mutate(original);
}
static GeometryCollectionBuilder mutate(GeometryCollectionBuilder original) throws IOException {
GeometryCollectionBuilder mutation = (GeometryCollectionBuilder) copyShape(original);
if (mutation.shapes.size() > 0) {
int shapePosition = randomIntBetween(0, mutation.shapes.size() - 1);
ShapeBuilder shapeToChange = mutation.shapes.get(shapePosition);
switch (shapeToChange.type()) {
case POINT:
shapeToChange = PointBuilderTests.mutate((PointBuilder) shapeToChange);
break;
case CIRCLE:
shapeToChange = CircleBuilderTests.mutate((CircleBuilder) shapeToChange);
break;
case ENVELOPE:
shapeToChange = EnvelopeBuilderTests.mutate((EnvelopeBuilder) shapeToChange);
break;
case LINESTRING:
shapeToChange = LineStringBuilderTests.mutate((LineStringBuilder) shapeToChange);
break;
case MULTILINESTRING:
shapeToChange = MultiLineStringBuilderTests.mutate((MultiLineStringBuilder) shapeToChange);
break;
case MULTIPOLYGON:
shapeToChange = MultiPolygonBuilderTests.mutate((MultiPolygonBuilder) shapeToChange);
break;
case MULTIPOINT:
shapeToChange = MultiPointBuilderTests.mutate((MultiPointBuilder) shapeToChange);
break;
case POLYGON:
shapeToChange = PolygonBuilderTests.mutate((PolygonBuilder) shapeToChange);
break;
case GEOMETRYCOLLECTION:
throw new UnsupportedOperationException("GeometryCollection should not be nested inside each other");
}
mutation.shapes.set(shapePosition, shapeToChange);
} else {
mutation.shape(RandomShapeGenerator.createShape(getRandom()));
}
return mutation;
}
}

View File

@ -0,0 +1,68 @@
/*
* 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.builders;
import com.vividsolutions.jts.geom.Coordinate;
import org.elasticsearch.test.geo.RandomShapeGenerator;
import org.elasticsearch.test.geo.RandomShapeGenerator.ShapeType;
import java.io.IOException;
public class LineStringBuilderTests extends AbstractShapeBuilderTestCase<LineStringBuilder> {
@Override
protected LineStringBuilder createTestShapeBuilder() {
return createRandomShape();
}
@Override
protected LineStringBuilder createMutation(LineStringBuilder original) throws IOException {
return mutate(original);
}
static LineStringBuilder mutate(LineStringBuilder original) throws IOException {
LineStringBuilder mutation = (LineStringBuilder) copyShape(original);
Coordinate[] coordinates = original.coordinates(false);
Coordinate coordinate = randomFrom(coordinates);
if (randomBoolean()) {
if (coordinate.x != 0.0) {
coordinate.x = coordinate.x / 2;
} else {
coordinate.x = randomDoubleBetween(-180.0, 180.0, true);
}
} else {
if (coordinate.y != 0.0) {
coordinate.y = coordinate.y / 2;
} else {
coordinate.y = randomDoubleBetween(-90.0, 90.0, true);
}
}
return mutation.points(coordinates);
}
static LineStringBuilder createRandomShape() {
LineStringBuilder lsb = (LineStringBuilder) RandomShapeGenerator.createShape(getRandom(), ShapeType.LINESTRING);
if (randomBoolean()) {
lsb.close();
}
return lsb;
}
}

View File

@ -0,0 +1,70 @@
/*
* 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.builders;
import com.vividsolutions.jts.geom.Coordinate;
import org.elasticsearch.test.geo.RandomShapeGenerator;
import org.elasticsearch.test.geo.RandomShapeGenerator.ShapeType;
import java.io.IOException;
public class MultiLineStringBuilderTests extends AbstractShapeBuilderTestCase<MultiLineStringBuilder> {
@Override
protected MultiLineStringBuilder createTestShapeBuilder() {
return createRandomShape();
}
@Override
protected MultiLineStringBuilder createMutation(MultiLineStringBuilder original) throws IOException {
return mutate(original);
}
static MultiLineStringBuilder mutate(MultiLineStringBuilder original) throws IOException {
MultiLineStringBuilder mutation = (MultiLineStringBuilder) copyShape(original);
Coordinate[][] coordinates = mutation.coordinates();
int lineToChange = randomInt(coordinates.length - 1);
for (int i = 0; i < coordinates.length; i++) {
Coordinate[] line = coordinates[i];
if (i == lineToChange) {
Coordinate coordinate = randomFrom(line);
if (randomBoolean()) {
if (coordinate.x != 0.0) {
coordinate.x = coordinate.x / 2;
} else {
coordinate.x = randomDoubleBetween(-180.0, 180.0, true);
}
} else {
if (coordinate.y != 0.0) {
coordinate.y = coordinate.y / 2;
} else {
coordinate.y = randomDoubleBetween(-90.0, 90.0, true);
}
}
}
}
return mutation;
}
static MultiLineStringBuilder createRandomShape() {
return (MultiLineStringBuilder) RandomShapeGenerator.createShape(getRandom(), ShapeType.MULTILINESTRING);
}
}

View File

@ -0,0 +1,64 @@
/*
* 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.builders;
import com.vividsolutions.jts.geom.Coordinate;
import org.elasticsearch.test.geo.RandomShapeGenerator;
import org.elasticsearch.test.geo.RandomShapeGenerator.ShapeType;
import java.io.IOException;
public class MultiPointBuilderTests extends AbstractShapeBuilderTestCase<MultiPointBuilder> {
@Override
protected MultiPointBuilder createTestShapeBuilder() {
return createRandomShape();
}
@Override
protected MultiPointBuilder createMutation(MultiPointBuilder original) throws IOException {
return mutate(original);
}
static MultiPointBuilder mutate(MultiPointBuilder original) throws IOException {
MultiPointBuilder mutation = (MultiPointBuilder) copyShape(original);
Coordinate[] coordinates = original.coordinates(false);
Coordinate coordinate = randomFrom(coordinates);
if (randomBoolean()) {
if (coordinate.x != 0.0) {
coordinate.x = coordinate.x / 2;
} else {
coordinate.x = randomDoubleBetween(-180.0, 180.0, true);
}
} else {
if (coordinate.y != 0.0) {
coordinate.y = coordinate.y / 2;
} else {
coordinate.y = randomDoubleBetween(-90.0, 90.0, true);
}
}
return mutation.points(coordinates);
}
static MultiPointBuilder createRandomShape() {
return (MultiPointBuilder) RandomShapeGenerator.createShape(getRandom(), ShapeType.MULTIPOINT);
}
}

View File

@ -0,0 +1,68 @@
/*
* 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.builders;
import org.elasticsearch.common.geo.builders.ShapeBuilder.Orientation;
import org.elasticsearch.test.geo.RandomShapeGenerator;
import org.elasticsearch.test.geo.RandomShapeGenerator.ShapeType;
import java.io.IOException;
public class MultiPolygonBuilderTests extends AbstractShapeBuilderTestCase<MultiPolygonBuilder> {
@Override
protected MultiPolygonBuilder createTestShapeBuilder() {
return createRandomShape();
}
@Override
protected MultiPolygonBuilder createMutation(MultiPolygonBuilder original) throws IOException {
return mutate(original);
}
static MultiPolygonBuilder mutate(MultiPolygonBuilder original) throws IOException {
MultiPolygonBuilder mutation;
if (randomBoolean()) {
mutation = new MultiPolygonBuilder(original.orientation() == Orientation.LEFT ? Orientation.RIGHT : Orientation.LEFT);
for (PolygonBuilder pb : original.polygons()) {
mutation.polygon((PolygonBuilder) copyShape(pb));
}
} else {
mutation = (MultiPolygonBuilder) copyShape(original);
if (mutation.polygons().size() > 0) {
int polyToChange = randomInt(mutation.polygons().size() - 1);
mutation.polygons().set(polyToChange, PolygonBuilderTests.mutatePolygonBuilder(mutation.polygons().get(polyToChange)));
} else {
mutation.polygon((PolygonBuilder) RandomShapeGenerator.createShape(getRandom(), ShapeType.POLYGON));
}
}
return mutation;
}
static MultiPolygonBuilder createRandomShape() {
MultiPolygonBuilder mpb = new MultiPolygonBuilder(randomFrom(Orientation.values()));
int polys = randomIntBetween(0, 10);
for (int i = 0; i < polys; i++) {
PolygonBuilder pgb = (PolygonBuilder) RandomShapeGenerator.createShape(getRandom(), ShapeType.POLYGON);
mpb.polygon(pgb);
}
return mpb;
}
}

View File

@ -24,15 +24,27 @@ import com.vividsolutions.jts.geom.Coordinate;
import org.elasticsearch.test.geo.RandomShapeGenerator;
import org.elasticsearch.test.geo.RandomShapeGenerator.ShapeType;
import java.io.IOException;
public class PointBuilderTests extends AbstractShapeBuilderTestCase<PointBuilder> {
@Override
protected PointBuilder createTestShapeBuilder() {
return (PointBuilder) RandomShapeGenerator.createShape(getRandom(), ShapeType.POINT);
return createRandomShape();
}
@Override
protected PointBuilder mutate(PointBuilder original) {
return new PointBuilder().coordinate(new Coordinate(original.longitude()/2, original.latitude()/2));
protected PointBuilder createMutation(PointBuilder original) throws IOException {
return mutate(original);
}
static PointBuilder mutate(PointBuilder original) {
return new PointBuilder().coordinate(new Coordinate(original.longitude() / 2, original.latitude() / 2));
}
static PointBuilder createRandomShape() {
return (PointBuilder) RandomShapeGenerator.createShape(getRandom(), ShapeType.POINT);
}
}

View File

@ -0,0 +1,96 @@
/*
* 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.builders;
import com.vividsolutions.jts.geom.Coordinate;
import org.elasticsearch.common.geo.builders.ShapeBuilder.Orientation;
import org.elasticsearch.test.geo.RandomShapeGenerator;
import org.elasticsearch.test.geo.RandomShapeGenerator.ShapeType;
import java.io.IOException;
public class PolygonBuilderTests extends AbstractShapeBuilderTestCase<PolygonBuilder> {
@Override
protected PolygonBuilder createTestShapeBuilder() {
return createRandomShape();
}
@Override
protected PolygonBuilder createMutation(PolygonBuilder original) throws IOException {
return mutate(original);
}
static PolygonBuilder mutate(PolygonBuilder original) throws IOException {
PolygonBuilder mutation = (PolygonBuilder) copyShape(original);
return mutatePolygonBuilder(mutation);
}
static PolygonBuilder mutatePolygonBuilder(PolygonBuilder pb) {
if (randomBoolean()) {
pb = polyWithOposingOrientation(pb);
} else {
// change either point in shell or in random hole
LineStringBuilder lineToChange;
if (randomBoolean() || pb.holes().size() == 0) {
lineToChange = pb.shell();
} else {
lineToChange = randomFrom(pb.holes());
}
Coordinate coordinate = randomFrom(lineToChange.coordinates(false));
if (randomBoolean()) {
if (coordinate.x != 0.0) {
coordinate.x = coordinate.x / 2;
} else {
coordinate.x = randomDoubleBetween(-180.0, 180.0, true);
}
} else {
if (coordinate.y != 0.0) {
coordinate.y = coordinate.y / 2;
} else {
coordinate.y = randomDoubleBetween(-90.0, 90.0, true);
}
}
}
return pb;
}
/**
* Takes an input polygon and returns an identical one, only with opposing orientation setting.
* This is done so we don't have to expose a setter for orientation in the actual class
*/
private static PolygonBuilder polyWithOposingOrientation(PolygonBuilder pb) {
PolygonBuilder mutation = new PolygonBuilder(pb.orientation() == Orientation.LEFT ? Orientation.RIGHT : Orientation.LEFT);
mutation.points(pb.shell().coordinates(false));
for (LineStringBuilder hole : pb.holes()) {
mutation.hole(hole);
}
return mutation;
}
static PolygonBuilder createRandomShape() {
PolygonBuilder pgb = (PolygonBuilder) RandomShapeGenerator.createShape(getRandom(), ShapeType.POLYGON);
if (randomBoolean()) {
pgb = polyWithOposingOrientation(pgb);
}
return pgb;
}
}

View File

@ -47,6 +47,7 @@ import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.geo.builders.ShapeBuilderRegistry;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.inject.Injector;
import org.elasticsearch.common.inject.ModulesBuilder;
@ -191,6 +192,7 @@ public abstract class AbstractQueryTestCase<QB extends AbstractQueryBuilder<QB>>
// skip services
bindQueryParsersExtension();
bindMapperExtension();
bind(ShapeBuilderRegistry.class).asEagerSingleton();
}
},
new ScriptModule(settings) {

View File

@ -59,14 +59,11 @@ public class GeoShapeQueryBuilderTests extends AbstractQueryTestCase<GeoShapeQue
protected GeoShapeQueryBuilder doCreateTestQueryBuilder() {
ShapeType shapeType = ShapeType.randomType(getRandom());
ShapeBuilder shape = RandomShapeGenerator.createShapeWithin(getRandom(), null, shapeType);
GeoShapeQueryBuilder builder;
clearShapeFields();
if (randomBoolean()) {
try {
builder = new GeoShapeQueryBuilder(GEO_SHAPE_FIELD_NAME, shape);
} catch (IOException e) {
throw new RuntimeException(e);
}
builder = new GeoShapeQueryBuilder(GEO_SHAPE_FIELD_NAME, shape);
} else {
indexedShapeToReturn = shape;
indexedShapeId = randomAsciiOfLengthBetween(3, 20);
@ -225,17 +222,17 @@ public class GeoShapeQueryBuilderTests extends AbstractQueryTestCase<GeoShapeQue
public void testFromJson() throws IOException {
String json =
"{\n" +
" \"geo_shape\" : {\n" +
" \"location\" : {\n" +
" \"shape\" : {\n" +
" \"type\" : \"envelope\",\n" +
" \"coordinates\" : [ [ 13.0, 53.0 ], [ 14.0, 52.0 ] ]\n" +
" },\n" +
" \"relation\" : \"intersects\"\n" +
" },\n" +
" \"boost\" : 42.0\n" +
" }\n" +
"{\n" +
" \"geo_shape\" : {\n" +
" \"location\" : {\n" +
" \"shape\" : {\n" +
" \"type\" : \"envelope\",\n" +
" \"coordinates\" : [ [ 13.0, 53.0 ], [ 14.0, 52.0 ] ]\n" +
" },\n" +
" \"relation\" : \"intersects\"\n" +
" },\n" +
" \"boost\" : 42.0\n" +
" }\n" +
"}";
GeoShapeQueryBuilder parsed = (GeoShapeQueryBuilder) parseQuery(json);
checkGeneratedJson(json, parsed);

View File

@ -20,6 +20,7 @@
package org.elasticsearch.search.geo;
import com.spatial4j.core.shape.Rectangle;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.geo.ShapeRelation;
@ -47,7 +48,10 @@ 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.Matchers.*;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.nullValue;
public class GeoShapeQueryTests extends ESSingleNodeTestCase {
public void testNullShape() throws Exception {
@ -396,6 +400,12 @@ public class GeoShapeQueryTests extends ESSingleNodeTestCase {
.setPostFilter(filter).get();
assertSearchResponse(result);
assertHitCount(result, 1);
// no shape
filter = QueryBuilders.geoShapeQuery("location", ShapeBuilders.newGeometryCollection());
result = client().prepareSearch("test").setTypes("type").setQuery(QueryBuilders.matchAllQuery())
.setPostFilter(filter).get();
assertSearchResponse(result);
assertHitCount(result, 0);
}
public void testPointsOnly() throws Exception {