mirror of https://github.com/apache/lucene.git
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
This commit is contained in:
parent
7234d8e256
commit
d6c583d9de
|
@ -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</a> 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]);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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,8 +135,8 @@ 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);
|
||||
}
|
||||
|
||||
|
@ -140,57 +144,24 @@ public class LatLonType extends AbstractSubTypeFieldType implements SpatialQuery
|
|||
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);
|
||||
SchemaField lonField = subField(options.field, LONG);
|
||||
|
@ -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;
|
||||
|
|
|
@ -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){
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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") {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.<ValueSource>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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue