Skip to content

Commit

Permalink
Geo Type Mapping: Add validation options to validate lat and lon valu…
Browse files Browse the repository at this point in the history
…es, closes #1252.
  • Loading branch information
kimchy committed Aug 17, 2011
1 parent 55f62ec commit 8a7b205
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 5 deletions.
Expand Up @@ -20,6 +20,7 @@
package org.elasticsearch.index.mapper.geo;

import org.apache.lucene.document.Field;
import org.elasticsearch.ElasticSearchIllegalArgumentException;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
Expand Down Expand Up @@ -77,6 +78,8 @@ public static class Defaults {
public static final boolean ENABLE_LATLON = false;
public static final boolean ENABLE_GEOHASH = false;
public static final int PRECISION = GeoHashUtils.PRECISION;
public static final boolean VALIDATE_LAT = false;
public static final boolean VALIDATE_LON = false;
}

public static class Builder extends Mapper.Builder<Builder, GeoPointFieldMapper> {
Expand All @@ -93,6 +96,9 @@ public static class Builder extends Mapper.Builder<Builder, GeoPointFieldMapper>

private Field.Store store = Defaults.STORE;

boolean validateLat = Defaults.VALIDATE_LAT;
boolean validateLon = Defaults.VALIDATE_LON;

public Builder(String name) {
super(name);
this.builder = this;
Expand Down Expand Up @@ -158,7 +164,9 @@ public Builder store(Field.Store store) {

context.path().pathType(origPathType);

return new GeoPointFieldMapper(name, pathType, enableLatLon, enableGeoHash, precisionStep, precision, latMapper, lonMapper, geohashMapper, geoStringMapper);
return new GeoPointFieldMapper(name, pathType, enableLatLon, enableGeoHash, precisionStep, precision,
latMapper, lonMapper, geohashMapper, geoStringMapper,
validateLon, validateLat);
}
}

Expand All @@ -181,6 +189,13 @@ public static class TypeParser implements Mapper.TypeParser {
builder.precisionStep(XContentMapValues.nodeIntegerValue(fieldNode));
} else if (fieldName.equals("geohash_precision")) {
builder.precision(XContentMapValues.nodeIntegerValue(fieldNode));
} else if (fieldName.equals("validate")) {
builder.validateLat = XContentMapValues.nodeBooleanValue(fieldNode);
builder.validateLon = XContentMapValues.nodeBooleanValue(fieldNode);
} else if (fieldName.equals("validate_lon")) {
builder.validateLon = XContentMapValues.nodeBooleanValue(fieldNode);
} else if (fieldName.equals("validate_lat")) {
builder.validateLat = XContentMapValues.nodeBooleanValue(fieldNode);
}
}
return builder;
Expand All @@ -207,8 +222,12 @@ public static class TypeParser implements Mapper.TypeParser {

private final StringFieldMapper geoStringMapper;

private final boolean validateLon;
private final boolean validateLat;

public GeoPointFieldMapper(String name, ContentPath.Type pathType, boolean enableLatLon, boolean enableGeoHash, Integer precisionStep, int precision,
NumberFieldMapper latMapper, NumberFieldMapper lonMapper, StringFieldMapper geohashMapper, StringFieldMapper geoStringMapper) {
NumberFieldMapper latMapper, NumberFieldMapper lonMapper, StringFieldMapper geohashMapper, StringFieldMapper geoStringMapper,
boolean validateLon, boolean validateLat) {
this.name = name;
this.pathType = pathType;
this.enableLatLon = enableLatLon;
Expand All @@ -220,6 +239,9 @@ public GeoPointFieldMapper(String name, ContentPath.Type pathType, boolean enabl
this.lonMapper = lonMapper;
this.geoStringMapper = geoStringMapper;
this.geohashMapper = geohashMapper;

this.validateLat = validateLat;
this.validateLon = validateLon;
}

@Override public String name() {
Expand Down Expand Up @@ -324,25 +346,47 @@ private void parseLatLon(ParseContext context, Double lat, Double lon) throws IO
geohashMapper.parse(context);
}
if (enableLatLon) {
if (validateLat) {
if (lat > 90.0 || lat < -90.0) {
throw new ElasticSearchIllegalArgumentException("illegal latitude value [" + lat + "] for " + name);
}
}
context.externalValue(lat);
latMapper.parse(context);
if (validateLon) {
if (lon > 180.0 || lon < -180) {
throw new ElasticSearchIllegalArgumentException("illegal longitude value [" + lon + "] for " + name);
}
}
context.externalValue(lon);
lonMapper.parse(context);
}
}

private void parseGeohash(ParseContext context, String geohash) throws IOException {
double[] values = GeoHashUtils.decode(geohash);
context.externalValue(Double.toString(values[0]) + ',' + Double.toString(values[1]));
double lat = values[0];
double lon = values[1];
context.externalValue(Double.toString(lat) + ',' + Double.toString(lon));
geoStringMapper.parse(context);
if (enableGeoHash) {
context.externalValue(geohash);
geohashMapper.parse(context);
}
if (enableLatLon) {
context.externalValue(values[0]);
if (validateLat) {
if (lat > 90.0 || lat < -90.0) {
throw new ElasticSearchIllegalArgumentException("illegal latitude value [" + lat + "] for " + name);
}
}
context.externalValue(lat);
latMapper.parse(context);
context.externalValue(values[1]);
if (validateLon) {
if (lon > 180.0 || lon < -180) {
throw new ElasticSearchIllegalArgumentException("illegal longitude value [" + lon + "] for " + name);
}
}
context.externalValue(lon);
lonMapper.parse(context);
}
}
Expand Down Expand Up @@ -401,6 +445,16 @@ private void parseGeohash(ParseContext context, String geohash) throws IOExcepti
if (precisionStep != null) {
builder.field("precision_step", precisionStep);
}
if (validateLat && validateLon) {
builder.field("validate", true);
} else {
if (validateLat != Defaults.VALIDATE_LAT) {
builder.field("validate_lat", validateLat);
}
if (validateLon != Defaults.VALIDATE_LON) {
builder.field("validate_lon", validateLon);
}
}

builder.endObject();
return builder;
Expand Down
Expand Up @@ -19,6 +19,7 @@

package org.elasticsearch.index.mapper.geopoint;

import org.elasticsearch.ElasticSearchIllegalArgumentException;
import org.elasticsearch.common.Numbers;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.mapper.DocumentMapper;
Expand All @@ -35,6 +36,105 @@
*/
public class LatLonMappingGeoPointTests {

@Test public void testValidateLatLonValues() throws Exception {
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("point").field("type", "geo_point").field("lat_lon", true).field("validate", true).endObject().endObject()
.endObject().endObject().string();

DocumentMapper defaultMapper = MapperTests.newParser().parse(mapping);


ParsedDocument doc = defaultMapper.parse("type", "1", XContentFactory.jsonBuilder()
.startObject()
.startObject("point").field("lat", 90).field("lon", 1.3).endObject()
.endObject()
.copiedBytes());

try {
defaultMapper.parse("type", "1", XContentFactory.jsonBuilder()
.startObject()
.startObject("point").field("lat", -91).field("lon", 1.3).endObject()
.endObject()
.copiedBytes());
assert false;
} catch (ElasticSearchIllegalArgumentException e) {

}

try {
defaultMapper.parse("type", "1", XContentFactory.jsonBuilder()
.startObject()
.startObject("point").field("lat", 91).field("lon", 1.3).endObject()
.endObject()
.copiedBytes());
assert false;
} catch (ElasticSearchIllegalArgumentException e) {

}

try {
defaultMapper.parse("type", "1", XContentFactory.jsonBuilder()
.startObject()
.startObject("point").field("lat", 1.2).field("lon", -181).endObject()
.endObject()
.copiedBytes());
assert false;
} catch (ElasticSearchIllegalArgumentException e) {

}

try {
defaultMapper.parse("type", "1", XContentFactory.jsonBuilder()
.startObject()
.startObject("point").field("lat", 1.2).field("lon", 181).endObject()
.endObject()
.copiedBytes());
assert false;
} catch (ElasticSearchIllegalArgumentException e) {

}
}


@Test public void testNoValidateLatLonValues() throws Exception {
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("point").field("type", "geo_point").field("lat_lon", true).endObject().endObject()
.endObject().endObject().string();

DocumentMapper defaultMapper = MapperTests.newParser().parse(mapping);


ParsedDocument doc = defaultMapper.parse("type", "1", XContentFactory.jsonBuilder()
.startObject()
.startObject("point").field("lat", 90).field("lon", 1.3).endObject()
.endObject()
.copiedBytes());

defaultMapper.parse("type", "1", XContentFactory.jsonBuilder()
.startObject()
.startObject("point").field("lat", -91).field("lon", 1.3).endObject()
.endObject()
.copiedBytes());

defaultMapper.parse("type", "1", XContentFactory.jsonBuilder()
.startObject()
.startObject("point").field("lat", 91).field("lon", 1.3).endObject()
.endObject()
.copiedBytes());

defaultMapper.parse("type", "1", XContentFactory.jsonBuilder()
.startObject()
.startObject("point").field("lat", 1.2).field("lon", -181).endObject()
.endObject()
.copiedBytes());

defaultMapper.parse("type", "1", XContentFactory.jsonBuilder()
.startObject()
.startObject("point").field("lat", 1.2).field("lon", 181).endObject()
.endObject()
.copiedBytes());
}

@Test public void testLatLonValues() throws Exception {
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("point").field("type", "geo_point").field("lat_lon", true).endObject().endObject()
Expand Down

0 comments on commit 8a7b205

Please sign in to comment.