简体   繁体   中英

Merging Nodes on Path calculating a (compound) Properties of the relationship

(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?

根据A和B的坐标,可以计算距离并将其作为属性添加到关系中

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)

添加第一张图中各个节点之间的距离,并将结果分配给第二张图中的distance属性,同时删除所有中间节点

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM