org.elasticsearch.common.geo.GeometryParser Maven / Gradle / Ivy
Show all versions of elasticsearch Show documentation
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.common.geo;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
import org.elasticsearch.geometry.Geometry;
import org.elasticsearch.geometry.GeometryCollection;
import org.elasticsearch.geometry.Point;
import org.elasticsearch.geometry.utils.GeometryValidator;
import org.elasticsearch.geometry.utils.StandardValidator;
import org.elasticsearch.xcontent.NamedXContentRegistry;
import org.elasticsearch.xcontent.XContentParser;
import org.elasticsearch.xcontent.support.MapXContentParser;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* An utility class with to read geometries from a XContentParser or generic object.
*/
public final class GeometryParser {
private final boolean rightOrientation, coerce, ignoreZValue;
private final GeometryValidator validator;
public GeometryParser(boolean rightOrientation, boolean coerce, boolean ignoreZValue) {
this.rightOrientation = rightOrientation;
this.coerce = coerce;
this.ignoreZValue = ignoreZValue;
this.validator = StandardValidator.instance(ignoreZValue);
}
/**
* Parses supplied XContent into Geometry
*/
public Geometry parse(XContentParser parser) throws IOException, ParseException {
return GeometryParserFormat.geometryFormat(parser).fromXContent(validator, coerce, rightOrientation, parser);
}
/**
* Parses the value as a {@link Geometry}. The following types of values are supported:
*
* Object: has to contain either lat and lon or geohash fields
*
* String: expected to be in "latitude, longitude" format, a geohash or WKT
*
* Array: two or more elements, the first element is longitude, the second is latitude, the rest is ignored if ignoreZValue is true
*
* Json structure: valid geojson definition
*/
public Geometry parseGeometry(Object value) throws ElasticsearchParseException {
if (value instanceof List> values) {
if (values.size() == 2 && values.get(0) instanceof Number) {
GeoPoint point = GeoUtils.parseGeoPoint(values, ignoreZValue);
return new Point(point.lon(), point.lat());
} else {
List geometries = new ArrayList<>(values.size());
for (Object object : values) {
geometries.add(parseGeometry(object));
}
return new GeometryCollection<>(geometries);
}
}
try (
XContentParser parser = new MapXContentParser(
NamedXContentRegistry.EMPTY,
LoggingDeprecationHandler.INSTANCE,
Collections.singletonMap("null_value", value),
null
)
) {
parser.nextToken(); // start object
parser.nextToken(); // field name
parser.nextToken(); // field value
if (isPoint(value)) {
GeoPoint point = GeoUtils.parseGeoPoint(parser, ignoreZValue);
return new Point(point.lon(), point.lat());
} else {
return parse(parser);
}
} catch (IOException | ParseException ex) {
throw new ElasticsearchParseException("error parsing geometry ", ex);
}
}
private static boolean isPoint(Object value) {
// can we do this better?
if (value instanceof Map, ?> map) {
return map.containsKey("lat") && map.containsKey("lon");
} else if (value instanceof String string) {
return Character.isDigit(string.charAt(0)) || string.indexOf('(') == -1;
}
return false;
}
}