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 lat = Double.NaN;
double lon = Double.NaN; double lon = Double.NaN;
String geohash = null; String geohash = null;
NumberFormatException numberFormatException = null;
if(parser.currentToken() == Token.START_OBJECT) { if(parser.currentToken() == Token.START_OBJECT) {
while(parser.nextToken() != Token.END_OBJECT) { while(parser.nextToken() != Token.END_OBJECT) {
@ -384,7 +385,11 @@ public class GeoUtils {
switch (parser.currentToken()) { switch (parser.currentToken()) {
case VALUE_NUMBER: case VALUE_NUMBER:
case VALUE_STRING: case VALUE_STRING:
lat = parser.doubleValue(true); try {
lat = parser.doubleValue(true);
} catch (NumberFormatException e) {
numberFormatException = e;
}
break; break;
default: default:
throw new ElasticsearchParseException("latitude must be a number"); throw new ElasticsearchParseException("latitude must be a number");
@ -394,7 +399,11 @@ public class GeoUtils {
switch (parser.currentToken()) { switch (parser.currentToken()) {
case VALUE_NUMBER: case VALUE_NUMBER:
case VALUE_STRING: case VALUE_STRING:
lon = parser.doubleValue(true); try {
lon = parser.doubleValue(true);
} catch (NumberFormatException e) {
numberFormatException = e;
}
break; break;
default: default:
throw new ElasticsearchParseException("longitude must be a number"); throw new ElasticsearchParseException("longitude must be a number");
@ -419,6 +428,9 @@ public class GeoUtils {
} else { } else {
return point.resetFromGeoHash(geohash); 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)) { } else if (Double.isNaN(lat)) {
throw new ElasticsearchParseException("field [{}] missing", LATITUDE); throw new ElasticsearchParseException("field [{}] missing", LATITUDE);
} else if (Double.isNaN(lon)) { } 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.spatial.util.GeoHashUtils;
import org.apache.lucene.util.LegacyNumericUtils; import org.apache.lucene.util.LegacyNumericUtils;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Explicit; import org.elasticsearch.common.Explicit;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.collect.Iterators; import org.elasticsearch.common.collect.Iterators;
@ -431,8 +432,14 @@ public abstract class BaseGeoPointFieldMapper extends FieldMapper implements Arr
if (token == XContentParser.Token.START_ARRAY) { if (token == XContentParser.Token.START_ARRAY) {
// its an array of array of lon/lat [ [1.2, 1.3], [1.4, 1.5] ] // its an array of array of lon/lat [ [1.2, 1.3], [1.4, 1.5] ]
while (token != XContentParser.Token.END_ARRAY) { while (token != XContentParser.Token.END_ARRAY) {
parse(context, GeoUtils.parseGeoPoint(context.parser(), sparse), null); try {
token = context.parser().nextToken(); parse(context, GeoUtils.parseGeoPoint(context.parser(), sparse), null);
} catch (ElasticsearchParseException e) {
if (ignoreMalformed.value() == false) {
throw e;
}
}
token = context.parser().nextToken();
} }
} else { } else {
// its an array of other possible values // 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) { if (token == XContentParser.Token.VALUE_STRING) {
parsePointFromString(context, sparse, context.parser().text()); parsePointFromString(context, sparse, context.parser().text());
} else { } 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) { } else if (token == XContentParser.Token.VALUE_STRING) {
parsePointFromString(context, sparse, context.parser().text()); parsePointFromString(context, sparse, context.parser().text());
} else if (token != XContentParser.Token.VALUE_NULL) { } 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.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.lang.NumberFormatException;
import static org.apache.lucene.spatial.util.GeoEncodingUtils.mortonHash; import static org.apache.lucene.spatial.util.GeoEncodingUtils.mortonHash;
import static org.apache.lucene.spatial.util.GeoHashUtils.stringEncode; import static org.apache.lucene.spatial.util.GeoHashUtils.stringEncode;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; 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.containsString;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@ -282,6 +284,42 @@ public class GeoPointFieldMapperTests extends ESSingleNodeTestCase {
} catch (MapperParsingException e) { } 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 { public void testNoValidateLatLonValues() throws Exception {
@ -325,6 +363,24 @@ public class GeoPointFieldMapperTests extends ESSingleNodeTestCase {
.startObject("point").field("lat", 1.2).field("lon", 181).endObject() .startObject("point").field("lat", 1.2).field("lon", 181).endObject()
.endObject() .endObject()
.bytes()); .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 { public void testLatLonValuesStored() throws Exception {