Find nodes with similar graph roles
The language tabs use earlier client interfaces. Check SDK versions and connection setup before running them.
Node2Vec learns embeddings from graph walks. It can find records in similar positions in the network.
Before you run it: A training response alone is not queryable unless persist is true. Keep the dimension, response-size and walk-budget limits below.
First load the five-person social graph. It creates the exact social.users table and follows relation used below.
An embedding is a numeric description learned from link patterns. This is different from embedding profile text. Train and save the vectors before calling the second endpoint.
- Load the relationshipsProvide the graph used for the training walks.
- Train and save embeddingsPersist the vectors learned from the graph structure.
- Query a node's neighborsSearch the saved embeddings using its node ID.
- Inspect similar node IDsThe query node itself is excluded from these results.
Follow the example
- Prepare the self-referencing relationship.
- Train with the shown settings.
- Set persist: true to make the result queryable.
- Query a node for similar nodes.
Set up the relationship
The relation must be declared in the schema's [[relations]] block. node2vec needs no feature columns - it learns from structure alone. See schemas/reference#relations.
Train and save the embeddings
rel is the only required field; every other knob has a default, so a body of just the relation name is a complete request. Set persist: true to store the vectors under the schema and relation so the topk route becomes available. Without it the call is a pure computation: it trains in memory, returns the vectors and writes nothing.
curl -X POST "https://$OC_HOST/v1/tenants/$OC_TENANT/graph/social.users/node2vec" \
-H "Authorization: Bearer $OC_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"rel": "follows",
"dim": 64,
"walks_per_node": 10,
"walk_length": 40,
"window_size": 5,
"epochs": 5,
"seed": 42,
"persist": true
}'Check training results
{
"embeddings": {
"alice": [0.0142, -0.0318, 0.0091],
"bob": [-0.0077, 0.0264, -0.0155],
"carol": [0.0203, -0.0119, 0.0288]
},
"vocab_size": 11,
"training_pairs": 4820,
"final_loss": 0.6931,
"dim": 64,
"persisted": true
}embeddings maps each node's primary key to its vector, and each vector is dim floats long - they are shortened above to keep the example readable. vocab_size is how many nodes appeared in a walk, training_pairs how many skip-gram pairs were consumed, and final_loss the loss at the end of the last epoch. persisted mirrors the request flag and is true only when the blob was actually written, so you can tell whether the next call will work without probing for it.
Find similar nodes
The relation name moves into the path here, because that is how the persisted blob is keyed. query is the node you are asking about and k is how many neighbours you want. metric accepts cosine, dot, l2 or manhattan and defaults to cosine.
curl -G "https://$OC_HOST/v1/tenants/$OC_TENANT/graph/social.users/node2vec/follows/topk" \
--data-urlencode "query=alice" \
--data-urlencode "k=5" \
--data-urlencode "metric=cosine" \
-H "Authorization: Bearer $OC_TOKEN"Read the matched nodes
[
{ "pk": "bob", "score": 0.94 },
{ "pk": "carol", "score": 0.91 },
{ "pk": "dave", "score": 0.72 }
]A flat array of { pk, score }, best first, with the query node itself excluded. pk is a plain string here, not the primary-key array the algorithm endpoints return. Fewer than k hits means the persisted set is smaller than k; asking for more than the engine's node ceiling truncates the result rather than failing the call.
Understand the behavior
- Training samples biased random walks from every node, then runs skip-gram with negative sampling over the resulting sequences.
pandqbias the walks exactly as they do on therandom-walkendpoint. - The same seed, graph and configuration produce byte-identical vectors, so a retrain is reproducible.
persist: truewrites one blob per schema and relation, and the next persist replaces it atomically. What is stored is the trained vectors themselves rather than the recipe - replaying training elsewhere would not land on the same numbers.- The response is capped at one million floats, which is
vocab_sizetimesdim. Above that the call is refused with a 400, because a body that large stops being something a normal gateway will carry. dimabove 1024 is refused, and so is a walk budget above ten million, where the budget iswalks_per_nodemultiplied bywalk_length.
Important limits and checks
- Forgetting
persist: true. Training without it returns the vectors and stores nothing, and the topk route then answers 503 telling you to post with persist first. That 503 is a missing prerequisite, not an outage. - Putting the relation in the query string on the topk call. It belongs in the path, as
.../node2vec/<rel>/topk. - Misspelling a knob. Unknown request fields are dropped rather than rejected by default, so
walk_leninstead ofwalk_lengthtrains at the default and still returns 200. Check the names against the body above. - Comparing scores across metrics. A cosine similarity and an l2 distance are not on the same scale. Pick one metric and stay with it.
Expected result
The query returns similar IDs and scores, excluding the query node.