From d6c583d9debe261054d673d2baaa51aa40b00f3e Mon Sep 17 00:00:00 2001 From: David Wayne Smiley Date: Wed, 22 Feb 2012 07:32:04 +0000 Subject: [PATCH] LUCENE-3795 Switch Solr over to new spatial module. Tests pass. git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene3795_lsp_spatial_module@1292162 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/solr/schema/GeoHashField.java | 29 ++--- .../org/apache/solr/schema/LatLonType.java | 101 +++++++----------- .../org/apache/solr/schema/PointType.java | 23 ++-- .../solr/search/SpatialFilterQParser.java | 4 +- .../apache/solr/search/SpatialOptions.java | 3 +- .../apache/solr/search/ValueSourceParser.java | 6 +- .../function/distance/GeohashFunction.java | 4 +- .../distance/GeohashHaversineFunction.java | 19 ++-- .../distance/HaversineConstFunction.java | 20 ++-- .../function/distance/HaversineFunction.java | 12 +-- .../distance/SquaredEuclideanFunction.java | 5 +- .../distance/VectorDistanceFunction.java | 2 +- .../distance/DistanceFunctionTest.java | 24 +++-- 13 files changed, 117 insertions(+), 135 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/schema/GeoHashField.java b/solr/core/src/java/org/apache/solr/schema/GeoHashField.java index 8380360e146..d5a25a29dc0 100644 --- a/solr/core/src/java/org/apache/solr/schema/GeoHashField.java +++ b/solr/core/src/java/org/apache/solr/schema/GeoHashField.java @@ -22,9 +22,12 @@ import org.apache.lucene.queries.function.valuesource.LiteralValueSource; import org.apache.lucene.index.IndexableField; import org.apache.lucene.search.Query; import org.apache.lucene.search.SortField; -import org.apache.lucene.spatial.geohash.GeoHashUtils; -import org.apache.lucene.spatial.DistanceUtils; -import org.apache.lucene.spatial.tier.InvalidGeoException; +import org.apache.lucene.spatial.base.context.ParseUtils; +import org.apache.lucene.spatial.base.context.SpatialContext; +import org.apache.lucene.spatial.base.context.simple.SimpleSpatialContext; +import org.apache.lucene.spatial.base.exception.InvalidShapeException; +import org.apache.lucene.spatial.base.prefix.geohash.GeohashUtils; +import org.apache.lucene.spatial.base.shape.Point; import org.apache.solr.common.SolrException; import org.apache.solr.response.TextResponseWriter; import org.apache.solr.search.QParser; @@ -41,11 +44,13 @@ import java.io.IOException; * href="http://en.wikipedia.org/wiki/Geohash">Geohash field. The field is * provided as a lat/lon pair and is internally represented as a string. * - * @see org.apache.lucene.spatial.DistanceUtils#parseLatitudeLongitude(double[], String) + * @see org.apache.lucene.spatial.base.context.ParseUtils#parseLatitudeLongitude(double[], String) */ public class GeoHashField extends FieldType implements SpatialQueryable { + private final SpatialContext ctx = SimpleSpatialContext.GEO_KM; + @Override public SortField getSortField(SchemaField field, boolean top) { return getStringSort(field, top); @@ -57,11 +62,11 @@ public class GeoHashField extends FieldType implements SpatialQueryable { public Query createSpatialQuery(QParser parser, SpatialOptions options) { double [] point = new double[0]; try { - point = DistanceUtils.parsePointDouble(null, options.pointStr, 2); - } catch (InvalidGeoException e) { + point = ParseUtils.parsePointDouble(null, options.pointStr, 2); + } catch (InvalidShapeException e) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e); } - String geohash = GeoHashUtils.encode(point[0], point[1]); + String geohash = GeohashUtils.encodeLatLon(point[0], point[1]); //TODO: optimize this return new SolrConstantScoreQuery(new ValueSourceRangeFilter(new GeohashHaversineFunction(getValueSource(options.field, parser), new LiteralValueSource(geohash), options.radius), "0", String.valueOf(options.distance), true, true)); @@ -76,8 +81,8 @@ public class GeoHashField extends FieldType implements SpatialQueryable { @Override public String toExternal(IndexableField f) { - double[] latLon = GeoHashUtils.decode(f.stringValue()); - return latLon[0] + "," + latLon[1]; + Point p = GeohashUtils.decode(f.stringValue(),ctx); + return p.getY() + "," + p.getX(); } @@ -87,11 +92,11 @@ public class GeoHashField extends FieldType implements SpatialQueryable { // latitude, longitude double[] latLon = new double[0]; try { - latLon = DistanceUtils.parseLatitudeLongitude(null, val); - } catch (InvalidGeoException e) { + latLon = ParseUtils.parseLatitudeLongitude(null, val); + } catch (InvalidShapeException e) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e); } - return GeoHashUtils.encode(latLon[0], latLon[1]); + return GeohashUtils.encodeLatLon(latLon[0], latLon[1]); } diff --git a/solr/core/src/java/org/apache/solr/schema/LatLonType.java b/solr/core/src/java/org/apache/solr/schema/LatLonType.java index e0fd0e50a76..6b1d0bff4c3 100644 --- a/solr/core/src/java/org/apache/solr/schema/LatLonType.java +++ b/solr/core/src/java/org/apache/solr/schema/LatLonType.java @@ -22,14 +22,18 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.AtomicReaderContext; import org.apache.lucene.queries.function.FunctionValues; import org.apache.lucene.queries.function.ValueSource; -import org.apache.lucene.queries.function.ValueSourceScorer; import org.apache.lucene.queries.function.valuesource.VectorValueSource; import org.apache.lucene.search.*; -import org.apache.lucene.spatial.DistanceUtils; -import org.apache.lucene.spatial.tier.InvalidGeoException; +import org.apache.lucene.spatial.base.context.ParseUtils; +import org.apache.lucene.spatial.base.context.SpatialContext; +import org.apache.lucene.spatial.base.context.simple.SimpleSpatialContext; +import org.apache.lucene.spatial.base.distance.DistanceCalculator; +import org.apache.lucene.spatial.base.distance.DistanceUtils; +import org.apache.lucene.spatial.base.distance.GeodesicSphereDistCalc; +import org.apache.lucene.spatial.base.exception.InvalidShapeException; +import org.apache.lucene.spatial.base.shape.Rectangle; import org.apache.lucene.util.Bits; import org.apache.solr.common.SolrException; -import org.apache.solr.common.params.SolrParams; import org.apache.solr.response.TextResponseWriter; import org.apache.solr.search.*; @@ -63,8 +67,8 @@ public class LatLonType extends AbstractSubTypeFieldType implements SpatialQuery int i = 0; double[] latLon; try { - latLon = DistanceUtils.parseLatitudeLongitude(null, externalVal); - } catch (InvalidGeoException e) { + latLon = ParseUtils.parseLatitudeLongitude(null, externalVal); + } catch (InvalidShapeException e) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e); } //latitude @@ -91,9 +95,9 @@ public class LatLonType extends AbstractSubTypeFieldType implements SpatialQuery String[] p1; String[] p2; try { - p1 = DistanceUtils.parsePoint(null, part1, dimension); - p2 = DistanceUtils.parsePoint(null, part2, dimension); - } catch (InvalidGeoException e) { + p1 = ParseUtils.parsePoint(null, part1, dimension); + p2 = ParseUtils.parsePoint(null, part2, dimension); + } catch (InvalidShapeException e) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e); } BooleanQuery result = new BooleanQuery(true); @@ -112,8 +116,8 @@ public class LatLonType extends AbstractSubTypeFieldType implements SpatialQuery String[] p1 = new String[0]; try { - p1 = DistanceUtils.parsePoint(null, externalVal, dimension); - } catch (InvalidGeoException e) { + p1 = ParseUtils.parsePoint(null, externalVal, dimension); + } catch (InvalidShapeException e) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e); } BooleanQuery bq = new BooleanQuery(true); @@ -131,65 +135,32 @@ public class LatLonType extends AbstractSubTypeFieldType implements SpatialQuery public Query createSpatialQuery(QParser parser, SpatialOptions options) { double[] point = null; try { - point = DistanceUtils.parseLatitudeLongitude(options.pointStr); - } catch (InvalidGeoException e) { + point = ParseUtils.parseLatitudeLongitude(options.pointStr); + } catch (InvalidShapeException e) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e); } // lat & lon in degrees double latCenter = point[LAT]; double lonCenter = point[LONG]; - - point[0] = point[0] * DistanceUtils.DEGREES_TO_RADIANS; - point[1] = point[1] * DistanceUtils.DEGREES_TO_RADIANS; - //Get the distance - - double[] tmp = new double[2]; - //these calculations aren't totally accurate, but it should be good enough - //TODO: Optimize to do in single calculations. Would need to deal with poles, prime meridian, etc. - double [] north = DistanceUtils.pointOnBearing(point[LAT], point[LONG], options.distance, 0, tmp, options.radius); - //This returns the point as radians, but we need degrees b/c that is what the field is stored as - double ur_lat = north[LAT] * DistanceUtils.RADIANS_TO_DEGREES;//get it now, as we are going to reuse tmp - double [] east = DistanceUtils.pointOnBearing(point[LAT], point[LONG], options.distance, DistanceUtils.DEG_90_AS_RADS, tmp, options.radius); - double ur_lon = east[LONG] * DistanceUtils.RADIANS_TO_DEGREES; - double [] south = DistanceUtils.pointOnBearing(point[LAT], point[LONG], options.distance, DistanceUtils.DEG_180_AS_RADS, tmp, options.radius); - double ll_lat = south[LAT] * DistanceUtils.RADIANS_TO_DEGREES; - double [] west = DistanceUtils.pointOnBearing(point[LAT], point[LONG], options.distance, DistanceUtils.DEG_270_AS_RADS, tmp, options.radius); - double ll_lon = west[LONG] * DistanceUtils.RADIANS_TO_DEGREES; - - //TODO: can we reuse our bearing calculations? - double angDist = DistanceUtils.angularDistance(options.distance, - options.radius);//in radians - - double latMin = -90.0, latMax = 90.0, lonMin = -180.0, lonMax = 180.0; - double lon2Min = -180.0, lon2Max = 180.0; // optional second longitude restriction - - // for the poles, do something slightly different - a polar "cap". - // Also, note point[LAT] is in radians, but ur and ll are in degrees - if (point[LAT] + angDist > DistanceUtils.DEG_90_AS_RADS) { // we cross the north pole - //we don't need a longitude boundary at all - latMin = Math.min(ll_lat, ur_lat); - } else if (point[LAT] - angDist < -DistanceUtils.DEG_90_AS_RADS) { // we cross the south pole - latMax = Math.max(ll_lat, ur_lat); + DistanceCalculator distCalc = new GeodesicSphereDistCalc.Haversine(options.units.earthRadius()); + SpatialContext ctx = new SimpleSpatialContext(options.units,distCalc,null); + Rectangle bbox = DistanceUtils.calcBoxByDistFromPtDEG(latCenter, lonCenter, options.distance, ctx); + double latMin = bbox.getMinY(); + double latMax = bbox.getMaxY(); + double lonMin, lonMax, lon2Min, lon2Max; + if (bbox.getCrossesDateLine()) { + lonMin = -180; + lonMax = bbox.getMaxX(); + lon2Min = bbox.getMinX(); + lon2Max = 180; } else { - // set the latitude restriction as normal - latMin = ll_lat; - latMax = ur_lat; - - if (ll_lon > ur_lon) { - // we crossed the +-180 deg longitude... need to make - // range queries of (-180 TO ur) OR (ll TO 180) - lonMin = -180; - lonMax = ur_lon; - lon2Min = ll_lon; - lon2Max = 180; - } else { - lonMin = ll_lon; - lonMax = ur_lon; - } + lonMin = bbox.getMinX(); + lonMax = bbox.getMaxX(); + lon2Min = -180; + lon2Max = 180; } - // Now that we've figured out the ranges, build them! SchemaField latField = subField(options.field, LAT); @@ -427,8 +398,8 @@ class SpatialDistanceQuery extends ExtendedQueryBase implements PostFilter { this.lon2 = SpatialDistanceQuery.this.lon2; this.calcDist = SpatialDistanceQuery.this.calcDist; - this.latCenterRad = SpatialDistanceQuery.this.latCenter * DistanceUtils.DEGREES_TO_RADIANS; - this.lonCenterRad = SpatialDistanceQuery.this.lonCenter * DistanceUtils.DEGREES_TO_RADIANS; + this.latCenterRad = Math.toRadians(SpatialDistanceQuery.this.latCenter); + this.lonCenterRad = Math.toRadians(SpatialDistanceQuery.this.lonCenter); this.latCenterRad_cos = this.calcDist ? Math.cos(latCenterRad) : 0; this.dist = SpatialDistanceQuery.this.dist; this.planetRadius = SpatialDistanceQuery.this.planetRadius; @@ -457,8 +428,8 @@ class SpatialDistanceQuery extends ExtendedQueryBase implements PostFilter { } double dist(double lat, double lon) { - double latRad = lat * DistanceUtils.DEGREES_TO_RADIANS; - double lonRad = lon * DistanceUtils.DEGREES_TO_RADIANS; + double latRad = Math.toRadians(lat); + double lonRad = Math.toRadians(lon); // haversine, specialized to avoid a cos() call on latCenterRad double diffX = latCenterRad - latRad; diff --git a/solr/core/src/java/org/apache/solr/schema/PointType.java b/solr/core/src/java/org/apache/solr/schema/PointType.java index 7cd3d57d6cd..48da54edcb5 100644 --- a/solr/core/src/java/org/apache/solr/schema/PointType.java +++ b/solr/core/src/java/org/apache/solr/schema/PointType.java @@ -25,8 +25,9 @@ import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.SortField; -import org.apache.lucene.spatial.DistanceUtils; -import org.apache.lucene.spatial.tier.InvalidGeoException; +import org.apache.lucene.spatial.base.context.ParseUtils; +import org.apache.lucene.spatial.base.distance.DistanceUtils; +import org.apache.lucene.spatial.base.exception.InvalidShapeException; import org.apache.solr.common.SolrException; import org.apache.solr.common.params.MapSolrParams; import org.apache.solr.common.params.SolrParams; @@ -72,8 +73,8 @@ public class PointType extends CoordinateFieldType implements SpatialQueryable { String externalVal = value.toString(); String[] point = new String[0]; try { - point = DistanceUtils.parsePoint(null, externalVal, dimension); - } catch (InvalidGeoException e) { + point = ParseUtils.parsePoint(null, externalVal, dimension); + } catch (InvalidShapeException e) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e); } @@ -137,9 +138,9 @@ public class PointType extends CoordinateFieldType implements SpatialQueryable { String[] p1; String[] p2; try { - p1 = DistanceUtils.parsePoint(null, part1, dimension); - p2 = DistanceUtils.parsePoint(null, part2, dimension); - } catch (InvalidGeoException e) { + p1 = ParseUtils.parsePoint(null, part1, dimension); + p2 = ParseUtils.parsePoint(null, part2, dimension); + } catch (InvalidShapeException e) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e); } BooleanQuery result = new BooleanQuery(true); @@ -155,8 +156,8 @@ public class PointType extends CoordinateFieldType implements SpatialQueryable { public Query getFieldQuery(QParser parser, SchemaField field, String externalVal) { String[] p1 = new String[0]; try { - p1 = DistanceUtils.parsePoint(null, externalVal, dimension); - } catch (InvalidGeoException e) { + p1 = ParseUtils.parsePoint(null, externalVal, dimension); + } catch (InvalidShapeException e) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e); } //TODO: should we assert that p1.length == dimension? @@ -179,8 +180,8 @@ public class PointType extends CoordinateFieldType implements SpatialQueryable { Query result = null; double [] point = new double[0]; try { - point = DistanceUtils.parsePointDouble(null, options.pointStr, dimension); - } catch (InvalidGeoException e) { + point = ParseUtils.parsePointDouble(null, options.pointStr, dimension); + } catch (InvalidShapeException e) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e); } if (dimension == 1){ diff --git a/solr/core/src/java/org/apache/solr/search/SpatialFilterQParser.java b/solr/core/src/java/org/apache/solr/search/SpatialFilterQParser.java index 05b749e81c2..94409504013 100644 --- a/solr/core/src/java/org/apache/solr/search/SpatialFilterQParser.java +++ b/solr/core/src/java/org/apache/solr/search/SpatialFilterQParser.java @@ -19,8 +19,8 @@ package org.apache.solr.search; import org.apache.lucene.queryparser.classic.ParseException; import org.apache.lucene.search.Query; -import org.apache.lucene.spatial.geometry.DistanceUnits; -import org.apache.lucene.spatial.DistanceUtils; +import org.apache.lucene.spatial.base.distance.DistanceUnits; +import org.apache.lucene.spatial.base.distance.DistanceUtils; import org.apache.solr.common.SolrException; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.params.SpatialParams; diff --git a/solr/core/src/java/org/apache/solr/search/SpatialOptions.java b/solr/core/src/java/org/apache/solr/search/SpatialOptions.java index 04d4cbbf76a..b9d8e6a2d2e 100644 --- a/solr/core/src/java/org/apache/solr/search/SpatialOptions.java +++ b/solr/core/src/java/org/apache/solr/search/SpatialOptions.java @@ -16,9 +16,8 @@ package org.apache.solr.search; * limitations under the License. */ +import org.apache.lucene.spatial.base.distance.DistanceUnits; import org.apache.solr.schema.SchemaField; -import org.apache.lucene.spatial.geometry.DistanceUnits; - /** * diff --git a/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java b/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java index 47887bb4c03..c8c21be73b0 100755 --- a/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java +++ b/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java @@ -34,7 +34,6 @@ import org.apache.lucene.search.spell.JaroWinklerDistance; import org.apache.lucene.search.spell.LevensteinDistance; import org.apache.lucene.search.spell.NGramDistance; import org.apache.lucene.search.spell.StringDistance; -import org.apache.lucene.spatial.DistanceUtils; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.UnicodeUtil; import org.apache.solr.common.SolrException; @@ -44,7 +43,6 @@ import org.apache.solr.schema.*; import org.apache.solr.search.function.distance.*; import org.apache.solr.util.plugin.NamedListInitializedPlugin; -import org.omg.PortableInterceptor.RequestInfo; import java.io.IOException; import java.util.*; @@ -364,13 +362,13 @@ public abstract class ValueSourceParser implements NamedListInitializedPlugin { addParser(new DoubleParser("rad") { @Override public double func(int doc, FunctionValues vals) { - return vals.doubleVal(doc) * DistanceUtils.DEGREES_TO_RADIANS; + return Math.toRadians(vals.doubleVal(doc)); } }); addParser(new DoubleParser("deg") { @Override public double func(int doc, FunctionValues vals) { - return vals.doubleVal(doc) * DistanceUtils.RADIANS_TO_DEGREES; + return Math.toDegrees(vals.doubleVal(doc)); } }); addParser(new DoubleParser("sqrt") { diff --git a/solr/core/src/java/org/apache/solr/search/function/distance/GeohashFunction.java b/solr/core/src/java/org/apache/solr/search/function/distance/GeohashFunction.java index 478b2d94b9b..b0d1a1aa86b 100644 --- a/solr/core/src/java/org/apache/solr/search/function/distance/GeohashFunction.java +++ b/solr/core/src/java/org/apache/solr/search/function/distance/GeohashFunction.java @@ -19,7 +19,7 @@ package org.apache.solr.search.function.distance; import org.apache.lucene.index.AtomicReaderContext; import org.apache.lucene.queries.function.FunctionValues; import org.apache.lucene.queries.function.ValueSource; -import org.apache.lucene.spatial.geohash.GeoHashUtils; +import org.apache.lucene.spatial.base.prefix.geohash.GeohashUtils; import java.util.Map; import java.io.IOException; @@ -55,7 +55,7 @@ public class GeohashFunction extends ValueSource { @Override public String strVal(int doc) { - return GeoHashUtils.encode(latDV.doubleVal(doc), lonDV.doubleVal(doc)); + return GeohashUtils.encodeLatLon(latDV.doubleVal(doc), lonDV.doubleVal(doc)); } @Override diff --git a/solr/core/src/java/org/apache/solr/search/function/distance/GeohashHaversineFunction.java b/solr/core/src/java/org/apache/solr/search/function/distance/GeohashHaversineFunction.java index 5e63d7dad7a..be5f9dc1500 100644 --- a/solr/core/src/java/org/apache/solr/search/function/distance/GeohashHaversineFunction.java +++ b/solr/core/src/java/org/apache/solr/search/function/distance/GeohashHaversineFunction.java @@ -20,10 +20,15 @@ package org.apache.solr.search.function.distance; import org.apache.lucene.queries.function.FunctionValues; import org.apache.lucene.queries.function.ValueSource; import org.apache.lucene.queries.function.docvalues.DoubleDocValues; -import org.apache.lucene.spatial.DistanceUtils; import org.apache.lucene.index.AtomicReaderContext; import org.apache.lucene.search.IndexSearcher; -import org.apache.lucene.spatial.geohash.GeoHashUtils; +import org.apache.lucene.spatial.base.context.SpatialContext; +import org.apache.lucene.spatial.base.context.simple.SimpleSpatialContext; +import org.apache.lucene.spatial.base.distance.DistanceCalculator; +import org.apache.lucene.spatial.base.distance.DistanceUnits; +import org.apache.lucene.spatial.base.distance.GeodesicSphereDistCalc; +import org.apache.lucene.spatial.base.prefix.geohash.GeohashUtils; +import org.apache.lucene.spatial.base.shape.Point; import java.util.Map; import java.io.IOException; @@ -43,11 +48,14 @@ public class GeohashHaversineFunction extends ValueSource { private ValueSource geoHash1, geoHash2; private double radius; + private final SpatialContext ctx; public GeohashHaversineFunction(ValueSource geoHash1, ValueSource geoHash2, double radius) { this.geoHash1 = geoHash1; this.geoHash2 = geoHash2; this.radius = radius; + DistanceCalculator distCalc = new GeodesicSphereDistCalc.Haversine(radius); + this.ctx = new SimpleSpatialContext(DistanceUnits.KILOMETERS,distCalc,null); } protected String name() { @@ -82,10 +90,9 @@ public class GeohashHaversineFunction extends ValueSource { if (h1 != null && h2 != null && h1.equals(h2) == false){ //TODO: If one of the hashes is a literal value source, seems like we could cache it //and avoid decoding every time - double[] h1Pair = GeoHashUtils.decode(h1); - double[] h2Pair = GeoHashUtils.decode(h2); - result = DistanceUtils.haversine(Math.toRadians(h1Pair[0]), Math.toRadians(h1Pair[1]), - Math.toRadians(h2Pair[0]), Math.toRadians(h2Pair[1]), radius); + Point p1 = GeohashUtils.decode(h1,ctx); + Point p2 = GeohashUtils.decode(h2,ctx); + result = ctx.getDistCalc().distance(p1, p2); } else if (h1 == null || h2 == null){ result = Double.MAX_VALUE; } diff --git a/solr/core/src/java/org/apache/solr/search/function/distance/HaversineConstFunction.java b/solr/core/src/java/org/apache/solr/search/function/distance/HaversineConstFunction.java index dd2b13d21a1..78becbad4af 100755 --- a/solr/core/src/java/org/apache/solr/search/function/distance/HaversineConstFunction.java +++ b/solr/core/src/java/org/apache/solr/search/function/distance/HaversineConstFunction.java @@ -26,13 +26,13 @@ import org.apache.lucene.queries.function.valuesource.MultiValueSource; import org.apache.lucene.queries.function.valuesource.VectorValueSource; import org.apache.lucene.queryparser.classic.ParseException; import org.apache.lucene.search.IndexSearcher; -import org.apache.lucene.spatial.DistanceUtils; -import org.apache.lucene.spatial.tier.InvalidGeoException; +import org.apache.lucene.spatial.base.context.ParseUtils; +import org.apache.lucene.spatial.base.distance.DistanceUtils; +import org.apache.lucene.spatial.base.exception.InvalidShapeException; import org.apache.solr.common.params.SpatialParams; import org.apache.solr.schema.SchemaField; import org.apache.solr.search.FunctionQParser; import org.apache.solr.search.ValueSourceParser; -import org.apache.solr.search.function.*; import java.io.IOException; import java.util.Arrays; @@ -144,8 +144,8 @@ public class HaversineConstFunction extends ValueSource { if (pt == null) return null; double[] point = null; try { - point = DistanceUtils.parseLatitudeLongitude(pt); - } catch (InvalidGeoException e) { + point = ParseUtils.parseLatitudeLongitude(pt); + } catch (InvalidShapeException e) { throw new ParseException("Bad spatial pt:" + pt); } return new VectorValueSource(Arrays.asList(new DoubleConstValueSource(point[0]),new DoubleConstValueSource(point[1]))); @@ -190,7 +190,7 @@ public class HaversineConstFunction extends ValueSource { this.p2 = vs; this.latSource = p2.getSources().get(0); this.lonSource = p2.getSources().get(1); - this.latCenterRad_cos = Math.cos(latCenter * DistanceUtils.DEGREES_TO_RADIANS); + this.latCenterRad_cos = Math.cos(Math.toRadians(latCenter)); } protected String name() { @@ -201,15 +201,15 @@ public class HaversineConstFunction extends ValueSource { public FunctionValues getValues(Map context, AtomicReaderContext readerContext) throws IOException { final FunctionValues latVals = latSource.getValues(context, readerContext); final FunctionValues lonVals = lonSource.getValues(context, readerContext); - final double latCenterRad = this.latCenter * DistanceUtils.DEGREES_TO_RADIANS; - final double lonCenterRad = this.lonCenter * DistanceUtils.DEGREES_TO_RADIANS; + final double latCenterRad = Math.toRadians(this.latCenter); + final double lonCenterRad = Math.toRadians(this.lonCenter); final double latCenterRad_cos = this.latCenterRad_cos; return new DoubleDocValues(this) { @Override public double doubleVal(int doc) { - double latRad = latVals.doubleVal(doc) * DistanceUtils.DEGREES_TO_RADIANS; - double lonRad = lonVals.doubleVal(doc) * DistanceUtils.DEGREES_TO_RADIANS; + double latRad = Math.toRadians(latVals.doubleVal(doc)); + double lonRad = Math.toRadians(lonVals.doubleVal(doc)); double diffX = latCenterRad - latRad; double diffY = lonCenterRad - lonRad; double hsinX = Math.sin(diffX * 0.5); diff --git a/solr/core/src/java/org/apache/solr/search/function/distance/HaversineFunction.java b/solr/core/src/java/org/apache/solr/search/function/distance/HaversineFunction.java index d281245f9c1..8994558a170 100644 --- a/solr/core/src/java/org/apache/solr/search/function/distance/HaversineFunction.java +++ b/solr/core/src/java/org/apache/solr/search/function/distance/HaversineFunction.java @@ -22,7 +22,7 @@ import org.apache.lucene.queries.function.ValueSource; import org.apache.lucene.queries.function.docvalues.DoubleDocValues; import org.apache.lucene.queries.function.valuesource.MultiValueSource; import org.apache.lucene.search.IndexSearcher; -import org.apache.lucene.spatial.DistanceUtils; +import org.apache.lucene.spatial.base.distance.DistanceUtils; import org.apache.solr.common.SolrException; import java.io.IOException; @@ -81,17 +81,17 @@ public class HaversineFunction extends ValueSource { double y2; double x2; if (convertToRadians) { - y1 = p1D[0] * DistanceUtils.DEGREES_TO_RADIANS; - x1 = p1D[1] * DistanceUtils.DEGREES_TO_RADIANS; - y2 = p2D[0] * DistanceUtils.DEGREES_TO_RADIANS; - x2 = p2D[1] * DistanceUtils.DEGREES_TO_RADIANS; + y1 = Math.toRadians(p1D[0]); + x1 = Math.toRadians(p1D[1]); + y2 = Math.toRadians(p2D[0]); + x2 = Math.toRadians(p2D[1]); } else { y1 = p1D[0]; x1 = p1D[1]; y2 = p2D[0]; x2 = p2D[1]; } - return DistanceUtils.haversine(y1, x1, y2, x2, radius); + return DistanceUtils.distHaversineRAD(y1,x1,y2,x2)*radius; } diff --git a/solr/core/src/java/org/apache/solr/search/function/distance/SquaredEuclideanFunction.java b/solr/core/src/java/org/apache/solr/search/function/distance/SquaredEuclideanFunction.java index e114f11a2b2..a1f184f453b 100644 --- a/solr/core/src/java/org/apache/solr/search/function/distance/SquaredEuclideanFunction.java +++ b/solr/core/src/java/org/apache/solr/search/function/distance/SquaredEuclideanFunction.java @@ -18,8 +18,7 @@ package org.apache.solr.search.function.distance; import org.apache.lucene.queries.function.FunctionValues; import org.apache.lucene.queries.function.valuesource.MultiValueSource; -import org.apache.lucene.spatial.DistanceUtils; - +import org.apache.lucene.spatial.base.distance.DistanceUtils; /** * While not strictly a distance, the Sq. Euclidean Distance is often all that is needed in many applications @@ -50,7 +49,7 @@ public class SquaredEuclideanFunction extends VectorDistanceFunction { dv1.doubleVal(doc, vals1); dv2.doubleVal(doc, vals2); - return DistanceUtils.squaredEuclideanDistance(vals1, vals2); + return DistanceUtils.distSquaredCartesian(vals1, vals2); } @Override diff --git a/solr/core/src/java/org/apache/solr/search/function/distance/VectorDistanceFunction.java b/solr/core/src/java/org/apache/solr/search/function/distance/VectorDistanceFunction.java index eb41e9beb4a..d5151d05d12 100644 --- a/solr/core/src/java/org/apache/solr/search/function/distance/VectorDistanceFunction.java +++ b/solr/core/src/java/org/apache/solr/search/function/distance/VectorDistanceFunction.java @@ -22,7 +22,7 @@ import org.apache.lucene.queries.function.ValueSource; import org.apache.lucene.queries.function.docvalues.DoubleDocValues; import org.apache.lucene.queries.function.valuesource.MultiValueSource; import org.apache.lucene.search.IndexSearcher; -import org.apache.lucene.spatial.DistanceUtils; +import org.apache.lucene.spatial.base.distance.DistanceUtils; import org.apache.solr.common.SolrException; import java.io.IOException; diff --git a/solr/core/src/test/org/apache/solr/search/function/distance/DistanceFunctionTest.java b/solr/core/src/test/org/apache/solr/search/function/distance/DistanceFunctionTest.java index 2ba9bb2a84a..b7ae7520e4c 100644 --- a/solr/core/src/test/org/apache/solr/search/function/distance/DistanceFunctionTest.java +++ b/solr/core/src/test/org/apache/solr/search/function/distance/DistanceFunctionTest.java @@ -16,8 +16,8 @@ package org.apache.solr.search.function.distance; * limitations under the License. */ -import org.apache.lucene.spatial.DistanceUtils; -import org.apache.lucene.spatial.geohash.GeoHashUtils; +import org.apache.lucene.spatial.base.distance.DistanceUtils; +import org.apache.lucene.spatial.base.prefix.geohash.GeohashUtils; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.common.SolrException; import org.junit.BeforeClass; @@ -36,12 +36,12 @@ public class DistanceFunctionTest extends SolrTestCaseJ4 { @Test public void testHaversine() throws Exception { clearIndex(); - assertU(adoc("id", "1", "x_td", "0", "y_td", "0", "gh_s1", GeoHashUtils.encode(32.7693246, -79.9289094))); - assertU(adoc("id", "2", "x_td", "0", "y_td", String.valueOf(Math.PI / 2), "gh_s1", GeoHashUtils.encode(32.7693246, -78.9289094))); - assertU(adoc("id", "3", "x_td", String.valueOf(Math.PI / 2), "y_td", String.valueOf(Math.PI / 2), "gh_s1", GeoHashUtils.encode(32.7693246, -80.9289094))); - assertU(adoc("id", "4", "x_td", String.valueOf(Math.PI / 4), "y_td", String.valueOf(Math.PI / 4), "gh_s1", GeoHashUtils.encode(32.7693246, -81.9289094))); + assertU(adoc("id", "1", "x_td", "0", "y_td", "0", "gh_s1", GeohashUtils.encodeLatLon(32.7693246, -79.9289094))); + assertU(adoc("id", "2", "x_td", "0", "y_td", String.valueOf(Math.PI / 2), "gh_s1", GeohashUtils.encodeLatLon(32.7693246, -78.9289094))); + assertU(adoc("id", "3", "x_td", String.valueOf(Math.PI / 2), "y_td", String.valueOf(Math.PI / 2), "gh_s1", GeohashUtils.encodeLatLon(32.7693246, -80.9289094))); + assertU(adoc("id", "4", "x_td", String.valueOf(Math.PI / 4), "y_td", String.valueOf(Math.PI / 4), "gh_s1", GeohashUtils.encodeLatLon(32.7693246, -81.9289094))); assertU(adoc("id", "5", "x_td", "45.0", "y_td", "45.0", - "gh_s1", GeoHashUtils.encode(32.7693246, -81.9289094))); + "gh_s1", GeohashUtils.encodeLatLon(32.7693246, -81.9289094))); assertU(adoc("id", "6", "point_hash", "32.5, -79.0", "point", "32.5, -79.0")); assertU(adoc("id", "7", "point_hash", "32.6, -78.0", "point", "32.6, -78.0")); assertU(commit()); @@ -56,17 +56,19 @@ public class DistanceFunctionTest extends SolrTestCaseJ4 { //Geo Hash Haversine //Can verify here: http://www.movable-type.co.uk/scripts/latlong.html, but they use a slightly different radius for the earth, so just be close - assertQ(req("fl", "*,score", "q", "{!func}ghhsin(" + DistanceUtils.EARTH_MEAN_RADIUS_KM + ", gh_s1, \"" + GeoHashUtils.encode(32, -79) + - "\",)", "fq", "id:1"), "//float[@name='score']='122.171875'"); + //note: using assertJQ because it supports numeric deltas, and by default too + assertJQ(req("fl", "*,score", "q", "{!func}ghhsin(" + DistanceUtils.EARTH_MEAN_RADIUS_KM + ", gh_s1, \"" + GeohashUtils.encodeLatLon(32, -79) + "\",)", "fq", "id:1"), + "/response/docs/[0]/score==122.171875"); - assertQ(req("fl", "id,point_hash,score", "q", "{!func}recip(ghhsin(" + DistanceUtils.EARTH_MEAN_RADIUS_KM + ", point_hash, \"" + GeoHashUtils.encode(32, -79) + "\"), 1, 1, 0)"), + assertQ(req("fl", "id,point_hash,score", "q", "{!func}recip(ghhsin(" + DistanceUtils.EARTH_MEAN_RADIUS_KM + ", point_hash, \"" + GeohashUtils.encodeLatLon(32, -79) + "\"), 1, 1, 0)"), "//*[@numFound='7']", "//result/doc[1]/str[@name='id'][.='6']", "//result/doc[2]/str[@name='id'][.='7']"//all the rest don't matter ); - assertQ(req("fl", "*,score", "q", "{!func}ghhsin(" + DistanceUtils.EARTH_MEAN_RADIUS_KM + ", gh_s1, geohash(32, -79))", "fq", "id:1"), "//float[@name='score']='122.171875'"); + assertJQ(req("fl", "*,score", "q", "{!func}ghhsin(" + DistanceUtils.EARTH_MEAN_RADIUS_KM + ", gh_s1, geohash(32, -79))", "fq", "id:1"), + "/response/docs/[0]/score==122.171875"); }