Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vector tiles: order hits by geometry size by default #75621

Merged
merged 4 commits into from
Jul 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ class org.elasticsearch.index.fielddata.ScriptDocValues$Geometry {
int getDimensionalType()
org.elasticsearch.common.geo.GeoPoint getCentroid()
org.elasticsearch.common.geo.GeoBoundingBox getBoundingBox()
double getMercatorWidth()
double getMercatorHeight()
}

class org.elasticsearch.index.fielddata.ScriptDocValues$GeoPoints {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,20 @@ setup:
source: "doc['geo_point'].getDimensionalType()"
- match: { hits.hits.0.fields.type.0: 0 }

- do:
search:
rest_total_hits_as_int: true
body:
script_fields:
width:
script:
source: "doc['geo_point'].getMercatorWidth()"
height:
script:
source: "doc['geo_point'].getMercatorHeight()"
- match: { hits.hits.0.fields.width.0: 0.0 }
- match: { hits.hits.0.fields.height.0: 0.0 }

---
"ip":
- do:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
/*
* 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.
* 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.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;
public static final double MERCATOR_BOUNDS = 20037508.34;
private static final double MERCATOR_FACTOR = MERCATOR_BOUNDS / 180.0;

/**
* Transforms WGS84 longitude to a Spherical mercator longitude
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,10 @@ public abstract static class Geometry<T> extends ScriptDocValues<T> {
public abstract GeoBoundingBox getBoundingBox();
/** Returns the centroid of this geometry */
public abstract GeoPoint getCentroid();
/** Returns the width of the bounding box diagonal in the spherical Mercator projection (meters) */
public abstract double getMercatorWidth();
/** Returns the height of the bounding box diagonal in the spherical Mercator projection (meters) */
public abstract double getMercatorHeight();
}

public static final class GeoPoints extends Geometry<GeoPoint> {
Expand Down Expand Up @@ -418,6 +422,16 @@ public GeoPoint getCentroid() {
return size() == 0 ? null : centroid;
}

@Override
public double getMercatorWidth() {
return 0;
}

@Override
public double getMercatorHeight() {
return 0;
}

@Override
public GeoBoundingBox getBoundingBox() {
return size() == 0 ? null : boundingBox;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* 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.common.geo;

import org.elasticsearch.geo.GeometryTestUtils;
import org.elasticsearch.geometry.Rectangle;
import org.elasticsearch.search.aggregations.bucket.geogrid.GeoTileUtils;
import org.elasticsearch.test.ESTestCase;
import org.hamcrest.Matchers;

import static org.elasticsearch.common.geo.SphericalMercatorUtils.MERCATOR_BOUNDS;
import static org.elasticsearch.common.geo.SphericalMercatorUtils.lonToSphericalMercator;
import static org.elasticsearch.common.geo.SphericalMercatorUtils.latToSphericalMercator;
import static org.elasticsearch.common.geo.SphericalMercatorUtils.recToSphericalMercator;

public class SphericalMercatorUtilTests extends ESTestCase {

public void testLon() {
assertThat(lonToSphericalMercator(180.0), Matchers.equalTo(MERCATOR_BOUNDS));
assertThat(lonToSphericalMercator(-180.0), Matchers.equalTo(-MERCATOR_BOUNDS));
assertThat(lonToSphericalMercator(0.0), Matchers.equalTo(0.0));
final double lon = lonToSphericalMercator(GeometryTestUtils.randomLon());
assertThat(lon, Matchers.greaterThanOrEqualTo(-MERCATOR_BOUNDS));
assertThat(lon, Matchers.lessThanOrEqualTo(MERCATOR_BOUNDS));
}

public void testLat() {
assertThat(latToSphericalMercator(GeoTileUtils.LATITUDE_MASK), Matchers.closeTo(MERCATOR_BOUNDS, 1e-7));
assertThat(latToSphericalMercator(-GeoTileUtils.LATITUDE_MASK), Matchers.closeTo(-MERCATOR_BOUNDS, 1e-7));
assertThat(latToSphericalMercator(0.0), Matchers.closeTo(0, 1e-7));
final double lat = latToSphericalMercator(randomValueOtherThanMany(
l -> l >= GeoTileUtils.LATITUDE_MASK || l <= -GeoTileUtils.LATITUDE_MASK,
GeometryTestUtils::randomLat
));
assertThat(lat, Matchers.greaterThanOrEqualTo(-MERCATOR_BOUNDS));
assertThat(lat, Matchers.lessThanOrEqualTo(MERCATOR_BOUNDS));
}

public void testRectangle() {
Rectangle rect = GeometryTestUtils.randomRectangle();
Rectangle mercatorRect = recToSphericalMercator(rect);
assertThat(mercatorRect.getMinX(), Matchers.equalTo(lonToSphericalMercator(rect.getMinX())));
assertThat(mercatorRect.getMaxX(), Matchers.equalTo(lonToSphericalMercator(rect.getMaxX())));
assertThat(mercatorRect.getMinY(), Matchers.equalTo(latToSphericalMercator(rect.getMinY())));
assertThat(mercatorRect.getMaxY(), Matchers.equalTo(latToSphericalMercator(rect.getMaxY())));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
import java.util.Collection;
import java.util.Collections;

import static org.elasticsearch.common.geo.SphericalMercatorUtils.latToSphericalMercator;
import static org.elasticsearch.common.geo.SphericalMercatorUtils.lonToSphericalMercator;

public abstract class AbstractAtomicGeoShapeShapeFieldData implements LeafGeoShapeFieldData {

@Override
Expand Down Expand Up @@ -88,6 +91,16 @@ public GeoPoint getCentroid() {
return value == null ? null : centroid;
}

@Override
public double getMercatorWidth() {
return lonToSphericalMercator(boundingBox.right()) - lonToSphericalMercator(boundingBox.left());
}

@Override
public double getMercatorHeight() {
return latToSphericalMercator(boundingBox.top()) - latToSphericalMercator(boundingBox.bottom());
}

@Override
public GeoBoundingBox getBoundingBox() {
return value == null ? null : boundingBox;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,19 @@ setup:
source: "doc['geo_shape'].get(0)"

- match: { error.root_cause.0.reason: "cannot write xcontent for geo_shape doc value" }

---
"diagonal length":
- do:
search:
rest_total_hits_as_int: true
body:
script_fields:
width:
script:
source: "doc['geo_shape'].getMercatorWidth()"
height:
script:
source: "doc['geo_shape'].getMercatorHeight()"
- match: { hits.hits.0.fields.width.0: 389.62170283915475 }
- match: { hits.hits.0.fields.height.0: 333.37976840604097 }
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ public void testBasicGet() throws Exception {
assertThat(tile.getLayersCount(), Matchers.equalTo(3));
assertLayer(tile, HITS_LAYER, 4096, 33, 1);
assertLayer(tile, AGGS_LAYER, 4096, 1, 1);
assertLayer(tile, META_LAYER, 4096, 1, 14);
assertLayer(tile, META_LAYER, 4096, 1, 13);
}

public void testIndexAllGet() throws Exception {
Expand All @@ -248,7 +248,7 @@ public void testIndexAllGet() throws Exception {
// 33 points, 1 polygon and two from geometry collection
assertLayer(tile, HITS_LAYER, 4096, 36, 1);
assertLayer(tile, AGGS_LAYER, 4096, 256 * 256, 1);
assertLayer(tile, META_LAYER, 4096, 1, 14);
assertLayer(tile, META_LAYER, 4096, 1, 13);
}

public void testExtent() throws Exception {
Expand All @@ -258,7 +258,7 @@ public void testExtent() throws Exception {
assertThat(tile.getLayersCount(), Matchers.equalTo(3));
assertLayer(tile, HITS_LAYER, 256, 33, 1);
assertLayer(tile, AGGS_LAYER, 256, 1, 1);
assertLayer(tile, META_LAYER, 256, 1, 14);
assertLayer(tile, META_LAYER, 256, 1, 13);
}

public void testExtentURL() throws Exception {
Expand All @@ -271,7 +271,7 @@ public void testExtentURL() throws Exception {
assertThat(tile.getLayersCount(), Matchers.equalTo(3));
assertLayer(tile, HITS_LAYER, 512, 33, 1);
assertLayer(tile, AGGS_LAYER, 512, 1, 1);
assertLayer(tile, META_LAYER, 512, 1, 14);
assertLayer(tile, META_LAYER, 512, 1, 13);
}

public void testExactBounds() throws Exception {
Expand Down Expand Up @@ -327,7 +327,7 @@ public void testGridPrecision() throws Exception {
assertThat(tile.getLayersCount(), Matchers.equalTo(3));
assertLayer(tile, HITS_LAYER, 4096, 33, 1);
assertLayer(tile, AGGS_LAYER, 4096, 1, 1);
assertLayer(tile, META_LAYER, 4096, 1, 14);
assertLayer(tile, META_LAYER, 4096, 1, 13);
}
{
final Request mvtRequest = new Request(getHttpMethod(), INDEX_POINTS + "/_mvt/location/" + z + "/" + x + "/" + y);
Expand All @@ -345,7 +345,7 @@ public void testGridType() throws Exception {
assertThat(tile.getLayersCount(), Matchers.equalTo(3));
assertLayer(tile, HITS_LAYER, 4096, 33, 1);
assertLayer(tile, AGGS_LAYER, 4096, 1, 1);
assertLayer(tile, META_LAYER, 4096, 1, 14);
assertLayer(tile, META_LAYER, 4096, 1, 13);
assertFeatureType(tile, AGGS_LAYER, VectorTile.Tile.GeomType.POINT);
}
{
Expand All @@ -355,7 +355,7 @@ public void testGridType() throws Exception {
assertThat(tile.getLayersCount(), Matchers.equalTo(3));
assertLayer(tile, HITS_LAYER, 4096, 33, 1);
assertLayer(tile, AGGS_LAYER, 4096, 1, 1);
assertLayer(tile, META_LAYER, 4096, 1, 14);
assertLayer(tile, META_LAYER, 4096, 1, 13);
assertFeatureType(tile, AGGS_LAYER, VectorTile.Tile.GeomType.POLYGON);
}
{
Expand All @@ -376,7 +376,7 @@ public void testGridTypeURL() throws Exception {
assertThat(tile.getLayersCount(), Matchers.equalTo(3));
assertLayer(tile, HITS_LAYER, 4096, 33, 1);
assertLayer(tile, AGGS_LAYER, 4096, 1, 1);
assertLayer(tile, META_LAYER, 4096, 1, 14);
assertLayer(tile, META_LAYER, 4096, 1, 13);
assertFeatureType(tile, AGGS_LAYER, VectorTile.Tile.GeomType.POLYGON);
}

Expand All @@ -386,7 +386,7 @@ public void testNoAggLayer() throws Exception {
final VectorTile.Tile tile = execute(mvtRequest);
assertThat(tile.getLayersCount(), Matchers.equalTo(2));
assertLayer(tile, HITS_LAYER, 4096, 33, 1);
assertLayer(tile, META_LAYER, 4096, 1, 9);
assertLayer(tile, META_LAYER, 4096, 1, 8);
}

public void testNoAggLayerURL() throws Exception {
Expand All @@ -398,7 +398,7 @@ public void testNoAggLayerURL() throws Exception {
final VectorTile.Tile tile = execute(mvtRequest);
assertThat(tile.getLayersCount(), Matchers.equalTo(2));
assertLayer(tile, HITS_LAYER, 4096, 33, 1);
assertLayer(tile, META_LAYER, 4096, 1, 9);
assertLayer(tile, META_LAYER, 4096, 1, 8);
}

public void testNoHitsLayer() throws Exception {
Expand All @@ -419,6 +419,31 @@ public void testNoHitsLayerURL() throws Exception {
assertLayer(tile, META_LAYER, 4096, 1, 13);
}

public void testDefaultSort() throws Exception {
{
final Request mvtRequest = new Request(getHttpMethod(), INDEX_POINTS_SHAPES + "/_mvt/location/" + z + "/" + x + "/" + y);
mvtRequest.setJsonEntity("{\"size\": 100 }");
final VectorTile.Tile tile = execute(mvtRequest);
assertThat(tile.getLayersCount(), Matchers.equalTo(3));
assertLayer(tile, HITS_LAYER, 4096, 34, 1);
final VectorTile.Tile.Layer layer = getLayer(tile, HITS_LAYER);
assertThat(layer.getFeatures(0).getType(), Matchers.equalTo(VectorTile.Tile.GeomType.POLYGON));
assertLayer(tile, AGGS_LAYER, 4096, 256 * 256, 1);
assertLayer(tile, META_LAYER, 4096, 1, 13);
}
{
final Request mvtRequest = new Request(getHttpMethod(), INDEX_POINTS_SHAPES + "/_mvt/location/" + z + "/" + x + "/" + y);
mvtRequest.setJsonEntity("{\"size\": 100, \"sort\" : []}"); // override default sort
final VectorTile.Tile tile = execute(mvtRequest);
assertThat(tile.getLayersCount(), Matchers.equalTo(3));
assertLayer(tile, HITS_LAYER, 4096, 34, 1);
final VectorTile.Tile.Layer layer = getLayer(tile, HITS_LAYER);
assertThat(layer.getFeatures(0).getType(), Matchers.equalTo(VectorTile.Tile.GeomType.POINT));
assertLayer(tile, AGGS_LAYER, 4096, 256 * 256, 1);
assertLayer(tile, META_LAYER, 4096, 1, 14);
}
}

public void testRuntimeFieldWithSort() throws Exception {
String runtimeMapping = "\"runtime_mappings\": {\n"
+ " \"width\": {\n"
Expand Down Expand Up @@ -498,7 +523,7 @@ public void testBasicQueryGet() throws Exception {
assertThat(tile.getLayersCount(), Matchers.equalTo(3));
assertLayer(tile, HITS_LAYER, 4096, 1, 1);
assertLayer(tile, AGGS_LAYER, 4096, 1, 1);
assertLayer(tile, META_LAYER, 4096, 1, 14);
assertLayer(tile, META_LAYER, 4096, 1, 13);
}

public void testBasicShape() throws Exception {
Expand All @@ -507,7 +532,7 @@ public void testBasicShape() throws Exception {
assertThat(tile.getLayersCount(), Matchers.equalTo(3));
assertLayer(tile, HITS_LAYER, 4096, 1, 1);
assertLayer(tile, AGGS_LAYER, 4096, 256 * 256, 1);
assertLayer(tile, META_LAYER, 4096, 1, 14);
assertLayer(tile, META_LAYER, 4096, 1, 13);
}

public void testWithFields() throws Exception {
Expand All @@ -517,7 +542,7 @@ public void testWithFields() throws Exception {
assertThat(tile.getLayersCount(), Matchers.equalTo(3));
assertLayer(tile, HITS_LAYER, 4096, 1, 3);
assertLayer(tile, AGGS_LAYER, 4096, 256 * 256, 1);
assertLayer(tile, META_LAYER, 4096, 1, 14);
assertLayer(tile, META_LAYER, 4096, 1, 13);
}

public void testMinAgg() throws Exception {
Expand All @@ -537,7 +562,7 @@ public void testMinAgg() throws Exception {
assertThat(tile.getLayersCount(), Matchers.equalTo(3));
assertLayer(tile, HITS_LAYER, 4096, 1, 1);
assertLayer(tile, AGGS_LAYER, 4096, 256 * 256, 2);
assertLayer(tile, META_LAYER, 4096, 1, 19);
assertLayer(tile, META_LAYER, 4096, 1, 18);
}

private String getHttpMethod() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package org.elasticsearch.xpack.vectortile.feature;

import org.apache.lucene.util.BitUtil;
import org.elasticsearch.common.geo.SphericalMercatorUtils;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.geometry.Point;
import org.elasticsearch.geometry.Rectangle;
Expand Down
Loading