I have two types of nodes Idea and Location, Idea contains some general information and Location node have 3 properties its id, latitude and longitude. The relationships between these nodes is of following types:
(i:Idea)-[:DEVELOPED_AT]->(l:Location)
(i: Idea)-[:DEPLOYED_AT]->(l:Location)
Now when a user search for any idea by geography using google place autocomple then I receive lat, long of searched location. Now I have to return all the related ideas either developed or deployed within a particular radius of that searched location. On searching I came accross spatial Neo4j but I don't know how to use it.
You have a few options here.
neo4j-spatial
As you mentioned, the Neo4j Spatial extension can be used for efficient geospatial indexing. One type of query that the spatial extension provides is withinDistance
which will query for indexed nodes within a given radius. There are a few tutorials online that explain how to get started with neo4j spatial, but once you have it installed and added the nodes to the spatial index you can use a Cypher query like this to filter for nodes within 50km of a specified latitude, longitude:
// Find all Location nodes within 50km of specified lat/lon
START l=node:geom('withinDistance:[46.9163, -114.0905, 50.0]')
// Find all Idea nodes developed or deployed at these locations
MATCH (l)<-[:DEVELOPED_AT|:DEPLOYED_AT]-(i:Idea)
RETURN i
The spatial query is backed by an RTree index and is therefore efficient.
Compute distance
Another option is to use the Haversine formula to compute distance and use this as a filter. Note that this method will not be as efficient as the indexed backed neo4j-spatial approach as the distance will be computed for each Location node.
Since Cypher includes a haversin
function this can be done using Cypher:
// Find all
WITH 46.9163 AS lat, -114.0905 AS lon
MATCH (l:Location)
WHERE 2 * 6371 * asin(sqrt(haversin(radians(lat - l.lat))+ cos(radians(lat))* cos(radians(l.lat))* haversin(radians(lon - l.lon)))) < 50.0
MATCH (l)<-[:DEVELOPED_AT|:DEPLOYED_AT]-(i:Idea)
RETURN i
UPDATE With Neo4j > 3.4 you can use the built in Spatial index to achieve this
MATCH (i:Idea)-[:DEVELOPED_AT|:DEPLOYED_AT]->(l:Location)
WHERE distance(l.coord, point({ latitude: 46.9163}, longitude: -114.0905}})) < 50.0
Here 50.0 is assumed to be a meter value.
Just to mention when you create the location data you must mention the point index.
References:-
https://neo4j.com/docs/cypher-manual/current/functions/spatial/
https://neo4j.com/docs/cypher-manual/current/syntax/spatial/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With