improve geo internal cache of lat/lon, stored two double arrays instead of an array of GeoPoints.
This commit is contained in:
parent
1f4aa5d9d2
commit
1578da404c
|
@ -75,8 +75,10 @@
|
||||||
<w>joda</w>
|
<w>joda</w>
|
||||||
<w>jsonp</w>
|
<w>jsonp</w>
|
||||||
<w>kimchy</w>
|
<w>kimchy</w>
|
||||||
|
<w>latlon</w>
|
||||||
<w>lifecycle</w>
|
<w>lifecycle</w>
|
||||||
<w>linefeeds</w>
|
<w>linefeeds</w>
|
||||||
|
<w>lons</w>
|
||||||
<w>loopback</w>
|
<w>loopback</w>
|
||||||
<w>lucene</w>
|
<w>lucene</w>
|
||||||
<w>mcast</w>
|
<w>mcast</w>
|
||||||
|
|
|
@ -24,7 +24,6 @@ import org.apache.lucene.search.DocIdSet;
|
||||||
import org.apache.lucene.search.Filter;
|
import org.apache.lucene.search.Filter;
|
||||||
import org.elasticsearch.common.lucene.docset.GetDocSet;
|
import org.elasticsearch.common.lucene.docset.GetDocSet;
|
||||||
import org.elasticsearch.index.cache.field.data.FieldDataCache;
|
import org.elasticsearch.index.cache.field.data.FieldDataCache;
|
||||||
import org.elasticsearch.index.mapper.xcontent.geo.GeoPoint;
|
|
||||||
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldData;
|
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldData;
|
||||||
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldDataType;
|
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldDataType;
|
||||||
|
|
||||||
|
@ -82,30 +81,34 @@ public class GeoBoundingBoxFilter extends Filter {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fieldData.multiValued()) {
|
if (fieldData.multiValued()) {
|
||||||
GeoPoint[] points = fieldData.values(doc);
|
double[] lats = fieldData.latValues(doc);
|
||||||
for (GeoPoint point : points) {
|
double[] lons = fieldData.lonValues(doc);
|
||||||
if (point.lon() < 0) {
|
for (int i = 0; i < lats.length; i++) {
|
||||||
if (-180.0 <= point.lon() && bottomRight.lon >= point.lon()
|
double lat = lats[i];
|
||||||
&& topLeft.lat >= point.lat() && bottomRight.lat <= point.lat()) {
|
double lon = lons[i];
|
||||||
|
if (lon < 0) {
|
||||||
|
if (-180.0 <= lon && bottomRight.lon >= lon
|
||||||
|
&& topLeft.lat >= lat && bottomRight.lat <= lat) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (topLeft.lon <= point.lon() && 180 >= point.lon()
|
if (topLeft.lon <= lon && 180 >= lon
|
||||||
&& topLeft.lat >= point.lat() && bottomRight.lat <= point.lat()) {
|
&& topLeft.lat >= lat && bottomRight.lat <= lat) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
GeoPoint point = fieldData.value(doc);
|
double lat = fieldData.latValue(doc);
|
||||||
if (point.lon() < 0) {
|
double lon = fieldData.lonValue(doc);
|
||||||
if (-180.0 <= point.lon() && bottomRight.lon >= point.lon()
|
if (lon < 0) {
|
||||||
&& topLeft.lat >= point.lat() && bottomRight.lat <= point.lat()) {
|
if (-180.0 <= lon && bottomRight.lon >= lon
|
||||||
|
&& topLeft.lat >= lat && bottomRight.lat <= lat) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (topLeft.lon <= point.lon() && 180 >= point.lon()
|
if (topLeft.lon <= lon && 180 >= lon
|
||||||
&& topLeft.lat >= point.lat() && bottomRight.lat <= point.lat()) {
|
&& topLeft.lat >= lat && bottomRight.lat <= lat) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,18 +132,20 @@ public class GeoBoundingBoxFilter extends Filter {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fieldData.multiValued()) {
|
if (fieldData.multiValued()) {
|
||||||
GeoPoint[] points = fieldData.values(doc);
|
double[] lats = fieldData.latValues(doc);
|
||||||
for (GeoPoint point : points) {
|
double[] lons = fieldData.lonValues(doc);
|
||||||
if (topLeft.lon <= point.lon() && bottomRight.lon >= point.lon()
|
for (int i = 0; i < lats.length; i++) {
|
||||||
&& topLeft.lat >= point.lat() && bottomRight.lat <= point.lat()) {
|
if (topLeft.lon <= lons[i] && bottomRight.lon >= lons[i]
|
||||||
|
&& topLeft.lat >= lats[i] && bottomRight.lat <= lats[i]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
GeoPoint point = fieldData.value(doc);
|
double lat = fieldData.latValue(doc);
|
||||||
|
double lon = fieldData.lonValue(doc);
|
||||||
|
|
||||||
if (topLeft.lon <= point.lon() && bottomRight.lon >= point.lon()
|
if (topLeft.lon <= lon && bottomRight.lon >= lon
|
||||||
&& topLeft.lat >= point.lat() && bottomRight.lat <= point.lat()) {
|
&& topLeft.lat >= lat && bottomRight.lat <= lat) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ import org.elasticsearch.common.unit.DistanceUnit;
|
||||||
import org.elasticsearch.index.cache.field.data.FieldDataCache;
|
import org.elasticsearch.index.cache.field.data.FieldDataCache;
|
||||||
import org.elasticsearch.index.mapper.FieldMapper;
|
import org.elasticsearch.index.mapper.FieldMapper;
|
||||||
import org.elasticsearch.index.mapper.MapperService;
|
import org.elasticsearch.index.mapper.MapperService;
|
||||||
import org.elasticsearch.index.mapper.xcontent.geo.GeoPoint;
|
|
||||||
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldData;
|
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldData;
|
||||||
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldDataType;
|
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldDataType;
|
||||||
|
|
||||||
|
@ -139,8 +138,7 @@ public class GeoDistanceDataComparator extends FieldComparator {
|
||||||
// is this true? push this to the "end"
|
// is this true? push this to the "end"
|
||||||
distance = Double.MAX_VALUE;
|
distance = Double.MAX_VALUE;
|
||||||
} else {
|
} else {
|
||||||
GeoPoint point = fieldData.value(doc);
|
distance = geoDistance.calculate(lat, lon, fieldData.latValue(doc), fieldData.lonValue(doc), unit);
|
||||||
distance = geoDistance.calculate(lat, lon, point.lat(), point.lon(), unit);
|
|
||||||
}
|
}
|
||||||
final double v2 = distance;
|
final double v2 = distance;
|
||||||
if (bottom > v2) {
|
if (bottom > v2) {
|
||||||
|
@ -158,8 +156,7 @@ public class GeoDistanceDataComparator extends FieldComparator {
|
||||||
// is this true? push this to the "end"
|
// is this true? push this to the "end"
|
||||||
distance = Double.MAX_VALUE;
|
distance = Double.MAX_VALUE;
|
||||||
} else {
|
} else {
|
||||||
GeoPoint point = fieldData.value(doc);
|
distance = geoDistance.calculate(lat, lon, fieldData.latValue(doc), fieldData.lonValue(doc), unit);
|
||||||
distance = geoDistance.calculate(lat, lon, point.lat(), point.lon(), unit);
|
|
||||||
}
|
}
|
||||||
values[slot] = distance;
|
values[slot] = distance;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ import org.apache.lucene.search.Filter;
|
||||||
import org.elasticsearch.common.lucene.docset.GetDocSet;
|
import org.elasticsearch.common.lucene.docset.GetDocSet;
|
||||||
import org.elasticsearch.common.unit.DistanceUnit;
|
import org.elasticsearch.common.unit.DistanceUnit;
|
||||||
import org.elasticsearch.index.cache.field.data.FieldDataCache;
|
import org.elasticsearch.index.cache.field.data.FieldDataCache;
|
||||||
import org.elasticsearch.index.mapper.xcontent.geo.GeoPoint;
|
|
||||||
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldData;
|
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldData;
|
||||||
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldDataType;
|
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldDataType;
|
||||||
|
|
||||||
|
@ -94,17 +93,17 @@ public class GeoDistanceFilter extends Filter {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fieldData.multiValued()) {
|
if (fieldData.multiValued()) {
|
||||||
GeoPoint[] points = fieldData.values(doc);
|
double[] lats = fieldData.latValues(doc);
|
||||||
for (GeoPoint point : points) {
|
double[] lons = fieldData.lonValues(doc);
|
||||||
double d = geoDistance.calculate(lat, lon, point.lat(), point.lon(), DistanceUnit.MILES);
|
for (int i = 0; i < lats.length; i++) {
|
||||||
|
double d = geoDistance.calculate(lat, lon, lats[i], lons[i], DistanceUnit.MILES);
|
||||||
if (d < distance) {
|
if (d < distance) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
GeoPoint point = fieldData.value(doc);
|
double d = geoDistance.calculate(lat, lon, fieldData.latValue(doc), fieldData.lonValue(doc), DistanceUnit.MILES);
|
||||||
double d = geoDistance.calculate(lat, lon, point.lat(), point.lon(), DistanceUnit.MILES);
|
|
||||||
return d < distance;
|
return d < distance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ import org.apache.lucene.search.DocIdSet;
|
||||||
import org.apache.lucene.search.Filter;
|
import org.apache.lucene.search.Filter;
|
||||||
import org.elasticsearch.common.lucene.docset.GetDocSet;
|
import org.elasticsearch.common.lucene.docset.GetDocSet;
|
||||||
import org.elasticsearch.index.cache.field.data.FieldDataCache;
|
import org.elasticsearch.index.cache.field.data.FieldDataCache;
|
||||||
import org.elasticsearch.index.mapper.xcontent.geo.GeoPoint;
|
|
||||||
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldData;
|
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldData;
|
||||||
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldDataType;
|
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldDataType;
|
||||||
|
|
||||||
|
@ -73,15 +72,17 @@ public class GeoPolygonFilter extends Filter {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fieldData.multiValued()) {
|
if (fieldData.multiValued()) {
|
||||||
GeoPoint[] docPoints = fieldData.values(doc);
|
double[] lats = fieldData.latValues(doc);
|
||||||
for (GeoPoint docPoint : docPoints) {
|
double[] lons = fieldData.lonValues(doc);
|
||||||
if (pointInPolygon(points, docPoint.lat(), docPoint.lon())) {
|
for (int i = 0; i < lats.length; i++) {
|
||||||
|
if (pointInPolygon(points, lats[i], lons[i])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
GeoPoint point = fieldData.value(doc);
|
double lat = fieldData.latValue(doc);
|
||||||
return pointInPolygon(points, point.lat(), point.lon());
|
double lon = fieldData.lonValue(doc);
|
||||||
|
return pointInPolygon(points, lat, lon);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,15 +26,23 @@ import org.elasticsearch.common.lucene.geo.GeoHashUtils;
|
||||||
*/
|
*/
|
||||||
public class GeoPoint {
|
public class GeoPoint {
|
||||||
|
|
||||||
private final double lat;
|
private double lat;
|
||||||
|
|
||||||
private final double lon;
|
private double lon;
|
||||||
|
|
||||||
|
GeoPoint() {
|
||||||
|
}
|
||||||
|
|
||||||
public GeoPoint(double lat, double lon) {
|
public GeoPoint(double lat, double lon) {
|
||||||
this.lat = lat;
|
this.lat = lat;
|
||||||
this.lon = lon;
|
this.lon = lon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void latlon(double lat, double lon) {
|
||||||
|
this.lat = lat;
|
||||||
|
this.lon = lon;
|
||||||
|
}
|
||||||
|
|
||||||
public final double lat() {
|
public final double lat() {
|
||||||
return this.lat;
|
return this.lat;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,4 +37,20 @@ public class GeoPointDocFieldData extends DocFieldData<GeoPointFieldData> {
|
||||||
public GeoPoint[] getValues() {
|
public GeoPoint[] getValues() {
|
||||||
return fieldData.values(docId);
|
return fieldData.values(docId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double getLat() {
|
||||||
|
return fieldData.latValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getLon() {
|
||||||
|
return fieldData.lonValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double[] getLats() {
|
||||||
|
return fieldData.latValues(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double[] getLons() {
|
||||||
|
return fieldData.lonValues(docId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,31 +20,49 @@
|
||||||
package org.elasticsearch.index.mapper.xcontent.geo;
|
package org.elasticsearch.index.mapper.xcontent.geo;
|
||||||
|
|
||||||
import org.apache.lucene.index.IndexReader;
|
import org.apache.lucene.index.IndexReader;
|
||||||
|
import org.elasticsearch.common.lucene.geo.GeoHashUtils;
|
||||||
|
import org.elasticsearch.common.thread.ThreadLocals;
|
||||||
|
import org.elasticsearch.common.trove.TDoubleArrayList;
|
||||||
import org.elasticsearch.index.field.data.FieldData;
|
import org.elasticsearch.index.field.data.FieldData;
|
||||||
import org.elasticsearch.index.field.data.FieldDataType;
|
import org.elasticsearch.index.field.data.FieldDataType;
|
||||||
import org.elasticsearch.index.field.data.support.FieldDataLoader;
|
import org.elasticsearch.index.field.data.support.FieldDataLoader;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kimchy (shay.banon)
|
* @author kimchy (shay.banon)
|
||||||
*/
|
*/
|
||||||
public abstract class GeoPointFieldData extends FieldData<GeoPointDocFieldData> {
|
public abstract class GeoPointFieldData extends FieldData<GeoPointDocFieldData> {
|
||||||
|
|
||||||
|
static ThreadLocal<ThreadLocals.CleanableValue<GeoPoint>> valuesCache = new ThreadLocal<ThreadLocals.CleanableValue<GeoPoint>>() {
|
||||||
|
@Override protected ThreadLocals.CleanableValue<GeoPoint> initialValue() {
|
||||||
|
return new ThreadLocals.CleanableValue<GeoPoint>(new GeoPoint());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public static final GeoPoint[] EMPTY_ARRAY = new GeoPoint[0];
|
public static final GeoPoint[] EMPTY_ARRAY = new GeoPoint[0];
|
||||||
|
|
||||||
protected final GeoPoint[] values;
|
protected final double[] lat;
|
||||||
|
protected final double[] lon;
|
||||||
|
|
||||||
protected GeoPointFieldData(String fieldName, GeoPoint[] values) {
|
protected GeoPointFieldData(String fieldName, double[] lat, double[] lon) {
|
||||||
super(fieldName);
|
super(fieldName);
|
||||||
this.values = values;
|
this.lat = lat;
|
||||||
|
this.lon = lon;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract public GeoPoint value(int docId);
|
abstract public GeoPoint value(int docId);
|
||||||
|
|
||||||
abstract public GeoPoint[] values(int docId);
|
abstract public GeoPoint[] values(int docId);
|
||||||
|
|
||||||
|
abstract public double latValue(int docId);
|
||||||
|
|
||||||
|
abstract public double lonValue(int docId);
|
||||||
|
|
||||||
|
abstract public double[] latValues(int docId);
|
||||||
|
|
||||||
|
abstract public double[] lonValues(int docId);
|
||||||
|
|
||||||
@Override public GeoPointDocFieldData docFieldData(int docId) {
|
@Override public GeoPointDocFieldData docFieldData(int docId) {
|
||||||
return super.docFieldData(docId);
|
return super.docFieldData(docId);
|
||||||
}
|
}
|
||||||
|
@ -62,19 +80,31 @@ public abstract class GeoPointFieldData extends FieldData<GeoPointDocFieldData>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void forEachValue(StringValueProc proc) {
|
@Override public void forEachValue(StringValueProc proc) {
|
||||||
for (int i = 1; i < values.length; i++) {
|
for (int i = 1; i < lat.length; i++) {
|
||||||
proc.onValue(values[i].geohash());
|
proc.onValue(GeoHashUtils.encode(lat[i], lon[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void forEachValue(PointValueProc proc) {
|
||||||
|
for (int i = 1; i < lat.length; i++) {
|
||||||
|
GeoPoint point = valuesCache.get().get();
|
||||||
|
point.latlon(lat[i], lon[i]);
|
||||||
|
proc.onValue(point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static interface PointValueProc {
|
||||||
|
void onValue(GeoPoint value);
|
||||||
|
}
|
||||||
|
|
||||||
public void forEachValue(ValueProc proc) {
|
public void forEachValue(ValueProc proc) {
|
||||||
for (int i = 1; i < values.length; i++) {
|
for (int i = 1; i < lat.length; i++) {
|
||||||
proc.onValue(values[i]);
|
proc.onValue(lat[i], lon[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static interface ValueProc {
|
public static interface ValueProc {
|
||||||
void onValue(GeoPoint value);
|
void onValue(double lat, double lon);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GeoPointFieldData load(IndexReader reader, String field) throws IOException {
|
public static GeoPointFieldData load(IndexReader reader, String field) throws IOException {
|
||||||
|
@ -83,27 +113,29 @@ public abstract class GeoPointFieldData extends FieldData<GeoPointDocFieldData>
|
||||||
|
|
||||||
static class StringTypeLoader extends FieldDataLoader.FreqsTypeLoader<GeoPointFieldData> {
|
static class StringTypeLoader extends FieldDataLoader.FreqsTypeLoader<GeoPointFieldData> {
|
||||||
|
|
||||||
private final ArrayList<GeoPoint> terms = new ArrayList<GeoPoint>();
|
private final TDoubleArrayList lat = new TDoubleArrayList();
|
||||||
|
private final TDoubleArrayList lon = new TDoubleArrayList();
|
||||||
|
|
||||||
StringTypeLoader() {
|
StringTypeLoader() {
|
||||||
super();
|
super();
|
||||||
// the first one indicates null value
|
// the first one indicates null value
|
||||||
terms.add(null);
|
lat.add(0);
|
||||||
|
lon.add(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void collectTerm(String term) {
|
@Override public void collectTerm(String term) {
|
||||||
int comma = term.indexOf(',');
|
int comma = term.indexOf(',');
|
||||||
double lat = Double.parseDouble(term.substring(0, comma));
|
lat.add(Double.parseDouble(term.substring(0, comma)));
|
||||||
double lon = Double.parseDouble(term.substring(comma + 1));
|
lon.add(Double.parseDouble(term.substring(comma + 1)));
|
||||||
terms.add(new GeoPoint(lat, lon));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public GeoPointFieldData buildSingleValue(String field, int[] order) {
|
@Override public GeoPointFieldData buildSingleValue(String field, int[] order) {
|
||||||
return new SingleValueGeoPointFieldData(field, order, terms.toArray(new GeoPoint[terms.size()]));
|
return new SingleValueGeoPointFieldData(field, order, lat.toNativeArray(), lon.toNativeArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public GeoPointFieldData buildMultiValue(String field, int[][] order) {
|
@Override public GeoPointFieldData buildMultiValue(String field, int[][] order) {
|
||||||
return new MultiValueGeoPointFieldData(field, order, terms.toArray(new GeoPoint[terms.size()]));
|
return new MultiValueGeoPointFieldData(field, order, lat.toNativeArray(), lon.toNativeArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,9 @@
|
||||||
|
|
||||||
package org.elasticsearch.index.mapper.xcontent.geo;
|
package org.elasticsearch.index.mapper.xcontent.geo;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.lucene.geo.GeoHashUtils;
|
||||||
import org.elasticsearch.common.thread.ThreadLocals;
|
import org.elasticsearch.common.thread.ThreadLocals;
|
||||||
|
import org.elasticsearch.index.field.data.doubles.DoubleFieldData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kimchy (shay.banon)
|
* @author kimchy (shay.banon)
|
||||||
|
@ -28,21 +30,44 @@ public class MultiValueGeoPointFieldData extends GeoPointFieldData {
|
||||||
|
|
||||||
private static final int VALUE_CACHE_SIZE = 100;
|
private static final int VALUE_CACHE_SIZE = 100;
|
||||||
|
|
||||||
private static ThreadLocal<ThreadLocals.CleanableValue<GeoPoint[][]>> valuesCache = new ThreadLocal<ThreadLocals.CleanableValue<GeoPoint[][]>>() {
|
private static ThreadLocal<ThreadLocals.CleanableValue<GeoPoint[][]>> valuesArrayCache = new ThreadLocal<ThreadLocals.CleanableValue<GeoPoint[][]>>() {
|
||||||
@Override protected ThreadLocals.CleanableValue<GeoPoint[][]> initialValue() {
|
@Override protected ThreadLocals.CleanableValue<GeoPoint[][]> initialValue() {
|
||||||
GeoPoint[][] value = new GeoPoint[VALUE_CACHE_SIZE][];
|
GeoPoint[][] value = new GeoPoint[VALUE_CACHE_SIZE][];
|
||||||
for (int i = 0; i < value.length; i++) {
|
for (int i = 0; i < value.length; i++) {
|
||||||
value[i] = new GeoPoint[i];
|
value[i] = new GeoPoint[i];
|
||||||
|
for (int j = 0; j < value.length; j++) {
|
||||||
|
value[i][j] = new GeoPoint();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return new ThreadLocals.CleanableValue<GeoPoint[][]>(value);
|
return new ThreadLocals.CleanableValue<GeoPoint[][]>(value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private ThreadLocal<ThreadLocals.CleanableValue<double[][]>> valuesLatCache = new ThreadLocal<ThreadLocals.CleanableValue<double[][]>>() {
|
||||||
|
@Override protected ThreadLocals.CleanableValue<double[][]> initialValue() {
|
||||||
|
double[][] value = new double[VALUE_CACHE_SIZE][];
|
||||||
|
for (int i = 0; i < value.length; i++) {
|
||||||
|
value[i] = new double[i];
|
||||||
|
}
|
||||||
|
return new ThreadLocals.CleanableValue<double[][]>(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private ThreadLocal<ThreadLocals.CleanableValue<double[][]>> valuesLonCache = new ThreadLocal<ThreadLocals.CleanableValue<double[][]>>() {
|
||||||
|
@Override protected ThreadLocals.CleanableValue<double[][]> initialValue() {
|
||||||
|
double[][] value = new double[VALUE_CACHE_SIZE][];
|
||||||
|
for (int i = 0; i < value.length; i++) {
|
||||||
|
value[i] = new double[i];
|
||||||
|
}
|
||||||
|
return new ThreadLocals.CleanableValue<double[][]>(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// order with value 0 indicates no value
|
// order with value 0 indicates no value
|
||||||
private final int[][] order;
|
private final int[][] order;
|
||||||
|
|
||||||
public MultiValueGeoPointFieldData(String fieldName, int[][] order, GeoPoint[] values) {
|
public MultiValueGeoPointFieldData(String fieldName, int[][] order, double[] lat, double[] lon) {
|
||||||
super(fieldName, values);
|
super(fieldName, lat, lon);
|
||||||
this.order = order;
|
this.order = order;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +85,7 @@ public class MultiValueGeoPointFieldData extends GeoPointFieldData {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (int docOrder : docOrders) {
|
for (int docOrder : docOrders) {
|
||||||
proc.onValue(docId, values[docOrder].geohash());
|
proc.onValue(docId, GeoHashUtils.encode(lat[docOrder], lon[docOrder]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +94,10 @@ public class MultiValueGeoPointFieldData extends GeoPointFieldData {
|
||||||
if (docOrders == null) {
|
if (docOrders == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return values[docOrders[0]];
|
GeoPoint point = valuesCache.get().get();
|
||||||
|
int loc = docOrders[0];
|
||||||
|
point.latlon(lat[loc], lon[loc]);
|
||||||
|
return point;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public GeoPoint[] values(int docId) {
|
@Override public GeoPoint[] values(int docId) {
|
||||||
|
@ -79,13 +107,68 @@ public class MultiValueGeoPointFieldData extends GeoPointFieldData {
|
||||||
}
|
}
|
||||||
GeoPoint[] points;
|
GeoPoint[] points;
|
||||||
if (docOrders.length < VALUE_CACHE_SIZE) {
|
if (docOrders.length < VALUE_CACHE_SIZE) {
|
||||||
points = valuesCache.get().get()[docOrders.length];
|
points = valuesArrayCache.get().get()[docOrders.length];
|
||||||
|
for (int i = 0; i < docOrders.length; i++) {
|
||||||
|
int loc = docOrders[i];
|
||||||
|
points[i].latlon(lat[loc], lon[loc]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
points = new GeoPoint[docOrders.length];
|
points = new GeoPoint[docOrders.length];
|
||||||
}
|
for (int i = 0; i < docOrders.length; i++) {
|
||||||
for (int i = 0; i < docOrders.length; i++) {
|
int loc = docOrders[i];
|
||||||
points[i] = values[docOrders[i]];
|
points[i] = new GeoPoint(lat[loc], lon[loc]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return points;
|
return points;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public double latValue(int docId) {
|
||||||
|
int[] docOrders = order[docId];
|
||||||
|
if (docOrders == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return lat[docOrders[0]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public double lonValue(int docId) {
|
||||||
|
int[] docOrders = order[docId];
|
||||||
|
if (docOrders == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return lon[docOrders[0]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public double[] latValues(int docId) {
|
||||||
|
int[] docOrders = order[docId];
|
||||||
|
if (docOrders == null) {
|
||||||
|
return DoubleFieldData.EMPTY_DOUBLE_ARRAY;
|
||||||
|
}
|
||||||
|
double[] doubles;
|
||||||
|
if (docOrders.length < VALUE_CACHE_SIZE) {
|
||||||
|
doubles = valuesLatCache.get().get()[docOrders.length];
|
||||||
|
} else {
|
||||||
|
doubles = new double[docOrders.length];
|
||||||
|
}
|
||||||
|
for (int i = 0; i < docOrders.length; i++) {
|
||||||
|
doubles[i] = lat[docOrders[i]];
|
||||||
|
}
|
||||||
|
return doubles;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public double[] lonValues(int docId) {
|
||||||
|
int[] docOrders = order[docId];
|
||||||
|
if (docOrders == null) {
|
||||||
|
return DoubleFieldData.EMPTY_DOUBLE_ARRAY;
|
||||||
|
}
|
||||||
|
double[] doubles;
|
||||||
|
if (docOrders.length < VALUE_CACHE_SIZE) {
|
||||||
|
doubles = valuesLonCache.get().get()[docOrders.length];
|
||||||
|
} else {
|
||||||
|
doubles = new double[docOrders.length];
|
||||||
|
}
|
||||||
|
for (int i = 0; i < docOrders.length; i++) {
|
||||||
|
doubles[i] = lon[docOrders[i]];
|
||||||
|
}
|
||||||
|
return doubles;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -19,35 +19,44 @@
|
||||||
|
|
||||||
package org.elasticsearch.index.mapper.xcontent.geo;
|
package org.elasticsearch.index.mapper.xcontent.geo;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.lucene.geo.GeoHashUtils;
|
||||||
import org.elasticsearch.common.thread.ThreadLocals;
|
import org.elasticsearch.common.thread.ThreadLocals;
|
||||||
|
import org.elasticsearch.index.field.data.doubles.DoubleFieldData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kimchy (shay.banon)
|
* @author kimchy (shay.banon)
|
||||||
*/
|
*/
|
||||||
public class SingleValueGeoPointFieldData extends GeoPointFieldData {
|
public class SingleValueGeoPointFieldData extends GeoPointFieldData {
|
||||||
|
|
||||||
private static ThreadLocal<ThreadLocals.CleanableValue<GeoPoint[]>> valuesCache = new ThreadLocal<ThreadLocals.CleanableValue<GeoPoint[]>>() {
|
private static ThreadLocal<ThreadLocals.CleanableValue<GeoPoint[]>> valuesArrayCache = new ThreadLocal<ThreadLocals.CleanableValue<GeoPoint[]>>() {
|
||||||
@Override protected ThreadLocals.CleanableValue<GeoPoint[]> initialValue() {
|
@Override protected ThreadLocals.CleanableValue<GeoPoint[]> initialValue() {
|
||||||
return new ThreadLocals.CleanableValue<GeoPoint[]>(new GeoPoint[1]);
|
GeoPoint[] value = new GeoPoint[1];
|
||||||
|
value[0] = new GeoPoint();
|
||||||
|
return new ThreadLocals.CleanableValue<GeoPoint[]>(value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private ThreadLocal<ThreadLocals.CleanableValue<double[]>> valuesLatCache = new ThreadLocal<ThreadLocals.CleanableValue<double[]>>() {
|
||||||
|
@Override protected ThreadLocals.CleanableValue<double[]> initialValue() {
|
||||||
|
return new ThreadLocals.CleanableValue<double[]>(new double[1]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private ThreadLocal<ThreadLocals.CleanableValue<double[]>> valuesLonCache = new ThreadLocal<ThreadLocals.CleanableValue<double[]>>() {
|
||||||
|
@Override protected ThreadLocals.CleanableValue<double[]> initialValue() {
|
||||||
|
return new ThreadLocals.CleanableValue<double[]>(new double[1]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// order with value 0 indicates no value
|
// order with value 0 indicates no value
|
||||||
private final int[] order;
|
private final int[] order;
|
||||||
|
|
||||||
public SingleValueGeoPointFieldData(String fieldName, int[] order, GeoPoint[] values) {
|
public SingleValueGeoPointFieldData(String fieldName, int[] order, double[] lat, double[] lon) {
|
||||||
super(fieldName, values);
|
super(fieldName, lat, lon);
|
||||||
this.order = order;
|
this.order = order;
|
||||||
}
|
}
|
||||||
|
|
||||||
int[] order() {
|
|
||||||
return order;
|
|
||||||
}
|
|
||||||
|
|
||||||
GeoPoint[] values() {
|
|
||||||
return this.values;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean multiValued() {
|
@Override public boolean multiValued() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -61,11 +70,17 @@ public class SingleValueGeoPointFieldData extends GeoPointFieldData {
|
||||||
if (loc == 0) {
|
if (loc == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
proc.onValue(docId, values[loc].geohash());
|
proc.onValue(docId, GeoHashUtils.encode(lat[loc], lon[loc]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public GeoPoint value(int docId) {
|
@Override public GeoPoint value(int docId) {
|
||||||
return values[order[docId]];
|
int loc = order[docId];
|
||||||
|
if (loc == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
GeoPoint point = valuesCache.get().get();
|
||||||
|
point.latlon(lat[loc], lon[loc]);
|
||||||
|
return point;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public GeoPoint[] values(int docId) {
|
@Override public GeoPoint[] values(int docId) {
|
||||||
|
@ -73,8 +88,36 @@ public class SingleValueGeoPointFieldData extends GeoPointFieldData {
|
||||||
if (loc == 0) {
|
if (loc == 0) {
|
||||||
return EMPTY_ARRAY;
|
return EMPTY_ARRAY;
|
||||||
}
|
}
|
||||||
GeoPoint[] ret = valuesCache.get().get();
|
GeoPoint[] ret = valuesArrayCache.get().get();
|
||||||
ret[0] = values[loc];
|
ret[0].latlon(lat[loc], lon[loc]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public double latValue(int docId) {
|
||||||
|
return lat[order[docId]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public double lonValue(int docId) {
|
||||||
|
return lon[order[docId]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public double[] latValues(int docId) {
|
||||||
|
int loc = order[docId];
|
||||||
|
if (loc == 0) {
|
||||||
|
return DoubleFieldData.EMPTY_DOUBLE_ARRAY;
|
||||||
|
}
|
||||||
|
double[] ret = valuesLatCache.get().get();
|
||||||
|
ret[0] = lat[loc];
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public double[] lonValues(int docId) {
|
||||||
|
int loc = order[docId];
|
||||||
|
if (loc == 0) {
|
||||||
|
return DoubleFieldData.EMPTY_DOUBLE_ARRAY;
|
||||||
|
}
|
||||||
|
double[] ret = valuesLonCache.get().get();
|
||||||
|
ret[0] = lon[loc];
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ import org.elasticsearch.common.lucene.geo.GeoDistance;
|
||||||
import org.elasticsearch.common.unit.DistanceUnit;
|
import org.elasticsearch.common.unit.DistanceUnit;
|
||||||
import org.elasticsearch.index.cache.field.data.FieldDataCache;
|
import org.elasticsearch.index.cache.field.data.FieldDataCache;
|
||||||
import org.elasticsearch.index.mapper.MapperService;
|
import org.elasticsearch.index.mapper.MapperService;
|
||||||
import org.elasticsearch.index.mapper.xcontent.geo.GeoPoint;
|
|
||||||
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldData;
|
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldData;
|
||||||
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldDataType;
|
import org.elasticsearch.index.mapper.xcontent.geo.GeoPointFieldDataType;
|
||||||
import org.elasticsearch.search.facets.Facet;
|
import org.elasticsearch.search.facets.Facet;
|
||||||
|
@ -94,9 +93,10 @@ public class GeoDistanceFacetCollector extends AbstractFacetCollector {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fieldData.multiValued()) {
|
if (fieldData.multiValued()) {
|
||||||
GeoPoint[] points = fieldData.values(doc);
|
double[] lats = fieldData.latValues(doc);
|
||||||
for (GeoPoint point : points) {
|
double[] lons = fieldData.lonValues(doc);
|
||||||
double distance = geoDistance.calculate(lat, lon, point.lat(), point.lon(), unit);
|
for (int i = 0; i < lats.length; i++) {
|
||||||
|
double distance = geoDistance.calculate(lat, lon, lats[i], lons[i], unit);
|
||||||
for (GeoDistanceFacet.Entry entry : entries) {
|
for (GeoDistanceFacet.Entry entry : entries) {
|
||||||
if (distance >= entry.getFrom() && distance < entry.getTo()) {
|
if (distance >= entry.getFrom() && distance < entry.getTo()) {
|
||||||
entry.count++;
|
entry.count++;
|
||||||
|
@ -105,8 +105,7 @@ public class GeoDistanceFacetCollector extends AbstractFacetCollector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
GeoPoint point = fieldData.value(doc);
|
double distance = geoDistance.calculate(lat, lon, fieldData.latValue(doc), fieldData.lonValue(doc), unit);
|
||||||
double distance = geoDistance.calculate(lat, lon, point.lat(), point.lon(), unit);
|
|
||||||
for (GeoDistanceFacet.Entry entry : entries) {
|
for (GeoDistanceFacet.Entry entry : entries) {
|
||||||
if (distance >= entry.getFrom() && distance < entry.getTo()) {
|
if (distance >= entry.getFrom() && distance < entry.getTo()) {
|
||||||
entry.count++;
|
entry.count++;
|
||||||
|
|
Loading…
Reference in New Issue