The Label Propagation algorithm (LPA) is a community detection method based on label propagation. Initially, each node is assigned a label. During each iteration, every node updates its label to the one most common among its neighbors. Through this iterative process, densely connected groups of nodes tend to reach a consensus on a shared label, with nodes sharing the same label ultimately forming a community.
LPA does not optimize any specific predefined measure of community quality, nor does it require the number of communities to be specified in advance. Instead, it relies purely on the network's structure to guide the progression. Its simplicity makes LPA highly efficient for analyzing large and complex networks.
Related material of the algorithm:
Label of a node is initialized with a specified property value or its unique UUID.
Nodes sharing the same label at the end of the algorithm are considered members of the same community.
In the simplest setting, at each propagation iteration, a node updates its label to the one held by the largest number of its neighbors.
For example, in the diagram below, the blue node’s label will change from d to c.

When node and edge weights are considered, the label weight is calculated as the sum of the products of corresponding node and edge weights. In this case, each node updates its label to the one with the highest total weight.
As the weights of nodes and edges shown in the example below, the label of the blue node will be updated from d to a.

In multi-label propagation, each node can hold multiple labels simultaneously. In this case, each label is assigned a label probability proportional to its weight, while the sum of all label probabilities for each node equals 1.
In the example below, each node keeps 2 labels with their probabilities written next to them. The labels of the blue node will be updated from d, c to a, c with label probabilities Pa = 6.3/(6.3+1.85) = 0.77 and Pc = 1.85/(6.3+1.85) = 0.23.


Run the following statements on an empty graph to define its structure and insert data:
ALTER GRAPH CURRENT_GRAPH ADD NODE { user ({interest string, level int32}) }; ALTER GRAPH CURRENT_GRAPH ADD EDGE { connect ()-[{strength int32}]->() }; INSERT (A:user {_id:"A",interest:"flute",level:2}), (B:user {_id:"B",interest:"football",level:4}), (C:user {_id:"C",interest:"piano",level:4}), (D:user {_id:"D",interest:"violin",level:2}), (E:user {_id:"E",interest:"piano",level:4}), (F:user {_id:"F",interest:"movie",level:1}), (G:user {_id:"G",interest:"piano",level:4}), (H:user {_id:"H",interest:"tennis",level:2}), (I:user {_id:"I",interest:"violin",level:3}), (J:user {_id:"J",interest:"badminton",level:5}), (K:user {_id:"K",interest:"swimming",level:4}), (L:user {_id:"L",interest:"cello",level:1}), (M:user {_id:"M",interest:"saxophone",level:2}), (N:user {_id:"N",interest:"novel",level:3}), (O:user {_id:"O",interest:"swimming",level:3}), (A)-[:connect {strength:3}]->(B), (A)-[:connect {strength:5}]->(C), (A)-[:connect {strength:8}]->(F), (A)-[:connect {strength:6}]->(K), (B)-[:connect {strength:2}]->(C), (C)-[:connect {strength:9}]->(D), (D)-[:connect {strength:5}]->(A), (D)-[:connect {strength:6}]->(E), (E)-[:connect {strength:5}]->(A), (F)-[:connect {strength:9}]->(G), (F)-[:connect {strength:4}]->(J), (G)-[:connect {strength:10}]->(H), (H)-[:connect {strength:3}]->(F), (I)-[:connect {strength:2}]->(F), (I)-[:connect {strength:4}]->(H), (J)-[:connect {strength:1}]->(I), (K)-[:connect {strength:1}]->(F), (K)-[:connect {strength:10}]->(N), (L)-[:connect {strength:1}]->(M), (L)-[:connect {strength:4}]->(N), (M)-[:connect {strength:10}]->(K), (M)-[:connect {strength:8}]->(N), (N)-[:connect {strength:4}]->(M), (O)-[:connect {strength:1}]->(N);
To load the entire graph to the HDC server hdc-server-1 as my_hdc_graph:
CREATE HDC GRAPH my_hdc_graph ON "hdc-server-1" OPTIONS { nodes: {"*": ["*"]}, edges: {"*": ["*"]}, direction: "undirected", load_id: true, update: "static" }
Algorithm name: lpa
Name | Type | Spec | Default | Optional | Description |
|---|---|---|---|---|---|
node_label_property | "<@schema.?><property>" | / | / | Yes | Specifies numeric or string node property used to initialize node labels; nodes without the specified property are ignored. The system will generate the labels if it is unset. |
node_weight_property | "<@schema.?><property>" | / | / | Yes | Numeric node property used as the node weights. |
edge_weight_property | "<@schema.?><property>" | / | / | Yes | Numeric edge property used as the edge weights. |
loop_num | Integer | ≥1 | 5 | Yes | Number of propagation iterations. |
k | Integer | ≥1 | 1 | Yes | Specifies the maximum number of labels to keep for each node at the end of the computation, with all labels sorted by probability in descending order. |
return_id_uuid | String | uuid, id, both | uuid | Yes | Includes _uuid, _id, or both to represent nodes in the results. |
CALL algo.lpa.write("my_hdc_graph", { return_id_uuid: "id", k: 2, loop_num: 5, edge_weight_property: 'strength' }, { file: { filename: "lpa" } })
Writes each label_<N> and the corresponding probability_<N> from the results to the specified node properties. The property types are string and float, respectively.
CALL algo.lpa.write("my_hdc_graph", { node_label_property: 'interest', k: 2, loop_num: 10 }, { db: { property: "lab" } })
The label and label probability of each node is written to new properties lab_1, probability_1, lab_2, and probability_2.
CALL algo.lpa.write("my_hdc_graph", { node_label_property: 'interest', k: 2, loop_num: 10 }, { stats: {} })
Result:
| label_count |
|---|
| 6 |
CALL algo.lpa.run("my_hdc_graph", { return_id_uuid: "id", node_label_property: "@user.interest", k: 2 }) YIELD r RETURN r
Result:
| _id | label_1 | probability_1 | label_2 | probability_2 |
|---|---|---|---|---|
| I | badminton | 0.517124 | movie | 0.482876 |
| G | movie | 0.563411 | badminton | 0.436589 |
| J | movie | 0.605133 | badminton | 0.394867 |
| D | piano | 0.701716 | flute | 0.298284 |
| N | swimming | 0.675096 | saxophone | 0.324904 |
| F | badminton | 0.564691 | movie | 0.435309 |
| H | movie | 0.535167 | badminton | 0.464833 |
| B | piano | 0.646695 | flute | 0.353305 |
| L | novel | 0.510868 | swimming | 0.489132 |
| A | piano | 0.736380 | flute | 0.263620 |
| O | novel | 0.765123 | swimming | 0.234877 |
| E | piano | 0.594943 | flute | 0.405057 |
| K | novel | 0.510868 | swimming | 0.489132 |
| M | novel | 0.515860 | swimming | 0.484140 |
| C | piano | 0.640369 | flute | 0.359631 |
CALL algo.lpa.stream("my_hdc_graph", { return_id_uuid: "id", node_label_property: "@user.interest", node_weight_property: "@user.level", edge_weight_property: "strength", loop_num: 10 }) YIELD r RETURN r.label_1 AS label, count(r) GROUP BY label
Result:
| label | count(r) |
|---|---|
| violin | 3 |
| tennis | 2 |
| swimming | 3 |
| novel | 2 |
| piano | 5 |
CALL algo.lpa.stats("my_hdc_graph", { node_label_property: "interest", edge_weight_property: "strength", k: 1, loop_num: 5 }) YIELD s RETURN s
Result:
| label_count |
|---|
| 5 |
To project the entire graph to its shard servers as myProj:
CREATE PROJECTION myProj OPTIONS { nodes: {"*": ["*"]}, edges: {"*": ["*"]}, direction: "undirected", load_id: true }
Algorithm name: lpa
Name | Type | Spec | Default | Optional | Description |
|---|---|---|---|---|---|
node_label_property | "<@schema.?><property>" | / | / | Yes | Numeric or string node property used to initialize node labels; nodes without the specified property are ignored. The system will generates the labels if it is unset. |
node_weight_property | "<@schema.?><property>" | / | / | Yes | Numeric node property used as the node weights. |
edge_weight_property | "<@schema.?><property>" | / | / | Yes | Numeric edge property used as the edge weights. |
loop_num | Integer | ≥1 | 5 | Yes | Number of propagation iterations. |
algo(lpa).params({ projection: "myProj", loop_num: 5, edge_weight_property: 'strength' }).write({ file: { filename: "lpa" } })
Writes each label_<N> and the corresponding probability_<N> from the results to the specified node properties. The property types are string and float, respectively.
CALL algo.lpa.write("myProj", { node_label_property: 'interest', loop_num: 10 }, { db: { property: "lab" } })