private Query getQuery(Function inner, Context context) { RefLiteralPair innerPair = new RefLiteralPair(inner); if (!innerPair.isValid()) { return null; } GeoPointFieldMapper mapper = getGeoPointFieldMapper( innerPair.reference().info().ident().columnIdent().fqn(), context.mapperService); Shape shape = (Shape) innerPair.input().value(); Geometry geometry = JtsSpatialContext.GEO.getGeometryFrom(shape); IndexGeoPointFieldData fieldData = context.fieldDataService.getForField(mapper); Filter filter; if (geometry.isRectangle()) { Rectangle boundingBox = shape.getBoundingBox(); filter = new InMemoryGeoBoundingBoxFilter( new GeoPoint(boundingBox.getMaxY(), boundingBox.getMinX()), new GeoPoint(boundingBox.getMinY(), boundingBox.getMaxX()), fieldData); } else { Coordinate[] coordinates = geometry.getCoordinates(); GeoPoint[] points = new GeoPoint[coordinates.length]; for (int i = 0; i < coordinates.length; i++) { Coordinate coordinate = coordinates[i]; points[i] = new GeoPoint(coordinate.y, coordinate.x); } filter = new GeoPolygonFilter(fieldData, points); } return new FilteredQuery( Queries.newMatchAllQuery(), context.indexCache.filter().cache(filter)); }
/** * @param parent the outer function. E.g. in the case of * <pre>where distance(p1, POINT (10 20)) > 20</pre> * this would be * <pre>gt( \<inner function\>, 20)</pre> * * @param inner has to be the distance function */ @Override public Query apply(Function parent, Function inner, Context context) { assert inner.info().ident().name().equals(DistanceFunction.NAME); RefLiteralPair distanceRefLiteral = new RefLiteralPair(inner); if (!distanceRefLiteral.isValid()) { // can't use distance filter without literal, fallback to genericFunction return null; } FunctionLiteralPair functionLiteralPair = new FunctionLiteralPair(parent); if (!functionLiteralPair.isValid()) { // must be something like eq(distance(..), non-literal) - fallback to genericFunction return null; } Double distance = DataTypes.DOUBLE.value(functionLiteralPair.input().value()); String fieldName = distanceRefLiteral.reference().info().ident().columnIdent().fqn(); FieldMapper mapper = getGeoPointFieldMapper(fieldName, context.mapperService); GeoPointFieldMapper geoMapper = ((GeoPointFieldMapper) mapper); IndexGeoPointFieldData fieldData = context.fieldDataService.getForField(mapper); Input geoPointInput = distanceRefLiteral.input(); Double[] pointValue = (Double[]) geoPointInput.value(); double lat = pointValue[1]; double lon = pointValue[0]; String parentName = functionLiteralPair.functionName(); Double from = null; Double to = null; boolean includeLower = false; boolean includeUpper = false; switch (parentName) { case EqOperator.NAME: includeLower = true; includeUpper = true; from = distance; to = distance; break; case LteOperator.NAME: includeUpper = true; to = distance; break; case LtOperator.NAME: to = distance; break; case GteOperator.NAME: from = distance; includeLower = true; break; case GtOperator.NAME: from = distance; break; default: // invalid operator? give up return null; } GeoPoint geoPoint = new GeoPoint(lat, lon); Filter filter = new GeoDistanceRangeFilter( geoPoint, from, to, includeLower, includeUpper, GEO_DISTANCE, geoMapper, fieldData, optimizeBox); return new FilteredQuery( Queries.newMatchAllQuery(), context.indexCache.filter().cache(filter)); }