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