Skip to content

Commit 77f9bb6

Browse files
committed
add doc_values mapping option to geo_shape field mapping (#47519)
This PR adds support for the `doc_values` field mapping parameter. `true` and `false` supported by the GeoShapeFieldMapper, only `false` is supported by the LegacyGeoShapeFieldMapper. relates #37206
1 parent 3d1e21b commit 77f9bb6

File tree

8 files changed

+254
-21
lines changed

8 files changed

+254
-21
lines changed

docs/reference/mapping/types/geo-shape.asciidoc

+5
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ and reject the whole document.
114114
|`coerce` |If `true` unclosed linear rings in polygons will be automatically closed.
115115
| `false`
116116

117+
|`doc_values` |Should the field be stored on disk in a column-stride fashion, so that it
118+
can later be used for sorting, aggregations, or scripting? Accepts `true`
119+
(default) or `false`.
120+
| `true` for BKD-backed geo_shape, `false` for prefix tree indexing strategy
121+
117122
|=======================================================================
118123

119124

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

+30-10
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ public static class Defaults {
7070
public static final Explicit<Boolean> COERCE = new Explicit<>(false, false);
7171
public static final Explicit<Boolean> IGNORE_MALFORMED = new Explicit<>(false, false);
7272
public static final Explicit<Boolean> IGNORE_Z_VALUE = new Explicit<>(true, false);
73+
public static final Explicit<Boolean> DOC_VALUES = new Explicit<>(false, false);
7374
}
7475

7576

@@ -122,15 +123,6 @@ public Builder(String name, MappedFieldType fieldType, MappedFieldType defaultFi
122123
super(name, fieldType, defaultFieldType);
123124
}
124125

125-
public Builder(String name, MappedFieldType fieldType, MappedFieldType defaultFieldType,
126-
boolean coerce, boolean ignoreMalformed, Orientation orientation, boolean ignoreZ) {
127-
super(name, fieldType, defaultFieldType);
128-
this.coerce = coerce;
129-
this.ignoreMalformed = ignoreMalformed;
130-
this.orientation = orientation;
131-
this.ignoreZValue = ignoreZ;
132-
}
133-
134126
public Builder coerce(boolean coerce) {
135127
this.coerce = coerce;
136128
return this;
@@ -190,6 +182,15 @@ public Builder ignoreZValue(final boolean ignoreZValue) {
190182
return this;
191183
}
192184

185+
protected Explicit<Boolean> docValues() {
186+
if (docValuesSet && fieldType.hasDocValues()) {
187+
return new Explicit<>(true, true);
188+
} else if (docValuesSet) {
189+
return new Explicit<>(false, true);
190+
}
191+
return Defaults.DOC_VALUES;
192+
}
193+
193194
@Override
194195
protected void setupFieldType(BuilderContext context) {
195196
super.setupFieldType(context);
@@ -251,13 +252,20 @@ public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext
251252
XContentMapValues.nodeBooleanValue(fieldNode,
252253
name + "." + GeoPointFieldMapper.Names.IGNORE_Z_VALUE.getPreferredName()));
253254
iterator.remove();
255+
} else if (TypeParsers.DOC_VALUES.equals(fieldName)) {
256+
params.put(TypeParsers.DOC_VALUES, XContentMapValues.nodeBooleanValue(fieldNode, name + "." + TypeParsers.DOC_VALUES));
257+
iterator.remove();
254258
}
255259
}
256260
if (parserContext.indexVersionCreated().onOrAfter(Version.V_6_6_0) && parsedDeprecatedParameters == false) {
257261
params.remove(DEPRECATED_PARAMETERS_KEY);
258262
}
259263
Builder builder = newBuilder(name, params);
260264

265+
if (params.containsKey(TypeParsers.DOC_VALUES)) {
266+
builder.docValues((Boolean) params.get(TypeParsers.DOC_VALUES));
267+
}
268+
261269
if (params.containsKey(Names.COERCE.getPreferredName())) {
262270
builder.coerce((Boolean)params.get(Names.COERCE.getPreferredName()));
263271
}
@@ -358,15 +366,17 @@ public QueryProcessor geometryQueryBuilder() {
358366
protected Explicit<Boolean> coerce;
359367
protected Explicit<Boolean> ignoreMalformed;
360368
protected Explicit<Boolean> ignoreZValue;
369+
protected Explicit<Boolean> docValues;
361370

362371
protected AbstractGeometryFieldMapper(String simpleName, MappedFieldType fieldType, MappedFieldType defaultFieldType,
363372
Explicit<Boolean> ignoreMalformed, Explicit<Boolean> coerce,
364-
Explicit<Boolean> ignoreZValue, Settings indexSettings,
373+
Explicit<Boolean> ignoreZValue, Explicit<Boolean> docValues, Settings indexSettings,
365374
MultiFields multiFields, CopyTo copyTo) {
366375
super(simpleName, fieldType, defaultFieldType, indexSettings, multiFields, copyTo);
367376
this.coerce = coerce;
368377
this.ignoreMalformed = ignoreMalformed;
369378
this.ignoreZValue = ignoreZValue;
379+
this.docValues = docValues;
370380
}
371381

372382
@Override
@@ -382,6 +392,9 @@ protected void doMerge(Mapper mergeWith) {
382392
if (gsfm.ignoreZValue.explicit()) {
383393
this.ignoreZValue = gsfm.ignoreZValue;
384394
}
395+
if (gsfm.docValues.explicit()) {
396+
this.docValues = gsfm.docValues;
397+
}
385398
}
386399

387400
@Override
@@ -405,6 +418,9 @@ public void doXContentBody(XContentBuilder builder, boolean includeDefaults, Par
405418
if (includeDefaults || ignoreZValue.explicit()) {
406419
builder.field(GeoPointFieldMapper.Names.IGNORE_Z_VALUE.getPreferredName(), ignoreZValue.value());
407420
}
421+
if (includeDefaults || docValues.explicit()) {
422+
builder.field(TypeParsers.DOC_VALUES, docValues.value());
423+
}
408424
}
409425

410426
public Explicit<Boolean> coerce() {
@@ -419,6 +435,10 @@ public Explicit<Boolean> ignoreZValue() {
419435
return ignoreZValue;
420436
}
421437

438+
public Explicit<Boolean> docValues() {
439+
return docValues;
440+
}
441+
422442
public Orientation orientation() {
423443
return ((AbstractGeometryFieldType)fieldType).orientation();
424444
}

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

+14-3
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,25 @@ public Builder(String name) {
6767
public GeoShapeFieldMapper build(BuilderContext context) {
6868
setupFieldType(context);
6969
return new GeoShapeFieldMapper(name, fieldType, defaultFieldType, ignoreMalformed(context), coerce(context),
70-
ignoreZValue(), context.indexSettings(), multiFieldsBuilder.build(this, context), copyTo);
70+
ignoreZValue(), docValues(), context.indexSettings(),
71+
multiFieldsBuilder.build(this, context), copyTo);
7172
}
7273

7374
@Override
7475
public boolean defaultDocValues(Version indexCreated) {
7576
return Version.CURRENT.onOrBefore(indexCreated);
7677
}
7778

79+
@Override
80+
protected Explicit<Boolean> docValues() {
81+
if (docValuesSet && fieldType.hasDocValues()) {
82+
return new Explicit<>(true, true);
83+
} else if (docValuesSet) {
84+
return new Explicit<>(false, true);
85+
}
86+
return new Explicit<>(fieldType.hasDocValues(), false);
87+
}
88+
7889
@Override
7990
protected void setupFieldType(BuilderContext context) {
8091
super.setupFieldType(context);
@@ -132,9 +143,9 @@ public String typeName() {
132143

133144
public GeoShapeFieldMapper(String simpleName, MappedFieldType fieldType, MappedFieldType defaultFieldType,
134145
Explicit<Boolean> ignoreMalformed, Explicit<Boolean> coerce,
135-
Explicit<Boolean> ignoreZValue, Settings indexSettings,
146+
Explicit<Boolean> ignoreZValue, Explicit<Boolean> docValues, Settings indexSettings,
136147
MultiFields multiFields, CopyTo copyTo) {
137-
super(simpleName, fieldType, defaultFieldType, ignoreMalformed, coerce, ignoreZValue, indexSettings,
148+
super(simpleName, fieldType, defaultFieldType, ignoreMalformed, coerce, ignoreZValue, docValues, indexSettings,
138149
multiFields, copyTo);
139150
}
140151

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

+15-4
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,16 @@ public GeoShapeFieldType fieldType() {
197197
return (GeoShapeFieldType)fieldType;
198198
}
199199

200+
public Builder docValues(boolean hasDocValues) {
201+
super.docValues(hasDocValues);
202+
if (hasDocValues) {
203+
throw new ElasticsearchParseException("geo_shape field [" + name
204+
+ "] indexed using prefix-trees do not support doc_values");
205+
}
206+
// doc-values already set to `false`
207+
return this;
208+
}
209+
200210
private void setupFieldTypeDeprecatedParameters(BuilderContext context) {
201211
GeoShapeFieldType ft = fieldType();
202212
if (deprecatedParameters.strategy != null) {
@@ -294,7 +304,7 @@ public LegacyGeoShapeFieldMapper build(BuilderContext context) {
294304
setupFieldType(context);
295305

296306
return new LegacyGeoShapeFieldMapper(name, fieldType, defaultFieldType, ignoreMalformed(context),
297-
coerce(context), orientation(), ignoreZValue(), context.indexSettings(),
307+
coerce(context), orientation(), ignoreZValue(), docValues(), context.indexSettings(),
298308
multiFieldsBuilder.build(this, context), copyTo);
299309
}
300310
}
@@ -320,6 +330,7 @@ public GeoShapeFieldType() {
320330
setStored(false);
321331
setStoreTermVectors(false);
322332
setOmitNorms(true);
333+
setHasDocValues(false);
323334
}
324335

325336
protected GeoShapeFieldType(GeoShapeFieldType ref) {
@@ -472,10 +483,10 @@ public PrefixTreeStrategy resolvePrefixTreeStrategy(String strategyName) {
472483

473484
public LegacyGeoShapeFieldMapper(String simpleName, MappedFieldType fieldType, MappedFieldType defaultFieldType,
474485
Explicit<Boolean> ignoreMalformed, Explicit<Boolean> coerce, Explicit<Orientation> orientation,
475-
Explicit<Boolean> ignoreZValue, Settings indexSettings,
486+
Explicit<Boolean> ignoreZValue, Explicit<Boolean> docValues, Settings indexSettings,
476487
MultiFields multiFields, CopyTo copyTo) {
477-
super(simpleName, fieldType, defaultFieldType, ignoreMalformed, coerce, ignoreZValue, indexSettings,
478-
multiFields, copyTo);
488+
super(simpleName, fieldType, defaultFieldType, ignoreMalformed, coerce, ignoreZValue, docValues,
489+
indexSettings, multiFields, copyTo);
479490
}
480491

481492
@Override

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

+59-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ public void testDefaultConfiguration() throws IOException {
6060
GeoShapeFieldMapper geoShapeFieldMapper = (GeoShapeFieldMapper) fieldMapper;
6161
assertThat(geoShapeFieldMapper.fieldType().orientation(),
6262
equalTo(GeoShapeFieldMapper.Defaults.ORIENTATION.value()));
63-
assertTrue(geoShapeFieldMapper.fieldType.hasDocValues());
63+
assertFalse(geoShapeFieldMapper.docValues().explicit());
64+
assertTrue(geoShapeFieldMapper.docValues().value());
65+
assertTrue(geoShapeFieldMapper.fieldType().hasDocValues());
6466
}
6567

6668
/**
@@ -214,6 +216,45 @@ public void testIgnoreMalformedParsing() throws IOException {
214216
assertThat(ignoreMalformed.value(), equalTo(false));
215217
}
216218

219+
/**
220+
* Test that doc_values parameter correctly parses
221+
*/
222+
public void testDocValues() throws IOException {
223+
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type1")
224+
.startObject("properties").startObject("location")
225+
.field("type", "geo_shape")
226+
.field("doc_values", true)
227+
.endObject().endObject()
228+
.endObject().endObject());
229+
230+
DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser()
231+
.parse("type1", new CompressedXContent(mapping));
232+
Mapper fieldMapper = defaultMapper.mappers().getMapper("location");
233+
assertThat(fieldMapper, instanceOf(GeoShapeFieldMapper.class));
234+
235+
assertTrue(((GeoShapeFieldMapper)fieldMapper).docValues().explicit());
236+
assertTrue(((GeoShapeFieldMapper)fieldMapper).docValues().value());
237+
boolean hasDocValues = ((GeoShapeFieldMapper)fieldMapper).fieldType().hasDocValues();
238+
assertTrue(hasDocValues);
239+
240+
// explicit false doc_values
241+
mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type1")
242+
.startObject("properties").startObject("location")
243+
.field("type", "geo_shape")
244+
.field("doc_values", "false")
245+
.endObject().endObject()
246+
.endObject().endObject());
247+
248+
defaultMapper = createIndex("test2").mapperService().documentMapperParser()
249+
.parse("type1", new CompressedXContent(mapping));
250+
fieldMapper = defaultMapper.mappers().getMapper("location");
251+
assertThat(fieldMapper, instanceOf(GeoShapeFieldMapper.class));
252+
253+
assertTrue(((GeoShapeFieldMapper)fieldMapper).docValues().explicit());
254+
assertFalse(((GeoShapeFieldMapper)fieldMapper).docValues().value());
255+
hasDocValues = ((GeoShapeFieldMapper)fieldMapper).fieldType().hasDocValues();
256+
assertFalse(hasDocValues);
257+
}
217258

218259
private void assertFieldWarnings(String... fieldNames) {
219260
String[] warnings = new String[fieldNames.length];
@@ -283,9 +324,26 @@ public void testSerializeDefaults() throws Exception {
283324
String serialized = toXContentString((GeoShapeFieldMapper) defaultMapper.mappers().getMapper("location"));
284325
assertTrue(serialized, serialized.contains("\"orientation\":\"" +
285326
AbstractGeometryFieldMapper.Defaults.ORIENTATION.value() + "\""));
327+
assertTrue(serialized, serialized.contains("\"doc_values\":true"));
286328
}
287329
}
288330

331+
public void testSerializeDocValues() throws IOException {
332+
boolean docValues = randomBoolean();
333+
DocumentMapperParser parser = createIndex("test").mapperService().documentMapperParser();
334+
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type1")
335+
.startObject("properties").startObject("location")
336+
.field("type", "geo_shape")
337+
.field("doc_values", docValues)
338+
.endObject().endObject()
339+
.endObject().endObject());
340+
DocumentMapper mapper = parser.parse("type1", new CompressedXContent(mapping));
341+
String serialized = toXContentString((GeoShapeFieldMapper) mapper.mappers().getMapper("location"));
342+
assertTrue(serialized, serialized.contains("\"orientation\":\"" +
343+
AbstractGeometryFieldMapper.Defaults.ORIENTATION.value() + "\""));
344+
assertTrue(serialized, serialized.contains("\"doc_values\":" + docValues));
345+
}
346+
289347
public String toXContentString(GeoShapeFieldMapper mapper, boolean includeDefaults) throws IOException {
290348
XContentBuilder builder = XContentFactory.jsonBuilder().startObject();
291349
ToXContent.Params params;

0 commit comments

Comments
 (0)