Group records using their neighbors
The language tabs use earlier client interfaces. Check SDK versions and connection setup before running them.
Label propagation repeatedly lets nearby nodes adopt a common label. It finds communities without a preset group count.
Before you run it: The iteration cap does not guarantee convergence. Use a seed when comparing repeat runs.
First load the five-person social graph. It creates the exact social.users table and follows relation used below.
A label is a temporary group identifier. Group records by equal labels; a larger label does not mean a better or larger community.
- Give each node a labelStart from the loaded self-relation.
- Update from neighboring labelsNodes adopt the common label among their neighbors.
- Read the final groupsEqual labels identify a group; their values are not rankings.
Follow the example
- Prepare the self-referencing relationship.
- Set an iteration limit and explicit seed.
- Run the request.
- Group equal labels.
Set up the relationship
The relation must be declared in the schema's [[relations]] block and must target the table it is declared on. See schemas/reference#relations.
Run the request
rel is required and max_iter defaults to 20. Set seed explicitly for repeatable runs. If omitted, the engine uses the current Unix timestamp and does not return that chosen seed.
curl -G "https://$OC_HOST/v1/tenants/$OC_TENANT/graph/social.users/label_propagation" \
--data-urlencode "rel=follows" \
--data-urlencode "max_iter=20" \
--data-urlencode "seed=42" \
-H "Authorization: Bearer $OC_TOKEN"Check the result
Labels identify groups and need not be contiguous numbers.
[
{ "pk": ["alice"], "label": 0 },
{ "pk": ["bob"], "label": 0 },
{ "pk": ["carol"], "label": 0 },
{ "pk": ["dave"], "label": 0 },
{ "pk": ["heidi"], "label": 7 },
{ "pk": ["ivan"], "label": 7 },
{ "pk": ["judy"], "label": 7 },
{ "pk": ["mallory"], "label": 10 }
]One row per node, ordered by primary key. pk is the primary-key array and label is an unsigned integer. Labels start as one-per-node identifiers and most of them die off during convergence, so the surviving values are not contiguous and carry no ordering - the only thing a label means is equality. Two nodes with the same label are in the same community.
Understand the behavior
- Every node starts with its own label. Each round visits nodes in a shuffled order and moves each node to whichever label most of its neighbours hold.
- The shuffle is the only thing the seed drives. Ties within a tally are broken deterministically by the smaller label, so the same seed on the same graph gives byte-identical output.
- The pass repeats until no label changes or
max_iterrounds have run. There is no convergence guarantee, which is exactly why the iteration cap exists. - Self-loops are ignored - a node never votes for itself by force.
max_iter=0is refused with a 400 rather than returning an unconverged answer.
Important limits and checks
- Omitting
seed. The engine falls back to the current unix timestamp and does not tell you which one it used. Two calls a second apart can return different groupings with nothing in the response to explain the difference. - Reading labels as group numbers. They are not dense, not ordered and not stable across graphs. Compare them for equality and nothing else.
- Expecting louvain's answer. Label propagation optimises nothing globally. On a graph without sharp community structure it can collapse most of the nodes into one label, which is a real result and not an error. Cross-check with louvain before trusting a partition.