topic Re: cypher: Calculate distances in Neo4j Graph Platform
https://community.neo4j.com/t5/neo4j-graph-platform/cypher-calculate-distances/m-p/60405#M35816
<P>The way I wrote the code, each name has less and less comparison to other nodes. The last name is not even given an output. This is because I just calculated the distance between the current node and the remaining nodes in the list, because the distance calculation is commutative. As such, the the results as is are not necessarily the top three closest nodes for each node. The only one that has this property is the first node, as it contains all node calculations in its list. This can be fixed. The easiest way is just calculate the distance for each node agains all nodes, and filter the closest three for each. This ignores the efficiency of not calculating distance(a, b) and distance(b, a). To retain the efficiency of not calculating each distance twice, the above query can be modified. It is just more work and less understandable. If you want, I can alter it so you can get a valid list of the top three closest nodes for each node. </P>Wed, 21 Sep 2022 16:28:42 GMTglilienfield2022-09-21T16:28:42Zcypher: Calculate distances
https://community.neo4j.com/t5/neo4j-graph-platform/cypher-calculate-distances/m-p/60370#M35798
<P>I am trying to calulate distances between each node.</P>
<P> </P>
<P> </P>
<LI-CODE lang="cypher">call n10s.inference.nodesLabelled('Entity', {catNameProp: "label", catLabel: "Resource", subCatRel: "SCO" }) YIELD node
match(node)-[:hasLocation]-(b:Location)
WITH node,point({latitude: avg(b.lat), longitude: avg(b.long)}) as entity_point
return node.name, entity_point</LI-CODE>
<P> </P>
<P> </P>
<P>is it possible to calculate the distance between the returned nodes and find the closest neighboor to each one? Ιn continuation of the above query is there any for loop way to impement something like this?</P>
<P>Thank you in advance.</P>Tue, 20 Sep 2022 12:35:56 GMThttps://community.neo4j.com/t5/neo4j-graph-platform/cypher-calculate-distances/m-p/60370#M35798dlyberis2022-09-20T12:35:56ZRe: cypher: Calculate distances
https://community.neo4j.com/t5/neo4j-graph-platform/cypher-calculate-distances/m-p/60389#M35806
<P>I don't have the library or data to test this. You can try to see if it results in what you are looking for. </P>
<LI-CODE lang="markup">call n10s.inference.nodesLabelled('Entity', {catNameProp: "label", catLabel: "Resource", subCatRel: "SCO" }) YIELD node
match(node)-[:hasLocation]-(b:Location)
with node, point({latitude: avg(b.lat), longitude: avg(b.long)}) as entity_point
with collect({name: node.name, point: entity_point}) as points
unwind range(0,size(points)-2) as index
with index, points[index] as n, points[index+1..] as otherNodes
return index, n.name, [x in otherNodes | {name: x.name, distance: n.point - x.point}] as distances</LI-CODE>
<P>The distance between two points occurs with the expression '<SPAN>n</SPAN><SPAN>.</SPAN><SPAN>point </SPAN><SPAN>-</SPAN><SPAN> x</SPAN><SPAN>.</SPAN><SPAN>point' on line 7. Replace this with the actual distance calculation between two entity points. The result of the query will be a row for each node, containing the name of the node and a collection of the other nodes and their distance from the row's node. The number of calculations per row decreases by one each row, as the algorithm does not calculate '</SPAN><SPAN>n</SPAN><SPAN>.</SPAN><SPAN>point </SPAN><SPAN>-</SPAN><SPAN> x</SPAN><SPAN>.</SPAN><SPAN><SPAN>point' and 'x</SPAN></SPAN><SPAN>.</SPAN><SPAN>point </SPAN><SPAN>-</SPAN><SPAN> n</SPAN><SPAN>.</SPAN><FONT face="inherit">point'. Let me know if there are issues and we can see if we can </FONT>resolve<FONT face="inherit"> them. </FONT></P>Wed, 21 Sep 2022 01:12:07 GMThttps://community.neo4j.com/t5/neo4j-graph-platform/cypher-calculate-distances/m-p/60389#M35806glilienfield2022-09-21T01:12:07ZRe: cypher: Calculate distances
https://community.neo4j.com/t5/neo4j-graph-platform/cypher-calculate-distances/m-p/60397#M35811
<P>Thank you very much for your answer it worked after using the distance function on line 7 as you can see at the following cypher code.</P>
<LI-CODE lang="cypher">call n10s.inference.nodesLabelled('Entity', {catNameProp: "label", catLabel: "Resource", subCatRel: "SCO" }) YIELD node
match(node)-[:hasLocation]-(b:Location)
with node, point({latitude: avg(b.lat), longitude: avg(b.long)}) as entity_point
with collect({name: node.name, point: entity_point}) as points
unwind range(0,size(points)-2) as index
with index, points[index] as n, points[index+1..] as otherNodes
return index, n.name, [x in otherNodes |{name: x.name, distance: distance(n.point,x.point)}] as distances</LI-CODE>
<P>a part of the result is depicted at the following image</P>
<P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="dlyberis_0-1663766063715.png" style="width: 400px;"><img src="https://community.neo4j.com/t5/image/serverpage/image-id/7337iD7FADF0D8040D470/image-size/medium/is-moderation-mode/true/strip-exif-data/true?v=v2&px=400" role="button" title="dlyberis_0-1663766063715.png" alt="dlyberis_0-1663766063715.png" /></span></P>
<P>Is it possible to get an order by "distance" key of the returned distances lists for each n.name? is there a sort way to do it in the code that you provided ?<BR />i really appreciate your help!</P>Wed, 21 Sep 2022 13:24:25 GMThttps://community.neo4j.com/t5/neo4j-graph-platform/cypher-calculate-distances/m-p/60397#M35811dlyberis2022-09-21T13:24:25ZRe: cypher: Calculate distances
https://community.neo4j.com/t5/neo4j-graph-platform/cypher-calculate-distances/m-p/60400#M35812
<P>try this:</P>
<LI-CODE lang="markup">call n10s.inference.nodesLabelled('Entity', {catNameProp: "label", catLabel: "Resource", subCatRel: "SCO" }) YIELD node
match(node)-[:hasLocation]-(b:Location)
with node, point({latitude: avg(b.lat), longitude: avg(b.long)}) as entity_point
with collect({name: node.name, point: entity_point}) as points
unwind range(0,size(points)-2) as index
with index, points[index] as n, points[index+1..] as otherNodes
with index, n.name as name, [x in otherNodes |{name: x.name, distance: distance(n.point,x.point)}] as distances
unwind distances as distance
with index, name, distance
order by distance desc
return index, name, collect(distance) as distances</LI-CODE>
<P>Do you want each name to have the full list of other names and their corresponding distances? </P>Wed, 21 Sep 2022 14:03:50 GMThttps://community.neo4j.com/t5/neo4j-graph-platform/cypher-calculate-distances/m-p/60400#M35812glilienfield2022-09-21T14:03:50ZRe: cypher: Calculate distances
https://community.neo4j.com/t5/neo4j-graph-platform/cypher-calculate-distances/m-p/60402#M35814
<P>with your code i can realize how cypher can handle data manipulation and aggregation, it is really helpfull. I prefer each <SPAN>name to have </SPAN>only the first 3 elements with the shortest distance.</P>
<P>i tried this one is it a proper way?</P>
<LI-CODE lang="cypher">match(node)-[:hasLocation]-(b:Location)
with node, point({latitude: avg(b.lat), longitude: avg(b.long)}) as entity_point
with collect({name: node.name, point: entity_point}) as points
unwind range(0,size(points)-2) as index
with index, points[index] as n, points[index+1..] as otherNodes
with index, n.name as name, [x in otherNodes |{name: x.name, distance: distance(n.point,x.point)}] as distances
unwind distances as distance
with index, name, distance
order by distance
with index,name,collect(distance) as distances
return index, name,distances[0..3] </LI-CODE>Wed, 21 Sep 2022 14:21:11 GMThttps://community.neo4j.com/t5/neo4j-graph-platform/cypher-calculate-distances/m-p/60402#M35814dlyberis2022-09-21T14:21:11ZRe: cypher: Calculate distances
https://community.neo4j.com/t5/neo4j-graph-platform/cypher-calculate-distances/m-p/60405#M35816
<P>The way I wrote the code, each name has less and less comparison to other nodes. The last name is not even given an output. This is because I just calculated the distance between the current node and the remaining nodes in the list, because the distance calculation is commutative. As such, the the results as is are not necessarily the top three closest nodes for each node. The only one that has this property is the first node, as it contains all node calculations in its list. This can be fixed. The easiest way is just calculate the distance for each node agains all nodes, and filter the closest three for each. This ignores the efficiency of not calculating distance(a, b) and distance(b, a). To retain the efficiency of not calculating each distance twice, the above query can be modified. It is just more work and less understandable. If you want, I can alter it so you can get a valid list of the top three closest nodes for each node. </P>Wed, 21 Sep 2022 16:28:42 GMThttps://community.neo4j.com/t5/neo4j-graph-platform/cypher-calculate-distances/m-p/60405#M35816glilienfield2022-09-21T16:28:42ZRe: cypher: Calculate distances
https://community.neo4j.com/t5/neo4j-graph-platform/cypher-calculate-distances/m-p/60406#M35817
<P>Try this version. It should provide you a list of all the nodes, with each nodes corresponding three closest other nodes in a list. To make the code simpler to understand, I just went ahead and calculated the distance between each pair of nodes in both orders. I assume the distance calculation does not take that long. </P>
<P>The double unwind of points results in rows that are the Cartesian product of the points elements. With this, you can calculate the distance between every two points. The rows that contain the same two points are filtered out with line 8. I used list slicing to keep only the first three other nodes (which are the closest since the data is sorted in ascending order). This is what you correctly did too. </P>
<LI-CODE lang="markup">call n10s.inference.nodesLabelled('Entity', {catNameProp: "label", catLabel: "Resource", subCatRel: "SCO" }) YIELD node
match(node)-[:hasLocation]-(b:Location)
with node, point({latitude: avg(b.lat), longitude: avg(b.long)}) as entity_point
with collect({name: node.name, point: entity_point}) as points
unwind points as a
unwind points as b
with a, b
where a.name <> b.name
with a, b, distance(a.point, b.point) as distance
order by distance
with a.name as name, collect({name: b.name, distance: distance}) as bNodes
return name, collect(bNodes)[..3] as otherNodes</LI-CODE>
<P> </P>Wed, 21 Sep 2022 16:43:24 GMThttps://community.neo4j.com/t5/neo4j-graph-platform/cypher-calculate-distances/m-p/60406#M35817glilienfield2022-09-21T16:43:24ZRe: cypher: Calculate distances
https://community.neo4j.com/t5/neo4j-graph-platform/cypher-calculate-distances/m-p/60407#M35818
<P>Oops, there is an error in line 12 and I can't edit the previous post. The following is the corrected version. </P>
<LI-CODE lang="markup">call n10s.inference.nodesLabelled('Entity', {catNameProp: "label", catLabel: "Resource", subCatRel: "SCO" }) YIELD node
match(node)-[:hasLocation]-(b:Location)
with node, point({latitude: avg(b.lat), longitude: avg(b.long)}) as entity_point
with collect({name: node.name, point: entity_point}) as points
unwind points as a
unwind points as b
with a, b
where a.name <> b.name
with a, b, distance(a.point, b.point) as distance
order by distance
return a.name as name, collect({name: b.name, distance: distance})[..3] as otherNodes</LI-CODE>Wed, 21 Sep 2022 16:46:55 GMThttps://community.neo4j.com/t5/neo4j-graph-platform/cypher-calculate-distances/m-p/60407#M35818glilienfield2022-09-21T16:46:55Z