From 77f9bb62254c2ab7bb9524ec2fb287ff7e794c34 Mon Sep 17 00:00:00 2001 From: Tal Levy Date: Mon, 24 Feb 2020 09:58:53 -0800 Subject: [PATCH] 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 --- .../mapping/types/geo-shape.asciidoc | 5 ++ .../mapper/AbstractGeometryFieldMapper.java | 40 +++++++++--- .../index/mapper/GeoShapeFieldMapper.java | 17 ++++- .../mapper/LegacyGeoShapeFieldMapper.java | 19 ++++-- .../mapper/GeoShapeFieldMapperTests.java | 60 ++++++++++++++++- .../LegacyGeoShapeFieldMapperTests.java | 64 +++++++++++++++++++ .../index/mapper/ShapeFieldMapper.java | 16 ++++- .../index/mapper/ShapeFieldMapperTests.java | 54 ++++++++++++++++ 8 files changed, 254 insertions(+), 21 deletions(-) diff --git a/docs/reference/mapping/types/geo-shape.asciidoc b/docs/reference/mapping/types/geo-shape.asciidoc index 274970e0668a0..7e2c0241d7d16 100644 --- a/docs/reference/mapping/types/geo-shape.asciidoc +++ b/docs/reference/mapping/types/geo-shape.asciidoc @@ -114,6 +114,11 @@ and reject the whole document. |`coerce` |If `true` unclosed linear rings in polygons will be automatically closed. | `false` +|`doc_values` |Should the field be stored on disk in a column-stride fashion, so that it + can later be used for sorting, aggregations, or scripting? Accepts `true` + (default) or `false`. +| `true` for BKD-backed geo_shape, `false` for prefix tree indexing strategy + |======================================================================= diff --git a/server/src/main/java/org/elasticsearch/index/mapper/AbstractGeometryFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/AbstractGeometryFieldMapper.java index 80eeeab3f0850..c41f0fd3549f3 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/AbstractGeometryFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/AbstractGeometryFieldMapper.java @@ -70,6 +70,7 @@ public static class Defaults { public static final Explicit COERCE = new Explicit<>(false, false); public static final Explicit IGNORE_MALFORMED = new Explicit<>(false, false); public static final Explicit IGNORE_Z_VALUE = new Explicit<>(true, false); + public static final Explicit DOC_VALUES = new Explicit<>(false, false); } @@ -122,15 +123,6 @@ public Builder(String name, MappedFieldType fieldType, MappedFieldType defaultFi super(name, fieldType, defaultFieldType); } - public Builder(String name, MappedFieldType fieldType, MappedFieldType defaultFieldType, - boolean coerce, boolean ignoreMalformed, Orientation orientation, boolean ignoreZ) { - super(name, fieldType, defaultFieldType); - this.coerce = coerce; - this.ignoreMalformed = ignoreMalformed; - this.orientation = orientation; - this.ignoreZValue = ignoreZ; - } - public Builder coerce(boolean coerce) { this.coerce = coerce; return this; @@ -190,6 +182,15 @@ public Builder ignoreZValue(final boolean ignoreZValue) { return this; } + protected Explicit docValues() { + if (docValuesSet && fieldType.hasDocValues()) { + return new Explicit<>(true, true); + } else if (docValuesSet) { + return new Explicit<>(false, true); + } + return Defaults.DOC_VALUES; + } + @Override protected void setupFieldType(BuilderContext context) { super.setupFieldType(context); @@ -251,6 +252,9 @@ public Mapper.Builder parse(String name, Map node, ParserContext XContentMapValues.nodeBooleanValue(fieldNode, name + "." + GeoPointFieldMapper.Names.IGNORE_Z_VALUE.getPreferredName())); iterator.remove(); + } else if (TypeParsers.DOC_VALUES.equals(fieldName)) { + params.put(TypeParsers.DOC_VALUES, XContentMapValues.nodeBooleanValue(fieldNode, name + "." + TypeParsers.DOC_VALUES)); + iterator.remove(); } } if (parserContext.indexVersionCreated().onOrAfter(Version.V_6_6_0) && parsedDeprecatedParameters == false) { @@ -258,6 +262,10 @@ public Mapper.Builder parse(String name, Map node, ParserContext } Builder builder = newBuilder(name, params); + if (params.containsKey(TypeParsers.DOC_VALUES)) { + builder.docValues((Boolean) params.get(TypeParsers.DOC_VALUES)); + } + if (params.containsKey(Names.COERCE.getPreferredName())) { builder.coerce((Boolean)params.get(Names.COERCE.getPreferredName())); } @@ -358,15 +366,17 @@ public QueryProcessor geometryQueryBuilder() { protected Explicit coerce; protected Explicit ignoreMalformed; protected Explicit ignoreZValue; + protected Explicit docValues; protected AbstractGeometryFieldMapper(String simpleName, MappedFieldType fieldType, MappedFieldType defaultFieldType, Explicit ignoreMalformed, Explicit coerce, - Explicit ignoreZValue, Settings indexSettings, + Explicit ignoreZValue, Explicit docValues, Settings indexSettings, MultiFields multiFields, CopyTo copyTo) { super(simpleName, fieldType, defaultFieldType, indexSettings, multiFields, copyTo); this.coerce = coerce; this.ignoreMalformed = ignoreMalformed; this.ignoreZValue = ignoreZValue; + this.docValues = docValues; } @Override @@ -382,6 +392,9 @@ protected void doMerge(Mapper mergeWith) { if (gsfm.ignoreZValue.explicit()) { this.ignoreZValue = gsfm.ignoreZValue; } + if (gsfm.docValues.explicit()) { + this.docValues = gsfm.docValues; + } } @Override @@ -405,6 +418,9 @@ public void doXContentBody(XContentBuilder builder, boolean includeDefaults, Par if (includeDefaults || ignoreZValue.explicit()) { builder.field(GeoPointFieldMapper.Names.IGNORE_Z_VALUE.getPreferredName(), ignoreZValue.value()); } + if (includeDefaults || docValues.explicit()) { + builder.field(TypeParsers.DOC_VALUES, docValues.value()); + } } public Explicit coerce() { @@ -419,6 +435,10 @@ public Explicit ignoreZValue() { return ignoreZValue; } + public Explicit docValues() { + return docValues; + } + public Orientation orientation() { return ((AbstractGeometryFieldType)fieldType).orientation(); } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/GeoShapeFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/GeoShapeFieldMapper.java index 36e24612044fb..fc1a697e30206 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/GeoShapeFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/GeoShapeFieldMapper.java @@ -67,7 +67,8 @@ public Builder(String name) { public GeoShapeFieldMapper build(BuilderContext context) { setupFieldType(context); return new GeoShapeFieldMapper(name, fieldType, defaultFieldType, ignoreMalformed(context), coerce(context), - ignoreZValue(), context.indexSettings(), multiFieldsBuilder.build(this, context), copyTo); + ignoreZValue(), docValues(), context.indexSettings(), + multiFieldsBuilder.build(this, context), copyTo); } @Override @@ -75,6 +76,16 @@ public boolean defaultDocValues(Version indexCreated) { return Version.CURRENT.onOrBefore(indexCreated); } + @Override + protected Explicit docValues() { + if (docValuesSet && fieldType.hasDocValues()) { + return new Explicit<>(true, true); + } else if (docValuesSet) { + return new Explicit<>(false, true); + } + return new Explicit<>(fieldType.hasDocValues(), false); + } + @Override protected void setupFieldType(BuilderContext context) { super.setupFieldType(context); @@ -132,9 +143,9 @@ public String typeName() { public GeoShapeFieldMapper(String simpleName, MappedFieldType fieldType, MappedFieldType defaultFieldType, Explicit ignoreMalformed, Explicit coerce, - Explicit ignoreZValue, Settings indexSettings, + Explicit ignoreZValue, Explicit docValues, Settings indexSettings, MultiFields multiFields, CopyTo copyTo) { - super(simpleName, fieldType, defaultFieldType, ignoreMalformed, coerce, ignoreZValue, indexSettings, + super(simpleName, fieldType, defaultFieldType, ignoreMalformed, coerce, ignoreZValue, docValues, indexSettings, multiFields, copyTo); } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/LegacyGeoShapeFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/LegacyGeoShapeFieldMapper.java index 907a7b2e901b3..e1ce6e32e159c 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/LegacyGeoShapeFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/LegacyGeoShapeFieldMapper.java @@ -197,6 +197,16 @@ public GeoShapeFieldType fieldType() { return (GeoShapeFieldType)fieldType; } + public Builder docValues(boolean hasDocValues) { + super.docValues(hasDocValues); + if (hasDocValues) { + throw new ElasticsearchParseException("geo_shape field [" + name + + "] indexed using prefix-trees do not support doc_values"); + } + // doc-values already set to `false` + return this; + } + private void setupFieldTypeDeprecatedParameters(BuilderContext context) { GeoShapeFieldType ft = fieldType(); if (deprecatedParameters.strategy != null) { @@ -294,7 +304,7 @@ public LegacyGeoShapeFieldMapper build(BuilderContext context) { setupFieldType(context); return new LegacyGeoShapeFieldMapper(name, fieldType, defaultFieldType, ignoreMalformed(context), - coerce(context), orientation(), ignoreZValue(), context.indexSettings(), + coerce(context), orientation(), ignoreZValue(), docValues(), context.indexSettings(), multiFieldsBuilder.build(this, context), copyTo); } } @@ -320,6 +330,7 @@ public GeoShapeFieldType() { setStored(false); setStoreTermVectors(false); setOmitNorms(true); + setHasDocValues(false); } protected GeoShapeFieldType(GeoShapeFieldType ref) { @@ -472,10 +483,10 @@ public PrefixTreeStrategy resolvePrefixTreeStrategy(String strategyName) { public LegacyGeoShapeFieldMapper(String simpleName, MappedFieldType fieldType, MappedFieldType defaultFieldType, Explicit ignoreMalformed, Explicit coerce, Explicit orientation, - Explicit ignoreZValue, Settings indexSettings, + Explicit ignoreZValue, Explicit docValues, Settings indexSettings, MultiFields multiFields, CopyTo copyTo) { - super(simpleName, fieldType, defaultFieldType, ignoreMalformed, coerce, ignoreZValue, indexSettings, - multiFields, copyTo); + super(simpleName, fieldType, defaultFieldType, ignoreMalformed, coerce, ignoreZValue, docValues, + indexSettings, multiFields, copyTo); } @Override diff --git a/server/src/test/java/org/elasticsearch/index/mapper/GeoShapeFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/GeoShapeFieldMapperTests.java index 280668c1c6dbc..a2c20762097b2 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/GeoShapeFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/GeoShapeFieldMapperTests.java @@ -60,7 +60,9 @@ public void testDefaultConfiguration() throws IOException { GeoShapeFieldMapper geoShapeFieldMapper = (GeoShapeFieldMapper) fieldMapper; assertThat(geoShapeFieldMapper.fieldType().orientation(), equalTo(GeoShapeFieldMapper.Defaults.ORIENTATION.value())); - assertTrue(geoShapeFieldMapper.fieldType.hasDocValues()); + assertFalse(geoShapeFieldMapper.docValues().explicit()); + assertTrue(geoShapeFieldMapper.docValues().value()); + assertTrue(geoShapeFieldMapper.fieldType().hasDocValues()); } /** @@ -214,6 +216,45 @@ public void testIgnoreMalformedParsing() throws IOException { assertThat(ignoreMalformed.value(), equalTo(false)); } + /** + * Test that doc_values parameter correctly parses + */ + public void testDocValues() throws IOException { + String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type1") + .startObject("properties").startObject("location") + .field("type", "geo_shape") + .field("doc_values", true) + .endObject().endObject() + .endObject().endObject()); + + DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser() + .parse("type1", new CompressedXContent(mapping)); + Mapper fieldMapper = defaultMapper.mappers().getMapper("location"); + assertThat(fieldMapper, instanceOf(GeoShapeFieldMapper.class)); + + assertTrue(((GeoShapeFieldMapper)fieldMapper).docValues().explicit()); + assertTrue(((GeoShapeFieldMapper)fieldMapper).docValues().value()); + boolean hasDocValues = ((GeoShapeFieldMapper)fieldMapper).fieldType().hasDocValues(); + assertTrue(hasDocValues); + + // explicit false doc_values + mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type1") + .startObject("properties").startObject("location") + .field("type", "geo_shape") + .field("doc_values", "false") + .endObject().endObject() + .endObject().endObject()); + + defaultMapper = createIndex("test2").mapperService().documentMapperParser() + .parse("type1", new CompressedXContent(mapping)); + fieldMapper = defaultMapper.mappers().getMapper("location"); + assertThat(fieldMapper, instanceOf(GeoShapeFieldMapper.class)); + + assertTrue(((GeoShapeFieldMapper)fieldMapper).docValues().explicit()); + assertFalse(((GeoShapeFieldMapper)fieldMapper).docValues().value()); + hasDocValues = ((GeoShapeFieldMapper)fieldMapper).fieldType().hasDocValues(); + assertFalse(hasDocValues); + } private void assertFieldWarnings(String... fieldNames) { String[] warnings = new String[fieldNames.length]; @@ -283,9 +324,26 @@ public void testSerializeDefaults() throws Exception { String serialized = toXContentString((GeoShapeFieldMapper) defaultMapper.mappers().getMapper("location")); assertTrue(serialized, serialized.contains("\"orientation\":\"" + AbstractGeometryFieldMapper.Defaults.ORIENTATION.value() + "\"")); + assertTrue(serialized, serialized.contains("\"doc_values\":true")); } } + public void testSerializeDocValues() throws IOException { + boolean docValues = randomBoolean(); + DocumentMapperParser parser = createIndex("test").mapperService().documentMapperParser(); + String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type1") + .startObject("properties").startObject("location") + .field("type", "geo_shape") + .field("doc_values", docValues) + .endObject().endObject() + .endObject().endObject()); + DocumentMapper mapper = parser.parse("type1", new CompressedXContent(mapping)); + String serialized = toXContentString((GeoShapeFieldMapper) mapper.mappers().getMapper("location")); + assertTrue(serialized, serialized.contains("\"orientation\":\"" + + AbstractGeometryFieldMapper.Defaults.ORIENTATION.value() + "\"")); + assertTrue(serialized, serialized.contains("\"doc_values\":" + docValues)); + } + public String toXContentString(GeoShapeFieldMapper mapper, boolean includeDefaults) throws IOException { XContentBuilder builder = XContentFactory.jsonBuilder().startObject(); ToXContent.Params params; diff --git a/server/src/test/java/org/elasticsearch/index/mapper/LegacyGeoShapeFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/LegacyGeoShapeFieldMapperTests.java index aaabf3f9edbf0..2b17ba8a55fa8 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/LegacyGeoShapeFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/LegacyGeoShapeFieldMapperTests.java @@ -83,6 +83,10 @@ public void testDefaultConfiguration() throws IOException { equalTo(LegacyGeoShapeFieldMapper.DeprecatedParameters.Defaults.DISTANCE_ERROR_PCT)); assertThat(geoShapeFieldMapper.fieldType().orientation(), equalTo(LegacyGeoShapeFieldMapper.Defaults.ORIENTATION.value())); + assertThat(geoShapeFieldMapper.docValues(), + equalTo(LegacyGeoShapeFieldMapper.Defaults.DOC_VALUES)); + assertThat(geoShapeFieldMapper.fieldType().hasDocValues(), + equalTo(LegacyGeoShapeFieldMapper.Defaults.DOC_VALUES.value())); assertFieldWarnings("strategy"); } @@ -598,6 +602,7 @@ public void testSerializeDefaults() throws Exception { String serialized = toXContentString((LegacyGeoShapeFieldMapper) defaultMapper.mappers().getMapper("location")); assertTrue(serialized, serialized.contains("\"precision\":\"50.0m\"")); assertTrue(serialized, serialized.contains("\"tree_levels\":21")); + assertTrue(serialized, serialized.contains("\"doc_values\":false")); } { String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type1") @@ -610,6 +615,7 @@ public void testSerializeDefaults() throws Exception { String serialized = toXContentString((LegacyGeoShapeFieldMapper) defaultMapper.mappers().getMapper("location")); assertTrue(serialized, serialized.contains("\"precision\":\"50.0m\"")); assertTrue(serialized, serialized.contains("\"tree_levels\":9")); + assertTrue(serialized, serialized.contains("\"doc_values\":false")); } { String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type1") @@ -623,6 +629,7 @@ public void testSerializeDefaults() throws Exception { String serialized = toXContentString((LegacyGeoShapeFieldMapper) defaultMapper.mappers().getMapper("location")); assertFalse(serialized, serialized.contains("\"precision\":")); assertTrue(serialized, serialized.contains("\"tree_levels\":6")); + assertTrue(serialized, serialized.contains("\"doc_values\":false")); } { String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type1") @@ -636,6 +643,7 @@ public void testSerializeDefaults() throws Exception { String serialized = toXContentString((LegacyGeoShapeFieldMapper) defaultMapper.mappers().getMapper("location")); assertTrue(serialized, serialized.contains("\"precision\":\"6.0m\"")); assertFalse(serialized, serialized.contains("\"tree_levels\":")); + assertTrue(serialized, serialized.contains("\"doc_values\":false")); } { String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type1") @@ -650,10 +658,29 @@ public void testSerializeDefaults() throws Exception { String serialized = toXContentString((LegacyGeoShapeFieldMapper) defaultMapper.mappers().getMapper("location")); assertTrue(serialized, serialized.contains("\"precision\":\"6.0m\"")); assertTrue(serialized, serialized.contains("\"tree_levels\":5")); + assertTrue(serialized, serialized.contains("\"doc_values\":false")); } assertFieldWarnings("tree", "tree_levels", "precision"); } + public void testSerializeDocValues() throws IOException { + DocumentMapperParser parser = createIndex("test").mapperService().documentMapperParser(); + String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type1") + .startObject("properties").startObject("location") + .field("type", "geo_shape") + .field("tree", "quadtree") + .field("doc_values", false) + .endObject().endObject() + .endObject().endObject()); + DocumentMapper mapper = parser.parse("type1", new CompressedXContent(mapping)); + String serialized = toXContentString((LegacyGeoShapeFieldMapper) mapper.mappers().getMapper("location")); + assertTrue(serialized, serialized.contains("\"orientation\":\"" + + AbstractGeometryFieldMapper.Defaults.ORIENTATION.value() + "\"")); + assertTrue(serialized, serialized.contains("\"doc_values\":false")); + + assertFieldWarnings("tree"); + } + public void testPointsOnlyDefaultsWithTermStrategy() throws IOException { String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type1") .startObject("properties").startObject("location") @@ -702,6 +729,43 @@ public void testPointsOnlyFalseWithTermStrategy() throws Exception { assertFieldWarnings("tree", "precision", "strategy", "points_only"); } + /** + * Test that doc_values parameter correctly parses + */ + public void testDocValues() throws IOException { + String trueMapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type1") + .startObject("properties").startObject("location") + .field("type", "geo_shape") + .field("tree", "quadtree") + .field("doc_values", true) + .endObject().endObject() + .endObject().endObject()); + + ElasticsearchParseException e = expectThrows(ElasticsearchParseException.class, + () -> createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(trueMapping))); + assertThat(e.getMessage(), equalTo("geo_shape field [location] indexed using prefix-trees do not support doc_values")); + + // explicit false doc_values + String falseMapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type1") + .startObject("properties").startObject("location") + .field("type", "geo_shape") + .field("tree", "quadtree") + .field("doc_values", "false") + .endObject().endObject() + .endObject().endObject()); + + DocumentMapper defaultMapper = createIndex("test2").mapperService().documentMapperParser() + .parse("type1", new CompressedXContent(falseMapping)); + Mapper fieldMapper = defaultMapper.mappers().getMapper("location"); + assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class)); + + assertTrue(((LegacyGeoShapeFieldMapper) fieldMapper).docValues().explicit()); + assertFalse(((LegacyGeoShapeFieldMapper) fieldMapper).docValues().value()); + assertFalse(((LegacyGeoShapeFieldMapper) fieldMapper).fieldType().hasDocValues()); + + assertFieldWarnings("tree"); + } + public void testDisallowExpensiveQueries() throws IOException { QueryShardContext queryShardContext = mock(QueryShardContext.class); when(queryShardContext.allowExpensiveQueries()).thenReturn(false); diff --git a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/ShapeFieldMapper.java b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/ShapeFieldMapper.java index 472caa6e8ed86..7768e3ed0804a 100644 --- a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/ShapeFieldMapper.java +++ b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/ShapeFieldMapper.java @@ -6,6 +6,7 @@ package org.elasticsearch.xpack.spatial.index.mapper; import org.apache.lucene.document.XYShape; +import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.common.Explicit; import org.elasticsearch.common.geo.GeometryParser; import org.elasticsearch.common.geo.builders.ShapeBuilder; @@ -53,7 +54,16 @@ public Builder(String name) { public ShapeFieldMapper build(BuilderContext context) { setupFieldType(context); return new ShapeFieldMapper(name, fieldType, defaultFieldType, ignoreMalformed(context), coerce(context), - ignoreZValue(), context.indexSettings(), multiFieldsBuilder.build(this, context), copyTo); + ignoreZValue(), docValues(), context.indexSettings(), multiFieldsBuilder.build(this, context), copyTo); + } + + public ShapeFieldMapper.Builder docValues(boolean hasDocValues) { + super.docValues(hasDocValues); + if (hasDocValues) { + throw new ElasticsearchParseException("field [" + name + "] of type [" + fieldType().typeName() + + "] does not support doc-values"); + } + return this; } @Override @@ -116,9 +126,9 @@ protected Indexer geometryIndexer() { public ShapeFieldMapper(String simpleName, MappedFieldType fieldType, MappedFieldType defaultFieldType, Explicit ignoreMalformed, Explicit coerce, - Explicit ignoreZValue, Settings indexSettings, + Explicit ignoreZValue, Explicit docValues, Settings indexSettings, MultiFields multiFields, CopyTo copyTo) { - super(simpleName, fieldType, defaultFieldType, ignoreMalformed, coerce, ignoreZValue, indexSettings, + super(simpleName, fieldType, defaultFieldType, ignoreMalformed, coerce, ignoreZValue, docValues, indexSettings, multiFields, copyTo); } diff --git a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/ShapeFieldMapperTests.java b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/ShapeFieldMapperTests.java index 809f9d621395e..d8012a6ea2f42 100644 --- a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/ShapeFieldMapperTests.java +++ b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/ShapeFieldMapperTests.java @@ -5,6 +5,7 @@ */ package org.elasticsearch.xpack.spatial.index.mapper; +import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.common.Explicit; import org.elasticsearch.common.Strings; import org.elasticsearch.common.compress.CompressedXContent; @@ -54,6 +55,9 @@ public void testDefaultConfiguration() throws IOException { ShapeFieldMapper shapeFieldMapper = (ShapeFieldMapper) fieldMapper; assertThat(shapeFieldMapper.fieldType().orientation(), equalTo(ShapeFieldMapper.Defaults.ORIENTATION.value())); + assertFalse(shapeFieldMapper.docValues().value()); + assertFalse(shapeFieldMapper.docValues().explicit()); + assertFalse(shapeFieldMapper.fieldType().hasDocValues()); } /** @@ -96,6 +100,40 @@ public void testOrientationParsing() throws IOException { assertThat(orientation, equalTo(ShapeBuilder.Orientation.CCW)); } + /** + * Test that doc_values parameter correctly parses + */ + public void testDocValues() throws IOException { + String trueMapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type1") + .startObject("properties").startObject("location") + .field("type", "shape") + .field("doc_values", true) + .endObject().endObject() + .endObject().endObject()); + + ElasticsearchParseException e = expectThrows(ElasticsearchParseException.class, + () -> createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(trueMapping))); + assertThat(e.getMessage(), equalTo("field [location] of type [shape] does not support doc-values")); + + // explicit false doc_values + String falseMapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type1") + .startObject("properties").startObject("location") + .field("type", "shape") + .field("doc_values", false) + .endObject().endObject() + .endObject().endObject()); + + DocumentMapper defaultMapper = createIndex("test2").mapperService().documentMapperParser() + .parse("type1", new CompressedXContent(falseMapping)); + Mapper fieldMapper = defaultMapper.mappers().getMapper("location"); + assertThat(fieldMapper, instanceOf(ShapeFieldMapper.class)); + + // since shape field has no doc-values, this field is ignored + assertTrue(((ShapeFieldMapper)fieldMapper).docValues().explicit()); + assertFalse(((ShapeFieldMapper)fieldMapper).docValues().value()); + assertFalse(((ShapeFieldMapper)fieldMapper).fieldType().hasDocValues()); + } + /** * Test that coerce parameter correctly parses */ @@ -276,9 +314,25 @@ public void testSerializeDefaults() throws Exception { String serialized = toXContentString((ShapeFieldMapper) defaultMapper.mappers().getMapper("location")); assertTrue(serialized, serialized.contains("\"orientation\":\"" + AbstractGeometryFieldMapper.Defaults.ORIENTATION.value() + "\"")); + assertTrue(serialized, serialized.contains("\"doc_values\":false")); } } + public void testSerializeDocValues() throws IOException { + DocumentMapperParser parser = createIndex("test").mapperService().documentMapperParser(); + String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type1") + .startObject("properties").startObject("location") + .field("type", "shape") + .field("doc_values", false) + .endObject().endObject() + .endObject().endObject()); + DocumentMapper mapper = parser.parse("type1", new CompressedXContent(mapping)); + String serialized = toXContentString((ShapeFieldMapper) mapper.mappers().getMapper("location")); + assertTrue(serialized, serialized.contains("\"orientation\":\"" + + AbstractGeometryFieldMapper.Defaults.ORIENTATION.value() + "\"")); + assertTrue(serialized, serialized.contains("\"doc_values\":false")); + } + public String toXContentString(ShapeFieldMapper mapper, boolean includeDefaults) throws IOException { XContentBuilder builder = XContentFactory.jsonBuilder().startObject(); ToXContent.Params params;