@Test public void testReusableBuilder() throws IOException { ShapeBuilder polygon = ShapeBuilder.newPolygon() .point(170, -10) .point(190, -10) .point(190, 10) .point(170, 10) .hole() .point(175, -5) .point(185, -5) .point(185, 5) .point(175, 5) .close() .close(); assertUnmodified(polygon); ShapeBuilder linestring = ShapeBuilder.newLineString().point(170, -10).point(190, -10).point(190, 10).point(170, 10); assertUnmodified(linestring); }
@Override public Mapper parse(ParseContext context) throws IOException { try { Shape shape = context.parseExternalValue(Shape.class); if (shape == null) { ShapeBuilder shapeBuilder = ShapeBuilder.parse(context.parser(), this); if (shapeBuilder == null) { return null; } shape = shapeBuilder.build(); } if (fieldType().pointsOnly() && !(shape instanceof Point)) { throw new MapperParsingException( "[{" + fieldType().names().fullName() + "}] is configured for points only but a " + ((shape instanceof JtsGeometry) ? ((JtsGeometry) shape).getGeom().getGeometryType() : shape.getClass()) + " was found"); } Field[] fields = fieldType().defaultStrategy().createIndexableFields(shape); if (fields == null || fields.length == 0) { return null; } for (Field field : fields) { if (!customBoost()) { field.setBoost(fieldType().boost()); } context.doc().add(field); } } catch (Exception e) { throw new MapperParsingException( "failed to parse [" + fieldType().names().fullName() + "]", e); } return null; }
@Override public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException { Builder builder = geoShapeField(name); for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext(); ) { Map.Entry<String, Object> entry = iterator.next(); String fieldName = Strings.toUnderscoreCase(entry.getKey()); Object fieldNode = entry.getValue(); if (Names.TREE.equals(fieldName)) { builder.fieldType().setTree(fieldNode.toString()); iterator.remove(); } else if (Names.TREE_LEVELS.equals(fieldName)) { builder.fieldType().setTreeLevels(Integer.parseInt(fieldNode.toString())); iterator.remove(); } else if (Names.TREE_PRESISION.equals(fieldName)) { builder .fieldType() .setPrecisionInMeters( DistanceUnit.parse( fieldNode.toString(), DistanceUnit.DEFAULT, DistanceUnit.DEFAULT)); iterator.remove(); } else if (Names.DISTANCE_ERROR_PCT.equals(fieldName)) { builder.fieldType().setDistanceErrorPct(Double.parseDouble(fieldNode.toString())); iterator.remove(); } else if (Names.ORIENTATION.equals(fieldName)) { builder .fieldType() .setOrientation(ShapeBuilder.orientationFromString(fieldNode.toString())); iterator.remove(); } else if (Names.STRATEGY.equals(fieldName)) { builder.fieldType().setStrategyName(fieldNode.toString()); iterator.remove(); } else if (Names.COERCE.equals(fieldName)) { builder.coerce(nodeBooleanValue(fieldNode)); iterator.remove(); } else if (Names.STRATEGY_POINTS_ONLY.equals(fieldName) && builder.fieldType().strategyName.equals(SpatialStrategy.TERM.getStrategyName()) == false) { builder.fieldType().setPointsOnly(XContentMapValues.nodeBooleanValue(fieldNode)); iterator.remove(); } } return builder; }
@Test public void testIndexPointsFilterRectangle() throws Exception { String mapping = XContentFactory.jsonBuilder() .startObject() .startObject("type1") .startObject("properties") .startObject("location") .field("type", "geo_shape") .field("tree", "quadtree") .endObject() .endObject() .endObject() .endObject() .string(); prepareCreate("test").addMapping("type1", mapping).execute().actionGet(); ensureGreen(); client() .prepareIndex("test", "type1", "1") .setSource( jsonBuilder() .startObject() .field("name", "Document 1") .startObject("location") .field("type", "point") .startArray("coordinates") .value(-30) .value(-30) .endArray() .endObject() .endObject()) .execute() .actionGet(); client() .prepareIndex("test", "type1", "2") .setSource( jsonBuilder() .startObject() .field("name", "Document 2") .startObject("location") .field("type", "point") .startArray("coordinates") .value(-45) .value(-50) .endArray() .endObject() .endObject()) .execute() .actionGet(); refresh(); client().admin().indices().prepareRefresh().execute().actionGet(); ShapeBuilder shape = ShapeBuilder.newEnvelope().topLeft(-45, 45).bottomRight(45, -45); SearchResponse searchResponse = client() .prepareSearch() .setQuery(filteredQuery(matchAllQuery(), geoIntersectionFilter("location", shape))) .execute() .actionGet(); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1l)); assertThat(searchResponse.getHits().hits().length, equalTo(1)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("1")); searchResponse = client().prepareSearch().setQuery(geoShapeQuery("location", shape)).execute().actionGet(); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1l)); assertThat(searchResponse.getHits().hits().length, equalTo(1)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("1")); }
private void assertUnmodified(ShapeBuilder builder) throws IOException { String before = jsonBuilder().startObject().field("area", builder).endObject().string(); builder.build(); String after = jsonBuilder().startObject().field("area", builder).endObject().string(); assertThat(before, equalTo(after)); }
// TODO this test causes hangs, blocking on the action get when fetching the shape for some reason @Test @AwaitsFix( bugUrl = "this test causes hangs, blocking on the action get when fetching the shape for some reason") public void testIndexedShapeReference() throws Exception { String mapping = XContentFactory.jsonBuilder() .startObject() .startObject("type1") .startObject("properties") .startObject("location") .field("type", "geo_shape") .field("tree", "quadtree") .endObject() .endObject() .endObject() .endObject() .string(); prepareCreate("test").addMapping("type1", mapping).execute().actionGet(); ensureGreen(); client() .prepareIndex("test", "type1", "1") .setSource( jsonBuilder() .startObject() .field("name", "Document 1") .startObject("location") .field("type", "point") .startArray("coordinates") .value(-30) .value(-30) .endArray() .endObject() .endObject()) .execute() .actionGet(); refresh(); ShapeBuilder shape = ShapeBuilder.newEnvelope().topLeft(-45, 45).bottomRight(45, -45); XContentBuilder shapeContent = jsonBuilder().startObject().field("shape", shape); shapeContent.endObject(); createIndex("shapes"); ensureGreen(); client() .prepareIndex("shapes", "shape_type", "Big_Rectangle") .setSource(shapeContent) .execute() .actionGet(); refresh(); SearchResponse searchResponse = client() .prepareSearch("test") .setQuery( filteredQuery( matchAllQuery(), geoIntersectionFilter("location", "Big_Rectangle", "shape_type"))) .execute() .actionGet(); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1l)); assertThat(searchResponse.getHits().hits().length, equalTo(1)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("1")); searchResponse = client() .prepareSearch() .setQuery(geoShapeQuery("location", "Big_Rectangle", "shape_type")) .execute() .actionGet(); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1l)); assertThat(searchResponse.getHits().hits().length, equalTo(1)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("1")); }
@Test public void testEdgeCases() throws Exception { String mapping = XContentFactory.jsonBuilder() .startObject() .startObject("type1") .startObject("properties") .startObject("location") .field("type", "geo_shape") .field("tree", "quadtree") .endObject() .endObject() .endObject() .endObject() .string(); prepareCreate("test").addMapping("type1", mapping).execute().actionGet(); ensureGreen(); client() .prepareIndex("test", "type1", "blakely") .setSource( jsonBuilder() .startObject() .field("name", "Blakely Island") .startObject("location") .field("type", "polygon") .startArray("coordinates") .startArray() .startArray() .value(-122.83) .value(48.57) .endArray() .startArray() .value(-122.77) .value(48.56) .endArray() .startArray() .value(-122.79) .value(48.53) .endArray() .startArray() .value(-122.83) .value(48.57) .endArray() // close the polygon .endArray() .endArray() .endObject() .endObject()) .execute() .actionGet(); client().admin().indices().prepareRefresh().execute().actionGet(); ShapeBuilder query = ShapeBuilder.newEnvelope().topLeft(-122.88, 48.62).bottomRight(-122.82, 48.54); // This search would fail if both geoshape indexing and geoshape filtering // used the bottom-level optimization in SpatialPrefixTree#recursiveGetNodes. SearchResponse searchResponse = client() .prepareSearch() .setQuery(filteredQuery(matchAllQuery(), geoIntersectionFilter("location", query))) .execute() .actionGet(); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1l)); assertThat(searchResponse.getHits().hits().length, equalTo(1)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("blakely")); }
@Test public void testExternalValues() throws Exception { prepareCreate("test-idx") .addMapping( "type", XContentFactory.jsonBuilder() .startObject() .startObject("type") .startObject(ExternalRootMapper.CONTENT_TYPE) .endObject() .startObject("properties") .startObject("field") .field("type", RegisterExternalTypes.EXTERNAL) .endObject() .endObject() .endObject() .endObject()) .execute() .get(); ensureYellow("test-idx"); index( "test-idx", "type", "1", XContentFactory.jsonBuilder().startObject().field("field", "1234").endObject()); refresh(); SearchResponse response; response = client() .prepareSearch("test-idx") .setPostFilter(FilterBuilders.termFilter("field.bool", "T")) .execute() .actionGet(); assertThat(response.getHits().totalHits(), equalTo((long) 1)); response = client() .prepareSearch("test-idx") .setPostFilter( FilterBuilders.geoDistanceRangeFilter("field.point").point(42.0, 51.0).to("1km")) .execute() .actionGet(); assertThat(response.getHits().totalHits(), equalTo((long) 1)); response = client() .prepareSearch("test-idx") .setPostFilter( FilterBuilders.geoShapeFilter( "field.shape", ShapeBuilder.newPoint(-100, 45), ShapeRelation.WITHIN)) .execute() .actionGet(); assertThat(response.getHits().totalHits(), equalTo((long) 1)); response = client() .prepareSearch("test-idx") .setPostFilter(FilterBuilders.termFilter("field.field", "foo")) .execute() .actionGet(); assertThat(response.getHits().totalHits(), equalTo((long) 1)); }
@Override public Filter parse(QueryParseContext parseContext) throws IOException, QueryParsingException { XContentParser parser = parseContext.parser(); String fieldName = null; ShapeRelation shapeRelation = ShapeRelation.INTERSECTS; String strategyName = null; ShapeBuilder shape = null; FilterCachingPolicy cache = parseContext.autoFilterCachePolicy(); HashedBytesRef cacheKey = null; String filterName = null; String id = null; String type = null; String index = DEFAULTS.INDEX_NAME; String shapePath = DEFAULTS.SHAPE_FIELD_NAME; XContentParser.Token token; String currentFieldName = null; while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { currentFieldName = parser.currentName(); } else if (token == XContentParser.Token.START_OBJECT) { fieldName = currentFieldName; while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { currentFieldName = parser.currentName(); token = parser.nextToken(); if ("shape".equals(currentFieldName)) { shape = ShapeBuilder.parse(parser); } else if ("relation".equals(currentFieldName)) { shapeRelation = ShapeRelation.getRelationByName(parser.text()); if (shapeRelation == null) { throw new QueryParsingException( parseContext.index(), "Unknown shape operation [" + parser.text() + "]"); } } else if ("strategy".equals(currentFieldName)) { strategyName = parser.text(); } else if ("indexed_shape".equals(currentFieldName) || "indexedShape".equals(currentFieldName)) { while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { currentFieldName = parser.currentName(); } else if (token.isValue()) { if ("id".equals(currentFieldName)) { id = parser.text(); } else if ("type".equals(currentFieldName)) { type = parser.text(); } else if ("index".equals(currentFieldName)) { index = parser.text(); } else if ("path".equals(currentFieldName)) { shapePath = parser.text(); } } } if (id == null) { throw new QueryParsingException( parseContext.index(), "ID for indexed shape not provided"); } else if (type == null) { throw new QueryParsingException( parseContext.index(), "Type for indexed shape not provided"); } shape = fetchService.fetch(id, type, index, shapePath); } else { throw new QueryParsingException( parseContext.index(), "[geo_shape] filter does not support [" + currentFieldName + "]"); } } } } else if (token.isValue()) { if ("_name".equals(currentFieldName)) { filterName = parser.text(); } else if ("_cache".equals(currentFieldName)) { cache = parseContext.parseFilterCachePolicy(); } else if ("_cache_key".equals(currentFieldName)) { cacheKey = new HashedBytesRef(parser.text()); } else { throw new QueryParsingException( parseContext.index(), "[geo_shape] filter does not support [" + currentFieldName + "]"); } } } if (shape == null) { throw new QueryParsingException(parseContext.index(), "No Shape defined"); } else if (shapeRelation == null) { throw new QueryParsingException(parseContext.index(), "No Shape Relation defined"); } MapperService.SmartNameFieldMappers smartNameFieldMappers = parseContext.smartFieldMappers(fieldName); if (smartNameFieldMappers == null || !smartNameFieldMappers.hasMapper()) { throw new QueryParsingException( parseContext.index(), "Failed to find geo_shape field [" + fieldName + "]"); } FieldMapper fieldMapper = smartNameFieldMappers.mapper(); // TODO: This isn't the nicest way to check this if (!(fieldMapper instanceof GeoShapeFieldMapper)) { throw new QueryParsingException( parseContext.index(), "Field [" + fieldName + "] is not a geo_shape"); } GeoShapeFieldMapper shapeFieldMapper = (GeoShapeFieldMapper) fieldMapper; PrefixTreeStrategy strategy = shapeFieldMapper.defaultStrategy(); if (strategyName != null) { strategy = shapeFieldMapper.resolveStrategy(strategyName); } Filter filter; if (strategy instanceof RecursivePrefixTreeStrategy && shapeRelation == ShapeRelation.DISJOINT) { // this strategy doesn't support disjoint anymore: but it did before, including creating // lucene fieldcache (!) // in this case, execute disjoint as exists && !intersects XBooleanFilter bool = new XBooleanFilter(); Filter exists = ExistsFilterParser.newFilter(parseContext, fieldName, null); Filter intersects = strategy.makeFilter(GeoShapeQueryParser.getArgs(shape, ShapeRelation.INTERSECTS)); bool.add(exists, BooleanClause.Occur.MUST); bool.add(intersects, BooleanClause.Occur.MUST_NOT); filter = bool; } else { filter = strategy.makeFilter(GeoShapeQueryParser.getArgs(shape, shapeRelation)); } if (cache != null) { filter = parseContext.cacheFilter(filter, cacheKey, cache); } if (filterName != null) { parseContext.addNamedFilter(filterName, filter); } return filter; }
@Test // see #3878 public void testThatXContentSerializationInsideOfArrayWorks() throws Exception { EnvelopeBuilder envelopeBuilder = ShapeBuilder.newEnvelope().topLeft(0, 0).bottomRight(10, 10); GeoShapeQueryBuilder geoQuery = QueryBuilders.geoShapeQuery("searchGeometry", envelopeBuilder); JsonXContent.contentBuilder().startArray().value(geoQuery).endArray(); }
@Test public void testShapeFilterWithDefinedGeoCollection() throws Exception { createIndex("shapes"); assertAcked(prepareCreate("test").addMapping("type", "location", "type=geo_shape")); XContentBuilder docSource = jsonBuilder() .startObject() .startObject("location") .field("type", "geometrycollection") .startArray("geometries") .startObject() .field("type", "point") .startArray("coordinates") .value(100.0) .value(0.0) .endArray() .endObject() .startObject() .field("type", "linestring") .startArray("coordinates") .startArray() .value(101.0) .value(0.0) .endArray() .startArray() .value(102.0) .value(1.0) .endArray() .endArray() .endObject() .endArray() .endObject() .endObject(); indexRandom(true, client().prepareIndex("test", "type", "1").setSource(docSource)); ensureSearchable("test"); GeoShapeFilterBuilder filter = FilterBuilders.geoShapeFilter( "location", ShapeBuilder.newGeometryCollection() .polygon( ShapeBuilder.newPolygon() .point(99.0, -1.0) .point(99.0, 3.0) .point(103.0, 3.0) .point(103.0, -1.0) .point(99.0, -1.0)), ShapeRelation.INTERSECTS); SearchResponse result = client() .prepareSearch("test") .setQuery(QueryBuilders.matchAllQuery()) .setPostFilter(filter) .get(); assertSearchResponse(result); assertHitCount(result, 1); filter = FilterBuilders.geoShapeFilter( "location", ShapeBuilder.newGeometryCollection() .polygon( ShapeBuilder.newPolygon() .point(199.0, -11.0) .point(199.0, 13.0) .point(193.0, 13.0) .point(193.0, -11.0) .point(199.0, -11.0)), ShapeRelation.INTERSECTS); result = client() .prepareSearch("test") .setQuery(QueryBuilders.matchAllQuery()) .setPostFilter(filter) .get(); assertSearchResponse(result); assertHitCount(result, 0); filter = FilterBuilders.geoShapeFilter( "location", ShapeBuilder.newGeometryCollection() .polygon( ShapeBuilder.newPolygon() .point(99.0, -1.0) .point(99.0, 3.0) .point(103.0, 3.0) .point(103.0, -1.0) .point(99.0, -1.0)) .polygon( ShapeBuilder.newPolygon() .point(199.0, -11.0) .point(199.0, 13.0) .point(193.0, 13.0) .point(193.0, -11.0) .point(199.0, -11.0)), ShapeRelation.INTERSECTS); result = client() .prepareSearch("test") .setQuery(QueryBuilders.matchAllQuery()) .setPostFilter(filter) .get(); assertSearchResponse(result); assertHitCount(result, 1); }
@Test public void testIndexedShapeReference() throws Exception { String mapping = XContentFactory.jsonBuilder() .startObject() .startObject("type1") .startObject("properties") .startObject("location") .field("type", "geo_shape") .field("tree", "quadtree") .endObject() .endObject() .endObject() .endObject() .string(); assertAcked(prepareCreate("test").addMapping("type1", mapping)); createIndex("shapes"); ensureGreen(); ShapeBuilder shape = ShapeBuilder.newEnvelope().topLeft(-45, 45).bottomRight(45, -45); indexRandom( true, client() .prepareIndex("shapes", "shape_type", "Big_Rectangle") .setSource(jsonBuilder().startObject().field("shape", shape).endObject()), client() .prepareIndex("test", "type1", "1") .setSource( jsonBuilder() .startObject() .field("name", "Document 1") .startObject("location") .field("type", "point") .startArray("coordinates") .value(-30) .value(-30) .endArray() .endObject() .endObject())); SearchResponse searchResponse = client() .prepareSearch("test") .setQuery(geoIntersectionQuery("location", "Big_Rectangle", "shape_type")) .execute() .actionGet(); assertSearchResponse(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1l)); assertThat(searchResponse.getHits().hits().length, equalTo(1)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("1")); searchResponse = client() .prepareSearch("test") .setQuery(geoShapeQuery("location", "Big_Rectangle", "shape_type")) .execute() .actionGet(); assertSearchResponse(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1l)); assertThat(searchResponse.getHits().hits().length, equalTo(1)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("1")); }