2
votes

I have a graph in neo4j (http://www.neo4j.org/) with nodes representing people. Some of these nodes have a physical location saved (in various properties: longitude, latitude, location_name, location_id), but they can be nil as well.

I would like to construct a cypher query that orders the resulting nodes by the distance from the origin node's listed physical location. For example, I want to query starting with node id 42 that has longitude -122.419, latitude 37.7793, location_name "San Francisco, California", and location_id 114952118516947, and retrieve the 10 closest people to node 42 by physical location (shortest distance). I've found resources for calculating the (approximate) distance between two points using longitudes and latitudes, so that's not an issue.

Is there a way to calculate a variable like that for each visited node and then order the results by that variable?

I realize this is probably computationally expensive, so here's an alternative that I'm trying to get to work:

  • In the query, check if the node's location_id or location_name matches that of the origin node and order those matching nodes first. (Not a perfect solution but perhaps acceptable in the short term)

When I try to use ORDER BY (http://docs.neo4j.org/chunked/milestone/query-order.html) with a variable calculated from the WITH operator (http://docs.neo4j.org/chunked/stable/query-with.html), I get this error:

SyntaxException: Unknown identifier `flag`.

Here's the full query:

start n = node(42) match (n)<-[:friends]->(f) WITH f, (f.fb_location_id = 114952118516947) AS flag RETURN DISTINCT f ORDER BY flag LIMIT 10

If this isn't possible, what's the best way to approach this?

  • [filter results without ordering] Prior to the query, calculate a range of latitude + longitude combinations that are within an acceptable distance (e.g. 20 miles), then filter others out of the result. Make another query if I want to expand the distance.
  • [filter results without ordering] Prior to the query, figure out which locations (cities) are within an acceptable distance (e.g. 20 miles), then filter others out of the result (using location_id). Make another query if I want to expand the distance.

Thank you!

1

1 Answers

4
votes

What about trying to use withinDistance? e.g.

START n=node:people('withinDistance:[53.489271,-2.246704, 20.0]')
<conditions here>
RETURN n

The lat/long supplied here is the location of node 42 in your example, 20.0 is the max distance in km. If you are using Neo4j 1.9+, take a look at http://architects.dzone.com/articles/neo4jcypher-finding-football which provides a good introduction for what you can do with Neo4j Spatial.

Note: the results of withinDistance are sorted by default on distance, asc