Neo4j Shortest Path and Dijkstra Algorithms

May 8: Hero City, One Month Graph Challenge

Vlad Batushkov
5 min readMay 8, 2019

Welcome word

In this series of small posts I do one simple graph daily. Domain model of graph somehow related to day’s history, some historical event, celebration or person. I do this challenge to learn Neo4j Data Modeling and Cypher. Every day. One month. Follow me. Maybe you will be inspired and next month would be yours One Month Graph Challenge. #OMGChallenge

Domain model

In 1965, 8 of May USSR government approved the Regulations on the honorary title “Hero City”. This title is conferred to the cities of the Soviet Union, whose residents displayed mass heroism and courage in defending the Homeland in the World War II of 1941–1945 (Eastern Front). This honor title is carried by 13 cities (one of which is a Hero Fortress in Brest, city of Belarus).

Today I want continue learn Cypher. I plan to build up a small graph of Hero Cities and apply path-finding query on it.

Graph

Create Hero Cities with connections to the nearest cities in both directions.

MERGE (b:Hero:Fortress { name: "Brest Fortress" })
MERGE (l:Hero:City { name: "Leningrad" })
MERGE (v:Hero:City { name: "Volgograd" })
MERGE (o:Hero:City { name: "Odessa" })
MERGE (s:Hero:City { name: "Sevastopol" })
MERGE (moscow:Hero:City { name: "Moscow" })
MERGE (k:Hero:City { name: "Kiev" })
MERGE (n:Hero:City { name: "Novorossiysk" })
MERGE (kerch:Hero:City { name: "Kerch" })
MERGE (minsk:Hero:City { name: "Minsk" })
MERGE (t:Hero:City { name: "Tula" })
MERGE (m:Hero:City { name: "Murmansk" })
MERGE (smolensk:Hero:City { name: "Smolensk" })
MERGE (m)-[:CONNECTED_TO { distance: 1013 }]->(l)-[:CONNECTED_TO { distance: 1013 }]->(m)
MERGE (l)-[:CONNECTED_TO { distance: 692 }]->(minsk)-[:CONNECTED_TO { distance: 692 }]->(l)
MERGE (l)-[:CONNECTED_TO { distance: 634 }]->(moscow)-[:CONNECTED_TO { distance: 634 }]->(l)
MERGE (l)-[:CONNECTED_TO { distance: 583 }]->(smolensk)-[:CONNECTED_TO { distance: 583 }]->(l)
MERGE (smolensk)-[:CONNECTED_TO { distance: 307 }]->(minsk)-[:CONNECTED_TO { distance: 307 }]->(smolensk)
MERGE (t)-[:CONNECTED_TO { distance: 173 }]->(moscow)-[:CONNECTED_TO { distance: 173 }]->(t)
MERGE (smolensk)-[:CONNECTED_TO { distance: 369 }]->(moscow)-[:CONNECTED_TO { distance: 369 }]->(smolensk)
MERGE (b)-[:CONNECTED_TO { distance: 325 }]->(minsk)-[:CONNECTED_TO { distance: 325 }]->(b)
MERGE (k)-[:CONNECTED_TO { distance: 434 }]->(minsk)-[:CONNECTED_TO { distance: 434 }]->(k)
MERGE (k)-[:CONNECTED_TO { distance: 508 }]->(b)-[:CONNECTED_TO { distance: 508 }]->(k)
MERGE (t)-[:CONNECTED_TO { distance: 365 }]->(smolensk)-[:CONNECTED_TO { distance: 365 }]->(t)
MERGE (k)-[:CONNECTED_TO { distance: 442 }]->(o)-[:CONNECTED_TO { distance: 442 }]->(k)
MERGE (s)-[:CONNECTED_TO { distance: 308 }]->(o)-[:CONNECTED_TO { distance: 308 }]->(s)
MERGE (kerch)-[:CONNECTED_TO { distance: 462 }]->(o)-[:CONNECTED_TO { distance: 462 }]->(kerch)
MERGE (kerch)-[:CONNECTED_TO { distance: 247 }]->(s)-[:CONNECTED_TO { distance: 247 }]->(kerch)
MERGE (kerch)-[:CONNECTED_TO { distance: 124 }]->(n)-[:CONNECTED_TO { distance: 124 }]->(kerch)
MERGE (v)-[:CONNECTED_TO { distance: 714 }]->(kerch)-[:CONNECTED_TO { distance: 714 }]->(v)
MERGE (v)-[:CONNECTED_TO { distance: 678 }]->(n)-[:CONNECTED_TO { distance: 678 }]->(v)
MERGE (v)-[:CONNECTED_TO { distance: 774 }]->(t)-[:CONNECTED_TO { distance: 774 }]->(v)

Nodes represent the cities and located accordingly, not exactly like on the picture, but I did my best. Now let’s try to find shortest path from Brest Hero Fortness to Hero City Volgograd:

MATCH (c1:Hero { name: 'Brest Fortress' })
MATCH (c2:City { name: 'Volgograd' })
MATCH path = shortestPath((c1)-[*]-(c2))
RETURN path

Result is ok. We asked Cypher to find shortest path by connected nodes. So it is just 2 nodes in between, result is true, can not be shorter than this. At the same time, we say nothing about actual distance between cities. And if we want to calculate shortest path with usage of distance, then it’s a different story. APOC comes here again. We need to set a start and end nodes, relationships type and property to use as a cost/weight of relationships. This is it:

MATCH (c1:Hero { name: 'Brest Fortress' })
MATCH (c2:City { name: 'Volgograd' })
CALL apoc.algo.dijkstra(c1, c2, 'CONNECTED_TO', 'distance') YIELD path, weight
RETURN path, weight

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Vlad Batushkov
Vlad Batushkov

Written by Vlad Batushkov

Engineering Manager @ Agoda. Neo4j Ninja. Articles brewed on modern tech, hops and indie rock’n’roll.

No responses yet

Write a response