/** * Decorates the given query request with attributes required for geo spatial querying. * * @param queryRequest the request that needs to be decorated with geo attributes * @param latitude the latitude of the item that is being queried * @param longitude the longitude of the item that is being queried * @param config the configuration to be used for decorating the request with geo attributes * @param compositeKeyValue the value of the column that is used in the construction of the * composite hash key(geoHashKey + someOtherColumnValue). This is needed when constructing * queries that need a composite hash key. For eg. Fetch an item where lat/long is 23.78787, * -70.6767 AND category = 'restaurants' * @return the decorated request */ public QueryRequest getItemQuery( QueryRequest queryRequest, double latitude, double longitude, GeoConfig config, Optional<String> compositeKeyValue) { checkConfigParams( config.getGeoIndexName(), config.getGeoHashKeyColumn(), config.getGeoHashColumn(), config.getGeoHashKeyLength()); // Generate the geohash and geoHashKey to query by global secondary index long geohash = s2Manager.generateGeohash(latitude, longitude); long geoHashKey = s2Manager.generateHashKey(geohash, config.getGeoHashKeyLength()); queryRequest.withIndexName(config.getGeoIndexName()); Map<String, Condition> keyConditions = new HashMap<String, Condition>(); // Construct the hashKey condition Condition geoHashKeyCondition; if (config.getHashKeyDecorator().isPresent() && compositeKeyValue.isPresent()) { String hashKey = config.getHashKeyDecorator().get().decorate(compositeKeyValue.get(), geoHashKey); geoHashKeyCondition = new Condition() .withComparisonOperator(ComparisonOperator.EQ) .withAttributeValueList(new AttributeValue().withS(hashKey)); } else { geoHashKeyCondition = new Condition() .withComparisonOperator(ComparisonOperator.EQ) .withAttributeValueList(new AttributeValue().withN(String.valueOf(geoHashKey))); } keyConditions.put(config.getGeoHashKeyColumn(), geoHashKeyCondition); // Construct the geohash condition Condition geoHashCondition = new Condition() .withComparisonOperator(ComparisonOperator.EQ) .withAttributeValueList(new AttributeValue().withN(String.valueOf(geohash))); keyConditions.put(config.getGeoHashColumn(), geoHashCondition); queryRequest.setKeyConditions(keyConditions); return queryRequest; }
/** * Decorates the given <code>updateItemRequest</code> with attributes required for geo spatial * querying. * * @param attributeValueMap the items that needs to be decorated with geo attributes * @param latitude the latitude that needs to be attached with the item * @param longitude the longitude that needs to be attached with the item * @param configs the collection of configurations to be used for decorating the request with geo * attributes */ public void updateAttributeValues( Map<String, AttributeValue> attributeValueMap, double latitude, double longitude, List<GeoConfig> configs) { if (configs == null) { throw new IllegalArgumentException("Geo configs should not be null"); } for (GeoConfig config : configs) { // Fail-fast if any of the preconditions fail checkConfigParams( config.getGeoIndexName(), config.getGeoHashKeyColumn(), config.getGeoHashColumn(), config.getGeoHashKeyLength()); long geohash = s2Manager.generateGeohash(latitude, longitude); long geoHashKey = s2Manager.generateHashKey(geohash, config.getGeoHashKeyLength()); // Decorate the request with the geohash AttributeValue geoHashValue = new AttributeValue().withN(Long.toString(geohash)); attributeValueMap.put(config.getGeoHashColumn(), geoHashValue); AttributeValue geoHashKeyValue; if (config.getHashKeyDecorator().isPresent() && config.getCompositeHashKeyColumn().isPresent()) { AttributeValue compositeHashKeyValue = attributeValueMap.get(config.getCompositeHashKeyColumn().get()); if (compositeHashKeyValue == null) { continue; } String compositeColumnValue = compositeHashKeyValue.getS(); String hashKey = config.getHashKeyDecorator().get().decorate(compositeColumnValue, geoHashKey); // Decorate the request with the composite geoHashKey (type String) geoHashKeyValue = new AttributeValue().withS(String.valueOf(hashKey)); } else { // Decorate the request with the geoHashKey (type Number) geoHashKeyValue = new AttributeValue().withN(String.valueOf(geoHashKey)); } attributeValueMap.put(config.getGeoHashKeyColumn(), geoHashKeyValue); } }
/** * Creates a wrapper that contains a collection of all queries that are generated as a result of * this rectangle query. It also contains a filter {@link * com.amazonaws.geo.model.filters.GeoFilter} that needs to be applied to the results of the query * to ensure that everything is in the bounding box of the queried rectangle. This is needed * because queries are fired for every cell that intersects with the rectangle's bounding box. * * @param queryRequest the request that needs to be decorated with geo attributes * @param minLatitude the latitude of the min point of the rectangle * @param minLongitude the longitude of the min point of the rectangle * @param maxLatitude the latitude of the max point of the rectangle * @param maxLongitude the longitude of the max point of the rectangle * @param config the configuration to be used for decorating the request with geo attributes * @param compositeKeyValue the value of the column that is used in the construction of the * composite hash key(geoHashKey + someOtherColumnValue). This is needed when constructing * queries that need a composite hash key. For eg. Fetch an item where lat/long is 23.78787, * -70.6767 AND category = 'restaurants' * @return the wrapper containing the generated queries and the geo filter */ public GeoQueryRequest rectangleQuery( QueryRequest queryRequest, double minLatitude, double minLongitude, double maxLatitude, double maxLongitude, GeoConfig config, Optional<String> compositeKeyValue) { checkConfigParams( config.getGeoIndexName(), config.getGeoHashKeyColumn(), config.getGeoHashColumn(), config.getGeoHashKeyLength()); // bounding box is needed for the filter and to generate the queries // for each cell that intersects with the bounding box S2LatLngRect boundingBox = s2Manager.getBoundingBoxForRectangleQuery( minLatitude, minLongitude, maxLatitude, maxLongitude); GeoFilter filter = GeoFilters.newRectangleFilter(boundingBox); List<QueryRequest> geoQueries = geoQueryHelper.generateGeoQueries(queryRequest, boundingBox, config, compositeKeyValue); return new GeoQueryRequest(geoQueries, filter); }
/** * Creates a wrapper that contains a collection of all queries that are generated as a result of * the radius query. It also contains a filter {@link com.amazonaws.geo.model.filters.GeoFilter} * that needs to be applied to the results of the query to ensure that everything is in the * radius. This is needed because queries are fired for every cell that intersects with the * radius' rectangle box. * * @param queryRequest the request that needs to be decorated with geo attributes * @param latitude the latitude of the center point for the radius query * @param longitude the longitude of the center point for the radius query * @param radius the radius (in metres) * @param config the configuration to be used for decorating the request with geo attributes * @param compositeKeyValue the value of the column that is used in the construction of the * composite hash key(geoHashKey + someOtherColumnValue). This is needed when constructing * queries that need a composite hash key. For eg. Fetch an item where lat/long is 23.78787, * -70.6767 AND category = 'restaurants' * @return the wrapper containing the generated queries and the geo filter */ public GeoQueryRequest radiusQuery( QueryRequest queryRequest, double latitude, double longitude, double radius, GeoConfig config, Optional<String> compositeKeyValue) { checkArgument(radius >= 0.0d, "radius has to be a positive value: %s", radius); checkConfigParams( config.getGeoIndexName(), config.getGeoHashKeyColumn(), config.getGeoHashColumn(), config.getGeoHashKeyLength()); // Center latLong is needed for the radius filter S2LatLng centerLatLng = S2LatLng.fromDegrees(latitude, longitude); GeoFilter filter = GeoFilters.newRadiusFilter(centerLatLng, radius); // Bounding box is needed to generate queries for each cell that intersects with the bounding // box S2LatLngRect boundingBox = s2Manager.getBoundingBoxForRadiusQuery(latitude, longitude, radius); List<QueryRequest> geoQueries = geoQueryHelper.generateGeoQueries(queryRequest, boundingBox, config, compositeKeyValue); return new GeoQueryRequest(geoQueries, filter); }