Skip to content

Commit

Permalink
Geo Overhaul (work with multiple locations), closes elastic#414.
Browse files Browse the repository at this point in the history
  • Loading branch information
kimchy committed Oct 8, 2010
1 parent 523a8b4 commit 6314c24
Show file tree
Hide file tree
Showing 38 changed files with 745 additions and 511 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@
import org.apache.lucene.search.Filter;
import org.elasticsearch.common.lucene.docset.GetDocSet;
import org.elasticsearch.index.cache.field.data.FieldDataCache;
import org.elasticsearch.index.field.data.FieldDataType;
import org.elasticsearch.index.field.data.NumericFieldData;
import org.elasticsearch.index.mapper.xcontent.geo.GeoPoint;
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldData;
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldDataType;

import java.io.IOException;

Expand All @@ -38,20 +39,14 @@ public class GeoBoundingBoxFilter extends Filter {

private final Point bottomRight;

private final String latFieldName;

private final String lonFieldName;

private final FieldDataType fieldDataType;
private final String fieldName;

private final FieldDataCache fieldDataCache;

public GeoBoundingBoxFilter(Point topLeft, Point bottomRight, String latFieldName, String lonFieldName, FieldDataType fieldDataType, FieldDataCache fieldDataCache) {
public GeoBoundingBoxFilter(Point topLeft, Point bottomRight, String fieldName, FieldDataCache fieldDataCache) {
this.topLeft = topLeft;
this.bottomRight = bottomRight;
this.latFieldName = latFieldName;
this.lonFieldName = lonFieldName;
this.fieldDataType = fieldDataType;
this.fieldName = fieldName;
this.fieldDataCache = fieldDataCache;
}

Expand All @@ -63,55 +58,46 @@ public Point bottomRight() {
return bottomRight;
}

public String latFieldName() {
return latFieldName;
}

public String lonFieldName() {
return lonFieldName;
public String fieldName() {
return fieldName;
}

@Override public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
final NumericFieldData latFieldData = (NumericFieldData) fieldDataCache.cache(fieldDataType, reader, latFieldName);
final NumericFieldData lonFieldData = (NumericFieldData) fieldDataCache.cache(fieldDataType, reader, lonFieldName);
final GeoPointFieldData fieldData = (GeoPointFieldData) fieldDataCache.cache(GeoPointFieldDataType.TYPE, reader, fieldName);

//checks to see if bounding box crosses 180 degrees
if (topLeft.lon > bottomRight.lon) {
return new GetDocSet(reader.maxDoc()) {
@Override public boolean get(int doc) throws IOException {
if (!latFieldData.hasValue(doc) || !lonFieldData.hasValue(doc)) {
if (!fieldData.hasValue(doc)) {
return false;
}

if (latFieldData.multiValued()) {
double[] lats = latFieldData.doubleValues(doc);
double[] lons = latFieldData.doubleValues(doc);
for (int i = 0; i < lats.length; i++) {
double lat = lats[i];
double lon = lons[i];
if (lon < 0) {
if (-180.0 <= lon && bottomRight.lon >= lon
&& topLeft.lat >= lat && bottomRight.lat <= lat) {
if (fieldData.multiValued()) {
GeoPoint[] points = fieldData.values(doc);
for (GeoPoint point : points) {
if (point.lon() < 0) {
if (-180.0 <= point.lon() && bottomRight.lon >= point.lon()
&& topLeft.lat >= point.lat() && bottomRight.lat <= point.lat()) {
return true;
}
} else {
if (topLeft.lon <= lon && 180 >= lon
&& topLeft.lat >= lat && bottomRight.lat <= lat) {
if (topLeft.lon <= point.lon() && 180 >= point.lon()
&& topLeft.lat >= point.lat() && bottomRight.lat <= point.lat()) {
return true;
}
}
}
} else {
double lat = latFieldData.doubleValue(doc);
double lon = lonFieldData.doubleValue(doc);
if (lon < 0) {
if (-180.0 <= lon && bottomRight.lon >= lon
&& topLeft.lat >= lat && bottomRight.lat <= lat) {
GeoPoint point = fieldData.value(doc);
if (point.lon() < 0) {
if (-180.0 <= point.lon() && bottomRight.lon >= point.lon()
&& topLeft.lat >= point.lat() && bottomRight.lat <= point.lat()) {
return true;
}
} else {
if (topLeft.lon <= lon && 180 >= lon
&& topLeft.lat >= lat && bottomRight.lat <= lat) {
if (topLeft.lon <= point.lon() && 180 >= point.lon()
&& topLeft.lat >= point.lat() && bottomRight.lat <= point.lat()) {
return true;
}
}
Expand All @@ -122,25 +108,23 @@ public String lonFieldName() {
} else {
return new GetDocSet(reader.maxDoc()) {
@Override public boolean get(int doc) throws IOException {
if (!latFieldData.hasValue(doc) || !lonFieldData.hasValue(doc)) {
if (!fieldData.hasValue(doc)) {
return false;
}

if (latFieldData.multiValued()) {
double[] lats = latFieldData.doubleValues(doc);
double[] lons = latFieldData.doubleValues(doc);
for (int i = 0; i < lats.length; i++) {
if (topLeft.lon <= lons[i] && bottomRight.lon >= lons[i]
&& topLeft.lat >= lats[i] && bottomRight.lat <= lats[i]) {
if (fieldData.multiValued()) {
GeoPoint[] points = fieldData.values(doc);
for (GeoPoint point : points) {
if (topLeft.lon <= point.lon() && bottomRight.lon >= point.lon()
&& topLeft.lat >= point.lat() && bottomRight.lat <= point.lat()) {
return true;
}
}
} else {
double lat = latFieldData.doubleValue(doc);
double lon = lonFieldData.doubleValue(doc);
GeoPoint point = fieldData.value(doc);

if (topLeft.lon <= lon && bottomRight.lon >= lon
&& topLeft.lat >= lat && bottomRight.lat <= lat) {
if (topLeft.lon <= point.lon() && bottomRight.lon >= point.lon()
&& topLeft.lat >= point.lat() && bottomRight.lat <= point.lat()) {
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@
import org.elasticsearch.ElasticSearchIllegalArgumentException;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.cache.field.data.FieldDataCache;
import org.elasticsearch.index.field.data.FieldDataType;
import org.elasticsearch.index.field.data.NumericFieldData;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.xcontent.GeoPointFieldMapper;
import org.elasticsearch.index.mapper.xcontent.geo.GeoPoint;
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldData;
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldDataType;

import java.io.IOException;

Expand Down Expand Up @@ -78,9 +78,7 @@ private InnerSource(String fieldName, double lat, double lon, DistanceUnit unit,

protected final String fieldName;

protected final String indexLatFieldName;

protected final String indexLonFieldName;
protected final String indexFieldName;

protected final double lat;

Expand All @@ -92,11 +90,7 @@ private InnerSource(String fieldName, double lat, double lon, DistanceUnit unit,

protected final FieldDataCache fieldDataCache;

protected final FieldDataType fieldDataType;

protected NumericFieldData latFieldData;

protected NumericFieldData lonFieldData;
protected GeoPointFieldData fieldData;


private final double[] values;
Expand All @@ -113,23 +107,18 @@ public GeoDistanceDataComparator(int numHits, String fieldName, double lat, doub
this.geoDistance = geoDistance;
this.fieldDataCache = fieldDataCache;

FieldMapper mapper = mapperService.smartNameFieldMapper(fieldName + GeoPointFieldMapper.Names.LAT_SUFFIX);
FieldMapper mapper = mapperService.smartNameFieldMapper(fieldName);
if (mapper == null) {
throw new ElasticSearchIllegalArgumentException("No mapping found for field [" + fieldName + "] for geo distance sort");
}
this.indexLatFieldName = mapper.names().indexName();

mapper = mapperService.smartNameFieldMapper(fieldName + GeoPointFieldMapper.Names.LON_SUFFIX);
if (mapper == null) {
throw new ElasticSearchIllegalArgumentException("No mapping found for field [" + fieldName + "] for geo distance sort");
if (mapper.fieldDataType() != GeoPointFieldDataType.TYPE) {
throw new ElasticSearchIllegalArgumentException("field [" + fieldName + "] is not a geo_point field");
}
this.indexLonFieldName = mapper.names().indexName();
this.fieldDataType = mapper.fieldDataType();
this.indexFieldName = mapper.names().indexName();
}

@Override public void setNextReader(IndexReader reader, int docBase) throws IOException {
latFieldData = (NumericFieldData) fieldDataCache.cache(fieldDataType, reader, indexLatFieldName);
lonFieldData = (NumericFieldData) fieldDataCache.cache(fieldDataType, reader, indexLonFieldName);
fieldData = (GeoPointFieldData) fieldDataCache.cache(GeoPointFieldDataType.TYPE, reader, indexFieldName);
}

@Override public int compare(int slot1, int slot2) {
Expand All @@ -146,11 +135,12 @@ public GeoDistanceDataComparator(int numHits, String fieldName, double lat, doub

@Override public int compareBottom(int doc) {
double distance;
if (!latFieldData.hasValue(doc) || !lonFieldData.hasValue(doc)) {
if (!fieldData.hasValue(doc)) {
// is this true? push this to the "end"
distance = Double.MAX_VALUE;
} else {
distance = geoDistance.calculate(lat, lon, latFieldData.doubleValue(doc), lonFieldData.doubleValue(doc), unit);
GeoPoint point = fieldData.value(doc);
distance = geoDistance.calculate(lat, lon, point.lat(), point.lon(), unit);
}
final double v2 = distance;
if (bottom > v2) {
Expand All @@ -164,11 +154,12 @@ public GeoDistanceDataComparator(int numHits, String fieldName, double lat, doub

@Override public void copy(int slot, int doc) {
double distance;
if (!latFieldData.hasValue(doc) || !lonFieldData.hasValue(doc)) {
if (!fieldData.hasValue(doc)) {
// is this true? push this to the "end"
distance = Double.MAX_VALUE;
} else {
distance = geoDistance.calculate(lat, lon, latFieldData.doubleValue(doc), lonFieldData.doubleValue(doc), unit);
GeoPoint point = fieldData.value(doc);
distance = geoDistance.calculate(lat, lon, point.lat(), point.lon(), unit);
}
values[slot] = distance;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@
import org.elasticsearch.common.lucene.docset.GetDocSet;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.cache.field.data.FieldDataCache;
import org.elasticsearch.index.field.data.FieldDataType;
import org.elasticsearch.index.field.data.NumericFieldData;
import org.elasticsearch.index.mapper.xcontent.geo.GeoPoint;
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldData;
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldDataType;

import java.io.IOException;

Expand All @@ -43,23 +44,16 @@ public class GeoDistanceFilter extends Filter {

private final GeoDistance geoDistance;

private final String latFieldName;

private final String lonFieldName;

private final FieldDataType fieldDataType;
private final String fieldName;

private final FieldDataCache fieldDataCache;

public GeoDistanceFilter(double lat, double lon, double distance, GeoDistance geoDistance, String latFieldName, String lonFieldName,
FieldDataType fieldDataType, FieldDataCache fieldDataCache) {
public GeoDistanceFilter(double lat, double lon, double distance, GeoDistance geoDistance, String fieldName, FieldDataCache fieldDataCache) {
this.lat = lat;
this.lon = lon;
this.distance = distance;
this.geoDistance = geoDistance;
this.latFieldName = latFieldName;
this.lonFieldName = lonFieldName;
this.fieldDataType = fieldDataType;
this.fieldName = fieldName;
this.fieldDataCache = fieldDataCache;
}

Expand All @@ -79,39 +73,34 @@ public GeoDistance geoDistance() {
return geoDistance;
}

public String latFieldName() {
return latFieldName;
}

public String lonFieldName() {
return lonFieldName;
public String fieldName() {
return fieldName;
}

@Override public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
final NumericFieldData latFieldData = (NumericFieldData) fieldDataCache.cache(fieldDataType, reader, latFieldName);
final NumericFieldData lonFieldData = (NumericFieldData) fieldDataCache.cache(fieldDataType, reader, lonFieldName);
final GeoPointFieldData fieldData = (GeoPointFieldData) fieldDataCache.cache(GeoPointFieldDataType.TYPE, reader, fieldName);
return new GetDocSet(reader.maxDoc()) {
@Override public boolean isCacheable() {
return false;
}

@Override public boolean get(int doc) throws IOException {
if (!latFieldData.hasValue(doc) || !lonFieldData.hasValue(doc)) {
if (!fieldData.hasValue(doc)) {
return false;
}

if (latFieldData.multiValued()) {
double[] lats = latFieldData.doubleValues(doc);
double[] lons = latFieldData.doubleValues(doc);
for (int i = 0; i < lats.length; i++) {
double d = geoDistance.calculate(lat, lon, lats[i], lons[i], DistanceUnit.MILES);
if (fieldData.multiValued()) {
GeoPoint[] points = fieldData.values(doc);
for (GeoPoint point : points) {
double d = geoDistance.calculate(lat, lon, point.lat(), point.lon(), DistanceUnit.MILES);
if (d < distance) {
return true;
}
}
return false;
} else {
double d = geoDistance.calculate(lat, lon, latFieldData.doubleValue(doc), lonFieldData.doubleValue(doc), DistanceUnit.MILES);
GeoPoint point = fieldData.value(doc);
double d = geoDistance.calculate(lat, lon, point.lat(), point.lon(), DistanceUnit.MILES);
return d < distance;
}
}
Expand All @@ -123,16 +112,13 @@ public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

GeoDistanceFilter that = (GeoDistanceFilter) o;
GeoDistanceFilter filter = (GeoDistanceFilter) o;

if (Double.compare(that.distance, distance) != 0) return false;
if (Double.compare(that.lat, lat) != 0) return false;
if (Double.compare(that.lon, lon) != 0) return false;
if (geoDistance != that.geoDistance) return false;
if (latFieldName != null ? !latFieldName.equals(that.latFieldName) : that.latFieldName != null)
return false;
if (lonFieldName != null ? !lonFieldName.equals(that.lonFieldName) : that.lonFieldName != null)
return false;
if (Double.compare(filter.distance, distance) != 0) return false;
if (Double.compare(filter.lat, lat) != 0) return false;
if (Double.compare(filter.lon, lon) != 0) return false;
if (fieldName != null ? !fieldName.equals(filter.fieldName) : filter.fieldName != null) return false;
if (geoDistance != filter.geoDistance) return false;

return true;
}
Expand All @@ -148,8 +134,7 @@ public int hashCode() {
temp = distance != +0.0d ? Double.doubleToLongBits(distance) : 0L;
result = 31 * result + (int) (temp ^ (temp >>> 32));
result = 31 * result + (geoDistance != null ? geoDistance.hashCode() : 0);
result = 31 * result + (latFieldName != null ? latFieldName.hashCode() : 0);
result = 31 * result + (lonFieldName != null ? lonFieldName.hashCode() : 0);
result = 31 * result + (fieldName != null ? fieldName.hashCode() : 0);
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ public static String encode(double latitude, double longitude, int precision) {
}

public static double[] decode(String geohash) {
return decode(geohash, new double[2]);
double[] ret = new double[2];
decode(geohash, ret);
return ret;
}

/**
Expand All @@ -122,7 +124,7 @@ public static double[] decode(String geohash) {
* @param geohash Geohash to deocde
* @return Array with the latitude at index 0, and longitude at index 1
*/
public static double[] decode(String geohash, double[] ret) {
public static void decode(String geohash, double[] ret) {
// double[] latInterval = {-90.0, 90.0};
// double[] lngInterval = {-180.0, 180.0};
double latInterval0 = -90.0;
Expand Down Expand Up @@ -162,6 +164,6 @@ public static double[] decode(String geohash, double[] ret) {
// longitude = (lngInterval[0] + lngInterval[1]) / 2D;
ret[1] = (lngInterval0 + lngInterval1) / 2D;

return ret;
// return ret;
}
}
Loading

0 comments on commit 6314c24

Please sign in to comment.