| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.usergrid.persistence; |
| |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.junit.Test; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import org.apache.usergrid.AbstractCoreIT; |
| import org.apache.usergrid.utils.MapUtils; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| |
| |
| public class GeoIT extends AbstractCoreIT { |
| private static final Logger logger = LoggerFactory.getLogger(GeoIT.class); |
| |
| int NEARBY_RADIUS = 10000; |
| int CIRCUMFERENCE_OF_THE_EARTH = 40000000; |
| |
| /* |
| A list of concrete entities with locations to be used for geoQuery tests |
| NOTE: Adding or removing items from this list could affect test outcome!!! |
| */ |
| private static List<Map<String, Object>> LOCATION_PROPERTIES = |
| new ArrayList<Map<String, Object>>(); |
| |
| static { |
| LOCATION_PROPERTIES.add(new LinkedHashMap<String, Object>() {{ |
| put("name", "norwest"); |
| put("location", new LinkedHashMap<String, Object>() {{ |
| put("latitude", -33.746369); |
| put("longitude", 150.952183); |
| }}); |
| }}); |
| LOCATION_PROPERTIES.add(new LinkedHashMap<String, Object>() {{ |
| put("type", "store"); |
| put("name", "ashfield"); |
| put("location", new LinkedHashMap<String, Object>() {{ |
| put("latitude", -33.889058); |
| put("longitude", 151.124024); |
| }}); |
| }}); |
| } |
| |
| public GeoIT() throws Exception { |
| super(); |
| } |
| |
| |
| @Test |
| public void testRoundingGeolocationIssue() throws Exception { |
| EntityManager em = app.getEntityManager(); |
| assertNotNull(em); |
| |
| //1. Create an entity with location |
| Entity office = createEntitywithLocation( em,"office",37.334115,-121.894340); |
| assertNotNull(office); |
| |
| Entity pizza = createEntitywithLocation( em,"pizza",37.335616,-121.894168); |
| assertNotNull(pizza); |
| |
| Entity market = createEntitywithLocation( em,"market",37.336499,-121.894356); |
| assertNotNull(market); |
| |
| Entity park = createEntitywithLocation( em,"park",37.339079,-121.891422); |
| assertNotNull(park); |
| |
| Entity news = createEntitywithLocation( em,"news",37.337812,-121.890784); |
| assertNotNull(news); |
| |
| Entity hotel = createEntitywithLocation( em,"hotel",37.334370,-121.895081); |
| assertNotNull(hotel); |
| |
| |
| app.waitForQueueDrainAndRefreshIndex(); |
| |
| //2. Query with a globally large distance to verify location |
| |
| Query query = Query.fromQL("select * where location within 609.7 of 37.334110260009766, -121.89434051513672"); |
| Results listResults = em.searchCollection(em.getApplicationRef(), "collars", query); |
| assertEquals( 5, listResults.size()); |
| |
| query = Query.fromQL("select * where location within 609.8 of 37.334110260009766, -121.89434051513672"); |
| listResults = em.searchCollection(em.getApplicationRef(), "collars", query); |
| assertEquals( 6, listResults.size()); |
| |
| |
| } |
| |
| |
| private Entity createEntitywithLocation( final EntityManager em,String name ,Double lat,Double lon) throws Exception { |
| Map<String, Object> properties = new LinkedHashMap<String, Object>() {{ |
| put("name", name); |
| put("location", new LinkedHashMap<String, Object>() {{ |
| put("latitude", lat); |
| put("longitude", lon); |
| }}); |
| }}; |
| |
| return em.create("collars", properties); |
| } |
| |
| |
| @Test |
| public void testRemovedLocationQuery() throws Exception { |
| //Get the EntityManager instance |
| EntityManager em = app.getEntityManager(); |
| assertNotNull(em); |
| |
| //1. Create an entity with location |
| Map<String, Object> properties = new LinkedHashMap<String, Object>() {{ |
| put("username", "edanuff"); |
| put("email", "ed@anuff.com"); |
| put("location", new LinkedHashMap<String, Object>() {{ |
| put("latitude", 37.776753); |
| put("longitude", -122.407846); |
| }}); |
| }}; |
| Entity user = em.create("user", properties); |
| assertNotNull(user); |
| app.waitForQueueDrainAndRefreshIndex(); |
| |
| //2. Query with a globally large distance to verify location |
| Query query = Query.fromQL("select * where location within " + Integer.MAX_VALUE + " of 0, 0"); |
| Results listResults = em.searchCollection(em.getApplicationRef(), "users", query); |
| assertEquals("1 result returned", 1, listResults.size()); |
| |
| //3. Remove the entity's location |
| properties.remove("location"); |
| user.getDynamicProperties().remove("location"); |
| em.updateProperties(user, properties); |
| em.update(user); |
| app.waitForQueueDrainAndRefreshIndex(); |
| |
| //4. Repeat the query, expecting no results |
| listResults = em.searchCollection(em.getApplicationRef(), "users", query); |
| assertEquals(0, listResults.size()); |
| |
| em.delete(user); |
| } |
| |
| /** |
| * Validate the ability to query a moving entity |
| * 1. Create an entity with location |
| * 2. Query from a point near the entity's location |
| * 3. Move the entity farther away from the center point |
| * 4. Run the same query again to verify the entity is no longer in the area |
| */ |
| @Test |
| public void testMovingTarget() throws Exception { |
| logger.info("GeoIT.testMovingTarget"); |
| //Get the EntityManager instance |
| EntityManager em = app.getEntityManager(); |
| assertNotNull(em); |
| |
| //1. Create an entity with location |
| Map<String, Object> properties = new LinkedHashMap<String, Object>() {{ |
| put("username", "edanuff"); |
| put("email", "ed@anuff.com"); |
| put("location", new LinkedHashMap<String, Object>() {{ |
| put("latitude", 37.776753); |
| put("longitude", -122.407846); |
| }}); |
| }}; |
| Entity user = em.create("user", properties); |
| assertNotNull(user); |
| app.waitForQueueDrainAndRefreshIndex(); |
| |
| final double lat = 37.776753; |
| final double lon = -122.407846; |
| //2. Query from a point near the entity's location |
| Query query = Query.fromQL("select * where location within 100 of " |
| + lat + "," + lon); |
| Results listResults = em.searchCollection(em.getApplicationRef(), "users", query); |
| assertEquals(1, listResults.size()); |
| |
| //3. Move the entity farther away from the center point |
| updatePos(em, user, 37.428526, -122.140916); |
| |
| //4. Run the same query again to verify the entity is no longer in the area |
| listResults = em.searchCollection(em.getApplicationRef(), "users", query); |
| assertEquals(0, listResults.size()); |
| |
| em.delete(user); |
| } |
| |
| |
| /** |
| * Validate the ability to query a moving entity |
| * 1. Create an entity with location |
| * 2. Query from a point near the entity's location |
| * 3. Move the entity farther away from the center point |
| * 4. Run the same query again to verify the entity is no longer in the area |
| */ |
| @Test |
| public void validateDistanceQueryExists() throws Exception { |
| logger.info("GeoIT.validateDistanceQueryExists"); |
| //Get the EntityManager instance |
| EntityManager em = app.getEntityManager(); |
| assertNotNull(em); |
| |
| //1. Create an entity with location |
| Map<String, Object> properties = new LinkedHashMap<String, Object>() {{ |
| put("username", "edanuff"); |
| put("email", "ed@anuff.com"); |
| put("location", new LinkedHashMap<String, Object>() {{ |
| put("latitude", 37.776753); |
| put("longitude", -122.407846); |
| }}); |
| }}; |
| Entity user = em.create("user", properties); |
| assertNotNull(user); |
| app.waitForQueueDrainAndRefreshIndex(); |
| |
| final double lat = 37.776753; |
| final double lon = -122.407846; |
| |
| //2. Query from a point near the entity's location |
| Query query = Query.fromQL("select * where location within 100 of " |
| + lat + "," + lon); |
| Results listResults = em.searchCollection(em.getApplicationRef(), "users", query); |
| assertEquals(1, listResults.size()); |
| Entity entity = listResults.getEntity(); |
| assertTrue(entity.getMetadata("distance")!=null); |
| assertTrue(Double.parseDouble( entity.getMetadata("distance").toString())>0); |
| |
| em.delete(user); |
| } |
| |
| /** |
| * Validate the ability to query connections within proximity of the users |
| * 1. Create an entity with location |
| * 2. Create a user with location |
| * 3. Create a connection between the user and the entity |
| * 4. Test that the user is within 2000m of the entity |
| * 5. Test that the user is NOT within 1000m of the entity |
| */ |
| @Test |
| public void testGeoDistanceOfConnection() throws Exception { |
| //Get the EntityManager instance |
| EntityManager em = app.getEntityManager(); |
| assertNotNull(em); |
| //1. Create an entity with location |
| Map<String, Object> restaurantProps = new LinkedHashMap<String, Object>(); |
| restaurantProps.put("name", "Brickhouse"); |
| restaurantProps.put("address", "426 Brannan Street"); |
| restaurantProps.put("location", getLocation(37.779632, -122.395131)); |
| |
| Entity restaurant = em.create("restaurant", restaurantProps); |
| assertNotNull(restaurant); |
| //2. Create a user with location |
| Map<String, Object> userProperties = new LinkedHashMap<String, Object>() {{ |
| put("username", "edanuff"); |
| put("email", "ed@anuff.com"); |
| put("location", new LinkedHashMap<String, Object>() {{ |
| put("latitude", 37.776753); |
| put("longitude", -122.407846); |
| }}); |
| }}; |
| |
| Entity user = em.create("user", userProperties); |
| assertNotNull(user); |
| app.waitForQueueDrainAndRefreshIndex(); |
| |
| //3. Create a connection between the user and the entity |
| em.createConnection(user, "likes", restaurant); |
| |
| app.waitForQueueDrainAndRefreshIndex(); |
| //4. Test that the user is within 2000m of the entity |
| Results emSearchResults = em.searchTargetEntities(user, |
| Query.fromQL("location within 5000 of " |
| + ((LinkedHashMap<String, Object>) userProperties.get("location")).get("latitude") |
| + ", " + ((LinkedHashMap<String, Object>) |
| userProperties.get("location")).get("longitude")).setConnectionType("likes")); |
| assertEquals(1, emSearchResults.size()); |
| //5. Test that the user is NOT within 1000m of the entity |
| emSearchResults = em.searchTargetEntities(user, |
| Query.fromQL("location within 1000 of " |
| + ((LinkedHashMap<String, Object>) userProperties.get("location")).get("latitude") |
| + ", " + ((LinkedHashMap<String, Object>) |
| userProperties.get("location")).get("longitude")).setConnectionType("likes")); |
| assertEquals(0, emSearchResults.size()); |
| //cleanup |
| em.delete(user); |
| em.delete(restaurant); |
| } |
| |
| /** |
| * Validate loaded entities for geo queries |
| * 1. load test entities |
| * 2. validate the size of the result |
| * 3. verify each entity has geo data |
| */ |
| @Test |
| public void testGeolocationEntities() throws Exception { |
| //1. load test entities |
| EntityManager em = app.getEntityManager(); |
| assertNotNull(em); |
| //2. load test entities |
| for (Map<String, Object> location : LOCATION_PROPERTIES) { |
| Entity entity = em.create("store", location); |
| assertNotNull(entity); |
| logger.debug("Entity {} created", entity.getProperty("name")); |
| } |
| app.waitForQueueDrainAndRefreshIndex(); |
| //2. validate the size of the result |
| Query query = new Query(); |
| Results listResults = em.searchCollection(em.getApplicationRef(), "stores", query); |
| assertEquals("total number of 'stores'", LOCATION_PROPERTIES.size(), listResults.size()); |
| //3. verify each entity has geo data |
| for (Entity entity : listResults.entities) { |
| Map location = (Map)entity.getProperty("location"); |
| assertNotNull(location); |
| assertNotNull(location.get("longitude")); |
| assertNotNull(location.get("latitude")); |
| } |
| |
| } |
| |
| @Test |
| public void testNonGeolocationEntities() throws Exception { |
| //1. load test entities |
| EntityManager em = app.getEntityManager(); |
| assertNotNull(em); |
| |
| List<Map<String, Object>> locations = |
| new ArrayList<Map<String, Object>>(); |
| |
| |
| locations.add(new LinkedHashMap<String, Object>() {{ |
| put("name", "norwest"); |
| put("location", "texas"); |
| }}); |
| locations.add(new LinkedHashMap<String, Object>() {{ |
| put("type", "store"); |
| put("name", "ashfield"); |
| put("location", "new jersey"); |
| }}); |
| |
| //2. load test entities |
| for (Map<String, Object> location : locations) { |
| Entity entity = em.create("store", location); |
| assertNotNull(entity); |
| logger.debug("Entity {} created", entity.getProperty("name")); |
| } |
| app.waitForQueueDrainAndRefreshIndex(); |
| //2. validate the size of the result |
| Query query = new Query(); |
| Results listResults = em.searchCollection(em.getApplicationRef(), "stores", query); |
| assertEquals("total number of 'stores'", locations.size(), listResults.size()); |
| //3. verify each entity has geo data |
| for (Entity entity : listResults.entities) { |
| Object location = entity.getProperty("location"); |
| assertNotNull(location); |
| assertTrue(location instanceof String); |
| } |
| |
| query = Query.fromQL("select * where location='texas'"); |
| listResults = em.searchCollection(em.getApplicationRef(), "stores", query); |
| assertEquals("total number of 'stores'", 1, listResults.size()); |
| //3. verify each entity has geo data |
| for (Entity entity : listResults.entities) { |
| Object location = entity.getProperty("location"); |
| assertNotNull(location); |
| assertTrue(location instanceof String); |
| } |
| |
| } |
| |
| @Test |
| /** |
| * Load entities with location data and query them from a far away location |
| * 1. create entities with geo |
| * 2. Query the collection from a point more than 10000m from the locations |
| * and ensure that no entities are returned when restricted to a 10000m radius |
| * 3. Query the collection from a point more than 10000m from the locations |
| * and ensure that all entities are returned when the distance is set to the |
| * circumference of the earth |
| */ |
| public void testGeoFromFarAwayLocation() throws Exception { |
| //1. create entities with geo |
| EntityManager em = loadGeolocationTestEntities(); |
| //2. Query the collection from a point more than 10000m from the locations |
| // and ensure that no entities are returned when restricted to a 10000m radius |
| final double lat = 37.776753; |
| final double lon = -122.407846; |
| Query query = Query.fromQL("select * where location within " + NEARBY_RADIUS + " of " |
| + lat + "," + lon); |
| Results listResults = em.searchCollection(em.getApplicationRef(), "stores", query); |
| |
| assertEquals("Results within " + NEARBY_RADIUS + "m from center", 0, listResults.size()); |
| //3. Query the collection from a point more than 10000m from the locations |
| // and ensure that all entities are returned when the distance is set to the |
| // circumference of the earth |
| Query query2 = Query.fromQL("select * where location within " + CIRCUMFERENCE_OF_THE_EARTH + " of " |
| + lat + "," + lon); |
| listResults = em.searchCollection(em.getApplicationRef(), "stores", query2); |
| |
| assertEquals("Results within " + CIRCUMFERENCE_OF_THE_EARTH |
| + "m from center", LOCATION_PROPERTIES.size(), listResults.size()); |
| |
| } |
| |
| @Test |
| /** |
| * Load entities with location data and query them from a nearby location |
| * 1. create entities with geo |
| * 2. Query the collection from a point less than 10000m from the locations |
| * and ensure that one entity is returned when restricted to a 10000m radius |
| * 3. Query the collection from a point less than 10000m from the locations |
| * and ensure that all entities are returned when the distance is set to the |
| * circumference of the earth |
| */ |
| public void testGeoFromNearbyLocation() throws Exception { |
| logger.info( "GeoIT.testGeoFromNearbyLocation" ); |
| //1. create entities with geo |
| EntityManager em = loadGeolocationTestEntities(); |
| |
| final double lat = -33.746369; |
| final double lon = 150.952185; |
| |
| //2. Query the collection from a point less than 10000m from the locations |
| // and ensure that one entity is returned when restricted to a 10000m radius |
| Query query = Query.fromQL("select * where location within " + NEARBY_RADIUS + " of " |
| + lat + "," + lon); |
| Results listResults = em.searchCollection(em.getApplicationRef(), "stores", query); |
| assertEquals( "Results within " + NEARBY_RADIUS + "m from center", 1, listResults.size() ); |
| |
| //3. Query the collection from a point less than 10000m from the locations |
| // and ensure that all entities are returned when the distance is set to the |
| // circumference of the earth |
| query = Query.fromQL( |
| "select * where location within " + CIRCUMFERENCE_OF_THE_EARTH + " of " + lat + "," + lon ); |
| listResults = em.searchCollection(em.getApplicationRef(), "stores", query); |
| assertEquals( "Results within " + CIRCUMFERENCE_OF_THE_EARTH + "m from center", LOCATION_PROPERTIES.size(), |
| listResults.size() ); |
| } |
| |
| /** |
| * Load entities with location data and query them from multiple locations |
| * to ensure proper bounds |
| * 1. Create entities with geo |
| * 2. Create a list of points from different geographic areas |
| * 3. Query the collection from each point |
| * and ensure that no entities are returned when restricted to a 10000m radius |
| * 4. Query the collection from each point |
| * and ensure that all entities are returned when the distance is set to the |
| * circumference of the earth |
| */ |
| @Test |
| public void testGeoFromMultipleLocations() throws Exception { |
| logger.info("GeoIT.testGeoFromMultipleLocations"); |
| //1 Create entities with geo |
| EntityManager em = loadGeolocationTestEntities(); |
| //2 Create a list of points from different geographic areas |
| List<double[]> points = new ArrayList<>(); |
| points.add(new double[]{-90.000000, 90.000000});//Antarctica |
| points.add(new double[]{90, 90});;//Santa's house |
| points.add( new double[]{ 33.746369, -89});;//Woodland, MS |
| points.add( new double[] { 34.35, 58.22 } );; //Buenos Aires |
| points.add( new double[] { 39.55, 116.25 } );;//Beijing, China |
| points.add( new double[]{ 44.52, 20.32});; //Belgrade, Serbia |
| points.add( new double[] { -1.000000, 102.000000 } );;//Somewhere in Indonesia |
| for (double[] center : points) { |
| //3 Query the collection from each point |
| // and ensure that no entities are returned when restricted to a 10000m radius |
| final double lat = center[0]; |
| final double lon = center[1]; |
| |
| Query query = Query.fromQL("select * where location within 10000 of " |
| + lat + "," + lon); |
| Results listResults = em.searchCollection(em.getApplicationRef(), "stores", query); |
| assertEquals("Results less than 10000m away from center", 0, listResults.size()); |
| //4 Query the collection from each point |
| // and ensure that all entities are returned when the distance is set to the |
| // circumference of the earth |
| Query query2 = Query.fromQL("select * where location within 40000000 of " |
| + lat + "," + lon); |
| listResults = em.searchCollection(em.getApplicationRef(), "stores", query2); |
| assertEquals("Results from center point to ridiculously far", |
| LOCATION_PROPERTIES.size(), listResults.size()); |
| } |
| } |
| |
| |
| @Test |
| public void testPointPaging() throws Exception { |
| |
| |
| EntityManager em = app.getEntityManager(); |
| assertNotNull( em ); |
| |
| // save objects in a diagonal line from -90 -180 to 90 180 |
| |
| int numEntities = 50; |
| |
| float minLattitude = -90; |
| float maxLattitude = 90; |
| float minLongitude = -180; |
| float maxLongitude = 180; |
| |
| float lattitudeDelta = (maxLattitude - minLattitude) / numEntities; |
| |
| float longitudeDelta = (maxLongitude - minLongitude) / numEntities; |
| |
| for (int i = 0; i < numEntities; i++) { |
| float lattitude = minLattitude + lattitudeDelta * i; |
| float longitude = minLongitude + longitudeDelta * i; |
| |
| Map<String, Float> location = MapUtils.hashMap("latitude", lattitude).map("longitude", longitude); |
| |
| Map<String, Object> data = new HashMap<String, Object>(2); |
| data.put("name", String.valueOf(i)); |
| data.put("location", location); |
| |
| em.create("store", data); |
| } |
| |
| app.waitForQueueDrainAndRefreshIndex(); |
| |
| // earth's circumference is 40,075 kilometers. Up it to 50,000kilometers |
| // just to be save |
| Query query = Query.fromQL("location within 50000000 of -90, -180" ); |
| |
| query.setLimit( 10 ); |
| |
| int count = 0; |
| Results results; |
| |
| double previousDistance = 0d; |
| do { |
| results = em.searchCollection(em.getApplicationRef(), "stores", query); |
| |
| for (Entity entity : results.getEntities()) { |
| assertEquals(String.valueOf(count), entity.getName()); |
| |
| Object distanceObject = entity.getMetadata("distance"); |
| assertNotNull( distanceObject ); |
| assertTrue( distanceObject instanceof Double ); |
| double distance = (Double)distanceObject; |
| assertTrue( distance >= previousDistance ); |
| previousDistance = distance; |
| |
| count++; |
| } |
| |
| // set for the next "page" |
| query.setCursor(results.getCursor()); |
| } |
| while (results.getCursor() != null); |
| |
| // check we got back all 500 entities |
| assertEquals( numEntities, count ); |
| } |
| |
| |
| @Test |
| public void testSamePointPaging() throws Exception { |
| |
| EntityManager em = app.getEntityManager(); |
| assertNotNull(em); |
| |
| // save objects in a diagonal line from -90 -180 to 90 180 |
| |
| int numEntities = 10; |
| |
| for (int i = 0; i < numEntities; i++) { |
| Map<String, Object> data = new HashMap<String, Object>(2); |
| data.put("name", String.valueOf(i)); |
| setPos(data, 0, 0); |
| |
| em.create("store", data); |
| } |
| |
| app.waitForQueueDrainAndRefreshIndex(); |
| Thread.sleep(2000); |
| |
| // earth's circumference is 40,075 kilometers. Up it to 50,000kilometers |
| // just to be save |
| Query query = Query.fromQL("location within 50000000 of 0, 0" ); |
| query.setLimit( 5 ); |
| |
| int count = 0; |
| Results results; |
| |
| |
| double previousDistance = 0d; |
| do { |
| results = em.searchCollection(em.getApplicationRef(), "stores", query); |
| |
| for (Entity entity : results.getEntities()) { |
| //TODO:can we assert order |
| final int expected = numEntities - count - 1; |
| |
| Object distanceObject = entity.getMetadata("distance"); |
| assertNotNull( distanceObject ); |
| assertTrue( distanceObject instanceof Double ); |
| double distance = (Double)distanceObject; |
| assertTrue( distance >= previousDistance ); |
| previousDistance = distance; |
| |
| assertEquals(String.valueOf(expected), entity.getName()); |
| count++; |
| } |
| |
| // set for the next "page" |
| query.setCursor(results.getCursor()); |
| } |
| while (results.getCursor() != null); |
| |
| // check we got back all 500 entities |
| assertEquals(numEntities, count); |
| } |
| |
| @Test |
| public void testDistanceByLimit() throws Exception { |
| |
| |
| EntityManager em = app.getEntityManager(); |
| assertNotNull(em); |
| |
| // save objects in a diagonal line from -90 -180 to 90 180 |
| |
| int numEntities = 10; |
| |
| float minLattitude = -90; |
| float maxLattitude = 90; |
| float minLongitude = -180; |
| float maxLongitude = 180; |
| |
| float lattitudeDelta = (maxLattitude - minLattitude) / numEntities; |
| |
| float longitudeDelta = (maxLongitude - minLongitude) / numEntities; |
| |
| for (int i = 0; i < numEntities; i++) { |
| float lattitude = minLattitude + lattitudeDelta * i; |
| float longitude = minLongitude + longitudeDelta * i; |
| |
| Map<String, Float> location = MapUtils.hashMap("latitude", lattitude).map("longitude", longitude); |
| |
| Map<String, Object> data = new HashMap<String, Object>(2); |
| data.put("name", String.valueOf(i)); |
| data.put("location", location); |
| |
| em.create("store", data); |
| } |
| |
| app.waitForQueueDrainAndRefreshIndex(); |
| |
| // earth's circumference is 40,075 kilometers. Up it to 50,000kilometers |
| // just to be save |
| Query query = Query.fromQL( "location within 50000000 of -90, -180" ); |
| |
| query.setLimit(10); |
| |
| int count = 0; |
| |
| do { |
| Results results = em.searchCollection(em.getApplicationRef(), "stores", query); |
| |
| double previousDistance = 0d; |
| |
| for (Entity entity : results.getEntities()) { |
| assertEquals(String.valueOf(count), entity.getName()); |
| |
| Object distanceObject = entity.getMetadata("distance"); |
| assertNotNull( distanceObject ); |
| assertTrue( distanceObject instanceof Double ); |
| double distance = (Double)distanceObject; |
| assertTrue( distance >= previousDistance ); |
| previousDistance = distance; |
| |
| count++; |
| } |
| } |
| while (query.getCursor().isPresent()); |
| |
| // check we got back all 500 entities |
| assertEquals(numEntities, count); |
| } |
| |
| |
| @Test |
| public void testGeoWithIntersection() throws Exception { |
| |
| EntityManager em = app.getEntityManager(); |
| assertNotNull( em ); |
| |
| int size = 10; |
| int min = 5; |
| int max = 9; |
| |
| List<Entity> created = new ArrayList<Entity>(size); |
| |
| for (int i = 0; i < size; i++) { |
| |
| // save all entities in the same location |
| Map<String, Object> data = new HashMap<String, Object>(2); |
| data.put("name", String.valueOf(i)); |
| data.put("index", i); |
| setPos(data, 0, 0); |
| |
| Entity e = em.create("store", data); |
| |
| created.add(e); |
| } |
| |
| app.waitForQueueDrainAndRefreshIndex(); |
| |
| int startDelta = size - min; |
| |
| // String queryString = String.format("select * where location within 100 of 0, |
| // 0 and index >= %d and index < %d order by index",min, max); |
| |
| String queryString = String.format( |
| "select * where index >= %d and index < %d order by index", min, max); |
| |
| Query query = Query.fromQL(queryString); |
| |
| Results r; |
| int count = 0; |
| |
| do { |
| |
| r = em.searchCollection(em.getApplicationRef(), "stores", query); |
| |
| for (Entity e : r.getEntities()) { |
| assertEquals(created.get(startDelta + count), e); |
| count++; |
| } |
| |
| query.setCursor(r.getCursor()); |
| } |
| while (r.hasCursor()); |
| |
| assertEquals(startDelta - (size - max), count); |
| } |
| |
| |
| @Test |
| public void testDenseSearch() throws Exception { |
| |
| EntityManager em = app.getEntityManager(); |
| assertNotNull(em); |
| |
| // save objects in a diagonal line from -90 -180 to 90 180 |
| |
| int numEntities = 25; |
| |
| float minLatitude = 48.32455f; |
| float maxLatitude = 48.46481f; |
| float minLongitude = 9.89561f; |
| float maxLongitude = 10.0471f; |
| |
| float latitudeDelta = (maxLatitude - minLatitude) / numEntities; |
| |
| float longitudeDelta = (maxLongitude - minLongitude) / numEntities; |
| |
| for (int i = 0; i < numEntities; i++) { |
| float latitude = minLatitude + latitudeDelta * i; |
| float longitude = minLongitude + longitudeDelta * i; |
| |
| Map<String, Float> location = |
| MapUtils.hashMap("latitude", latitude).map("longitude", longitude); |
| |
| Map<String, Object> data = new HashMap<String, Object>(2); |
| data.put("name", String.valueOf(i)); |
| data.put("location", location); |
| |
| em.create("store", data); |
| } |
| |
| app.waitForQueueDrainAndRefreshIndex(); |
| |
| //do a direct geo iterator test. We need to make sure that we short circuit on the correct tile. |
| |
| |
| int limit = 8; |
| |
| |
| long startTime = System.currentTimeMillis(); |
| |
| //now test at the EM level, there should be 0 results. |
| Query query = Query.fromQL("location within 1000 of 48.38626, 9.94175"); |
| query.setLimit(limit); |
| |
| Results results = em.searchCollection(em.getApplicationRef(), "stores", query); |
| |
| assertEquals(0, results.size()); |
| |
| long endTime = System.currentTimeMillis(); |
| |
| logger.info("Runtime took {} milliseconds to search", endTime - startTime); |
| } |
| |
| |
| /** |
| * Load entities for geo queries |
| * 1. Get an instance of the entity manager |
| * 2. load test entities |
| * 3. refresh the index |
| * 4. return the entity manager |
| */ |
| private EntityManager loadGeolocationTestEntities() throws Exception { |
| logger.info("GeoIT.loadGeolocationTestEntities"); |
| //1. Get an instance of the entity manager |
| |
| EntityManager em = app.getEntityManager(); |
| assertNotNull(em); |
| //2. load test entities |
| for (Map<String, Object> location : LOCATION_PROPERTIES) { |
| logger.info("Create entity with location '{}'", location.get("name")); |
| Entity entity = em.create("store", location); |
| assertNotNull(entity); |
| } |
| //3. refresh the index |
| app.waitForQueueDrainAndRefreshIndex(); |
| //4. return the entity manager |
| return em; |
| } |
| |
| public Map<String, Object> getLocation(double latitude, double longitude) throws Exception { |
| Map<String, Object> latlong = new LinkedHashMap<String, Object>(); |
| latlong.put("latitude", latitude); |
| latlong.put("longitude", longitude); |
| return latlong; |
| } |
| |
| |
| public void updatePos(EntityManager em, EntityRef entity, double latitude, double longitude) throws Exception { |
| Map<String, Object> latlong = new LinkedHashMap<String, Object>(); |
| latlong.put("latitude", latitude); |
| latlong.put("longitude", longitude); |
| |
| em.setProperty(entity, "location", latlong); |
| app.waitForQueueDrainAndRefreshIndex(); |
| } |
| |
| |
| public void setPos(Map<String, Object> data, double latitude, double longitude) { |
| Map<String, Object> latlong = new LinkedHashMap<String, Object>(); |
| latlong.put("latitude", latitude); |
| latlong.put("longitude", longitude); |
| |
| data.put("location", latlong); |
| } |
| } |