Skip to content

Commit

Permalink
Support cartesian shape with doc values (#88487)
Browse files Browse the repository at this point in the history
Shape field type generated doc values by default now.
  • Loading branch information
craigtaverner committed Jul 14, 2022
1 parent 8b0832d commit 6797d44
Show file tree
Hide file tree
Showing 44 changed files with 2,969 additions and 1,749 deletions.
5 changes: 5 additions & 0 deletions docs/changelog/88487.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 88487
summary: Support cartesian shape with doc values
area: Geo
type: enhancement
issues: []
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public void testPointsOnlyExplicit() throws Exception {
XContentFactory.jsonBuilder()
.startObject()
.startObject("properties")
.startObject(defaultGeoFieldName)
.startObject(defaultFieldName)
.field("type", "geo_shape")
.field("tree", randomBoolean() ? "quadtree" : "geohash")
.field("tree_levels", "6")
Expand All @@ -89,15 +89,15 @@ public void testPointsOnlyExplicit() throws Exception {
MultiPoint multiPoint = GeometryTestUtils.randomMultiPoint(false);
client().prepareIndex("geo_points_only")
.setId("1")
.setSource(GeoJson.toXContent(multiPoint, jsonBuilder().startObject().field(defaultGeoFieldName), null).endObject())
.setSource(GeoJson.toXContent(multiPoint, jsonBuilder().startObject().field(defaultFieldName), null).endObject())
.setRefreshPolicy(IMMEDIATE)
.get();

// POINT
Point point = GeometryTestUtils.randomPoint(false);
client().prepareIndex("geo_points_only")
.setId("2")
.setSource(GeoJson.toXContent(point, jsonBuilder().startObject().field(defaultGeoFieldName), null).endObject())
.setSource(GeoJson.toXContent(point, jsonBuilder().startObject().field(defaultFieldName), null).endObject())
.setRefreshPolicy(IMMEDIATE)
.get();

Expand All @@ -112,7 +112,7 @@ public void testPointsOnly() throws Exception {
XContentFactory.jsonBuilder()
.startObject()
.startObject("properties")
.startObject(defaultGeoFieldName)
.startObject(defaultFieldName)
.field("type", "geo_shape")
.field("tree", randomBoolean() ? "quadtree" : "geohash")
.field("tree_levels", "6")
Expand All @@ -130,7 +130,7 @@ public void testPointsOnly() throws Exception {
try {
client().prepareIndex("geo_points_only")
.setId("1")
.setSource(GeoJson.toXContent(geometry, jsonBuilder().startObject().field(defaultGeoFieldName), null).endObject())
.setSource(GeoJson.toXContent(geometry, jsonBuilder().startObject().field(defaultFieldName), null).endObject())
.setRefreshPolicy(IMMEDIATE)
.get();
} catch (MapperParsingException e) {
Expand All @@ -141,7 +141,7 @@ public void testPointsOnly() throws Exception {

// test that point was inserted
SearchResponse response = client().prepareSearch("geo_points_only")
.setQuery(geoIntersectionQuery(defaultGeoFieldName, geometry))
.setQuery(geoIntersectionQuery(defaultFieldName, geometry))
.get();
assertEquals(1, response.getHits().getTotalHits().value);
}
Expand All @@ -151,13 +151,13 @@ public void testFieldAlias() throws IOException {
XContentFactory.jsonBuilder()
.startObject()
.startObject("properties")
.startObject(defaultGeoFieldName)
.startObject(defaultFieldName)
.field("type", "geo_shape")
.field("tree", randomBoolean() ? "quadtree" : "geohash")
.endObject()
.startObject("alias")
.field("type", "alias")
.field("path", defaultGeoFieldName)
.field("path", defaultFieldName)
.endObject()
.endObject()
.endObject()
Expand All @@ -169,7 +169,7 @@ public void testFieldAlias() throws IOException {
MultiPoint multiPoint = GeometryTestUtils.randomMultiPoint(false);
client().prepareIndex(defaultIndexName)
.setId("1")
.setSource(GeoJson.toXContent(multiPoint, jsonBuilder().startObject().field(defaultGeoFieldName), null).endObject())
.setSource(GeoJson.toXContent(multiPoint, jsonBuilder().startObject().field(defaultFieldName), null).endObject())
.setRefreshPolicy(IMMEDIATE)
.get();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
/**
* Utility class that converts geometries into Lucene-compatible form for indexing in a geo_shape field.
*/
public class GeoShapeIndexer {
public class GeoShapeIndexer implements ShapeIndexer {

private final Orientation orientation;
private final String name;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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.index.mapper;

import org.apache.lucene.index.IndexableField;
import org.elasticsearch.geometry.Geometry;

import java.util.List;

/**
* Utility that converts geometries into Lucene-compatible form for indexing in a shape or geo_shape field.
* Implementing classes handle the specifics for converting either geo_shape into LatLon lucene index format
* or shape into XY lucene format.
*/
public interface ShapeIndexer {
List<IndexableField> indexShape(Geometry geometry);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.elasticsearch.geo.GeometryTestUtils;
import org.elasticsearch.geometry.Point;
import org.elasticsearch.geometry.utils.WellKnownText;
import org.elasticsearch.index.query.GeoShapeQueryBuilder;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.TestGeoShapeFieldMapperPlugin;
import org.elasticsearch.xcontent.XContentBuilder;
Expand All @@ -29,7 +30,19 @@
import static org.elasticsearch.index.query.QueryBuilders.geoShapeQuery;
import static org.elasticsearch.xcontent.XContentFactory.jsonBuilder;

public class GeoPointShapeQueryTests extends GeoPointShapeQueryTestCase {
public class GeoPointShapeQueryTests extends BasePointShapeQueryTestCase<GeoShapeQueryBuilder> {

private final SpatialQueryBuilders<GeoShapeQueryBuilder> geoShapeQueryBuilder = SpatialQueryBuilders.GEO;

@Override
protected SpatialQueryBuilders<GeoShapeQueryBuilder> queryBuilder() {
return geoShapeQueryBuilder;
}

@Override
protected String fieldTypeName() {
return "geo_shape";
}

@SuppressWarnings("deprecation")
@Override
Expand All @@ -55,12 +68,12 @@ public void testFieldAlias() throws IOException {
XContentFactory.jsonBuilder()
.startObject()
.startObject("properties")
.startObject(defaultGeoFieldName)
.startObject(defaultFieldName)
.field("type", "geo_point")
.endObject()
.startObject("alias")
.field("type", "alias")
.field("path", defaultGeoFieldName)
.field("path", defaultFieldName)
.endObject()
.endObject()
.endObject()
Expand All @@ -72,14 +85,28 @@ public void testFieldAlias() throws IOException {
Point point = GeometryTestUtils.randomPoint(false);
client().prepareIndex(defaultIndexName)
.setId("1")
.setSource(jsonBuilder().startObject().field(defaultGeoFieldName, WellKnownText.toWKT(point)).endObject())
.setSource(jsonBuilder().startObject().field(defaultFieldName, WellKnownText.toWKT(point)).endObject())
.setRefreshPolicy(IMMEDIATE)
.get();

SearchResponse response = client().prepareSearch(defaultIndexName).setQuery(geoShapeQuery("alias", point)).get();
assertEquals(1, response.getHits().getTotalHits().value);
}

private final DatelinePointShapeQueryTestCase dateline = new DatelinePointShapeQueryTestCase();

public void testRectangleSpanningDateline() throws Exception {
dateline.testRectangleSpanningDateline(this);
}

public void testPolygonSpanningDateline() throws Exception {
dateline.testPolygonSpanningDateline(this);
}

public void testMultiPolygonSpanningDateline() throws Exception {
dateline.testMultiPolygonSpanningDateline(this);
}

/**
* Produce an array of objects each representing a single point in a variety of
* supported point formats. For `geo_shape` we only support GeoJSON and WKT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,73 +8,16 @@

package org.elasticsearch.search.geo;

import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.geo.GeoJson;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.geo.GeometryTestUtils;
import org.elasticsearch.geometry.MultiPoint;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.TestGeoShapeFieldMapperPlugin;
import org.elasticsearch.xcontent.XContentBuilder;
import org.elasticsearch.xcontent.XContentFactory;

import java.io.IOException;
import java.util.Collection;
import java.util.Collections;

import static org.elasticsearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE;
import static org.elasticsearch.index.query.QueryBuilders.geoShapeQuery;
import static org.elasticsearch.xcontent.XContentFactory.jsonBuilder;

public class GeoShapeQueryTests extends GeoShapeQueryTestCase {

@SuppressWarnings("deprecation")
@Override
protected Collection<Class<? extends Plugin>> getPlugins() {
return Collections.singleton(TestGeoShapeFieldMapperPlugin.class);
}

@Override
protected void createMapping(String indexName, String fieldName, Settings settings) throws Exception {
XContentBuilder xcb = XContentFactory.jsonBuilder()
.startObject()
.startObject("properties")
.startObject(fieldName)
.field("type", "geo_shape")
.endObject()
.endObject()
.endObject();
client().admin().indices().prepareCreate(indexName).setMapping(xcb).setSettings(settings).get();
}

public void testFieldAlias() throws IOException {
String mapping = Strings.toString(
XContentFactory.jsonBuilder()
.startObject()
.startObject("properties")
.startObject(defaultGeoFieldName)
.field("type", "geo_shape")
.endObject()
.startObject("alias")
.field("type", "alias")
.field("path", defaultGeoFieldName)
.endObject()
.endObject()
.endObject()
);

client().admin().indices().prepareCreate(defaultIndexName).setMapping(mapping).get();
ensureGreen();

MultiPoint multiPoint = GeometryTestUtils.randomMultiPoint(false);
client().prepareIndex(defaultIndexName)
.setId("1")
.setSource(GeoJson.toXContent(multiPoint, jsonBuilder().startObject().field(defaultGeoFieldName), null).endObject())
.setRefreshPolicy(IMMEDIATE)
.get();

SearchResponse response = client().prepareSearch(defaultIndexName).setQuery(geoShapeQuery("alias", multiPoint)).get();
assertEquals(1, response.getHits().getTotalHits().value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ public static Geometry randomGeometry(ShapeType type, boolean hasAlt) {
case CIRCLE -> randomCircle(hasAlt);
case MULTIPOINT -> randomMultiPoint(hasAlt);
case POINT -> randomPoint(hasAlt);
default -> throw new IllegalArgumentException("Ussuported shape type [" + type + "]");
default -> throw new IllegalArgumentException("Unsupported shape type [" + type + "]");
};
}

Expand Down

0 comments on commit 6797d44

Please sign in to comment.