cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.

More efficient way without cartesian product?

Hello Community,

This does a proper job of building a relationship between two airports where I then indicate the distance between the airports in both miles and kilometers. The query build a cartesian product - is there a more efficient slash elegant way of performing this? I have tested this with a small subset of airports (8 airports, 64 relationships), but fear this will not scale to 10's of thousand of airports.

MATCH (a:Airport), (b:Airport)
WHERE
a.iata_code <> b.iata_code
WITH
a, b,
point({latitude:a.latitude_deg, longitude:a.longitude_deg, height: a.elevation_ft / 3.281}) AS p_a,
point({latitude:b.latitude_deg, longitude:b.longitude_deg, height: b.elevation_ft / 3.281}) AS p_b
MERGE
(a)-[:DISTANCE_BETWEEN {distance_miles: round(point.distance(p_a, p_b) / 1609, 1),
distance_kilometers: round(point.distance(p_a, p_b) / 1000, 1)}]-(b) 

Thanks much all,

Douglas

 

1 ACCEPTED SOLUTION

Hello @DouglasWiley 🙂

Here is a query where it reduce the number of operations but you still have a Cartesian product:

MATCH (a:Airport) 
MATCH (b:Airport) 
WHERE id(a) > id(b) 
WITH 
    a, b, 
    point({latitude:a.latitude_deg, longitude:a.longitude_deg, height: a.elevation_ft / 3.281}) AS p_a, 
    point({latitude:b.latitude_deg, longitude:b.longitude_deg, height: b.elevation_ft / 3.281}) AS p_b 
MERGE (a)-[r:DISTANCE_BETWEEN]-(b) 
SET r += {
    distance_miles: round(point.distance(p_a, p_b) / 1609, 1), 
    distance_kilometers: round(point.distance(p_a, p_b) / 1000, 1)
    }

Regards,
Cobra

View solution in original post

3 REPLIES 3

Hello @DouglasWiley 🙂

Here is a query where it reduce the number of operations but you still have a Cartesian product:

MATCH (a:Airport) 
MATCH (b:Airport) 
WHERE id(a) > id(b) 
WITH 
    a, b, 
    point({latitude:a.latitude_deg, longitude:a.longitude_deg, height: a.elevation_ft / 3.281}) AS p_a, 
    point({latitude:b.latitude_deg, longitude:b.longitude_deg, height: b.elevation_ft / 3.281}) AS p_b 
MERGE (a)-[r:DISTANCE_BETWEEN]-(b) 
SET r += {
    distance_miles: round(point.distance(p_a, p_b) / 1609, 1), 
    distance_kilometers: round(point.distance(p_a, p_b) / 1000, 1)
    }

Regards,
Cobra

Thanks so much @Cobra! This is excellent. What is the rational with "WHERE id(a) > id(b)"?

The Cartesian product is equivalent to a matrix multiplication so this clause allows you to do the calculation only in one direction. Instead of doing n² operations, there are (n(n-1))/2 operations. I don't know if it's clear 🙂