Traverse query #
Term and full-text queries match document content; none of them can
ask “what is connected to these documents?” — the question citation
graphs, reference data and knowledge graphs are made of. The traverse
query answers it: a bounded graph traversal over a relation-typed
edge field — starting from seed documents, walk the edges up to
max_depth hops and emit every reached node as a hit.
Scores encode distance — 1.0 / (1.0 + depth) — so seeds outrank
1-hop neighbors, which outrank 2-hop neighbors, and the standard top-K
collector orders the results.
How it works #
Edges live in the collection itself: a relation-typed field is
written as its own document — {"related_to": {"from": "A01", "to": "A02"}} — and a writer-side hook resolves both endpoints
(string keys through the key map, numbers as ids) into an in-memory
adjacency index that stores every edge in both directions, so
incoming and both cost the same per step as outgoing. An
endpoint that cannot be resolved is dropped with a warning; the edge
document itself is still stored.
The walk is breadth-first: the seed frontier expands level by level,
and each node is recorded at the depth it was first reached — its
shortest hop from any seed. Every reached node becomes an ordinary hit
scored 1.0 / (1.0 + depth).
Seeds resolve before the walk dispatches: a query seed runs first
and its hits become the id list; keys go through the store’s key map
(missing keys drop — the same semantics the writer applies to edge
endpoints). On Pizza server the gateway rewrites a mixed seed list per
shard: system ids in "rolling,seq" form de-roll on the rolling that
owns them and drop everywhere else, user keys pass through untouched.
Live numbers over the articles teaching graph (20 article nodes, 24
citation edges): seeding with author = medcl matches 5 documents,
max_depth: 0 returns exactly those 5, and one undirected hop reaches
17 — the seeds plus every article they cite or are cited by.
Examples #
POST /my-collection/_search
{
"query": {
"traverse": {
"field": "related_to",
"seed": {
"query": { "term": { "field": "topic", "value": "search-engines" } }
},
"max_depth": 2,
"direction": "outgoing"
}
}
}
Seeds by document _key (the string ids you index with):
POST /my-collection/_search
{
"query": {
"traverse": {
"field": "related_to",
"seed": { "keys": ["A01", "A05"] },
"max_depth": 1
}
}
}
Shard placement #
Edge endpoints resolve against the key map of the shard that stores the edge document. Endpoints living on a different shard cannot be resolved there, and the edge is dropped with a warning — so keep a graph collection (or at least its edge documents and the nodes they reference) on a single shard:
{
"settings": {
"rolling": {
"partitions_sharding_strategy": { "hash": { "number_of_shards": 1 } }
}
},
"schema": { "properties": { "related_to": { "type": "relation" } } }
}
Use cases #
- “Read these too.” One or two hops over
related_tofrom the articles a search already returned — citation-neighborhood expansion with no co-occurrence index to maintain. - Structural recommendation. Walk curated relation edges instead of vector similarity when the relationship is editorial — related products, co-authored papers, linked issues. The edges you wrote define the candidates; distance ranks them.
- GraphRAG retrieval. Seed with an ordinary query, then traverse to pull the structured neighborhood into the prompt — the retrieved set and its context arrive scored in one request.
- Impact analysis. “Which entities sit within two hops of this flagged one?” — reachability over a graph you already store, without exporting it to a graph database.
Parameters for traverse
#
field
(Required, string) Edge field to traverse; must be declared in the schema with therelationtype.seed
(Required) Seed selector, one of:query— a sub-Queryresolved before the traversal dispatches.keys— document_keys; resolved through the store’s key map, keys that do not exist are dropped. On Pizza server, keys may also be system ids in"rolling,seq"form (the same mixed-id convention as GET/DELETE) — the gateway routes them to the owning shard and de-rolls them; keys containing,are reserved and rejected at ingest, so the two forms never conflict.ids— pre-resolved internal_ids (u32).
max_depth
(Required, integer) Maximum hop count. Seeds are at depth 0, somax_depth: 0returns just the seeds.direction
(Optional, string) Traversal direction along the edges:outgoing,incomingorboth(the default).
Related #
graph— the rendering counterpart: project the hit set as nodes and edges instead of searching by walking them.join— cross-collection membership when the relationship lives in another collection’s keys rather than edge documents.nested— same-element correlation inside one document’s array, the intra-document counterpart of edges.- Relational parameters
— the schema side of
relationfields and the references they declare. - Nested aggregation and children aggregation — bucket-side analytics over nested and parent/child structures.