Skip to content

Commit 94d3ddd

Browse files
authored
Fix handling of points_only with term strategy in geo_shape (#31766)
Fixes 2 issues that together cause errors during index creation with geo_shapes that use the term strategy. The term strategy changes the default for points_only parameter, but this wasn't taken into account during serialization. So, setting the term strategy would add `"points_only": true` to serialization. At the same time if the term strategy would also cause the `points_only` setting to be not marked as a processed element during parsing, which would cause index creation to fail with the error: `Mapping definition for [location] has unsupported` `parameters: [points_only : true]`. Fixes #31707
1 parent 09e8ac8 commit 94d3ddd

File tree

2 files changed

+78
-9
lines changed

2 files changed

+78
-9
lines changed

server/src/main/java/org/elasticsearch/index/mapper/GeoShapeFieldMapper.java

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ public static class TypeParser implements Mapper.TypeParser {
199199
@Override
200200
public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException {
201201
Builder builder = new Builder(name);
202+
Boolean pointsOnly = null;
202203
for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext();) {
203204
Map.Entry<String, Object> entry = iterator.next();
204205
String fieldName = entry.getKey();
@@ -230,13 +231,18 @@ public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext
230231
} else if (GeoPointFieldMapper.Names.IGNORE_Z_VALUE.getPreferredName().equals(fieldName)) {
231232
builder.ignoreZValue(XContentMapValues.nodeBooleanValue(fieldNode, name + "." + GeoPointFieldMapper.Names.IGNORE_Z_VALUE.getPreferredName()));
232233
iterator.remove();
233-
} else if (Names.STRATEGY_POINTS_ONLY.equals(fieldName)
234-
&& builder.fieldType().strategyName.equals(SpatialStrategy.TERM.getStrategyName()) == false) {
235-
boolean pointsOnly = XContentMapValues.nodeBooleanValue(fieldNode, name + "." + Names.STRATEGY_POINTS_ONLY);
236-
builder.fieldType().setPointsOnly(pointsOnly);
234+
} else if (Names.STRATEGY_POINTS_ONLY.equals(fieldName)) {
235+
pointsOnly = XContentMapValues.nodeBooleanValue(fieldNode, name + "." + Names.STRATEGY_POINTS_ONLY);
237236
iterator.remove();
238237
}
239238
}
239+
if (pointsOnly != null) {
240+
if (builder.fieldType().strategyName.equals(SpatialStrategy.TERM.getStrategyName()) && pointsOnly == false) {
241+
throw new IllegalArgumentException("points_only cannot be set to false for term strategy");
242+
} else {
243+
builder.fieldType().setPointsOnly(pointsOnly);
244+
}
245+
}
240246
return builder;
241247
}
242248
}
@@ -565,7 +571,7 @@ protected void doXContentBody(XContentBuilder builder, boolean includeDefaults,
565571
} else if (includeDefaults && fieldType().treeLevels() == 0) { // defaults only make sense if tree levels are not specified
566572
builder.field(Names.TREE_PRESISION, DistanceUnit.METERS.toString(50));
567573
}
568-
if (includeDefaults || fieldType().strategyName() != Defaults.STRATEGY) {
574+
if (includeDefaults || fieldType().strategyName().equals(Defaults.STRATEGY) == false) {
569575
builder.field(Names.STRATEGY, fieldType().strategyName());
570576
}
571577
if (includeDefaults || fieldType().distanceErrorPct() != fieldType().defaultDistanceErrorPct) {
@@ -574,8 +580,15 @@ protected void doXContentBody(XContentBuilder builder, boolean includeDefaults,
574580
if (includeDefaults || fieldType().orientation() != Defaults.ORIENTATION) {
575581
builder.field(Names.ORIENTATION, fieldType().orientation());
576582
}
577-
if (includeDefaults || fieldType().pointsOnly() != GeoShapeFieldMapper.Defaults.POINTS_ONLY) {
578-
builder.field(Names.STRATEGY_POINTS_ONLY, fieldType().pointsOnly());
583+
if (fieldType().strategyName().equals(SpatialStrategy.TERM.getStrategyName())) {
584+
// For TERMs strategy the defaults for points only change to true
585+
if (includeDefaults || fieldType().pointsOnly() != true) {
586+
builder.field(Names.STRATEGY_POINTS_ONLY, fieldType().pointsOnly());
587+
}
588+
} else {
589+
if (includeDefaults || fieldType().pointsOnly() != GeoShapeFieldMapper.Defaults.POINTS_ONLY) {
590+
builder.field(Names.STRATEGY_POINTS_ONLY, fieldType().pointsOnly());
591+
}
579592
}
580593
if (includeDefaults || coerce.explicit()) {
581594
builder.field(Names.COERCE, coerce.value());

server/src/test/java/org/elasticsearch/index/mapper/GeoShapeFieldMapperTests.java

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import static org.hamcrest.Matchers.containsString;
4343
import static org.hamcrest.Matchers.equalTo;
4444
import static org.hamcrest.Matchers.instanceOf;
45+
import static org.hamcrest.Matchers.not;
4546

4647
public class GeoShapeFieldMapperTests extends ESSingleNodeTestCase {
4748

@@ -588,10 +589,65 @@ public void testSerializeDefaults() throws Exception {
588589
}
589590
}
590591

591-
public String toXContentString(GeoShapeFieldMapper mapper) throws IOException {
592+
public void testPointsOnlyDefaultsWithTermStrategy() throws IOException {
593+
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type1")
594+
.startObject("properties").startObject("location")
595+
.field("type", "geo_shape")
596+
.field("tree", "quadtree")
597+
.field("precision", "10m")
598+
.field("strategy", "term")
599+
.endObject().endObject()
600+
.endObject().endObject());
601+
602+
DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));
603+
FieldMapper fieldMapper = defaultMapper.mappers().getMapper("location");
604+
assertThat(fieldMapper, instanceOf(GeoShapeFieldMapper.class));
605+
606+
GeoShapeFieldMapper geoShapeFieldMapper = (GeoShapeFieldMapper) fieldMapper;
607+
PrefixTreeStrategy strategy = geoShapeFieldMapper.fieldType().defaultStrategy();
608+
609+
assertThat(strategy.getDistErrPct(), equalTo(0.0));
610+
assertThat(strategy.getGrid(), instanceOf(QuadPrefixTree.class));
611+
assertThat(strategy.getGrid().getMaxLevels(), equalTo(23));
612+
assertThat(strategy.isPointsOnly(), equalTo(true));
613+
// term strategy changes the default for points_only, check that we handle it correctly
614+
assertThat(toXContentString(geoShapeFieldMapper, false), not(containsString("points_only")));
615+
}
616+
617+
618+
public void testPointsOnlyFalseWithTermStrategy() throws Exception {
619+
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type1")
620+
.startObject("properties").startObject("location")
621+
.field("type", "geo_shape")
622+
.field("tree", "quadtree")
623+
.field("precision", "10m")
624+
.field("strategy", "term")
625+
.field("points_only", false)
626+
.endObject().endObject()
627+
.endObject().endObject());
628+
629+
DocumentMapperParser parser = createIndex("test").mapperService().documentMapperParser();
630+
631+
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
632+
() -> parser.parse("type1", new CompressedXContent(mapping))
633+
);
634+
assertThat(e.getMessage(), containsString("points_only cannot be set to false for term strategy"));
635+
}
636+
637+
public String toXContentString(GeoShapeFieldMapper mapper, boolean includeDefaults) throws IOException {
592638
XContentBuilder builder = XContentFactory.jsonBuilder().startObject();
593-
mapper.doXContentBody(builder, true, new ToXContent.MapParams(Collections.singletonMap("include_defaults", "true")));
639+
ToXContent.Params params;
640+
if (includeDefaults) {
641+
params = new ToXContent.MapParams(Collections.singletonMap("include_defaults", "true"));
642+
} else {
643+
params = ToXContent.EMPTY_PARAMS;
644+
}
645+
mapper.doXContentBody(builder, includeDefaults, params);
594646
return Strings.toString(builder.endObject());
595647
}
596648

649+
public String toXContentString(GeoShapeFieldMapper mapper) throws IOException {
650+
return toXContentString(mapper, true);
651+
}
652+
597653
}

0 commit comments

Comments
 (0)