Graph Algorithms in Production with Neo4j GDS
Why Graph Algorithms in Production?
Graph databases excel at storing and querying relationships, but the real value emerges when you analyse the structure of those relationships. Who are the most influential people in a social network? Which transactions form a suspicious ring? How do communities form around topics in a knowledge graph?
These questions demand graph algorithms — and Neo4j's Graph Data Science (GDS) library brings them into production without exporting data to a separate analytics environment. GDS provides over 50 algorithms implemented for performance, with parallel execution, memory-efficient graph projections, and incremental loading.
This article walks through the three families of algorithms that deliver the most immediate value in production: centrality, community detection, and pathfinding — with real Cypher and GDS examples you can run today.
Setting Up GDS
GDS ships as a Neo4j plugin. If you are running Neo4j in Docker, add the plugin volume:
volumes:
- ./plugins:/plugins
environment:
NEO4J_dbms_security_procedures_unrestricted: gds.*
Then install the jar matching your Neo4j version from the Neo4j GDS releases page. Once installed, verify:
CALL gds.version();
All GDS algorithms work on named graphs — in-memory projections of your stored graph. This decouples your operational schema from your analytics workload:
CALL gds.graph.project(
'myGraph',
['Person', 'Company'],
{KNOWS: {orientation: 'UNDIRECTED'}, INVESTED_IN: {orientation: 'NATURAL'}}
);
A projected graph lives in memory, is shared across algorithms, and can be streamed, written back, or dropped when done.
Centrality Algorithms
Centrality answers "which nodes matter most?" Different algorithms reveal different kinds of importance.
PageRank
PageRank measures influence based on incoming connections — a node is important if other important nodes link to it. It is the foundation of recommendation engines, fraud detection, and knowledge graph summarisation.
CALL gds.pageRank.stream('myGraph')
YIELD nodeId, score
RETURN gds.util.asNode(nodeId).name AS entity, score
ORDER BY score DESC
LIMIT 10;
In a knowledge graph of research papers, PageRank surfaces the seminal works that the field builds on. In a transaction graph, it flags accounts that receive money from many other high-value accounts — a classic money-laundering signal.
Betweenness Centrality
Betweenness measures how often a node lies on the shortest paths between all other pairs of nodes. High-betweenness nodes are bridges — they connect otherwise disconnected parts of the graph.
CALL gds.betweenness.stream('myGraph')
YIELD nodeId, score
RETURN gds.util.asNode(nodeId).name AS entity, score
ORDER BY score DESC
LIMIT 10;
In a supply chain graph, the node with the highest betweenness is the single point of failure. In an organisational chart, it is the person who connects teams — lose them and collaboration breaks down.
Degree Centrality
The simplest measure: count of relationships. In directed graphs, you can separate in-degree (influence) from out-degree (reach).
CALL gds.degree.stream('myGraph', {orientation: 'REVERSE'})
YIELD nodeId, score
RETURN gds.util.asNode(nodeId).name AS entity, score AS indegree
ORDER BY indegree DESC
LIMIT 10;
Community Detection
Community detection finds groups of nodes that are more densely connected internally than to the rest of the graph. This is where graph algorithms outperform every other analytic technique.
Louvain (Modularity Optimisation)
Louvain iteratively moves nodes between communities to maximise modularity — a measure of how well the graph partitions into communities. It is fast, scalable to millions of nodes, and requires no prior knowledge of the number of communities.
CALL gds.louvain.stream('myGraph')
YIELD nodeId, communityId
RETURN communityId, collect(gds.util.asNode(nodeId).name) AS members
ORDER BY size(members) DESC;
Microsoft's GraphRAG uses a variant of this to organise retrieved entities into community summaries. In a customer graph, Louvain naturally segments users into interest groups without any manual labelling.
Weakly Connected Components (WCC)
The simplest community algorithm: find islands of connectivity. Two nodes are in the same WCC if there is any undirected path between them.
CALL gds.wcc.stream('myGraph')
YIELD nodeId, componentId
RETURN componentId, count(*) AS size
ORDER BY size DESC;
WCC is indispensable for data quality. In a knowledge graph built from multiple sources, WCC reveals whether your entity resolution worked — if the same real-world entity appears in multiple components, your merge logic has gaps.
Label Propagation (LPA)
LPA propagates labels through the graph: each node adopts the most frequent label among its neighbours. It is semi-supervised — seed a few known labels and let the algorithm infer the rest.
CALL gds.labelPropagation.stream('myGraph')
YIELD nodeId, communityId
RETURN communityId, collect(gds.util.asNode(nodeId).name) AS members
ORDER BY size(members) DESC;
Use LPA when you have ground-truth labels for a subset of nodes and want to classify the rest — for example, flagging fraudulent merchants from a small seed set.
Pathfinding
The existing Graph Theory for Software Engineers article covers BFS and Dijkstra conceptually. GDS brings these to production with Delta-Stepping (a parallel variant of Dijkstra) and Yen's k-shortest-paths:
MATCH (a:Location {name: 'Berlin'}), (b:Location {name: 'Munich'})
CALL gds.shortestPath.dijkstra.stream('roadGraph', {
sourceNode: a,
targetNode: b,
relationshipWeightProperty: 'distance_km'
})
YIELD nodeIds, totalCost
RETURN [nodeId IN nodeIds | gds.util.asNode(nodeId).name] AS route, totalCost;
Algorithm Selection Guide
| Problem | Algorithm | Family | When to Use |
|---|---|---|---|
| Find influencers | PageRank | Centrality | Recommendation, content ranking, expert finder |
| Find bridges | Betweenness | Centrality | Supply chain risk, org analysis, fault tolerance |
| Segment users | Louvain | Community | Customer segmentation, topic clustering |
| Detect fraud rings | WCC + PageRank | Hybrid | Transaction laundering, bot detection |
| Classify nodes | Label Propagation | Community | Semi-supervised ML with sparse labels |
| Shortest route | Delta-Stepping | Pathfinding | Logistics, network routing, dependency resolution |
Putting It Together: Fraud Detection Pipeline
A real fraud detection system combines multiple GDS algorithms:
- WCC on the transaction graph to find connected components
- PageRank within each component to score account influence
- Louvain to find tightly-knit subgroups (potential fraud rings)
- Betweenness to identify mule accounts that bridge legitimate and fraudulent clusters
// Step 1: Project the transaction graph
CALL gds.graph.project(
'fraudGraph',
'Account',
{TRANSFERRED_TO: {orientation: 'UNDIRECTED'}}
);
// Step 2: Community detection
CALL gds.louvain.stream('fraudGraph')
YIELD nodeId, communityId
WITH communityId, collect(gds.util.asNode(nodeId)) AS accounts
WHERE size(accounts) > 5 AND size(accounts) < 50
// Report mid-size communities — typical fraud ring size
RETURN communityId, [acc IN accounts | acc.id] AS accountIds,
size(accounts) AS memberCount;
Performance Considerations
GDS algorithms run in-memory, so the size of your projected graph matters:
- Project only what you need: filter nodes and relationships with Cypher projections:
CALL gds.graph.project.cypher('g', 'MATCH (n:Person) RETURN id(n) AS id', 'MATCH (n:Person)-[:KNOWS]->(m:Person) RETURN id(n) AS source, id(m) AS target') - Use
NATURALorientation unless you need undirected traversal — it halves memory - Tier your algorithms: PageRank and Betweenness are O(n²) or worse on dense graphs. Run WCC as a cheap filter first, then run expensive algorithms on the largest component only
- Stream, don't write: use
streammode during development andwritemode only for the final pipeline
Conclusion
Graph algorithms transform a graph database from a passive store of relationships into an active analytics engine. Neo4j GDS makes this practical in production — you run the same algorithms that power Google's search ranking and Facebook's community detection on your own data, without leaving Cypher.
Start with centrality to find what matters, community detection to discover hidden structure, and pathfinding to connect it all together. The algorithms are well-understood; the hard part is knowing which one to apply. The table above should give you a starting point, but the real learning comes from running them against your own data and observing what emerges.
For a deeper dive into the data models that make graph algorithms effective, see Ontology in Graph Databases. For the fundamentals these algorithms build on, start with Graph Theory for Software Engineers.