use of org.elasticsearch.common.geo.GeoPoint in project elasticsearch by elastic.
the class GeoDistanceSortBuilder method toXContent.
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.startObject(NAME);
builder.startArray(fieldName);
for (GeoPoint point : points) {
builder.value(point);
}
builder.endArray();
builder.field(UNIT_FIELD.getPreferredName(), unit);
builder.field(DISTANCE_TYPE_FIELD.getPreferredName(), geoDistance.name().toLowerCase(Locale.ROOT));
builder.field(ORDER_FIELD.getPreferredName(), order);
if (sortMode != null) {
builder.field(SORTMODE_FIELD.getPreferredName(), sortMode);
}
if (nestedPath != null) {
builder.field(NESTED_PATH_FIELD.getPreferredName(), nestedPath);
}
if (nestedFilter != null) {
builder.field(NESTED_FILTER_FIELD.getPreferredName(), nestedFilter, params);
}
builder.field(VALIDATION_METHOD_FIELD.getPreferredName(), validation);
builder.endObject();
builder.endObject();
return builder;
}
use of org.elasticsearch.common.geo.GeoPoint in project elasticsearch by elastic.
the class GeoDistanceSortBuilder method fromXContent.
/**
* Creates a new {@link GeoDistanceSortBuilder} from the query held by the {@link QueryParseContext} in
* {@link org.elasticsearch.common.xcontent.XContent} format.
*
* @param context the input parse context. The state on the parser contained in this context will be changed as a
* side effect of this method call
* @param elementName in some sort syntax variations the field name precedes the xContent object that specifies
* further parameters, e.g. in '{ "foo": { "order" : "asc"} }'. When parsing the inner object,
* the field name can be passed in via this argument
*/
public static GeoDistanceSortBuilder fromXContent(QueryParseContext context, String elementName) throws IOException {
XContentParser parser = context.parser();
String fieldName = null;
List<GeoPoint> geoPoints = new ArrayList<>();
DistanceUnit unit = DistanceUnit.DEFAULT;
GeoDistance geoDistance = GeoDistance.ARC;
SortOrder order = SortOrder.ASC;
SortMode sortMode = null;
QueryBuilder nestedFilter = null;
String nestedPath = null;
GeoValidationMethod validation = null;
XContentParser.Token token;
String currentName = parser.currentName();
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentName = parser.currentName();
} else if (token == XContentParser.Token.START_ARRAY) {
parseGeoPoints(parser, geoPoints);
fieldName = currentName;
} else if (token == XContentParser.Token.START_OBJECT) {
if (NESTED_FILTER_FIELD.match(currentName)) {
nestedFilter = context.parseInnerQueryBuilder();
} else {
// the json in the format of -> field : { lat : 30, lon : 12 }
if (fieldName != null && fieldName.equals(currentName) == false) {
throw new ParsingException(parser.getTokenLocation(), "Trying to reset fieldName to [{}], already set to [{}].", currentName, fieldName);
}
fieldName = currentName;
GeoPoint point = new GeoPoint();
GeoUtils.parseGeoPoint(parser, point);
geoPoints.add(point);
}
} else if (token.isValue()) {
if (ORDER_FIELD.match(currentName)) {
order = SortOrder.fromString(parser.text());
} else if (UNIT_FIELD.match(currentName)) {
unit = DistanceUnit.fromString(parser.text());
} else if (DISTANCE_TYPE_FIELD.match(currentName)) {
geoDistance = GeoDistance.fromString(parser.text());
} else if (VALIDATION_METHOD_FIELD.match(currentName)) {
validation = GeoValidationMethod.fromString(parser.text());
} else if (SORTMODE_FIELD.match(currentName)) {
sortMode = SortMode.fromString(parser.text());
} else if (NESTED_PATH_FIELD.match(currentName)) {
nestedPath = parser.text();
} else if (token == Token.VALUE_STRING) {
if (fieldName != null && fieldName.equals(currentName) == false) {
throw new ParsingException(parser.getTokenLocation(), "Trying to reset fieldName to [{}], already set to [{}].", currentName, fieldName);
}
GeoPoint point = new GeoPoint();
point.resetFromString(parser.text());
geoPoints.add(point);
fieldName = currentName;
} else if (fieldName.equals(currentName)) {
throw new ParsingException(parser.getTokenLocation(), "Only geohashes of type string supported for field [{}]", currentName);
} else {
throw new ParsingException(parser.getTokenLocation(), "[{}] does not support [{}]", NAME, currentName);
}
}
}
GeoDistanceSortBuilder result = new GeoDistanceSortBuilder(fieldName, geoPoints.toArray(new GeoPoint[geoPoints.size()]));
result.geoDistance(geoDistance);
result.unit(unit);
result.order(order);
if (sortMode != null) {
result.sortMode(sortMode);
}
if (nestedFilter != null) {
result.setNestedFilter(nestedFilter);
}
result.setNestedPath(nestedPath);
if (validation != null) {
result.validation(validation);
}
return result;
}
use of org.elasticsearch.common.geo.GeoPoint in project elasticsearch by elastic.
the class GeoDistanceSortBuilder method parseGeoPoints.
static void parseGeoPoints(XContentParser parser, List<GeoPoint> geoPoints) throws IOException {
while (!parser.nextToken().equals(XContentParser.Token.END_ARRAY)) {
if (parser.currentToken() == XContentParser.Token.VALUE_NUMBER) {
// we might get here if the geo point is " number, number] " and the parser already moved over the
// opening bracket in this case we cannot use GeoUtils.parseGeoPoint(..) because this expects an opening
// bracket
double lon = parser.doubleValue();
parser.nextToken();
if (!parser.currentToken().equals(XContentParser.Token.VALUE_NUMBER)) {
throw new ElasticsearchParseException("geo point parsing: expected second number but got [{}] instead", parser.currentToken());
}
double lat = parser.doubleValue();
GeoPoint point = new GeoPoint();
point.reset(lat, lon);
geoPoints.add(point);
} else {
GeoPoint point = new GeoPoint();
GeoUtils.parseGeoPoint(parser, point);
geoPoints.add(point);
}
}
}
use of org.elasticsearch.common.geo.GeoPoint in project elasticsearch by elastic.
the class GeoDistanceSortBuilder method build.
@Override
public SortFieldAndFormat build(QueryShardContext context) throws IOException {
final boolean indexCreatedBeforeV2_0 = context.indexVersionCreated().before(Version.V_2_0_0);
// validation was not available prior to 2.x, so to support bwc percolation queries we only ignore_malformed
// on 2.x created indexes
GeoPoint[] localPoints = points.toArray(new GeoPoint[points.size()]);
if (!indexCreatedBeforeV2_0 && !GeoValidationMethod.isIgnoreMalformed(validation)) {
for (GeoPoint point : localPoints) {
if (GeoUtils.isValidLatitude(point.lat()) == false) {
throw new ElasticsearchParseException("illegal latitude value [{}] for [GeoDistanceSort] for field [{}].", point.lat(), fieldName);
}
if (GeoUtils.isValidLongitude(point.lon()) == false) {
throw new ElasticsearchParseException("illegal longitude value [{}] for [GeoDistanceSort] for field [{}].", point.lon(), fieldName);
}
}
}
if (GeoValidationMethod.isCoerce(validation)) {
for (GeoPoint point : localPoints) {
GeoUtils.normalizePoint(point, true, true);
}
}
boolean reverse = (order == SortOrder.DESC);
final MultiValueMode finalSortMode;
if (sortMode == null) {
finalSortMode = reverse ? MultiValueMode.MAX : MultiValueMode.MIN;
} else {
finalSortMode = MultiValueMode.fromString(sortMode.toString());
}
MappedFieldType fieldType = context.fieldMapper(fieldName);
if (fieldType == null) {
throw new IllegalArgumentException("failed to find mapper for [" + fieldName + "] for geo distance based sort");
}
final IndexGeoPointFieldData geoIndexFieldData = context.getForField(fieldType);
final Nested nested = resolveNested(context, nestedPath, nestedFilter);
if (// only works with 5.x geo_point
geoIndexFieldData.getClass() == LatLonPointDVIndexFieldData.class && nested == null && // LatLonDocValuesField internally picks the closest point
finalSortMode == MultiValueMode.MIN && unit == DistanceUnit.METERS && reverse == false && localPoints.length == 1) {
return new SortFieldAndFormat(LatLonDocValuesField.newDistanceSort(fieldName, localPoints[0].lat(), localPoints[0].lon()), DocValueFormat.RAW);
}
IndexFieldData.XFieldComparatorSource geoDistanceComparatorSource = new IndexFieldData.XFieldComparatorSource() {
@Override
public SortField.Type reducedType() {
return SortField.Type.DOUBLE;
}
@Override
public FieldComparator<?> newComparator(String fieldname, int numHits, int sortPos, boolean reversed) {
return new FieldComparator.DoubleComparator(numHits, null, null) {
@Override
protected NumericDocValues getNumericDocValues(LeafReaderContext context, String field) throws IOException {
final MultiGeoPointValues geoPointValues = geoIndexFieldData.load(context).getGeoPointValues();
final SortedNumericDoubleValues distanceValues = GeoUtils.distanceValues(geoDistance, unit, geoPointValues, localPoints);
final NumericDoubleValues selectedValues;
if (nested == null) {
selectedValues = finalSortMode.select(distanceValues, Double.POSITIVE_INFINITY);
} else {
final BitSet rootDocs = nested.rootDocs(context);
final DocIdSetIterator innerDocs = nested.innerDocs(context);
selectedValues = finalSortMode.select(distanceValues, Double.POSITIVE_INFINITY, rootDocs, innerDocs, context.reader().maxDoc());
}
return selectedValues.getRawDoubleValues();
}
};
}
};
return new SortFieldAndFormat(new SortField(fieldName, geoDistanceComparatorSource, reverse), DocValueFormat.RAW);
}
use of org.elasticsearch.common.geo.GeoPoint in project elasticsearch by elastic.
the class DecayFunctionBuilder method parseGeoVariable.
private AbstractDistanceScoreFunction parseGeoVariable(XContentParser parser, QueryShardContext context, MappedFieldType fieldType, MultiValueMode mode) throws IOException {
XContentParser.Token token;
String parameterName = null;
GeoPoint origin = new GeoPoint();
String scaleString = null;
String offsetString = "0km";
double decay = 0.5;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
parameterName = parser.currentName();
} else if (DecayFunctionBuilder.SCALE.equals(parameterName)) {
scaleString = parser.text();
} else if (DecayFunctionBuilder.ORIGIN.equals(parameterName)) {
origin = GeoUtils.parseGeoPoint(parser);
} else if (DecayFunctionBuilder.DECAY.equals(parameterName)) {
decay = parser.doubleValue();
} else if (DecayFunctionBuilder.OFFSET.equals(parameterName)) {
offsetString = parser.text();
} else {
throw new ElasticsearchParseException("parameter [{}] not supported!", parameterName);
}
}
if (origin == null || scaleString == null) {
throw new ElasticsearchParseException("[{}] and [{}] must be set for geo fields.", DecayFunctionBuilder.ORIGIN, DecayFunctionBuilder.SCALE);
}
double scale = DistanceUnit.DEFAULT.parse(scaleString, DistanceUnit.DEFAULT);
double offset = DistanceUnit.DEFAULT.parse(offsetString, DistanceUnit.DEFAULT);
IndexGeoPointFieldData indexFieldData = context.getForField(fieldType);
return new GeoFieldDataScoreFunction(origin, scale, decay, offset, getDecayFunction(), indexFieldData, mode);
}
Aggregations