Enhanced lat/long error handling

NumberFormatExceptions caused by non-double lat/long values are now
handled when the ignore_malformed flag is set to true.

Closes #16833
This commit is contained in:
James Bertouch 2016-02-26 10:56:47 -05:00 committed by Jason Tedor
parent 20b398daea
commit 3651854bf6
3 changed files with 94 additions and 7 deletions

View File

@ -374,6 +374,7 @@ public class GeoUtils {
double lat = Double.NaN;
double lon = Double.NaN;
String geohash = null;
NumberFormatException numberFormatException = null;
if(parser.currentToken() == Token.START_OBJECT) {
while(parser.nextToken() != Token.END_OBJECT) {
@ -384,7 +385,11 @@ public class GeoUtils {
switch (parser.currentToken()) {
case VALUE_NUMBER:
case VALUE_STRING:
lat = parser.doubleValue(true);
try {
lat = parser.doubleValue(true);
} catch (NumberFormatException e) {
numberFormatException = e;
}
break;
default:
throw new ElasticsearchParseException("latitude must be a number");
@ -394,7 +399,11 @@ public class GeoUtils {
switch (parser.currentToken()) {
case VALUE_NUMBER:
case VALUE_STRING:
lon = parser.doubleValue(true);
try {
lon = parser.doubleValue(true);
} catch (NumberFormatException e) {
numberFormatException = e;
}
break;
default:
throw new ElasticsearchParseException("longitude must be a number");
@ -419,6 +428,9 @@ public class GeoUtils {
} else {
return point.resetFromGeoHash(geohash);
}
} else if (numberFormatException != null) {
throw new ElasticsearchParseException("[{}] and [{}] must be valid double values", numberFormatException, LATITUDE,
LONGITUDE);
} else if (Double.isNaN(lat)) {
throw new ElasticsearchParseException("field [{}] missing", LATITUDE);
} else if (Double.isNaN(lon)) {

View File

@ -23,6 +23,7 @@ import org.apache.lucene.document.Field;
import org.apache.lucene.spatial.util.GeoHashUtils;
import org.apache.lucene.util.LegacyNumericUtils;
import org.elasticsearch.Version;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Explicit;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.collect.Iterators;
@ -431,8 +432,14 @@ public abstract class BaseGeoPointFieldMapper extends FieldMapper implements Arr
if (token == XContentParser.Token.START_ARRAY) {
// its an array of array of lon/lat [ [1.2, 1.3], [1.4, 1.5] ]
while (token != XContentParser.Token.END_ARRAY) {
parse(context, GeoUtils.parseGeoPoint(context.parser(), sparse), null);
token = context.parser().nextToken();
try {
parse(context, GeoUtils.parseGeoPoint(context.parser(), sparse), null);
} catch (ElasticsearchParseException e) {
if (ignoreMalformed.value() == false) {
throw e;
}
}
token = context.parser().nextToken();
}
} else {
// its an array of other possible values
@ -447,16 +454,28 @@ public abstract class BaseGeoPointFieldMapper extends FieldMapper implements Arr
if (token == XContentParser.Token.VALUE_STRING) {
parsePointFromString(context, sparse, context.parser().text());
} else {
parse(context, GeoUtils.parseGeoPoint(context.parser(), sparse), null);
try {
parse(context, GeoUtils.parseGeoPoint(context.parser(), sparse), null);
} catch (ElasticsearchParseException e) {
if (ignoreMalformed.value() == false) {
throw e;
}
}
}
token = context.parser().nextToken();
token = context.parser().nextToken();
}
}
}
} else if (token == XContentParser.Token.VALUE_STRING) {
parsePointFromString(context, sparse, context.parser().text());
} else if (token != XContentParser.Token.VALUE_NULL) {
parse(context, GeoUtils.parseGeoPoint(context.parser(), sparse), null);
try {
parse(context, GeoUtils.parseGeoPoint(context.parser(), sparse), null);
} catch (ElasticsearchParseException e) {
if (ignoreMalformed.value() == false) {
throw e;
}
}
}
}

View File

@ -43,11 +43,13 @@ import org.elasticsearch.test.geo.RandomGeoGenerator;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.lang.NumberFormatException;
import static org.apache.lucene.spatial.util.GeoEncodingUtils.mortonHash;
import static org.apache.lucene.spatial.util.GeoHashUtils.stringEncode;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
@ -282,6 +284,42 @@ public class GeoPointFieldMapperTests extends ESSingleNodeTestCase {
} catch (MapperParsingException e) {
}
try {
defaultMapper.parse("test", "type", "1", XContentFactory.jsonBuilder()
.startObject()
.startObject("point").field("lat", "-").field("lon", 1.3).endObject()
.endObject()
.bytes());
fail();
} catch (MapperParsingException e) {
assertThat(e.getRootCause(), instanceOf(NumberFormatException.class));
assertThat(e.getRootCause().toString(), containsString("java.lang.NumberFormatException: For input string: \"-\""));
}
try {
defaultMapper.parse("test", "type", "1", XContentFactory.jsonBuilder()
.startObject()
.startObject("point").field("lat", 1.2).field("lon", "-").endObject()
.endObject()
.bytes());
fail();
} catch (MapperParsingException e) {
assertThat(e.getRootCause(), instanceOf(NumberFormatException.class));
assertThat(e.getRootCause().toString(), containsString("java.lang.NumberFormatException: For input string: \"-\""));
}
try {
defaultMapper.parse("test", "type", "1", XContentFactory.jsonBuilder()
.startObject()
.startObject("point").field("lat", "-").field("lon", "-").endObject()
.endObject()
.bytes());
fail();
} catch (MapperParsingException e) {
assertThat(e.getRootCause(), instanceOf(NumberFormatException.class));
assertThat(e.getRootCause().toString(), containsString("java.lang.NumberFormatException: For input string: \"-\""));
}
}
public void testNoValidateLatLonValues() throws Exception {
@ -325,6 +363,24 @@ public class GeoPointFieldMapperTests extends ESSingleNodeTestCase {
.startObject("point").field("lat", 1.2).field("lon", 181).endObject()
.endObject()
.bytes());
defaultMapper.parse("test", "type", "1", XContentFactory.jsonBuilder()
.startObject()
.startObject("point").field("lat", "-").field("lon", 1.3).endObject()
.endObject()
.bytes());
defaultMapper.parse("test", "type", "1", XContentFactory.jsonBuilder()
.startObject()
.startObject("point").field("lat", 1.2).field("lon", "-").endObject()
.endObject()
.bytes());
defaultMapper.parse("test", "type", "1", XContentFactory.jsonBuilder()
.startObject()
.startObject("point").field("lat", "-").field("lon", "-").endObject()
.endObject()
.bytes());
}
public void testLatLonValuesStored() throws Exception {