Skip to content

Commit b2ba384

Browse files
committed
Refactor geo_point validate* and normalize* options to ignore_malformed and coerce*
For consistency geo_point mapper's validate and normalize options are converted to ignore_malformed and coerced
1 parent 68307aa commit b2ba384

21 files changed

+550
-217
lines changed

core/src/main/java/org/elasticsearch/index/mapper/geo/GeoPointFieldMapper.java

Lines changed: 68 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ public static class Names {
8585
public static final String LON_SUFFIX = "." + LON;
8686
public static final String GEOHASH = "geohash";
8787
public static final String GEOHASH_SUFFIX = "." + GEOHASH;
88+
public static final String IGNORE_MALFORMED = "ignore_malformed";
89+
public static final String COERCE = "coerce";
8890
}
8991

9092
public static class Defaults {
@@ -93,10 +95,9 @@ public static class Defaults {
9395
public static final boolean ENABLE_GEOHASH = false;
9496
public static final boolean ENABLE_GEOHASH_PREFIX = false;
9597
public static final int GEO_HASH_PRECISION = GeoHashUtils.PRECISION;
96-
public static final boolean NORMALIZE_LAT = true;
97-
public static final boolean NORMALIZE_LON = true;
98-
public static final boolean VALIDATE_LAT = true;
99-
public static final boolean VALIDATE_LON = true;
98+
99+
public static final boolean IGNORE_MALFORMED = false;
100+
public static final boolean COERCE = false;
100101

101102
public static final MappedFieldType FIELD_TYPE = new GeoPointFieldType();
102103

@@ -215,6 +216,7 @@ public static class TypeParser implements Mapper.TypeParser {
215216
@Override
216217
public Mapper.Builder<?, ?> parse(String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException {
217218
Builder builder = geoPointField(name);
219+
final boolean indexCreatedBeforeV2_0 = parserContext.indexVersionCreated().before(Version.V_2_0_0);
218220
parseField(builder, name, node, parserContext);
219221
for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext();) {
220222
Map.Entry<String, Object> entry = iterator.next();
@@ -245,25 +247,42 @@ public static class TypeParser implements Mapper.TypeParser {
245247
builder.geoHashPrecision(GeoUtils.geoHashLevelsForPrecision(fieldNode.toString()));
246248
}
247249
iterator.remove();
248-
} else if (fieldName.equals("validate")) {
249-
builder.fieldType().setValidateLat(XContentMapValues.nodeBooleanValue(fieldNode));
250-
builder.fieldType().setValidateLon(XContentMapValues.nodeBooleanValue(fieldNode));
250+
} else if (fieldName.equals(Names.IGNORE_MALFORMED)) {
251+
if (builder.fieldType().coerce == false) {
252+
builder.fieldType().ignoreMalformed = XContentMapValues.nodeBooleanValue(fieldNode);
253+
}
251254
iterator.remove();
252-
} else if (fieldName.equals("validate_lon")) {
253-
builder.fieldType().setValidateLon(XContentMapValues.nodeBooleanValue(fieldNode));
255+
} else if (indexCreatedBeforeV2_0 && fieldName.equals("validate")) {
256+
if (builder.fieldType().ignoreMalformed == false) {
257+
builder.fieldType().ignoreMalformed = !XContentMapValues.nodeBooleanValue(fieldNode);
258+
}
259+
iterator.remove();
260+
} else if (indexCreatedBeforeV2_0 && fieldName.equals("validate_lon")) {
261+
if (builder.fieldType().ignoreMalformed() == false) {
262+
builder.fieldType().ignoreMalformed = !XContentMapValues.nodeBooleanValue(fieldNode);
263+
}
254264
iterator.remove();
255-
} else if (fieldName.equals("validate_lat")) {
256-
builder.fieldType().setValidateLat(XContentMapValues.nodeBooleanValue(fieldNode));
265+
} else if (indexCreatedBeforeV2_0 && fieldName.equals("validate_lat")) {
266+
if (builder.fieldType().ignoreMalformed == false) {
267+
builder.fieldType().ignoreMalformed = !XContentMapValues.nodeBooleanValue(fieldNode);
268+
}
257269
iterator.remove();
258-
} else if (fieldName.equals("normalize")) {
259-
builder.fieldType().setNormalizeLat(XContentMapValues.nodeBooleanValue(fieldNode));
260-
builder.fieldType().setNormalizeLon(XContentMapValues.nodeBooleanValue(fieldNode));
270+
} else if (fieldName.equals(Names.COERCE)) {
271+
builder.fieldType().coerce = XContentMapValues.nodeBooleanValue(fieldNode);
272+
if (builder.fieldType().coerce == true) {
273+
builder.fieldType().ignoreMalformed = true;
274+
}
275+
iterator.remove();
276+
} else if (indexCreatedBeforeV2_0 && fieldName.equals("normalize")) {
277+
builder.fieldType().coerce = XContentMapValues.nodeBooleanValue(fieldNode);
261278
iterator.remove();
262-
} else if (fieldName.equals("normalize_lat")) {
263-
builder.fieldType().setNormalizeLat(XContentMapValues.nodeBooleanValue(fieldNode));
279+
} else if (indexCreatedBeforeV2_0 && fieldName.equals("normalize_lat")) {
280+
builder.fieldType().coerce = XContentMapValues.nodeBooleanValue(fieldNode);
264281
iterator.remove();
265-
} else if (fieldName.equals("normalize_lon")) {
266-
builder.fieldType().setNormalizeLon(XContentMapValues.nodeBooleanValue(fieldNode));
282+
} else if (indexCreatedBeforeV2_0 && fieldName.equals("normalize_lon")) {
283+
if (builder.fieldType().coerce == false) {
284+
builder.fieldType().coerce = XContentMapValues.nodeBooleanValue(fieldNode);
285+
}
267286
iterator.remove();
268287
} else if (parseMultiField(builder, name, parserContext, fieldName, fieldNode)) {
269288
iterator.remove();
@@ -281,10 +300,8 @@ public static final class GeoPointFieldType extends MappedFieldType {
281300

282301
private MappedFieldType latFieldType;
283302
private MappedFieldType lonFieldType;
284-
private boolean validateLon = true;
285-
private boolean validateLat = true;
286-
private boolean normalizeLon = true;
287-
private boolean normalizeLat = true;
303+
private boolean ignoreMalformed = false;
304+
private boolean coerce = false;
288305

289306
public GeoPointFieldType() {}
290307

@@ -295,10 +312,8 @@ protected GeoPointFieldType(GeoPointFieldType ref) {
295312
this.geohashPrefixEnabled = ref.geohashPrefixEnabled;
296313
this.latFieldType = ref.latFieldType; // copying ref is ok, this can never be modified
297314
this.lonFieldType = ref.lonFieldType; // copying ref is ok, this can never be modified
298-
this.validateLon = ref.validateLon;
299-
this.validateLat = ref.validateLat;
300-
this.normalizeLon = ref.normalizeLon;
301-
this.normalizeLat = ref.normalizeLat;
315+
this.coerce = ref.coerce;
316+
this.ignoreMalformed = ref.ignoreMalformed;
302317
}
303318

304319
@Override
@@ -312,18 +327,17 @@ public boolean equals(Object o) {
312327
GeoPointFieldType that = (GeoPointFieldType) o;
313328
return geohashPrecision == that.geohashPrecision &&
314329
geohashPrefixEnabled == that.geohashPrefixEnabled &&
315-
validateLon == that.validateLon &&
316-
validateLat == that.validateLat &&
317-
normalizeLon == that.normalizeLon &&
318-
normalizeLat == that.normalizeLat &&
330+
coerce == that.coerce &&
331+
ignoreMalformed == that.ignoreMalformed &&
319332
java.util.Objects.equals(geohashFieldType, that.geohashFieldType) &&
320333
java.util.Objects.equals(latFieldType, that.latFieldType) &&
321334
java.util.Objects.equals(lonFieldType, that.lonFieldType);
322335
}
323336

324337
@Override
325338
public int hashCode() {
326-
return java.util.Objects.hash(super.hashCode(), geohashFieldType, geohashPrecision, geohashPrefixEnabled, latFieldType, lonFieldType, validateLon, validateLat, normalizeLon, normalizeLat);
339+
return java.util.Objects.hash(super.hashCode(), geohashFieldType, geohashPrecision, geohashPrefixEnabled, latFieldType,
340+
lonFieldType, coerce, ignoreMalformed);
327341
}
328342

329343
@Override
@@ -347,22 +361,10 @@ public void checkCompatibility(MappedFieldType fieldType, List<String> conflicts
347361
if (isGeohashPrefixEnabled() != other.isGeohashPrefixEnabled()) {
348362
conflicts.add("mapper [" + names().fullName() + "] has different geohash_prefix");
349363
}
350-
if (normalizeLat() != other.normalizeLat()) {
351-
conflicts.add("mapper [" + names().fullName() + "] has different normalize_lat");
352-
}
353-
if (normalizeLon() != other.normalizeLon()) {
354-
conflicts.add("mapper [" + names().fullName() + "] has different normalize_lon");
355-
}
356-
if (isLatLonEnabled() &&
364+
if (isLatLonEnabled() && other.isLatLonEnabled() &&
357365
latFieldType().numericPrecisionStep() != other.latFieldType().numericPrecisionStep()) {
358366
conflicts.add("mapper [" + names().fullName() + "] has different precision_step");
359367
}
360-
if (validateLat() != other.validateLat()) {
361-
conflicts.add("mapper [" + names().fullName() + "] has different validate_lat");
362-
}
363-
if (validateLon() != other.validateLon()) {
364-
conflicts.add("mapper [" + names().fullName() + "] has different validate_lon");
365-
}
366368
}
367369

368370
public boolean isGeohashEnabled() {
@@ -406,40 +408,22 @@ public void setLatLonEnabled(MappedFieldType latFieldType, MappedFieldType lonFi
406408
this.lonFieldType = lonFieldType;
407409
}
408410

409-
public boolean validateLon() {
410-
return validateLon;
411-
}
412-
413-
public void setValidateLon(boolean validateLon) {
414-
checkIfFrozen();
415-
this.validateLon = validateLon;
416-
}
417-
418-
public boolean validateLat() {
419-
return validateLat;
420-
}
421-
422-
public void setValidateLat(boolean validateLat) {
423-
checkIfFrozen();
424-
this.validateLat = validateLat;
411+
public boolean coerce() {
412+
return this.coerce;
425413
}
426414

427-
public boolean normalizeLon() {
428-
return normalizeLon;
429-
}
430-
431-
public void setNormalizeLon(boolean normalizeLon) {
415+
public void setCoerce(boolean coerce) {
432416
checkIfFrozen();
433-
this.normalizeLon = normalizeLon;
417+
this.coerce = coerce;
434418
}
435419

436-
public boolean normalizeLat() {
437-
return normalizeLat;
420+
public boolean ignoreMalformed() {
421+
return this.ignoreMalformed;
438422
}
439423

440-
public void setNormalizeLat(boolean normalizeLat) {
424+
public void setIgnoreMalformed(boolean ignoreMalformed) {
441425
checkIfFrozen();
442-
this.normalizeLat = normalizeLat;
426+
this.ignoreMalformed = ignoreMalformed;
443427
}
444428

445429
@Override
@@ -586,7 +570,8 @@ public GeoPoint decode(long latBits, long lonBits, GeoPoint out) {
586570
private final StringFieldMapper geohashMapper;
587571

588572
public GeoPointFieldMapper(String simpleName, MappedFieldType fieldType, MappedFieldType defaultFieldType, Settings indexSettings,
589-
ContentPath.Type pathType, DoubleFieldMapper latMapper, DoubleFieldMapper lonMapper, StringFieldMapper geohashMapper,MultiFields multiFields) {
573+
ContentPath.Type pathType, DoubleFieldMapper latMapper, DoubleFieldMapper lonMapper, StringFieldMapper geohashMapper,
574+
MultiFields multiFields) {
590575
super(simpleName, fieldType, defaultFieldType, indexSettings, multiFields, null);
591576
this.pathType = pathType;
592577
this.latMapper = latMapper;
@@ -680,21 +665,22 @@ private void parsePointFromString(ParseContext context, GeoPoint sparse, String
680665
}
681666

682667
private void parse(ParseContext context, GeoPoint point, String geohash) throws IOException {
683-
if (fieldType().normalizeLat() || fieldType().normalizeLon()) {
684-
GeoUtils.normalizePoint(point, fieldType().normalizeLat(), fieldType().normalizeLon());
685-
}
686-
687-
if (fieldType().validateLat()) {
668+
if (fieldType().ignoreMalformed == false) {
688669
if (point.lat() > 90.0 || point.lat() < -90.0) {
689670
throw new IllegalArgumentException("illegal latitude value [" + point.lat() + "] for " + name());
690671
}
691-
}
692-
if (fieldType().validateLon()) {
693672
if (point.lon() > 180.0 || point.lon() < -180) {
694673
throw new IllegalArgumentException("illegal longitude value [" + point.lon() + "] for " + name());
695674
}
696675
}
697676

677+
if (fieldType().coerce) {
678+
// by setting coerce to false we are assuming all geopoints are already in a valid coordinate system
679+
// thus this extra step can be skipped
680+
// LUCENE WATCH: This will be folded back into Lucene's GeoPointField
681+
GeoUtils.normalizePoint(point, true, true);
682+
}
683+
698684
if (fieldType().indexOptions() != IndexOptions.NONE || fieldType().stored()) {
699685
Field field = new Field(fieldType().names().indexName(), Double.toString(point.lat()) + ',' + Double.toString(point.lon()), fieldType());
700686
context.doc().add(field);
@@ -755,33 +741,11 @@ protected void doXContentBody(XContentBuilder builder, boolean includeDefaults,
755741
if (fieldType().isLatLonEnabled() && (includeDefaults || fieldType().latFieldType().numericPrecisionStep() != NumericUtils.PRECISION_STEP_DEFAULT)) {
756742
builder.field("precision_step", fieldType().latFieldType().numericPrecisionStep());
757743
}
758-
if (includeDefaults || fieldType().validateLat() != Defaults.VALIDATE_LAT || fieldType().validateLon() != Defaults.VALIDATE_LON) {
759-
if (fieldType().validateLat() && fieldType().validateLon()) {
760-
builder.field("validate", true);
761-
} else if (!fieldType().validateLat() && !fieldType().validateLon()) {
762-
builder.field("validate", false);
763-
} else {
764-
if (includeDefaults || fieldType().validateLat() != Defaults.VALIDATE_LAT) {
765-
builder.field("validate_lat", fieldType().validateLat());
766-
}
767-
if (includeDefaults || fieldType().validateLon() != Defaults.VALIDATE_LON) {
768-
builder.field("validate_lon", fieldType().validateLon());
769-
}
770-
}
744+
if (includeDefaults || fieldType().coerce != Defaults.COERCE) {
745+
builder.field(Names.COERCE, fieldType().coerce);
771746
}
772-
if (includeDefaults || fieldType().normalizeLat() != Defaults.NORMALIZE_LAT || fieldType().normalizeLon() != Defaults.NORMALIZE_LON) {
773-
if (fieldType().normalizeLat() && fieldType().normalizeLon()) {
774-
builder.field("normalize", true);
775-
} else if (!fieldType().normalizeLat() && !fieldType().normalizeLon()) {
776-
builder.field("normalize", false);
777-
} else {
778-
if (includeDefaults || fieldType().normalizeLat() != Defaults.NORMALIZE_LAT) {
779-
builder.field("normalize_lat", fieldType().normalizeLat());
780-
}
781-
if (includeDefaults || fieldType().normalizeLon() != Defaults.NORMALIZE_LON) {
782-
builder.field("normalize_lon", fieldType().normalizeLon());
783-
}
784-
}
747+
if (includeDefaults || fieldType().ignoreMalformed != Defaults.IGNORE_MALFORMED) {
748+
builder.field(Names.IGNORE_MALFORMED, fieldType().ignoreMalformed);
785749
}
786750
}
787751

@@ -812,5 +776,4 @@ public BytesRef binaryValue() {
812776
return new BytesRef(bytes);
813777
}
814778
}
815-
816779
}

core/src/main/java/org/elasticsearch/index/query/GeoBoundingBoxQueryBuilder.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ public class GeoBoundingBoxQueryBuilder extends QueryBuilder {
4141

4242
private String queryName;
4343
private String type;
44+
private Boolean coerce;
45+
private Boolean ignoreMalformed;
4446

4547
public GeoBoundingBoxQueryBuilder(String name) {
4648
this.name = name;
@@ -134,6 +136,16 @@ public GeoBoundingBoxQueryBuilder queryName(String queryName) {
134136
return this;
135137
}
136138

139+
public GeoBoundingBoxQueryBuilder coerce(boolean coerce) {
140+
this.coerce = coerce;
141+
return this;
142+
}
143+
144+
public GeoBoundingBoxQueryBuilder ignoreMalformed(boolean ignoreMalformed) {
145+
this.ignoreMalformed = ignoreMalformed;
146+
return this;
147+
}
148+
137149
/**
138150
* Sets the type of executing of the geo bounding box. Can be either `memory` or `indexed`. Defaults
139151
* to `memory`.
@@ -169,6 +181,12 @@ protected void doXContent(XContentBuilder builder, Params params) throws IOExcep
169181
if (type != null) {
170182
builder.field("type", type);
171183
}
184+
if (coerce != null) {
185+
builder.field("coerce", coerce);
186+
}
187+
if (ignoreMalformed != null) {
188+
builder.field("ignore_malformed", ignoreMalformed);
189+
}
172190

173191
builder.endObject();
174192
}

0 commit comments

Comments
 (0)