OriginChainDB
Graph

Find nodes with similar graph roles

← Graph examples

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.

Turn graph structure into searchable vectorsTraining must persist the embeddings before the separate similarity query can use them.
  1. Load the relationshipsProvide the graph used for the training walks.
  2. Train and save embeddingsPersist the vectors learned from the graph structure.
  3. Query a node's neighborsSearch the saved embeddings using its node ID.
  4. Inspect similar node IDsThe query node itself is excluded from these results.

Follow the example

  1. Prepare the self-referencing relationship.
  2. Train with the shown settings.
  3. Set persist: true to make the result queryable.
  4. 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. p and q bias the walks exactly as they do on the random-walk endpoint.
  • The same seed, graph and configuration produce byte-identical vectors, so a retrain is reproducible.
  • persist: true writes 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_size times dim. Above that the call is refused with a 400, because a body that large stops being something a normal gateway will carry.
  • dim above 1024 is refused, and so is a walk budget above ten million, where the budget is walks_per_node multiplied by walk_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_len instead of walk_length trains 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.

Continue

Continue to combine links with row features.

© 2026 Silicoyn Technologies Pvt Ltd

On this page