Traverse query

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_to from 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 the relation type.
  • seed
    (Required) Seed selector, one of:
    • query — a sub-Query resolved 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, so max_depth: 0 returns just the seeds.
  • direction
    (Optional, string) Traversal direction along the edges: outgoing, incoming or both (the default).
  • 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 relation fields and the references they declare.
  • Nested aggregation and children aggregation — bucket-side analytics over nested and parent/child structures.
Calendar October 6, 2026
Edit Edit this page