Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to search all nodes within particular radius using latitude and longitude in neo4j

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.

like image 667
iit2011081 Avatar asked Feb 01 '16 07:02

iit2011081


2 Answers

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
like image 111
William Lyon Avatar answered Sep 20 '22 14:09

William Lyon


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/

like image 40
Mithun Das Avatar answered Sep 19 '22 14:09

Mithun Das