(Using Neo4j 3.x and the neo4j.v1 Python driver)
I have a track consisting of a linked list of nodes each one representing a (lon, lat) pair of coordinates.
(A)-[:NEXT]->(B)-[:NEXT]->(C) etc. with properties lon, lat on each node
Question 1
The direct distance between the coordinates of two neighboring nodes, eg (0,0) and (1,1), could be added as a "distance" property of the relationship -[:NEXT {distance: 1.41421}]-> between the two neighboring nodes. How could you do that given that I have thousands of nodes like this?
Question 2
Whole segments of this linked list of nodes could be replaced by a single -[:NEXT]-> relationship with the "distance" property as the sum of all the distances between adjacent nodes of the original list. How could this be done efficiently for, again, thousands or more nodes?
(A)-[:NEXT {distance: 1}]->(B)-...->(D)-[:NEXT {distance: 1}]->(E) (A)-[:NEXT {distance: 4}}->(E)
Thank you for your guidance and hints.
Part1 : You're using lat/lon, in neo4j 3.0 there is native support for point and distance, make sure to use latitude
and longitude
property keys. You can then set this property on the relationship with the following :
MATCH (start:YourNodeLabel)-[r:NEXT]->(end)
SET r.distance = distance(point(start), point(end)) / 1000
Part 2 : If you know the start and end node of the path, you can then create this next relationship by reducing the distance properties of the relationships :
MATCH (start:YourNodeLabel {name:"A"}), (end:YourNodeLabel {name:"E"})
MATCH (start)-[r:NEXT*]->(end)
CREATE (start)-[newrel:NEXT]->(end)
SET newrel.distance = reduce(d=0.0, x IN r | d + x.distance)
Be careful however with this, taking into account that there could be more than one path
from start
to end
, in that case for eg if you want to find the shortest distance from start to end, you will need to calculate the total distance and take the lowest one :
MATCH (start:YourNodeLabel {name:"A"}), (end:YourNodeLabel {name:"E"})
MATCH p=(start)-[:NEXT*]->(end)
WITH p, start ,end, reduce(d=0.0, x IN rels(p) | d + x.distance) as totalDistance
ORDER BY totalDistance ASC
LIMIT 1
CREATE (start)-[newRel:NEXT]->(end)
SET newRel.distance = totalDistance
If you don't have the distance properties on the relationships, you can also calculate the geo distance on the fly in the reduce functions :
MATCH (start:YourNodeLabel {name:"A"}), (end:YourNodeLabel {name:"E"})
MATCH p=(start)-[:NEXT*]->(end)
WITH p, start, end,
reduce(d=0.0, x IN range(1, size(nodes(p))-1) | d + distance(point(nodes(p)[x-1]), point(nodes(p)[x])) / 1000) as distance
ORDER BY distance ASC
LIMIT 1
CREATE (start)-[newRel:NEXT]->(end)
SET newRel.distance = distance
As a general advise, I wouldn't use the same relationship type name for the relationship used as a shortcut, maybe CONNECT_TO
or REACH_POINT
can be more suited in order to not to interfer with the NEXT
relationships in other queries.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.