From 78978aa05d9afccc8a63b57d81ce2ef2d216668f Mon Sep 17 00:00:00 2001 From: iverase Date: Thu, 15 Jul 2021 10:58:21 +0200 Subject: [PATCH 1/9] Add 'mvt' field type format to geo fields --- .../common/geo/GeoFormatterFactory.java | 77 ++++++++++++ .../common/geo}/SimpleFeatureFactory.java | 27 ++-- .../common/geo}/SphericalMercatorUtils.java | 12 +- .../index/mapper/GeoPointFieldMapper.java | 8 +- .../geo}/SimpleFeatureFactoryTests.java | 35 +++--- .../index/mapper/GeoPointFieldTypeTests.java | 37 ++++++ x-pack/plugin/spatial/build.gradle | 1 + .../GeoShapeWithDocValuesFieldMapper.java | 16 ++- .../GeoShapeWithDocValuesFieldTypeTests.java | 119 ++++++++++++++++++ .../vectortile/feature/FeatureFactory.java | 14 ++- .../vectortile/rest/RestVectorTileAction.java | 49 ++++---- .../FeatureFactoriesConsistencyTests.java | 26 ++-- .../feature/FeatureFactoryTests.java | 75 +++++------ 13 files changed, 380 insertions(+), 116 deletions(-) create mode 100644 server/src/main/java/org/elasticsearch/common/geo/GeoFormatterFactory.java rename {x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/feature => server/src/main/java/org/elasticsearch/common/geo}/SimpleFeatureFactory.java (86%) rename {x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/feature => server/src/main/java/org/elasticsearch/common/geo}/SphericalMercatorUtils.java (76%) rename {x-pack/plugin/vector-tile/src/test/java/org/elasticsearch/xpack/vectortile/feature => server/src/test/java/org/elasticsearch/common/geo}/SimpleFeatureFactoryTests.java (84%) create mode 100644 x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java diff --git a/server/src/main/java/org/elasticsearch/common/geo/GeoFormatterFactory.java b/server/src/main/java/org/elasticsearch/common/geo/GeoFormatterFactory.java new file mode 100644 index 0000000000000..4e2251b34e150 --- /dev/null +++ b/server/src/main/java/org/elasticsearch/common/geo/GeoFormatterFactory.java @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.common.geo; + +import org.elasticsearch.geometry.Geometry; +import org.elasticsearch.search.aggregations.bucket.geogrid.GeoTileUtils; + +import java.util.List; +import java.util.Locale; +import java.util.function.Function; + +/** + * Output formatters for geo fields. Adds support for vector tiles. + */ +public class GeoFormatterFactory { + + @FunctionalInterface + public interface VectorTileEngine { + /** + * Returns a formatter for a specific tile. + */ + Function, List> getFormatter(int z, int x, int y, int extent); + } + + private static final String MVT = "mvt"; + + /** + * Returns a formatter by name + */ + public static Function, List> getFormatter(String format, Function toGeometry, + VectorTileEngine mvt) { + final int start = format.indexOf('('); + if (start == -1) { + return GeometryFormatterFactory.getFormatter(format, toGeometry); + } + final String formatName = format.substring(0, start); + if (MVT.equals(formatName) == false) { + throw new IllegalArgumentException("Invalid format: " + formatName); + } + final String param = format.substring(start + 1, format.length() - 1); + // we expect either z/x/y or z/x/y@extent + final String[] parts = param.split("@", 3); + if (parts.length > 2) { + throw new IllegalArgumentException( + "Invalid mvt formatter parameter [" + param + "]. Must have the form \"zoom/x/y\" or \"zoom/x/y@extent\"." + ); + } + final int extent = parts.length == 2 ? Integer.parseInt(parts[1]) : 4096; + final String[] tileBits = parts[0].split("/", 4); + if (tileBits.length != 3) { + throw new IllegalArgumentException( + "Invalid tile string [" + parts[0] + "]. Must be three integers in a form \"zoom/x/y\"." + ); + } + final int z = GeoTileUtils.checkPrecisionRange(Integer.parseInt(tileBits[0])); + final int tiles = 1 << z; + final int x = Integer.parseInt(tileBits[1]); + final int y = Integer.parseInt(tileBits[2]); + if (x < 0 || y < 0 || x >= tiles || y >= tiles) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Zoom/X/Y combination is not valid: %d/%d/%d", z, x, y)); + } + return mvt.getFormatter(z, x, y, extent); + } +} diff --git a/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/feature/SimpleFeatureFactory.java b/server/src/main/java/org/elasticsearch/common/geo/SimpleFeatureFactory.java similarity index 86% rename from x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/feature/SimpleFeatureFactory.java rename to server/src/main/java/org/elasticsearch/common/geo/SimpleFeatureFactory.java index b797ee495ab29..a6e6b62b8dde3 100644 --- a/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/feature/SimpleFeatureFactory.java +++ b/server/src/main/java/org/elasticsearch/common/geo/SimpleFeatureFactory.java @@ -1,3 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License @@ -5,21 +13,20 @@ * 2.0. */ -package org.elasticsearch.xpack.vectortile.feature; +package org.elasticsearch.common.geo; import org.apache.lucene.util.BitUtil; import org.elasticsearch.common.io.stream.BytesStreamOutput; -import org.elasticsearch.geometry.Point; import org.elasticsearch.geometry.Rectangle; import org.elasticsearch.search.aggregations.bucket.geogrid.GeoTileUtils; import java.io.IOException; +import java.io.UncheckedIOException; import java.util.Comparator; import java.util.List; /** - * Similar to {@link FeatureFactory} but only supports points and rectangles. It is just - * more efficient for those shapes and it does not use external dependencies. + * Transforms points and rectangles objects in WGS84 into mvt features. */ public class SimpleFeatureFactory { @@ -63,12 +70,12 @@ public byte[] point(double lon, double lat) throws IOException { /** * Returns a {@code byte[]} containing the mvt representation of the provided points */ - public byte[] points(List multiPoint) throws IOException { - multiPoint.sort(Comparator.comparingDouble(Point::getLon).thenComparingDouble(Point::getLat)); + public byte[] points(List multiPoint) { + multiPoint.sort(Comparator.comparingDouble(GeoPoint::getLon).thenComparingDouble(GeoPoint::getLat)); final int[] commands = new int[2 * multiPoint.size() + 1]; int pos = 1, prevLon = 0, prevLat = 0, numPoints = 0; for (int i = 0; i < multiPoint.size(); i++) { - final Point point = multiPoint.get(i); + final GeoPoint point = multiPoint.get(i); final int posLon = lon(point.getLon()); if (posLon > extent || posLon < 0) { continue; @@ -89,7 +96,11 @@ public byte[] points(List multiPoint) throws IOException { return EMPTY; } commands[0] = encodeCommand(MOVETO, numPoints); - return writeCommands(commands, 1, pos); + try { + return writeCommands(commands, 1, pos); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } } /** diff --git a/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/feature/SphericalMercatorUtils.java b/server/src/main/java/org/elasticsearch/common/geo/SphericalMercatorUtils.java similarity index 76% rename from x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/feature/SphericalMercatorUtils.java rename to server/src/main/java/org/elasticsearch/common/geo/SphericalMercatorUtils.java index da0949582d36c..fd5d6820eb3e5 100644 --- a/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/feature/SphericalMercatorUtils.java +++ b/server/src/main/java/org/elasticsearch/common/geo/SphericalMercatorUtils.java @@ -1,3 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License @@ -5,14 +13,14 @@ * 2.0. */ -package org.elasticsearch.xpack.vectortile.feature; +package org.elasticsearch.common.geo; import org.elasticsearch.geometry.Rectangle; /** * Utility functions to transforms WGS84 coordinates into spherical mercator. */ -class SphericalMercatorUtils { +public class SphericalMercatorUtils { private static double MERCATOR_FACTOR = 20037508.34 / 180.0; diff --git a/server/src/main/java/org/elasticsearch/index/mapper/GeoPointFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/GeoPointFieldMapper.java index e53e738a6df4e..97a4ed250fdf1 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/GeoPointFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/GeoPointFieldMapper.java @@ -19,11 +19,13 @@ import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.common.CheckedBiFunction; import org.elasticsearch.common.Explicit; +import org.elasticsearch.common.geo.GeoFormatterFactory; import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.geo.GeoShapeUtils; import org.elasticsearch.common.geo.GeoUtils; import org.elasticsearch.common.geo.GeometryFormatterFactory; import org.elasticsearch.common.geo.ShapeRelation; +import org.elasticsearch.common.geo.SimpleFeatureFactory; import org.elasticsearch.common.unit.DistanceUnit; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.support.MapXContentParser; @@ -243,7 +245,11 @@ public String typeName() { @Override protected Function, List> getFormatter(String format) { - return GeometryFormatterFactory.getFormatter(format, p -> new Point(p.lon(), p.lat())); + return GeoFormatterFactory.getFormatter(format, p -> new Point(p.getLon(), p.getLat()), + (z, x, y, extent) -> { + final SimpleFeatureFactory featureFactory = new SimpleFeatureFactory(z, x, y, extent); + return points -> List.of(featureFactory.points(points)); + }); } @Override diff --git a/x-pack/plugin/vector-tile/src/test/java/org/elasticsearch/xpack/vectortile/feature/SimpleFeatureFactoryTests.java b/server/src/test/java/org/elasticsearch/common/geo/SimpleFeatureFactoryTests.java similarity index 84% rename from x-pack/plugin/vector-tile/src/test/java/org/elasticsearch/xpack/vectortile/feature/SimpleFeatureFactoryTests.java rename to server/src/test/java/org/elasticsearch/common/geo/SimpleFeatureFactoryTests.java index 1166600f5c962..73f4810566126 100644 --- a/x-pack/plugin/vector-tile/src/test/java/org/elasticsearch/xpack/vectortile/feature/SimpleFeatureFactoryTests.java +++ b/server/src/test/java/org/elasticsearch/common/geo/SimpleFeatureFactoryTests.java @@ -1,3 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License @@ -5,10 +13,9 @@ * 2.0. */ -package org.elasticsearch.xpack.vectortile.feature; +package org.elasticsearch.common.geo; import org.apache.lucene.geo.GeoTestUtil; -import org.elasticsearch.geometry.Point; import org.elasticsearch.geometry.Rectangle; import org.elasticsearch.search.aggregations.bucket.geogrid.GeoTileUtils; import org.elasticsearch.test.ESTestCase; @@ -41,7 +48,7 @@ public void testPoint() throws IOException { } @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/75358") - public void testMultiPoint() throws IOException { + public void testMultiPoint() { int z = randomIntBetween(1, 10); int x = randomIntBetween(0, (1 << z) - 1); int y = randomIntBetween(0, (1 << z) - 1); @@ -50,17 +57,17 @@ public void testMultiPoint() throws IOException { Rectangle rectangle = GeoTileUtils.toBoundingBox(x, y, z); int numPoints = randomIntBetween(2, 10); { - List points = new ArrayList<>(); + List points = new ArrayList<>(); double lat = randomValueOtherThanMany((l) -> rectangle.getMinY() > l || rectangle.getMaxY() < l, GeoTestUtil::nextLatitude); double lon = randomValueOtherThanMany((l) -> rectangle.getMinX() > l || rectangle.getMaxX() < l, GeoTestUtil::nextLongitude); - points.add(new Point(lon, lat)); + points.add(new GeoPoint(lat, lon)); for (int i = 0; i < numPoints - 1; i++) { - points.add(new Point(GeoTestUtil.nextLongitude(), GeoTestUtil.nextLatitude())); + points.add(new GeoPoint(GeoTestUtil.nextLatitude(), GeoTestUtil.nextLongitude())); } assertThat(builder.points(points).length, Matchers.greaterThan(0)); } { - List points = new ArrayList<>(); + List points = new ArrayList<>(); for (int i = 0; i < numPoints; i++) { double lat = randomValueOtherThanMany( (l) -> rectangle.getMinY() <= l && rectangle.getMaxY() >= l, @@ -70,7 +77,7 @@ public void testMultiPoint() throws IOException { (l) -> rectangle.getMinX() <= l && rectangle.getMaxX() >= l, GeoTestUtil::nextLongitude ); - points.add(new Point(lon, lat)); + points.add(new GeoPoint(lat, lon)); } assertThat(builder.points(points).length, Matchers.equalTo(0)); } @@ -85,24 +92,24 @@ public void testPointsMethodConsistency() throws IOException { Rectangle rectangle = GeoTileUtils.toBoundingBox(x, y, z); int extraPoints = randomIntBetween(1, 10); { - List points = new ArrayList<>(); + List points = new ArrayList<>(); double lat = randomValueOtherThanMany((l) -> rectangle.getMinY() > l || rectangle.getMaxY() < l, GeoTestUtil::nextLatitude); double lon = randomValueOtherThanMany((l) -> rectangle.getMinX() > l || rectangle.getMaxX() < l, GeoTestUtil::nextLongitude); - points.add(new Point(lon, lat)); + points.add(new GeoPoint(lat, lon)); assertArrayEquals(builder.points(points), builder.point(lon, lat)); for (int i = 0; i < extraPoints; i++) { - points.add(new Point(lon, lat)); + points.add(new GeoPoint(lat, lon)); } assertArrayEquals(builder.points(points), builder.point(lon, lat)); } { - List points = new ArrayList<>(); + List points = new ArrayList<>(); double lat = randomValueOtherThanMany((l) -> rectangle.getMinY() <= l && rectangle.getMaxY() >= l, GeoTestUtil::nextLatitude); double lon = randomValueOtherThanMany((l) -> rectangle.getMinX() <= l && rectangle.getMaxX() >= l, GeoTestUtil::nextLongitude); - points.add(new Point(lon, lat)); + points.add(new GeoPoint(lat, lon)); assertArrayEquals(builder.points(points), builder.point(lon, lat)); for (int i = 0; i < extraPoints; i++) { - points.add(new Point(lon, lat)); + points.add(new GeoPoint(lat, lon)); } assertArrayEquals(builder.points(points), builder.point(lon, lat)); } diff --git a/server/src/test/java/org/elasticsearch/index/mapper/GeoPointFieldTypeTests.java b/server/src/test/java/org/elasticsearch/index/mapper/GeoPointFieldTypeTests.java index cb70e66cc61f9..e414c7ca86ba7 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/GeoPointFieldTypeTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/GeoPointFieldTypeTests.java @@ -8,9 +8,14 @@ package org.elasticsearch.index.mapper; +import org.apache.lucene.geo.GeoTestUtil; +import org.elasticsearch.common.geo.GeoPoint; +import org.elasticsearch.common.geo.SimpleFeatureFactory; import org.elasticsearch.script.ScriptCompiler; +import org.hamcrest.Matchers; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -54,4 +59,36 @@ public void testFetchSourceValue() throws IOException { sourceValue = "malformed"; assertEquals(List.of(), fetchSourceValue(mapper, sourceValue, null)); } + + public void testFetchVectorTile() throws IOException { + MappedFieldType mapper + = new GeoPointFieldMapper.Builder("field", ScriptCompiler.NONE, false).build(new ContentPath()).fieldType(); + final int z = randomIntBetween(1, 10); + int x = randomIntBetween(0, (1 << z) - 1); + int y = randomIntBetween(0, (1 << z) - 1); + final SimpleFeatureFactory featureFactory; + final String mvtString; + if (randomBoolean()) { + int extent = randomIntBetween(1 << 8, 1 << 14); + mvtString = "mvt(" + z + "/" + x + "/" + y + "@" + extent + ")"; + featureFactory = new SimpleFeatureFactory(z, x, y, extent); + } else { + mvtString = "mvt(" + z + "/" + x + "/" + y + ")"; + featureFactory = new SimpleFeatureFactory(z, x, y, 4096); + } + List geoPoints = new ArrayList<>(); + List> values = new ArrayList<>(); + for (int i = 0; i < randomIntBetween(1, 10); i++) { + final double lat = GeoTestUtil.nextLatitude(); + final double lon = GeoTestUtil.nextLongitude(); + List sourceValue = fetchSourceValue(mapper, List.of(lon, lat), mvtString); + assertThat(sourceValue.size(), Matchers.equalTo(1)); + assertThat(sourceValue.get(0), Matchers.equalTo(featureFactory.point(lon, lat))); + geoPoints.add(new GeoPoint(lat, lon)); + values.add(List.of(lon, lat)); + } + List sourceValue = fetchSourceValue(mapper, values, mvtString); + assertThat(sourceValue.size(), Matchers.equalTo(1)); + assertThat(sourceValue.get(0), Matchers.equalTo(featureFactory.points(geoPoints))); + } } diff --git a/x-pack/plugin/spatial/build.gradle b/x-pack/plugin/spatial/build.gradle index 9169e7f4c41e7..242997a0ea7ae 100644 --- a/x-pack/plugin/spatial/build.gradle +++ b/x-pack/plugin/spatial/build.gradle @@ -15,6 +15,7 @@ dependencies { testImplementation(testArtifact(project(xpackModule('core')))) yamlRestTestImplementation(testArtifact(project(xpackModule('core')))) api project(path: ':modules:geo') + api project(path: xpackModule('vector-tile')) restTestConfig project(path: ':modules:geo', configuration: 'restTests') } diff --git a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapper.java b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapper.java index f1cb70725f53d..d4c8f50151b1e 100644 --- a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapper.java +++ b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapper.java @@ -15,14 +15,15 @@ import org.apache.lucene.search.Query; import org.elasticsearch.Version; import org.elasticsearch.common.Explicit; +import org.elasticsearch.common.geo.GeoFormatterFactory; import org.elasticsearch.common.geo.GeoShapeUtils; -import org.elasticsearch.common.geo.GeometryFormatterFactory; import org.elasticsearch.common.geo.GeometryParser; import org.elasticsearch.common.geo.Orientation; import org.elasticsearch.common.geo.ShapeRelation; import org.elasticsearch.common.logging.DeprecationCategory; import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.geometry.Geometry; +import org.elasticsearch.geometry.GeometryCollection; import org.elasticsearch.index.fielddata.IndexFieldData; import org.elasticsearch.index.mapper.AbstractShapeGeometryFieldMapper; import org.elasticsearch.index.mapper.ContentPath; @@ -40,6 +41,7 @@ import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.xpack.spatial.index.fielddata.plain.AbstractLatLonShapeIndexFieldData; import org.elasticsearch.xpack.spatial.search.aggregations.support.GeoShapeValuesSourceType; +import org.elasticsearch.xpack.vectortile.feature.FeatureFactory; import java.io.IOException; import java.util.Arrays; @@ -174,7 +176,17 @@ public Query geoShapeQuery(Geometry shape, String fieldName, ShapeRelation relat @Override protected Function, List> getFormatter(String format) { - return GeometryFormatterFactory.getFormatter(format, Function.identity()); + return GeoFormatterFactory.getFormatter(format, Function.identity(), + (z, x, y, extent) -> { + final FeatureFactory featureFactory = new FeatureFactory(z, x, y, extent); + return geometries -> { + if (geometries.size() == 1) { + return List.of(featureFactory.getFeature(geometries.get(0))); + } else { + return List.of(featureFactory.getFeature(new GeometryCollection<>(geometries))); + } + }; + }); } } diff --git a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java new file mode 100644 index 0000000000000..9bb3c02433919 --- /dev/null +++ b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java @@ -0,0 +1,119 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +package org.elasticsearch.xpack.spatial.index.mapper; + +import org.elasticsearch.Version; +import org.elasticsearch.geo.GeometryTestUtils; +import org.elasticsearch.geometry.Geometry; +import org.elasticsearch.geometry.utils.WellKnownText; +import org.elasticsearch.index.mapper.ContentPath; +import org.elasticsearch.index.mapper.FieldTypeTestCase; +import org.elasticsearch.index.mapper.GeoShapeFieldMapper; +import org.elasticsearch.index.mapper.MappedFieldType; +import org.elasticsearch.xpack.vectortile.feature.FeatureFactory; +import org.hamcrest.Matchers; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +public class GeoShapeWithDocValuesFieldTypeTests extends FieldTypeTestCase { + + public void testFetchSourceValue() throws IOException { + MappedFieldType mapper + = new GeoShapeFieldMapper.Builder("field", true, true).build(new ContentPath()).fieldType(); + + Map jsonLineString = Map.of("type", "LineString", "coordinates", + List.of(List.of(42.0, 27.1), List.of(30.0, 50.0))); + Map jsonPoint = Map.of("type", "Point", "coordinates", List.of(14.0, 15.0)); + Map jsonMalformed = Map.of("type", "Point", "coordinates", "foo"); + String wktLineString = "LINESTRING (42.0 27.1, 30.0 50.0)"; + String wktPoint = "POINT (14.0 15.0)"; + String wktMalformed = "POINT foo"; + + // Test a single shape in geojson format. + Object sourceValue = jsonLineString; + assertEquals(List.of(jsonLineString), fetchSourceValue(mapper, sourceValue, null)); + assertEquals(List.of(wktLineString), fetchSourceValue(mapper, sourceValue, "wkt")); + + // Test a malformed single shape in geojson format + sourceValue = jsonMalformed; + assertEquals(List.of(), fetchSourceValue(mapper, sourceValue, null)); + assertEquals(List.of(), fetchSourceValue(mapper, sourceValue, "wkt")); + + // Test a list of shapes in geojson format. + sourceValue = List.of(jsonLineString, jsonPoint); + assertEquals(List.of(jsonLineString, jsonPoint), fetchSourceValue(mapper, sourceValue, null)); + assertEquals(List.of(wktLineString, wktPoint), fetchSourceValue(mapper, sourceValue, "wkt")); + + // Test a list of shapes including one malformed in geojson format + sourceValue = List.of(jsonLineString, jsonMalformed, jsonPoint); + assertEquals(List.of(jsonLineString, jsonPoint), fetchSourceValue(mapper, sourceValue, null)); + assertEquals(List.of(wktLineString, wktPoint), fetchSourceValue(mapper, sourceValue, "wkt")); + + // Test a single shape in wkt format. + sourceValue = wktLineString; + assertEquals(List.of(jsonLineString), fetchSourceValue(mapper, sourceValue, null)); + assertEquals(List.of(wktLineString), fetchSourceValue(mapper, sourceValue, "wkt")); + + // Test a single malformed shape in wkt format + sourceValue = wktMalformed; + assertEquals(List.of(), fetchSourceValue(mapper, sourceValue, null)); + assertEquals(List.of(), fetchSourceValue(mapper, sourceValue, "wkt")); + + // Test a list of shapes in wkt format. + sourceValue = List.of(wktLineString, wktPoint); + assertEquals(List.of(jsonLineString, jsonPoint), fetchSourceValue(mapper, sourceValue, null)); + assertEquals(List.of(wktLineString, wktPoint), fetchSourceValue(mapper, sourceValue, "wkt")); + + // Test a list of shapes including one malformed in wkt format + sourceValue = List.of(wktLineString, wktMalformed, wktPoint); + assertEquals(List.of(jsonLineString, jsonPoint), fetchSourceValue(mapper, sourceValue, null)); + assertEquals(List.of(wktLineString, wktPoint), fetchSourceValue(mapper, sourceValue, "wkt")); + } + + public void testFetchVectorTile() throws IOException { + fetchVectorTile(GeometryTestUtils.randomPoint()); + fetchVectorTile(GeometryTestUtils.randomMultiPoint(false)); + fetchVectorTile(GeometryTestUtils.randomRectangle()); + fetchVectorTile(GeometryTestUtils.randomLine(false)); + fetchVectorTile(GeometryTestUtils.randomMultiLine(false)); + fetchVectorTile(GeometryTestUtils.randomPolygon(false)); + fetchVectorTile(GeometryTestUtils.randomMultiPolygon(false)); + } + + private void fetchVectorTile(Geometry geometry) throws IOException { + MappedFieldType mapper + = new GeoShapeWithDocValuesFieldMapper.Builder("field", Version.CURRENT, false, false).build(new ContentPath()).fieldType(); + final int z = randomIntBetween(1, 10); + int x = randomIntBetween(0, (1 << z) - 1); + int y = randomIntBetween(0, (1 << z) - 1); + final FeatureFactory featureFactory; + final String mvtString; + if (randomBoolean()) { + int extent = randomIntBetween(1 << 8, 1 << 14); + mvtString = "mvt(" + z + "/" + x + "/" + y + "@" + extent + ")"; + featureFactory = new FeatureFactory(z, x, y, extent); + } else { + mvtString = "mvt(" + z + "/" + x + "/" + y + ")"; + featureFactory = new FeatureFactory(z, x, y, 4096); + } + + List sourceValue = fetchSourceValue(mapper, WellKnownText.toWKT(geometry), mvtString); + assertThat(sourceValue.size(), Matchers.equalTo(1)); + assertThat(sourceValue.get(0), Matchers.equalTo(featureFactory.getFeature(geometry))); + } +} diff --git a/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactory.java b/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactory.java index 570e8f5b1c1cd..4e0275c29de90 100644 --- a/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactory.java +++ b/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactory.java @@ -12,9 +12,11 @@ import com.wdtinc.mapbox_vector_tile.adapt.jts.IUserDataConverter; import com.wdtinc.mapbox_vector_tile.adapt.jts.JtsAdapter; import com.wdtinc.mapbox_vector_tile.adapt.jts.TileGeomResult; +import com.wdtinc.mapbox_vector_tile.adapt.jts.UserDataIgnoreConverter; import com.wdtinc.mapbox_vector_tile.build.MvtLayerParams; import com.wdtinc.mapbox_vector_tile.build.MvtLayerProps; +import org.elasticsearch.common.geo.SphericalMercatorUtils; import org.elasticsearch.geometry.Circle; import org.elasticsearch.geometry.Geometry; import org.elasticsearch.geometry.GeometryCollection; @@ -40,10 +42,13 @@ */ public class FeatureFactory { + private static final byte[] EMPTY = new byte[0]; + private final IGeometryFilter acceptAllGeomFilter = geometry -> true; private final MvtLayerParams layerParams; private final GeometryFactory geomFactory = new GeometryFactory(); private final MvtLayerProps layerProps = new MvtLayerProps(); + private final IUserDataConverter ignoreDataConverter = new UserDataIgnoreConverter(); private final JTSGeometryBuilder builder; private final Envelope tileEnvelope; @@ -59,7 +64,7 @@ public FeatureFactory(int z, int x, int y, int extent) { this.layerParams = new MvtLayerParams(extent, extent); } - public List getFeatures(Geometry geometry, IUserDataConverter userData) { + public byte[] getFeature(Geometry geometry) { TileGeomResult tileGeom = JtsAdapter.createTileGeom( JtsAdapter.flatFeatureList(geometry.visit(builder)), tileEnvelope, @@ -69,11 +74,8 @@ public List getFeatures(Geometry geometry, IUserDataCon acceptAllGeomFilter ); // MVT tile geometry to MVT features - return JtsAdapter.toFeatures(tileGeom.mvtGeoms, layerProps, userData); - } - - public MvtLayerProps getLayerProps() { - return layerProps; + List features = JtsAdapter.toFeatures(tileGeom.mvtGeoms, layerProps, ignoreDataConverter); + return features.size() == 0 ? EMPTY : features.get(0).toByteArray(); } private static class JTSGeometryBuilder implements GeometryVisitor { diff --git a/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/rest/RestVectorTileAction.java b/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/rest/RestVectorTileAction.java index 7dc4284e93440..21028cfd38f1d 100644 --- a/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/rest/RestVectorTileAction.java +++ b/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/rest/RestVectorTileAction.java @@ -7,7 +7,6 @@ package org.elasticsearch.xpack.vectortile.rest; import com.wdtinc.mapbox_vector_tile.VectorTile; -import com.wdtinc.mapbox_vector_tile.adapt.jts.IUserDataConverter; import com.wdtinc.mapbox_vector_tile.build.MvtLayerProps; import org.elasticsearch.action.search.SearchRequestBuilder; @@ -17,10 +16,9 @@ import org.elasticsearch.common.document.DocumentField; import org.elasticsearch.common.geo.GeoBoundingBox; import org.elasticsearch.common.geo.GeoPoint; -import org.elasticsearch.common.geo.GeometryParser; +import org.elasticsearch.common.geo.SimpleFeatureFactory; import org.elasticsearch.common.io.Streams; import org.elasticsearch.common.io.stream.BytesStream; -import org.elasticsearch.geometry.Geometry; import org.elasticsearch.geometry.Rectangle; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; @@ -49,8 +47,6 @@ import org.elasticsearch.search.fetch.subphase.FieldAndFormat; import org.elasticsearch.search.profile.SearchProfileShardResults; import org.elasticsearch.search.sort.SortBuilder; -import org.elasticsearch.xpack.vectortile.feature.FeatureFactory; -import org.elasticsearch.xpack.vectortile.feature.SimpleFeatureFactory; import java.io.IOException; import java.util.Collection; @@ -172,8 +168,12 @@ private static SearchRequestBuilder searchRequestBuilder(RestCancellableNodeClie final SearchRequestBuilder searchRequestBuilder = client.prepareSearch(request.getIndexes()); searchRequestBuilder.setSize(request.getSize()); searchRequestBuilder.setFetchSource(false); - // TODO: I wonder if we can leverage field and format so what we get in the result is already the mvt commands. - searchRequestBuilder.addFetchField(new FieldAndFormat(request.getField(), null)); + searchRequestBuilder.addFetchField( + new FieldAndFormat( + request.getField(), + "mvt(" + request.getZ() + "/" + request.getX() + "/" + request.getY() + "@" + request.getExtent() + ")" + ) + ); for (FieldAndFormat field : request.getFieldAndFormats()) { searchRequestBuilder.addFetchField(field); } @@ -221,28 +221,31 @@ private static SearchRequestBuilder searchRequestBuilder(RestCancellableNodeClie return searchRequestBuilder; } - private static VectorTile.Tile.Layer.Builder buildHitsLayer(SearchHit[] hits, VectorTileRequest request) { - final FeatureFactory featureFactory = new FeatureFactory(request.getZ(), request.getX(), request.getY(), request.getExtent()); - final GeometryParser parser = new GeometryParser(true, false, false); + private static VectorTile.Tile.Layer.Builder buildHitsLayer(SearchHit[] hits, VectorTileRequest request) throws IOException { final VectorTile.Tile.Layer.Builder hitsLayerBuilder = VectorTileUtils.createLayerBuilder(HITS_LAYER, request.getExtent()); final List fields = request.getFieldAndFormats(); + final MvtLayerProps layerProps = new MvtLayerProps(); + final VectorTile.Tile.Feature.Builder featureBuilder = VectorTile.Tile.Feature.newBuilder(); for (SearchHit searchHit : hits) { - final IUserDataConverter tags = (userData, layerProps, featureBuilder) -> { - VectorTileUtils.addPropertyToFeature(featureBuilder, layerProps, ID_TAG, searchHit.getId()); - if (fields != null) { - for (FieldAndFormat field : fields) { - final DocumentField documentField = searchHit.field(field.field); - if (documentField != null) { - VectorTileUtils.addPropertyToFeature(featureBuilder, layerProps, field.field, documentField.getValue()); - } + final DocumentField geoField = searchHit.field(request.getField()); + if (geoField == null) { + continue; + } + featureBuilder.clear(); + final byte[] bytes = geoField.getValue(); + featureBuilder.mergeFrom(bytes); + VectorTileUtils.addPropertyToFeature(featureBuilder, layerProps, ID_TAG, searchHit.getId()); + if (fields != null) { + for (FieldAndFormat field : fields) { + final DocumentField documentField = searchHit.field(field.field); + if (documentField != null) { + VectorTileUtils.addPropertyToFeature(featureBuilder, layerProps, field.field, documentField.getValue()); } } - }; - // TODO: See comment on field formats. - final Geometry geometry = parser.parseGeometry(searchHit.field(request.getField()).getValue()); - hitsLayerBuilder.addAllFeatures(featureFactory.getFeatures(geometry, tags)); + } + hitsLayerBuilder.addFeatures(featureBuilder); } - VectorTileUtils.addPropertiesToLayer(hitsLayerBuilder, featureFactory.getLayerProps()); + VectorTileUtils.addPropertiesToLayer(hitsLayerBuilder, layerProps); return hitsLayerBuilder; } diff --git a/x-pack/plugin/vector-tile/src/test/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactoriesConsistencyTests.java b/x-pack/plugin/vector-tile/src/test/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactoriesConsistencyTests.java index c3a65137c68b3..6b56ed8b3e32c 100644 --- a/x-pack/plugin/vector-tile/src/test/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactoriesConsistencyTests.java +++ b/x-pack/plugin/vector-tile/src/test/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactoriesConsistencyTests.java @@ -7,10 +7,10 @@ package org.elasticsearch.xpack.vectortile.feature; -import com.wdtinc.mapbox_vector_tile.VectorTile; -import com.wdtinc.mapbox_vector_tile.adapt.jts.UserDataIgnoreConverter; - import org.apache.lucene.geo.GeoTestUtil; +import org.elasticsearch.common.geo.GeoPoint; +import org.elasticsearch.common.geo.SimpleFeatureFactory; +import org.elasticsearch.common.geo.SphericalMercatorUtils; import org.elasticsearch.geometry.MultiPoint; import org.elasticsearch.geometry.Point; import org.elasticsearch.geometry.Rectangle; @@ -36,21 +36,19 @@ public void testPoint() throws IOException { SimpleFeatureFactory builder = new SimpleFeatureFactory(z, x, y, extent); FeatureFactory factory = new FeatureFactory(z, x, y, extent); List points = new ArrayList<>(); + List geoPoints = new ArrayList<>(); for (int i = 0; i < 10; i++) { double lat = randomValueOtherThanMany((l) -> rectangle.getMinY() > l || rectangle.getMaxY() < l, GeoTestUtil::nextLatitude); double lon = randomValueOtherThanMany((l) -> rectangle.getMinX() > l || rectangle.getMaxX() < l, GeoTestUtil::nextLongitude); byte[] b1 = builder.point(lon, lat); Point point = new Point(lon, lat); - List features = factory.getFeatures(point, new UserDataIgnoreConverter()); - assertThat(features.size(), Matchers.equalTo(1)); - byte[] b2 = features.get(0).toByteArray(); + byte[] b2 = factory.getFeature(point); assertArrayEquals(b1, b2); points.add(point); + geoPoints.add(new GeoPoint(lat, lon)); } - byte[] b1 = builder.points(points); - List features = factory.getFeatures(new MultiPoint(points), new UserDataIgnoreConverter()); - assertThat(features.size(), Matchers.equalTo(1)); - byte[] b2 = features.get(0).toByteArray(); + byte[] b1 = builder.points(geoPoints); + byte[] b2 = factory.getFeature(new MultiPoint(points)); assertArrayEquals(b1, b2); } @@ -67,9 +65,7 @@ public void testIssue74341() throws IOException { FeatureFactory factory = new FeatureFactory(z, x, y, extent); byte[] b1 = builder.point(lon, lat); Point point = new Point(lon, lat); - List features = factory.getFeatures(point, new UserDataIgnoreConverter()); - assertThat(features.size(), Matchers.equalTo(1)); - byte[] b2 = features.get(0).toByteArray(); + byte[] b2 = factory.getFeature(point); assertThat(Arrays.equals(b1, b2), Matchers.equalTo(false)); } @@ -90,9 +86,7 @@ public void testRectangle() throws IOException { Rectangle r = GeoTileUtils.toBoundingBox(x, y, z); for (int i = 0; i < extent; i++) { byte[] b1 = builder.box(r.getMinLon(), r.getMaxLon(), r.getMinLat(), r.getMaxLat()); - List features = factory.getFeatures(r, new UserDataIgnoreConverter()); - assertThat(features.size(), Matchers.equalTo(1)); - byte[] b2 = features.get(0).toByteArray(); + byte[] b2 = factory.getFeature(r); assertArrayEquals(extent + "", b1, b2); } } diff --git a/x-pack/plugin/vector-tile/src/test/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactoryTests.java b/x-pack/plugin/vector-tile/src/test/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactoryTests.java index fa24dbd3aa6a8..c972e3468e70b 100644 --- a/x-pack/plugin/vector-tile/src/test/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactoryTests.java +++ b/x-pack/plugin/vector-tile/src/test/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactoryTests.java @@ -8,7 +8,6 @@ package org.elasticsearch.xpack.vectortile.feature; import com.wdtinc.mapbox_vector_tile.VectorTile; -import com.wdtinc.mapbox_vector_tile.adapt.jts.UserDataIgnoreConverter; import org.apache.lucene.geo.GeoTestUtil; import org.elasticsearch.geometry.Geometry; @@ -25,6 +24,7 @@ import org.elasticsearch.test.ESTestCase; import org.hamcrest.Matchers; +import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -32,7 +32,7 @@ public class FeatureFactoryTests extends ESTestCase { @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/75325") - public void testPoint() { + public void testPoint() throws IOException { int z = randomIntBetween(1, 10); int x = randomIntBetween(0, (1 << z) - 1); int y = randomIntBetween(0, (1 << z) - 1); @@ -42,21 +42,19 @@ public void testPoint() { { double lat = randomValueOtherThanMany((l) -> rectangle.getMinY() > l || rectangle.getMaxY() < l, GeoTestUtil::nextLatitude); double lon = randomValueOtherThanMany((l) -> rectangle.getMinX() > l || rectangle.getMaxX() < l, GeoTestUtil::nextLongitude); - List features = builder.getFeatures(new Point(lon, lat), new UserDataIgnoreConverter()); - assertThat(features.size(), Matchers.equalTo(1)); - VectorTile.Tile.Feature feature = features.get(0); + VectorTile.Tile.Feature feature = VectorTile.Tile.Feature.parseFrom(builder.getFeature(new Point(lon, lat))); + assertThat(feature, Matchers.notNullValue()); assertThat(feature.getType(), Matchers.equalTo(VectorTile.Tile.GeomType.POINT)); } { double lat = randomValueOtherThanMany((l) -> rectangle.getMinY() <= l && rectangle.getMaxY() >= l, GeoTestUtil::nextLatitude); double lon = randomValueOtherThanMany((l) -> rectangle.getMinX() <= l && rectangle.getMaxX() >= l, GeoTestUtil::nextLongitude); - List features = builder.getFeatures(new Point(lon, lat), new UserDataIgnoreConverter()); - assertThat(features.size(), Matchers.equalTo(0)); + assertThat(builder.getFeature(new Point(lon, lat)).length, Matchers.equalTo(0)); } } @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/75325") - public void testMultiPoint() { + public void testMultiPoint() throws IOException { int z = randomIntBetween(1, 10); int x = randomIntBetween(0, (1 << z) - 1); int y = randomIntBetween(0, (1 << z) - 1); @@ -72,9 +70,8 @@ public void testMultiPoint() { for (int i = 0; i < numPoints - 1; i++) { points.add(new Point(GeoTestUtil.nextLongitude(), GeoTestUtil.nextLatitude())); } - List features = builder.getFeatures(new MultiPoint(points), new UserDataIgnoreConverter()); - assertThat(features.size(), Matchers.equalTo(1)); - VectorTile.Tile.Feature feature = features.get(0); + VectorTile.Tile.Feature feature = VectorTile.Tile.Feature.parseFrom(builder.getFeature(new MultiPoint(points))); + assertThat(feature, Matchers.notNullValue()); assertThat(feature.getType(), Matchers.equalTo(VectorTile.Tile.GeomType.POINT)); } { @@ -90,12 +87,11 @@ public void testMultiPoint() { ); points.add(new Point(lon, lat)); } - List features = builder.getFeatures(new MultiPoint(points), new UserDataIgnoreConverter()); - assertThat(features.size(), Matchers.equalTo(0)); + assertThat(builder.getFeature(new MultiPoint(points)).length, Matchers.equalTo(0)); } } - public void testRectangle() { + public void testRectangle() throws IOException { int z = randomIntBetween(3, 10); int x = randomIntBetween(2, (1 << z) - 1); int y = randomIntBetween(2, (1 << z) - 1); @@ -103,19 +99,17 @@ public void testRectangle() { FeatureFactory builder = new FeatureFactory(z, x, y, extent); { Rectangle r = GeoTileUtils.toBoundingBox(x, y, z); - List features = builder.getFeatures(r, new UserDataIgnoreConverter()); - assertThat(features.size(), Matchers.equalTo(1)); - VectorTile.Tile.Feature feature = features.get(0); + VectorTile.Tile.Feature feature = VectorTile.Tile.Feature.parseFrom(builder.getFeature(r)); + assertThat(feature, Matchers.notNullValue()); assertThat(feature.getType(), Matchers.equalTo(VectorTile.Tile.GeomType.POLYGON)); } { Rectangle r = GeoTileUtils.toBoundingBox(x - 2, y, z); - List features = builder.getFeatures(r, new UserDataIgnoreConverter()); - assertThat(features.size(), Matchers.equalTo(0)); + assertThat(builder.getFeature(r).length, Matchers.equalTo(0)); } } - public void testLine() { + public void testLine() throws IOException { int z = randomIntBetween(3, 10); int x = randomIntBetween(2, (1 << z) - 1); int y = randomIntBetween(2, (1 << z) - 1); @@ -123,19 +117,17 @@ public void testLine() { FeatureFactory builder = new FeatureFactory(z, x, y, extent); { Rectangle r = GeoTileUtils.toBoundingBox(x, y, z); - List features = builder.getFeatures(buildLine(r), new UserDataIgnoreConverter()); - assertThat(features.size(), Matchers.equalTo(1)); - VectorTile.Tile.Feature feature = features.get(0); + VectorTile.Tile.Feature feature = VectorTile.Tile.Feature.parseFrom(builder.getFeature(buildLine(r))); + assertThat(feature, Matchers.notNullValue()); assertThat(feature.getType(), Matchers.equalTo(VectorTile.Tile.GeomType.LINESTRING)); } { Rectangle r = GeoTileUtils.toBoundingBox(x - 2, y, z); - List features = builder.getFeatures(buildLine(r), new UserDataIgnoreConverter()); - assertThat(features.size(), Matchers.equalTo(0)); + assertThat(builder.getFeature(buildLine(r)).length, Matchers.equalTo(0)); } } - public void testMultiLine() { + public void testMultiLine() throws IOException { int z = randomIntBetween(3, 10); int x = randomIntBetween(2, (1 << z) - 1); int y = randomIntBetween(2, (1 << z) - 1); @@ -143,19 +135,17 @@ public void testMultiLine() { FeatureFactory builder = new FeatureFactory(z, x, y, extent); { Rectangle r = GeoTileUtils.toBoundingBox(x, y, z); - List features = builder.getFeatures(buildMultiLine(r), new UserDataIgnoreConverter()); - assertThat(features.size(), Matchers.equalTo(1)); - VectorTile.Tile.Feature feature = features.get(0); + VectorTile.Tile.Feature feature = VectorTile.Tile.Feature.parseFrom(builder.getFeature(buildMultiLine(r))); + assertThat(feature, Matchers.notNullValue()); assertThat(feature.getType(), Matchers.equalTo(VectorTile.Tile.GeomType.LINESTRING)); } { Rectangle r = GeoTileUtils.toBoundingBox(x - 2, y, z); - List features = builder.getFeatures(buildMultiLine(r), new UserDataIgnoreConverter()); - assertThat(features.size(), Matchers.equalTo(0)); + assertThat(builder.getFeature(buildMultiLine(r)).length, Matchers.equalTo(0)); } } - public void testPolygon() { + public void testPolygon() throws IOException { int z = randomIntBetween(3, 10); int x = randomIntBetween(2, (1 << z) - 1); int y = randomIntBetween(2, (1 << z) - 1); @@ -163,19 +153,17 @@ public void testPolygon() { FeatureFactory builder = new FeatureFactory(z, x, y, extent); { Rectangle r = GeoTileUtils.toBoundingBox(x, y, z); - List features = builder.getFeatures(buildPolygon(r), new UserDataIgnoreConverter()); - assertThat(features.size(), Matchers.equalTo(1)); - VectorTile.Tile.Feature feature = features.get(0); + VectorTile.Tile.Feature feature = VectorTile.Tile.Feature.parseFrom(builder.getFeature(buildPolygon(r))); + assertThat(feature, Matchers.notNullValue()); assertThat(feature.getType(), Matchers.equalTo(VectorTile.Tile.GeomType.POLYGON)); } { Rectangle r = GeoTileUtils.toBoundingBox(x - 2, y, z); - List features = builder.getFeatures(buildPolygon(r), new UserDataIgnoreConverter()); - assertThat(features.size(), Matchers.equalTo(0)); + assertThat(builder.getFeature(buildPolygon(r)).length, Matchers.equalTo(0)); } } - public void testMultiPolygon() { + public void testMultiPolygon() throws IOException { int z = randomIntBetween(3, 10); int x = randomIntBetween(2, (1 << z) - 1); int y = randomIntBetween(2, (1 << z) - 1); @@ -183,15 +171,14 @@ public void testMultiPolygon() { FeatureFactory builder = new FeatureFactory(z, x, y, extent); { Rectangle r = GeoTileUtils.toBoundingBox(x, y, z); - List features = builder.getFeatures(buildMultiPolygon(r), new UserDataIgnoreConverter()); - assertThat(features.size(), Matchers.equalTo(1)); - VectorTile.Tile.Feature feature = features.get(0); + VectorTile.Tile.Feature feature = VectorTile.Tile.Feature.parseFrom(builder.getFeature(buildMultiPolygon(r))); + assertThat(feature, Matchers.notNullValue()); assertThat(feature.getType(), Matchers.equalTo(VectorTile.Tile.GeomType.POLYGON)); } { Rectangle r = GeoTileUtils.toBoundingBox(x - 2, y, z); - List features = builder.getFeatures(buildMultiPolygon(r), new UserDataIgnoreConverter()); - assertThat(features.size(), Matchers.equalTo(0)); + assertThat(builder.getFeature(buildMultiPolygon(r)).length, Matchers.equalTo(0)); + } } @@ -206,7 +193,7 @@ public void testGeometryCollection() { List geometries = List.of(buildPolygon(r), buildLine(r)); IllegalArgumentException ex = expectThrows( IllegalArgumentException.class, - () -> builder.getFeatures(new GeometryCollection<>(geometries), new UserDataIgnoreConverter()) + () -> builder.getFeature(new GeometryCollection<>(geometries)) ); assertThat(ex.getMessage(), Matchers.equalTo("GeometryCollection is not supported")); } From 549b2ec1d00be10ab205fe0832f6f960a7de0a01 Mon Sep 17 00:00:00 2001 From: iverase Date: Mon, 19 Jul 2021 13:09:25 +0200 Subject: [PATCH 2/9] remove lincense header left-over --- .../org/elasticsearch/common/geo/GeoFormatterFactory.java | 7 ------- .../org/elasticsearch/common/geo/SimpleFeatureFactory.java | 7 ------- .../elasticsearch/common/geo/SphericalMercatorUtils.java | 7 ------- 3 files changed, 21 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/common/geo/GeoFormatterFactory.java b/server/src/main/java/org/elasticsearch/common/geo/GeoFormatterFactory.java index 4e2251b34e150..fae7f3f804524 100644 --- a/server/src/main/java/org/elasticsearch/common/geo/GeoFormatterFactory.java +++ b/server/src/main/java/org/elasticsearch/common/geo/GeoFormatterFactory.java @@ -6,13 +6,6 @@ * Side Public License, v 1. */ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - package org.elasticsearch.common.geo; import org.elasticsearch.geometry.Geometry; diff --git a/server/src/main/java/org/elasticsearch/common/geo/SimpleFeatureFactory.java b/server/src/main/java/org/elasticsearch/common/geo/SimpleFeatureFactory.java index a6e6b62b8dde3..87e4b9448121d 100644 --- a/server/src/main/java/org/elasticsearch/common/geo/SimpleFeatureFactory.java +++ b/server/src/main/java/org/elasticsearch/common/geo/SimpleFeatureFactory.java @@ -6,13 +6,6 @@ * Side Public License, v 1. */ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - package org.elasticsearch.common.geo; import org.apache.lucene.util.BitUtil; diff --git a/server/src/main/java/org/elasticsearch/common/geo/SphericalMercatorUtils.java b/server/src/main/java/org/elasticsearch/common/geo/SphericalMercatorUtils.java index fd5d6820eb3e5..eff8220bd6916 100644 --- a/server/src/main/java/org/elasticsearch/common/geo/SphericalMercatorUtils.java +++ b/server/src/main/java/org/elasticsearch/common/geo/SphericalMercatorUtils.java @@ -6,13 +6,6 @@ * Side Public License, v 1. */ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - package org.elasticsearch.common.geo; import org.elasticsearch.geometry.Rectangle; From bce3493e0e8af7aa9324516f8fbd2b0f3f881210 Mon Sep 17 00:00:00 2001 From: iverase Date: Tue, 20 Jul 2021 12:28:38 +0200 Subject: [PATCH 3/9] more double licenses --- .../common/geo/SimpleFeatureFactoryTests.java | 7 ------- .../index/mapper/GeoShapeWithDocValuesFieldTypeTests.java | 8 -------- 2 files changed, 15 deletions(-) diff --git a/server/src/test/java/org/elasticsearch/common/geo/SimpleFeatureFactoryTests.java b/server/src/test/java/org/elasticsearch/common/geo/SimpleFeatureFactoryTests.java index df3f4e6cac811..e172c6ad8702b 100644 --- a/server/src/test/java/org/elasticsearch/common/geo/SimpleFeatureFactoryTests.java +++ b/server/src/test/java/org/elasticsearch/common/geo/SimpleFeatureFactoryTests.java @@ -6,13 +6,6 @@ * Side Public License, v 1. */ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - package org.elasticsearch.common.geo; import org.apache.lucene.geo.GeoTestUtil; diff --git a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java index 9bb3c02433919..1eb8f29023f2a 100644 --- a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java +++ b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java @@ -5,14 +5,6 @@ * 2.0. */ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - package org.elasticsearch.xpack.spatial.index.mapper; import org.elasticsearch.Version; From 9feff822d53ffaf81d651e57091b08276ed5b90d Mon Sep 17 00:00:00 2001 From: iverase Date: Tue, 27 Jul 2021 12:59:55 +0200 Subject: [PATCH 4/9] Use plugin extensibility mechanism so vector tile module extends the spatial module. --- x-pack/plugin/spatial/build.gradle | 2 +- .../xpack/spatial/SpatialPlugin.java | 15 +++- .../xpack/spatial/VectorTileExtension.java | 20 +++++ .../GeoShapeWithDocValuesFieldMapper.java | 90 ++++++++++++------- .../GeoShapeWithDocValuesFieldTypeTests.java | 10 ++- .../spatial/ingest/CircleProcessorTests.java | 3 +- .../geogrid/GeoShapeGeoGridTestCase.java | 3 +- .../GeoShapeBoundsAggregatorTests.java | 11 +-- .../GeoShapeCentroidAggregatorTests.java | 11 +-- x-pack/plugin/vector-tile/build.gradle | 3 +- .../SpatialVectorTileExtension.java | 32 +++++++ ...icsearch.xpack.spatial.VectorTileExtension | 8 ++ 12 files changed, 156 insertions(+), 52 deletions(-) create mode 100644 x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/VectorTileExtension.java create mode 100644 x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/SpatialVectorTileExtension.java create mode 100644 x-pack/plugin/vector-tile/src/main/resources/META-INF/services/org.elasticsearch.xpack.spatial.VectorTileExtension diff --git a/x-pack/plugin/spatial/build.gradle b/x-pack/plugin/spatial/build.gradle index 242997a0ea7ae..fd93d5b67dcc3 100644 --- a/x-pack/plugin/spatial/build.gradle +++ b/x-pack/plugin/spatial/build.gradle @@ -13,9 +13,9 @@ esplugin { dependencies { compileOnly project(path: xpackModule('core')) testImplementation(testArtifact(project(xpackModule('core')))) + testImplementation project(path: xpackModule('vector-tile')) yamlRestTestImplementation(testArtifact(project(xpackModule('core')))) api project(path: ':modules:geo') - api project(path: xpackModule('vector-tile')) restTestConfig project(path: ':modules:geo', configuration: 'restTests') } diff --git a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/SpatialPlugin.java b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/SpatialPlugin.java index 144b3a874f940..cc00f0728b4e0 100644 --- a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/SpatialPlugin.java +++ b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/SpatialPlugin.java @@ -6,6 +6,7 @@ */ package org.elasticsearch.xpack.spatial; +import org.apache.lucene.util.SetOnce; import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionResponse; import org.elasticsearch.common.xcontent.ContextParser; @@ -15,6 +16,7 @@ import org.elasticsearch.license.LicenseUtils; import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.plugins.ActionPlugin; +import org.elasticsearch.plugins.ExtensiblePlugin; import org.elasticsearch.plugins.IngestPlugin; import org.elasticsearch.plugins.MapperPlugin; import org.elasticsearch.plugins.SearchPlugin; @@ -63,7 +65,7 @@ import static java.util.Collections.singletonList; -public class SpatialPlugin extends GeoPlugin implements ActionPlugin, MapperPlugin, SearchPlugin, IngestPlugin { +public class SpatialPlugin extends GeoPlugin implements ActionPlugin, MapperPlugin, SearchPlugin, IngestPlugin, ExtensiblePlugin { private final SpatialUsage usage = new SpatialUsage(); // to be overriden by tests @@ -71,6 +73,9 @@ protected XPackLicenseState getLicenseState() { return XPackPlugin.getSharedLicenseState(); } + // register the vector tile factory from a different module + private final SetOnce vectorTileExtension = new SetOnce<>(); + @Override public List> getActions() { return Arrays.asList( @@ -84,7 +89,7 @@ public Map getMappers() { Map mappers = new HashMap<>(super.getMappers()); mappers.put(ShapeFieldMapper.CONTENT_TYPE, ShapeFieldMapper.PARSER); mappers.put(PointFieldMapper.CONTENT_TYPE, PointFieldMapper.PARSER); - mappers.put(GeoShapeWithDocValuesFieldMapper.CONTENT_TYPE, GeoShapeWithDocValuesFieldMapper.PARSER); + mappers.put(GeoShapeWithDocValuesFieldMapper.CONTENT_TYPE, new GeoShapeWithDocValuesFieldMapper.TypeParser(vectorTileExtension)); return Collections.unmodifiableMap(mappers); } @@ -205,4 +210,10 @@ private ContextParser checkLicense(ContextParser realP return realParser.parse(parser, name); }; } + + @Override + public void loadExtensions(ExtensionLoader loader) { + // we only expect one vector tile extension that comes from the vector tile module. + loader.loadExtensions(VectorTileExtension.class).forEach(vectorTileExtension::set); + } } diff --git a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/VectorTileExtension.java b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/VectorTileExtension.java new file mode 100644 index 0000000000000..8fb6331f6cbe4 --- /dev/null +++ b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/VectorTileExtension.java @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.spatial; + +import org.elasticsearch.common.geo.GeoFormatterFactory; +import org.elasticsearch.geometry.Geometry; + + +public interface VectorTileExtension { + /** + * Get the vector tile engine. This is called when user ask for the MVT format on the field API. + * We are only expecting one instance of a vector tile engine coming from the vector tile module. + */ + GeoFormatterFactory.VectorTileEngine getVectorTileEngine(); +} diff --git a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapper.java b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapper.java index 6102d36ad4e7f..f1f43c7acf1ce 100644 --- a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapper.java +++ b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapper.java @@ -13,6 +13,7 @@ import org.apache.lucene.search.IndexOrDocValuesQuery; import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.util.SetOnce; import org.elasticsearch.Version; import org.elasticsearch.common.Explicit; import org.elasticsearch.common.geo.GeoFormatterFactory; @@ -23,7 +24,6 @@ import org.elasticsearch.common.logging.DeprecationCategory; import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.geometry.Geometry; -import org.elasticsearch.geometry.GeometryCollection; import org.elasticsearch.index.fielddata.IndexFieldData; import org.elasticsearch.index.mapper.AbstractShapeGeometryFieldMapper; import org.elasticsearch.index.mapper.ContentPath; @@ -36,12 +36,14 @@ import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper; import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.Mapper; +import org.elasticsearch.index.mapper.MapperParsingException; +import org.elasticsearch.index.mapper.MappingParserContext; import org.elasticsearch.index.query.QueryShardException; import org.elasticsearch.index.query.SearchExecutionContext; import org.elasticsearch.search.lookup.SearchLookup; +import org.elasticsearch.xpack.spatial.VectorTileExtension; import org.elasticsearch.xpack.spatial.index.fielddata.plain.AbstractLatLonShapeIndexFieldData; import org.elasticsearch.xpack.spatial.search.aggregations.support.GeoShapeValuesSourceType; -import org.elasticsearch.xpack.vectortile.feature.FeatureFactory; import java.io.IOException; import java.util.Arrays; @@ -95,10 +97,13 @@ public static class Builder extends FieldMapper.Builder { final Parameter> meta = Parameter.metaParam(); private final Version version; + private final SetOnce vectorTileExtension; - public Builder(String name, Version version, boolean ignoreMalformedByDefault, boolean coerceByDefault) { + public Builder(String name, Version version, boolean ignoreMalformedByDefault, boolean coerceByDefault, + SetOnce vectorTileExtension) { super(name); this.version = version; + this.vectorTileExtension = vectorTileExtension; this.ignoreMalformed = ignoreMalformedParam(m -> builder(m).ignoreMalformed.get(), ignoreMalformedByDefault); this.coerce = coerceParam(m -> builder(m).coerce.get(), coerceByDefault); this.hasDocValues @@ -130,6 +135,7 @@ public GeoShapeWithDocValuesFieldMapper build(ContentPath contentPath) { hasDocValues.get(), orientation.get().value(), parser, + vectorTileExtension, meta.get()); return new GeoShapeWithDocValuesFieldMapper(name, ft, multiFieldsBuilder.build(this, contentPath), copyTo.build(), @@ -140,9 +146,12 @@ public GeoShapeWithDocValuesFieldMapper build(ContentPath contentPath) { public static final class GeoShapeWithDocValuesFieldType extends AbstractShapeGeometryFieldType implements GeoShapeQueryable { + private final SetOnce vectorTileExtension; public GeoShapeWithDocValuesFieldType(String name, boolean indexed, boolean hasDocValues, - Orientation orientation, GeoShapeParser parser, Map meta) { + Orientation orientation, GeoShapeParser parser, + SetOnce vectorTileExtension, Map meta) { super(name, indexed, false, hasDocValues, parser, orientation, meta); + this.vectorTileExtension = vectorTileExtension; } public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName, Supplier searchLookup) { @@ -178,41 +187,53 @@ public Query geoShapeQuery(Geometry shape, String fieldName, ShapeRelation relat protected Function, List> getFormatter(String format) { return GeoFormatterFactory.getFormatter(format, Function.identity(), (z, x, y, extent) -> { - final FeatureFactory featureFactory = new FeatureFactory(z, x, y, extent); - return geometries -> { - final Geometry geometry = (geometries.size() == 1) ? geometries.get(0) : new GeometryCollection<>(geometries); - return featureFactory.getFeatures(geometry); - }; + final VectorTileExtension extension = vectorTileExtension.get(); + if (extension == null) { + throw new IllegalArgumentException("vector tile format is not supported"); + } + return extension.getVectorTileEngine().getFormatter(z, x, y, extent); }); } } - @SuppressWarnings("deprecation") - public static Mapper.TypeParser PARSER = (name, node, parserContext) -> { - FieldMapper.Builder builder; - boolean ignoreMalformedByDefault = IGNORE_MALFORMED_SETTING.get(parserContext.getSettings()); - boolean coerceByDefault = COERCE_SETTING.get(parserContext.getSettings()); - if (LegacyGeoShapeFieldMapper.containsDeprecatedParameter(node.keySet())) { - if (parserContext.indexVersionCreated().onOrAfter(Version.V_8_0_0)) { - Set deprecatedParams = LegacyGeoShapeFieldMapper.getDeprecatedParameters(node.keySet()); - throw new IllegalArgumentException("using deprecated parameters " + Arrays.toString(deprecatedParams.toArray()) - + " in mapper [" + name + "] of type [geo_shape] is no longer allowed"); + public static class TypeParser implements Mapper.TypeParser { + + private final SetOnce vectorTileExtension; + + public TypeParser(SetOnce vectorTileExtension) { + this.vectorTileExtension = vectorTileExtension; + } + + @Override + @SuppressWarnings("deprecation") + public Mapper.Builder parse(String name, Map node, MappingParserContext parserContext) + throws MapperParsingException { + FieldMapper.Builder builder; + boolean ignoreMalformedByDefault = IGNORE_MALFORMED_SETTING.get(parserContext.getSettings()); + boolean coerceByDefault = COERCE_SETTING.get(parserContext.getSettings()); + if (LegacyGeoShapeFieldMapper.containsDeprecatedParameter(node.keySet())) { + if (parserContext.indexVersionCreated().onOrAfter(Version.V_8_0_0)) { + Set deprecatedParams = LegacyGeoShapeFieldMapper.getDeprecatedParameters(node.keySet()); + throw new IllegalArgumentException("using deprecated parameters " + Arrays.toString(deprecatedParams.toArray()) + + " in mapper [" + name + "] of type [geo_shape] is no longer allowed"); + } + builder = new LegacyGeoShapeFieldMapper.Builder( + name, + parserContext.indexVersionCreated(), + ignoreMalformedByDefault, + coerceByDefault); + } else { + builder = new GeoShapeWithDocValuesFieldMapper.Builder( + name, + parserContext.indexVersionCreated(), + ignoreMalformedByDefault, + coerceByDefault, + vectorTileExtension); } - builder = new LegacyGeoShapeFieldMapper.Builder( - name, - parserContext.indexVersionCreated(), - ignoreMalformedByDefault, - coerceByDefault); - } else { - builder = new GeoShapeWithDocValuesFieldMapper.Builder( - name, - parserContext.indexVersionCreated(), - ignoreMalformedByDefault, - coerceByDefault); + builder.parse(name, parserContext, node); + return builder; } - builder.parse(name, parserContext, node); - return builder; - }; + } private final Builder builder; private final GeoShapeIndexer indexer; @@ -261,7 +282,8 @@ public FieldMapper.Builder getMergeBuilder() { simpleName(), builder.version, builder.ignoreMalformed.getDefaultValue().value(), - builder.coerce.getDefaultValue().value() + builder.coerce.getDefaultValue().value(), + builder.vectorTileExtension ).init(this); } diff --git a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java index ffd24ed0a6067..ca46f6a2461e0 100644 --- a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java +++ b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java @@ -7,6 +7,7 @@ package org.elasticsearch.xpack.spatial.index.mapper; +import org.apache.lucene.util.SetOnce; import org.elasticsearch.Version; import org.elasticsearch.geo.GeometryTestUtils; import org.elasticsearch.geometry.Geometry; @@ -15,6 +16,8 @@ import org.elasticsearch.index.mapper.FieldTypeTestCase; import org.elasticsearch.index.mapper.GeoShapeFieldMapper; import org.elasticsearch.index.mapper.MappedFieldType; +import org.elasticsearch.xpack.spatial.VectorTileExtension; +import org.elasticsearch.xpack.vectortile.SpatialVectorTileExtension; import org.elasticsearch.xpack.vectortile.feature.FeatureFactory; import org.hamcrest.Matchers; @@ -88,8 +91,11 @@ public void testFetchVectorTile() throws IOException { } private void fetchVectorTile(Geometry geometry) throws IOException { - MappedFieldType mapper - = new GeoShapeWithDocValuesFieldMapper.Builder("field", Version.CURRENT, false, false).build(new ContentPath()).fieldType(); + final SetOnce vectorTileExtension = new SetOnce<>(); + vectorTileExtension.set(new SpatialVectorTileExtension()); + final MappedFieldType mapper + = new GeoShapeWithDocValuesFieldMapper.Builder("field", Version.CURRENT, false, false, vectorTileExtension) + .build(new ContentPath()).fieldType(); final int z = randomIntBetween(1, 10); int x = randomIntBetween(0, (1 << z) - 1); int y = randomIntBetween(0, (1 << z) - 1); diff --git a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/ingest/CircleProcessorTests.java b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/ingest/CircleProcessorTests.java index ffee7a46a490c..bd5c14a6fb1fd 100644 --- a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/ingest/CircleProcessorTests.java +++ b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/ingest/CircleProcessorTests.java @@ -13,6 +13,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.store.Directory; +import org.apache.lucene.util.SetOnce; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.core.Tuple; import org.elasticsearch.common.geo.GeoJson; @@ -213,7 +214,7 @@ public void testGeoShapeQueryAcrossDateline() throws IOException { Geometry geometry = SpatialUtils.createRegularGeoShapePolygon(circle, numSides); GeoShapeWithDocValuesFieldType shapeType - = new GeoShapeWithDocValuesFieldType(fieldName, true, false, Orientation.RIGHT, null, Collections.emptyMap()); + = new GeoShapeWithDocValuesFieldType(fieldName, true, false, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); SearchExecutionContext mockedContext = mock(SearchExecutionContext.class); when(mockedContext.getFieldType(any())).thenReturn(shapeType); diff --git a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/bucket/geogrid/GeoShapeGeoGridTestCase.java b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/bucket/geogrid/GeoShapeGeoGridTestCase.java index 4c682981e67b0..657d86de001a3 100644 --- a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/bucket/geogrid/GeoShapeGeoGridTestCase.java +++ b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/bucket/geogrid/GeoShapeGeoGridTestCase.java @@ -18,6 +18,7 @@ import org.apache.lucene.search.Query; import org.apache.lucene.store.Directory; import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.SetOnce; import org.elasticsearch.core.CheckedConsumer; import org.elasticsearch.common.geo.GeoBoundingBox; import org.elasticsearch.common.geo.Orientation; @@ -293,7 +294,7 @@ private void testCase(Query query, int precision, GeoBoundingBox geoBoundingBox, } MappedFieldType fieldType - = new GeoShapeWithDocValuesFieldType(FIELD_NAME, true, true, Orientation.RIGHT, null, Collections.emptyMap()); + = new GeoShapeWithDocValuesFieldType(FIELD_NAME, true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); Aggregator aggregator = createAggregator(aggregationBuilder, indexSearcher, fieldType); aggregator.preCollection(); diff --git a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/metrics/GeoShapeBoundsAggregatorTests.java b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/metrics/GeoShapeBoundsAggregatorTests.java index b295eb3ff3183..0feb060ecd2fc 100644 --- a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/metrics/GeoShapeBoundsAggregatorTests.java +++ b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/metrics/GeoShapeBoundsAggregatorTests.java @@ -16,6 +16,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.store.Directory; +import org.apache.lucene.util.SetOnce; import org.elasticsearch.common.geo.Orientation; import org.elasticsearch.geo.GeometryTestUtils; import org.elasticsearch.geometry.Geometry; @@ -58,7 +59,7 @@ public void testEmpty() throws Exception { .wrapLongitude(false); MappedFieldType fieldType - = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, Collections.emptyMap()); + = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); try (IndexReader reader = w.getReader()) { IndexSearcher searcher = new IndexSearcher(reader); InternalGeoBounds bounds = searchAndReduce(searcher, new MatchAllDocsQuery(), aggBuilder, fieldType); @@ -86,7 +87,7 @@ public void testUnmappedFieldWithDocs() throws Exception { .wrapLongitude(false); MappedFieldType fieldType - = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, Collections.emptyMap()); + = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); try (IndexReader reader = w.getReader()) { IndexSearcher searcher = new IndexSearcher(reader); InternalGeoBounds bounds = searchAndReduce(searcher, new MatchAllDocsQuery(), aggBuilder, fieldType); @@ -108,7 +109,7 @@ public void testMissing() throws Exception { w.addDocument(doc); MappedFieldType fieldType - = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, Collections.emptyMap()); + = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); Point point = GeometryTestUtils.randomPoint(false); double lon = GeoEncodingUtils.decodeLongitude(GeoEncodingUtils.encodeLongitude(point.getX())); @@ -140,7 +141,7 @@ public void testInvalidMissing() throws Exception { w.addDocument(doc); MappedFieldType fieldType - = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, Collections.emptyMap()); + = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); GeoBoundsAggregationBuilder aggBuilder = new GeoBoundsAggregationBuilder("my_agg") .field("field") @@ -200,7 +201,7 @@ public void testRandomShapes() throws Exception { .wrapLongitude(false); MappedFieldType fieldType - = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, Collections.emptyMap()); + = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); try (IndexReader reader = w.getReader()) { IndexSearcher searcher = new IndexSearcher(reader); InternalGeoBounds bounds = searchAndReduce(searcher, new MatchAllDocsQuery(), aggBuilder, fieldType); diff --git a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/metrics/GeoShapeCentroidAggregatorTests.java b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/metrics/GeoShapeCentroidAggregatorTests.java index f7d8f634050fd..1a62dd75d9dbb 100644 --- a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/metrics/GeoShapeCentroidAggregatorTests.java +++ b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/metrics/GeoShapeCentroidAggregatorTests.java @@ -15,6 +15,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.store.Directory; +import org.apache.lucene.util.SetOnce; import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.geo.Orientation; import org.elasticsearch.geo.GeometryTestUtils; @@ -63,7 +64,7 @@ public void testEmpty() throws Exception { .field("field"); MappedFieldType fieldType - = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, Collections.emptyMap()); + = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); try (IndexReader reader = w.getReader()) { IndexSearcher searcher = new IndexSearcher(reader); InternalGeoCentroid result = searchAndReduce(searcher, new MatchAllDocsQuery(), aggBuilder, fieldType); @@ -86,12 +87,12 @@ public void testUnmapped() throws Exception { IndexSearcher searcher = new IndexSearcher(reader); MappedFieldType fieldType = new GeoShapeWithDocValuesFieldType("another_field", - true, true, Orientation.RIGHT, null, Collections.emptyMap()); + true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); InternalGeoCentroid result = searchAndReduce(searcher, new MatchAllDocsQuery(), aggBuilder, fieldType); assertNull(result.centroid()); fieldType = new GeoShapeWithDocValuesFieldType("field", - true, true, Orientation.RIGHT, null, Collections.emptyMap()); + true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); result = searchAndReduce(searcher, new MatchAllDocsQuery(), aggBuilder, fieldType); assertNull(result.centroid()); assertFalse(AggregationInspectionHelper.hasValue(result)); @@ -116,7 +117,7 @@ public void testUnmappedWithMissing() throws Exception { IndexSearcher searcher = new IndexSearcher(reader); MappedFieldType fieldType = new GeoShapeWithDocValuesFieldType("another_field", - true, true, Orientation.RIGHT, null, Collections.emptyMap()); + true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); InternalGeoCentroid result = searchAndReduce(searcher, new MatchAllDocsQuery(), aggBuilder, fieldType); assertThat(result.centroid(), equalTo(expectedCentroid)); assertTrue(AggregationInspectionHelper.hasValue(result)); @@ -179,7 +180,7 @@ public void testSingleValuedField() throws Exception { private void assertCentroid(RandomIndexWriter w, GeoPoint expectedCentroid) throws IOException { MappedFieldType fieldType = new GeoShapeWithDocValuesFieldType("field", - true, true, Orientation.RIGHT, null, Collections.emptyMap()); + true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); GeoCentroidAggregationBuilder aggBuilder = new GeoCentroidAggregationBuilder("my_agg") .field("field"); try (IndexReader reader = w.getReader()) { diff --git a/x-pack/plugin/vector-tile/build.gradle b/x-pack/plugin/vector-tile/build.gradle index 337d4986cbf1d..5cb14d2f82ba7 100644 --- a/x-pack/plugin/vector-tile/build.gradle +++ b/x-pack/plugin/vector-tile/build.gradle @@ -22,11 +22,12 @@ esplugin { name 'vector-tile' description 'A plugin for mapbox vector tile features' classname 'org.elasticsearch.xpack.vectortile.VectorTilePlugin' - extendedPlugins = ['x-pack-core'] + extendedPlugins = ['spatial'] } dependencies { compileOnly project(path: xpackModule('core')) + compileOnly project(path: xpackModule('spatial')) testImplementation(testArtifact(project(xpackModule('core')))) api "com.wdtinc:mapbox-vector-tile:3.1.0" api "com.google.protobuf:protobuf-java:3.14.0" diff --git a/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/SpatialVectorTileExtension.java b/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/SpatialVectorTileExtension.java new file mode 100644 index 0000000000000..c6bf602995897 --- /dev/null +++ b/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/SpatialVectorTileExtension.java @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.vectortile; + +import org.elasticsearch.common.geo.GeoFormatterFactory; +import org.elasticsearch.geometry.Geometry; +import org.elasticsearch.geometry.GeometryCollection; +import org.elasticsearch.xpack.spatial.VectorTileExtension; +import org.elasticsearch.xpack.vectortile.feature.FeatureFactory; + +/** + * Unique implementation of VectorTileExtension so we can transform geometries + * into its vector tile representation from the spatial module. + */ +public class SpatialVectorTileExtension implements VectorTileExtension { + + @Override + public GeoFormatterFactory.VectorTileEngine getVectorTileEngine() { + return (z, x, y, extent) -> { + final FeatureFactory featureFactory = new FeatureFactory(z, x, y, extent); + return geometries -> { + final Geometry geometry = (geometries.size() == 1) ? geometries.get(0) : new GeometryCollection<>(geometries); + return featureFactory.getFeatures(geometry); + }; + }; + } +} diff --git a/x-pack/plugin/vector-tile/src/main/resources/META-INF/services/org.elasticsearch.xpack.spatial.VectorTileExtension b/x-pack/plugin/vector-tile/src/main/resources/META-INF/services/org.elasticsearch.xpack.spatial.VectorTileExtension new file mode 100644 index 0000000000000..5f2a083ea5410 --- /dev/null +++ b/x-pack/plugin/vector-tile/src/main/resources/META-INF/services/org.elasticsearch.xpack.spatial.VectorTileExtension @@ -0,0 +1,8 @@ +# +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. +# + +org.elasticsearch.xpack.vectortile.SpatialVectorTileExtension From d6ed8deef247d983a1e401b5104b6d70d413a9fa Mon Sep 17 00:00:00 2001 From: iverase Date: Tue, 27 Jul 2021 14:23:49 +0200 Subject: [PATCH 5/9] iter --- .../mapper/GeoShapeWithDocValuesFieldTypeTests.java | 12 +++++------- .../xpack/vectortile/SpatialVectorTileExtension.java | 4 +++- .../xpack/vectortile/feature/FeatureFactory.java | 4 ++-- .../xpack/vectortile/rest/RestVectorTileAction.java | 1 + .../feature/FeatureFactoriesConsistencyTests.java | 8 ++++---- .../vectortile/feature/FeatureFactoryTests.java | 8 ++++---- 6 files changed, 19 insertions(+), 18 deletions(-) diff --git a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java index ca46f6a2461e0..939c6f13fb2fa 100644 --- a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java +++ b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java @@ -110,13 +110,11 @@ private void fetchVectorTile(Geometry geometry) throws IOException { featureFactory = new FeatureFactory(z, x, y, 4096); } - List sourceValue = fetchSourceValue(mapper, WellKnownText.toWKT(geometry), mvtString); - List features = featureFactory.getFeatures(geometry); - if (sourceValue.size() == 0) { - assertThat(features.size(), Matchers.equalTo(0)); - } else { - assertThat(sourceValue.size(), Matchers.equalTo(1)); - assertThat(sourceValue.get(0), Matchers.equalTo(features.get(0))); + final List sourceValue = fetchSourceValue(mapper, WellKnownText.toWKT(geometry), mvtString); + final List features = featureFactory.getFeatures(geometry); + assertThat(features.size(), Matchers.equalTo(sourceValue.size())); + for (int i = 0; i < features.size(); i++) { + assertThat(sourceValue.get(i), Matchers.equalTo(features.get(i))); } } } diff --git a/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/SpatialVectorTileExtension.java b/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/SpatialVectorTileExtension.java index c6bf602995897..261199c24c9ef 100644 --- a/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/SpatialVectorTileExtension.java +++ b/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/SpatialVectorTileExtension.java @@ -13,6 +13,8 @@ import org.elasticsearch.xpack.spatial.VectorTileExtension; import org.elasticsearch.xpack.vectortile.feature.FeatureFactory; +import java.util.ArrayList; + /** * Unique implementation of VectorTileExtension so we can transform geometries * into its vector tile representation from the spatial module. @@ -25,7 +27,7 @@ public GeoFormatterFactory.VectorTileEngine getVectorTileEngine() { final FeatureFactory featureFactory = new FeatureFactory(z, x, y, extent); return geometries -> { final Geometry geometry = (geometries.size() == 1) ? geometries.get(0) : new GeometryCollection<>(geometries); - return featureFactory.getFeatures(geometry); + return new ArrayList<>(featureFactory.getFeatures(geometry)); }; }; } diff --git a/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactory.java b/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactory.java index 8fc7776b9b3eb..0fab0ce78f4b7 100644 --- a/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactory.java +++ b/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactory.java @@ -63,7 +63,7 @@ public FeatureFactory(int z, int x, int y, int extent) { this.layerParams = new MvtLayerParams(extent, extent); } - public List getFeatures(Geometry geometry) { + public List getFeatures(Geometry geometry) { final TileGeomResult tileGeom = JtsAdapter.createTileGeom( JtsAdapter.flatFeatureList(geometry.visit(builder)), tileEnvelope, @@ -74,7 +74,7 @@ public List getFeatures(Geometry geometry) { ); // MVT tile geometry to MVT features final List features = JtsAdapter.toFeatures(tileGeom.mvtGeoms, layerProps, userDataIgnoreConverter); - final List byteFeatures = new ArrayList<>(features.size()); + final List byteFeatures = new ArrayList<>(features.size()); features.forEach(f -> byteFeatures.add(f.toByteArray())); return byteFeatures; } diff --git a/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/rest/RestVectorTileAction.java b/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/rest/RestVectorTileAction.java index f7b1fe04d0365..c85e2ca29f92f 100644 --- a/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/rest/RestVectorTileAction.java +++ b/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/rest/RestVectorTileAction.java @@ -222,6 +222,7 @@ private static SearchRequestBuilder searchRequestBuilder(RestCancellableNodeClie return searchRequestBuilder; } + @SuppressWarnings("unchecked") private static VectorTile.Tile.Layer.Builder buildHitsLayer(SearchHit[] hits, VectorTileRequest request) throws IOException { final VectorTile.Tile.Layer.Builder hitsLayerBuilder = VectorTileUtils.createLayerBuilder(HITS_LAYER, request.getExtent()); final List fields = request.getFieldAndFormats(); diff --git a/x-pack/plugin/vector-tile/src/test/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactoriesConsistencyTests.java b/x-pack/plugin/vector-tile/src/test/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactoriesConsistencyTests.java index ace046dd8b896..5ba51d51636d4 100644 --- a/x-pack/plugin/vector-tile/src/test/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactoriesConsistencyTests.java +++ b/x-pack/plugin/vector-tile/src/test/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactoriesConsistencyTests.java @@ -42,13 +42,13 @@ public void testPoint() throws IOException { double lon = randomValueOtherThanMany((l) -> rectangle.getMinX() > l || rectangle.getMaxX() < l, GeoTestUtil::nextLongitude); byte[] b1 = builder.point(lon, lat); Point point = new Point(lon, lat); - byte[] b2 = (byte[]) factory.getFeatures(point).get(0); + byte[] b2 = factory.getFeatures(point).get(0); assertArrayEquals(b1, b2); points.add(point); geoPoints.add(new GeoPoint(lat, lon)); } byte[] b1 = builder.points(geoPoints); - byte[] b2 = (byte[]) factory.getFeatures(new MultiPoint(points)).get(0); + byte[] b2 = factory.getFeatures(new MultiPoint(points)).get(0); assertArrayEquals(b1, b2); } @@ -65,7 +65,7 @@ public void testIssue74341() throws IOException { FeatureFactory factory = new FeatureFactory(z, x, y, extent); byte[] b1 = builder.point(lon, lat); Point point = new Point(lon, lat); - byte[] b2 = (byte[]) factory.getFeatures(point).get(0); + byte[] b2 = factory.getFeatures(point).get(0); assertThat(Arrays.equals(b1, b2), Matchers.equalTo(false)); } @@ -86,7 +86,7 @@ public void testRectangle() throws IOException { Rectangle r = GeoTileUtils.toBoundingBox(x, y, z); for (int i = 0; i < extent; i++) { byte[] b1 = builder.box(r.getMinLon(), r.getMaxLon(), r.getMinLat(), r.getMaxLat()); - byte[] b2 = (byte[]) factory.getFeatures(r).get(0); + byte[] b2 = factory.getFeatures(r).get(0); assertArrayEquals(extent + "", b1, b2); } } diff --git a/x-pack/plugin/vector-tile/src/test/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactoryTests.java b/x-pack/plugin/vector-tile/src/test/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactoryTests.java index 5717d5a17004d..6ed5ebef5fb7f 100644 --- a/x-pack/plugin/vector-tile/src/test/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactoryTests.java +++ b/x-pack/plugin/vector-tile/src/test/java/org/elasticsearch/xpack/vectortile/feature/FeatureFactoryTests.java @@ -99,16 +99,16 @@ private void doTestGeometry(Function provider, Consumer byteFeatures = builder.getFeatures(provider.apply(r)); + final List byteFeatures = builder.getFeatures(provider.apply(r)); final List features = new ArrayList<>(byteFeatures.size()); - for (Object byteFeature : byteFeatures) { - features.add(VectorTile.Tile.Feature.parseFrom((byte[]) byteFeature)); + for (byte[] byteFeature : byteFeatures) { + features.add(VectorTile.Tile.Feature.parseFrom(byteFeature)); } consumer.accept(features); } { final Rectangle r = GeoTileUtils.toBoundingBox(x - 2, y, z); - final List byteFeatures = builder.getFeatures(provider.apply(r)); + final List byteFeatures = builder.getFeatures(provider.apply(r)); assertThat(byteFeatures.size(), Matchers.equalTo(0)); } } From 2ce4c4bbb07629da43ddf800c710a6be9d9eb578 Mon Sep 17 00:00:00 2001 From: iverase Date: Tue, 27 Jul 2021 14:37:25 +0200 Subject: [PATCH 6/9] iter --- .../xpack/vectortile/rest/RestVectorTileAction.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/rest/RestVectorTileAction.java b/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/rest/RestVectorTileAction.java index c85e2ca29f92f..b9ad4abc44e6e 100644 --- a/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/rest/RestVectorTileAction.java +++ b/x-pack/plugin/vector-tile/src/main/java/org/elasticsearch/xpack/vectortile/rest/RestVectorTileAction.java @@ -233,8 +233,7 @@ private static VectorTile.Tile.Layer.Builder buildHitsLayer(SearchHit[] hits, Ve if (geoField == null) { continue; } - final List bytesFeatures = geoField.getValues(); - for (Object feature : bytesFeatures) { + for (Object feature : geoField) { featureBuilder.clear(); featureBuilder.mergeFrom((byte[]) feature); VectorTileUtils.addPropertyToFeature(featureBuilder, layerProps, ID_TAG, searchHit.getId()); From aa4e3a7a6eadc702ea3a618b3fd35399d0981895 Mon Sep 17 00:00:00 2001 From: iverase Date: Tue, 27 Jul 2021 19:34:31 +0200 Subject: [PATCH 7/9] don't propagate SetOnce to mapper --- .../xpack/spatial/SpatialPlugin.java | 9 +++++++-- .../GeoShapeWithDocValuesFieldMapper.java | 18 ++++++++---------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/SpatialPlugin.java b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/SpatialPlugin.java index cc00f0728b4e0..7ed67578767ed 100644 --- a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/SpatialPlugin.java +++ b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/SpatialPlugin.java @@ -72,9 +72,10 @@ public class SpatialPlugin extends GeoPlugin implements ActionPlugin, MapperPlug protected XPackLicenseState getLicenseState() { return XPackPlugin.getSharedLicenseState(); } - // register the vector tile factory from a different module private final SetOnce vectorTileExtension = new SetOnce<>(); + // make sure extensions are loaded before calling the mappers + private boolean extensionsLoaded; @Override public List> getActions() { @@ -86,10 +87,12 @@ protected XPackLicenseState getLicenseState() { @Override public Map getMappers() { + assert extensionsLoaded; Map mappers = new HashMap<>(super.getMappers()); mappers.put(ShapeFieldMapper.CONTENT_TYPE, ShapeFieldMapper.PARSER); mappers.put(PointFieldMapper.CONTENT_TYPE, PointFieldMapper.PARSER); - mappers.put(GeoShapeWithDocValuesFieldMapper.CONTENT_TYPE, new GeoShapeWithDocValuesFieldMapper.TypeParser(vectorTileExtension)); + mappers.put(GeoShapeWithDocValuesFieldMapper.CONTENT_TYPE, + new GeoShapeWithDocValuesFieldMapper.TypeParser(vectorTileExtension.get())); return Collections.unmodifiableMap(mappers); } @@ -213,6 +216,8 @@ private ContextParser checkLicense(ContextParser realP @Override public void loadExtensions(ExtensionLoader loader) { + assert extensionsLoaded == false; + extensionsLoaded = true; // we only expect one vector tile extension that comes from the vector tile module. loader.loadExtensions(VectorTileExtension.class).forEach(vectorTileExtension::set); } diff --git a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapper.java b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapper.java index f1f43c7acf1ce..5d455d497634e 100644 --- a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapper.java +++ b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapper.java @@ -13,7 +13,6 @@ import org.apache.lucene.search.IndexOrDocValuesQuery; import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.Query; -import org.apache.lucene.util.SetOnce; import org.elasticsearch.Version; import org.elasticsearch.common.Explicit; import org.elasticsearch.common.geo.GeoFormatterFactory; @@ -97,10 +96,10 @@ public static class Builder extends FieldMapper.Builder { final Parameter> meta = Parameter.metaParam(); private final Version version; - private final SetOnce vectorTileExtension; + private final VectorTileExtension vectorTileExtension; public Builder(String name, Version version, boolean ignoreMalformedByDefault, boolean coerceByDefault, - SetOnce vectorTileExtension) { + VectorTileExtension vectorTileExtension) { super(name); this.version = version; this.vectorTileExtension = vectorTileExtension; @@ -146,10 +145,10 @@ public GeoShapeWithDocValuesFieldMapper build(ContentPath contentPath) { public static final class GeoShapeWithDocValuesFieldType extends AbstractShapeGeometryFieldType implements GeoShapeQueryable { - private final SetOnce vectorTileExtension; + private final VectorTileExtension vectorTileExtension; public GeoShapeWithDocValuesFieldType(String name, boolean indexed, boolean hasDocValues, Orientation orientation, GeoShapeParser parser, - SetOnce vectorTileExtension, Map meta) { + VectorTileExtension vectorTileExtension, Map meta) { super(name, indexed, false, hasDocValues, parser, orientation, meta); this.vectorTileExtension = vectorTileExtension; } @@ -187,20 +186,19 @@ public Query geoShapeQuery(Geometry shape, String fieldName, ShapeRelation relat protected Function, List> getFormatter(String format) { return GeoFormatterFactory.getFormatter(format, Function.identity(), (z, x, y, extent) -> { - final VectorTileExtension extension = vectorTileExtension.get(); - if (extension == null) { + if (vectorTileExtension == null) { throw new IllegalArgumentException("vector tile format is not supported"); } - return extension.getVectorTileEngine().getFormatter(z, x, y, extent); + return vectorTileExtension.getVectorTileEngine().getFormatter(z, x, y, extent); }); } } public static class TypeParser implements Mapper.TypeParser { - private final SetOnce vectorTileExtension; + private final VectorTileExtension vectorTileExtension; - public TypeParser(SetOnce vectorTileExtension) { + public TypeParser(VectorTileExtension vectorTileExtension) { this.vectorTileExtension = vectorTileExtension; } From 15a595f6cf24c5c4a4d0a1bf257851d0efd681d1 Mon Sep 17 00:00:00 2001 From: iverase Date: Tue, 27 Jul 2021 22:40:21 +0200 Subject: [PATCH 8/9] fix compile issue --- .../mapper/GeoShapeWithDocValuesFieldTypeTests.java | 6 +----- .../xpack/spatial/ingest/CircleProcessorTests.java | 3 +-- .../bucket/geogrid/GeoShapeGeoGridTestCase.java | 3 +-- .../metrics/GeoShapeBoundsAggregatorTests.java | 11 +++++------ .../metrics/GeoShapeCentroidAggregatorTests.java | 11 +++++------ 5 files changed, 13 insertions(+), 21 deletions(-) diff --git a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java index 939c6f13fb2fa..30d6bbb6ab990 100644 --- a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java +++ b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldTypeTests.java @@ -7,7 +7,6 @@ package org.elasticsearch.xpack.spatial.index.mapper; -import org.apache.lucene.util.SetOnce; import org.elasticsearch.Version; import org.elasticsearch.geo.GeometryTestUtils; import org.elasticsearch.geometry.Geometry; @@ -16,7 +15,6 @@ import org.elasticsearch.index.mapper.FieldTypeTestCase; import org.elasticsearch.index.mapper.GeoShapeFieldMapper; import org.elasticsearch.index.mapper.MappedFieldType; -import org.elasticsearch.xpack.spatial.VectorTileExtension; import org.elasticsearch.xpack.vectortile.SpatialVectorTileExtension; import org.elasticsearch.xpack.vectortile.feature.FeatureFactory; import org.hamcrest.Matchers; @@ -91,10 +89,8 @@ public void testFetchVectorTile() throws IOException { } private void fetchVectorTile(Geometry geometry) throws IOException { - final SetOnce vectorTileExtension = new SetOnce<>(); - vectorTileExtension.set(new SpatialVectorTileExtension()); final MappedFieldType mapper - = new GeoShapeWithDocValuesFieldMapper.Builder("field", Version.CURRENT, false, false, vectorTileExtension) + = new GeoShapeWithDocValuesFieldMapper.Builder("field", Version.CURRENT, false, false, new SpatialVectorTileExtension()) .build(new ContentPath()).fieldType(); final int z = randomIntBetween(1, 10); int x = randomIntBetween(0, (1 << z) - 1); diff --git a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/ingest/CircleProcessorTests.java b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/ingest/CircleProcessorTests.java index bd5c14a6fb1fd..13f53e560710c 100644 --- a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/ingest/CircleProcessorTests.java +++ b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/ingest/CircleProcessorTests.java @@ -13,7 +13,6 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.store.Directory; -import org.apache.lucene.util.SetOnce; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.core.Tuple; import org.elasticsearch.common.geo.GeoJson; @@ -214,7 +213,7 @@ public void testGeoShapeQueryAcrossDateline() throws IOException { Geometry geometry = SpatialUtils.createRegularGeoShapePolygon(circle, numSides); GeoShapeWithDocValuesFieldType shapeType - = new GeoShapeWithDocValuesFieldType(fieldName, true, false, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); + = new GeoShapeWithDocValuesFieldType(fieldName, true, false, Orientation.RIGHT, null, null, Collections.emptyMap()); SearchExecutionContext mockedContext = mock(SearchExecutionContext.class); when(mockedContext.getFieldType(any())).thenReturn(shapeType); diff --git a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/bucket/geogrid/GeoShapeGeoGridTestCase.java b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/bucket/geogrid/GeoShapeGeoGridTestCase.java index 657d86de001a3..afc331dcb8622 100644 --- a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/bucket/geogrid/GeoShapeGeoGridTestCase.java +++ b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/bucket/geogrid/GeoShapeGeoGridTestCase.java @@ -18,7 +18,6 @@ import org.apache.lucene.search.Query; import org.apache.lucene.store.Directory; import org.apache.lucene.util.BytesRef; -import org.apache.lucene.util.SetOnce; import org.elasticsearch.core.CheckedConsumer; import org.elasticsearch.common.geo.GeoBoundingBox; import org.elasticsearch.common.geo.Orientation; @@ -294,7 +293,7 @@ private void testCase(Query query, int precision, GeoBoundingBox geoBoundingBox, } MappedFieldType fieldType - = new GeoShapeWithDocValuesFieldType(FIELD_NAME, true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); + = new GeoShapeWithDocValuesFieldType(FIELD_NAME, true, true, Orientation.RIGHT, null, null, Collections.emptyMap()); Aggregator aggregator = createAggregator(aggregationBuilder, indexSearcher, fieldType); aggregator.preCollection(); diff --git a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/metrics/GeoShapeBoundsAggregatorTests.java b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/metrics/GeoShapeBoundsAggregatorTests.java index 0feb060ecd2fc..4934c302e833c 100644 --- a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/metrics/GeoShapeBoundsAggregatorTests.java +++ b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/metrics/GeoShapeBoundsAggregatorTests.java @@ -16,7 +16,6 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.store.Directory; -import org.apache.lucene.util.SetOnce; import org.elasticsearch.common.geo.Orientation; import org.elasticsearch.geo.GeometryTestUtils; import org.elasticsearch.geometry.Geometry; @@ -59,7 +58,7 @@ public void testEmpty() throws Exception { .wrapLongitude(false); MappedFieldType fieldType - = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); + = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, null, Collections.emptyMap()); try (IndexReader reader = w.getReader()) { IndexSearcher searcher = new IndexSearcher(reader); InternalGeoBounds bounds = searchAndReduce(searcher, new MatchAllDocsQuery(), aggBuilder, fieldType); @@ -87,7 +86,7 @@ public void testUnmappedFieldWithDocs() throws Exception { .wrapLongitude(false); MappedFieldType fieldType - = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); + = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, null, Collections.emptyMap()); try (IndexReader reader = w.getReader()) { IndexSearcher searcher = new IndexSearcher(reader); InternalGeoBounds bounds = searchAndReduce(searcher, new MatchAllDocsQuery(), aggBuilder, fieldType); @@ -109,7 +108,7 @@ public void testMissing() throws Exception { w.addDocument(doc); MappedFieldType fieldType - = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); + = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, null, Collections.emptyMap()); Point point = GeometryTestUtils.randomPoint(false); double lon = GeoEncodingUtils.decodeLongitude(GeoEncodingUtils.encodeLongitude(point.getX())); @@ -141,7 +140,7 @@ public void testInvalidMissing() throws Exception { w.addDocument(doc); MappedFieldType fieldType - = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); + = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, null, Collections.emptyMap()); GeoBoundsAggregationBuilder aggBuilder = new GeoBoundsAggregationBuilder("my_agg") .field("field") @@ -201,7 +200,7 @@ public void testRandomShapes() throws Exception { .wrapLongitude(false); MappedFieldType fieldType - = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); + = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, null, Collections.emptyMap()); try (IndexReader reader = w.getReader()) { IndexSearcher searcher = new IndexSearcher(reader); InternalGeoBounds bounds = searchAndReduce(searcher, new MatchAllDocsQuery(), aggBuilder, fieldType); diff --git a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/metrics/GeoShapeCentroidAggregatorTests.java b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/metrics/GeoShapeCentroidAggregatorTests.java index 1a62dd75d9dbb..ab7a22445fe9e 100644 --- a/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/metrics/GeoShapeCentroidAggregatorTests.java +++ b/x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/search/aggregations/metrics/GeoShapeCentroidAggregatorTests.java @@ -15,7 +15,6 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.store.Directory; -import org.apache.lucene.util.SetOnce; import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.geo.Orientation; import org.elasticsearch.geo.GeometryTestUtils; @@ -64,7 +63,7 @@ public void testEmpty() throws Exception { .field("field"); MappedFieldType fieldType - = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); + = new GeoShapeWithDocValuesFieldType("field", true, true, Orientation.RIGHT, null, null, Collections.emptyMap()); try (IndexReader reader = w.getReader()) { IndexSearcher searcher = new IndexSearcher(reader); InternalGeoCentroid result = searchAndReduce(searcher, new MatchAllDocsQuery(), aggBuilder, fieldType); @@ -87,12 +86,12 @@ public void testUnmapped() throws Exception { IndexSearcher searcher = new IndexSearcher(reader); MappedFieldType fieldType = new GeoShapeWithDocValuesFieldType("another_field", - true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); + true, true, Orientation.RIGHT, null, null, Collections.emptyMap()); InternalGeoCentroid result = searchAndReduce(searcher, new MatchAllDocsQuery(), aggBuilder, fieldType); assertNull(result.centroid()); fieldType = new GeoShapeWithDocValuesFieldType("field", - true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); + true, true, Orientation.RIGHT, null, null, Collections.emptyMap()); result = searchAndReduce(searcher, new MatchAllDocsQuery(), aggBuilder, fieldType); assertNull(result.centroid()); assertFalse(AggregationInspectionHelper.hasValue(result)); @@ -117,7 +116,7 @@ public void testUnmappedWithMissing() throws Exception { IndexSearcher searcher = new IndexSearcher(reader); MappedFieldType fieldType = new GeoShapeWithDocValuesFieldType("another_field", - true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); + true, true, Orientation.RIGHT, null, null, Collections.emptyMap()); InternalGeoCentroid result = searchAndReduce(searcher, new MatchAllDocsQuery(), aggBuilder, fieldType); assertThat(result.centroid(), equalTo(expectedCentroid)); assertTrue(AggregationInspectionHelper.hasValue(result)); @@ -180,7 +179,7 @@ public void testSingleValuedField() throws Exception { private void assertCentroid(RandomIndexWriter w, GeoPoint expectedCentroid) throws IOException { MappedFieldType fieldType = new GeoShapeWithDocValuesFieldType("field", - true, true, Orientation.RIGHT, null, new SetOnce<>(), Collections.emptyMap()); + true, true, Orientation.RIGHT, null, null, Collections.emptyMap()); GeoCentroidAggregationBuilder aggBuilder = new GeoCentroidAggregationBuilder("my_agg") .field("field"); try (IndexReader reader = w.getReader()) { From a9e0a70a0541ca17f2ebd4f9d4f6e14d3769206d Mon Sep 17 00:00:00 2001 From: iverase Date: Wed, 28 Jul 2021 07:26:39 +0200 Subject: [PATCH 9/9] iter --- .../java/org/elasticsearch/xpack/spatial/SpatialPlugin.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/SpatialPlugin.java b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/SpatialPlugin.java index 7ed67578767ed..b50854572f43a 100644 --- a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/SpatialPlugin.java +++ b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/SpatialPlugin.java @@ -74,8 +74,6 @@ protected XPackLicenseState getLicenseState() { } // register the vector tile factory from a different module private final SetOnce vectorTileExtension = new SetOnce<>(); - // make sure extensions are loaded before calling the mappers - private boolean extensionsLoaded; @Override public List> getActions() { @@ -87,7 +85,6 @@ protected XPackLicenseState getLicenseState() { @Override public Map getMappers() { - assert extensionsLoaded; Map mappers = new HashMap<>(super.getMappers()); mappers.put(ShapeFieldMapper.CONTENT_TYPE, ShapeFieldMapper.PARSER); mappers.put(PointFieldMapper.CONTENT_TYPE, PointFieldMapper.PARSER); @@ -216,8 +213,6 @@ private ContextParser checkLicense(ContextParser realP @Override public void loadExtensions(ExtensionLoader loader) { - assert extensionsLoaded == false; - extensionsLoaded = true; // we only expect one vector tile extension that comes from the vector tile module. loader.loadExtensions(VectorTileExtension.class).forEach(vectorTileExtension::set); }