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.
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
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
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;
}
}
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;
}
}

0 comments on commit 6314c24

Please sign in to comment.