For AI agents: this page is also available as Markdown at /docs/graph.md. Every docs page is: add .md to its URL. llms.txt lists them all.
Graph search
Graph search queries a knowledge graph stored in an ordinary collection. Most graph retrieval is a few hops from a handful of seed entities: find the entities a question is about, walk to their neighbors, score what you reached by how close it is to the seeds, and fetch the passages that mention them. WarpSearch does this inside one collection, in one request, against one consistent snapshot, with the same filters, facets and vector search as any other search.
| Feature | What it does |
|---|---|
lookup | A query that selects documents by the values another query's matches hold (a semi-join). Covers one hop, reverse edges, and ACLs read from a user's document. |
| Graph expand | Bounded multi-hop expansion with scoring: up to 3 hops over adjacency fields or edge documents, ranked by spreading activation or personalized PageRank, with facets and searches over the neighborhood, the traversed edges as a subgraph, and a size budget for prompt context. |
| Graph paths | Shortest and k-shortest paths between sets of entities, or every path in a length range, with the edges that link them as evidence. |
#Modeling a graph
A graph lives in an ordinary collection. A node is a document, identified by its id. Edges come in two forms, and you can use both in one collection and mix them in one request.
#Adjacency fields
The simplest edge is a multi-valued string field on the node that holds neighbor ids:
{"id": "svc-pay", "kind_s": "entity", "type_s": "service", "name_t": "Payments Service",
"aliases_ss": ["payments", "pay-svc"], "related_ss": ["team-core", "svc-ledger"],
"ancestors_ss": ["org", "eng", "platform"], "pagerank_f": 0.9, "acl_ss": ["eng"],
"embedding_v": [0.12, 0.98, 0.04]}
{"id": "ch1", "kind_s": "chunk", "text_t": "payments outage postmortem",
"mentions_ss": ["svc-pay", "team-core"], "acl_ss": ["eng"]}
- Following an edge outward reads the node's field:
svc-paypoints atteam-core. - Following it inward finds the documents whose field holds a node's id:
team-coreis pointed at bysvc-pay. This uses the field's index, so reverse edges need not be stored. - Keyword string fields (
_s,_ss) work both ways. A field must be indexed to follow it inward and have a column to follow it outward; the default string fields have both.
#Edge documents
When an edge needs a type, a weight, a validity window or provenance, store one document per edge:
{"id": "e1", "kind_s": "edge", "src_s": "alice", "dst_s": "svc-pay", "type_s": "WORKS_ON",
"weight_f": 0.9, "source_chunk_s": "ch7", "valid_from_dt": "2024-01-01", "valid_to_dt": "2030-01-01"}
src_s and dst_s hold node ids (rename them per request), the weight is any numeric field, and any other field can be filtered on or returned as evidence. Edge and node documents can share the collection, told apart by a field such as kind_s.
#Which to use
| Adjacency field | Edge documents | |
|---|---|---|
| Storage | One field per relation on the node | One document per edge |
| Edge type | One field per type (works_on_ss, owns_ss) | A field on the edge, filterable |
| Weight | None (every edge counts 1) | Any numeric field |
| Validity, ACL, provenance | No | Yes, as filters and returned fields |
| Fan-out cap | First values of the field | Heaviest edges first |
| Best for | Entity links, mentions, hierarchies | Extracted relations, temporal facts, cited links |
Two more modeling patterns need no graph feature at all:
- Hierarchies: store the ancestor path (
ancestors_ss: ["org", "eng", "platform"]). Descendants of X are a filter onancestors_ss, and a facet on it rolls counts up the tree. - Importance priors: store a score such as PageRank (
pagerank_f) and multiply it in at query time with a rescore expression.
#lookup: one hop as a query
lookup selects the documents whose field holds any value of from_field across the documents matching from. It is a query in the native warpsearch language, usable in query or filters, combined with AND, or nested inside another lookup. Native expressions run unsigned on dedicated collections without row filters or field restrictions; on restricted collections, replay a signed translation (see Query languages).
{"language": "warpsearch",
"query": "lookup(id, from=id:=$seed, from_field=related_ss)",
"vars": {"seed": "svc-pay"}}
| Parameter | Meaning |
|---|---|
field | The field to match on. |
from | The query whose matches supply the values. Put values in vars. |
from_field | The field whose values those matches hold. |
max_values | Cap on the distinct values (default 65536). Exceeding it is an error. |
| Use | Setting | Result |
|---|---|---|
| Outbound neighbors | field: id, from_field: related_ss | The entities svc-pay points at. |
| Inbound neighbors | field: related_ss, from_field: id | The entities pointing at the seeds. |
| ACLs from the user's document | field: acl_ss, from: id:=$user, from_field: groups_ss | The documents visible to any of the user's groups. |
| Two hops | A lookup nested in from | For example "everyone working on the projects Alice works on", or a group-of-groups closure. |
Both fields are string-valued (keyword and id fields) or both integer-valued (integer and date fields). The values come from the same snapshot as the rest of the search, and the inner query sees every live document, not the request's other filters. A repeated lookup, such as the same user's ACL filter on every search, is cached as one entry however many values it resolves.
#Graph expand
POST /v1/collections/{collection}/graph/expand starts from seed documents, follows up to 3 hops, scores every node it reaches and returns them best first:
curl -s https://api.warpsearch.io/v1/collections/kg/graph/expand \
-H "Authorization: Bearer $WARPSEARCH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"seeds": {"query": "name_t:\"payments outage\"", "limit": 20},
"hops": [
{"field": "related_ss", "direction": "out", "decay": 0.5,
"max_per_node": 25, "max_frontier": 500, "filter": "type_s:(service OR team)"},
{"field": "mentions_ss", "direction": "in", "filter": "kind_s:chunk"}
],
"propagate": "sum",
"limit": 50,
"fields": ["id", "name_t", "type_s"],
"facets": {"types": {"field": "type_s"}}
}'
{"took_ms": 6, "collection": "kg", "total": 31,
"hits": [
{"id": "svc-pay", "score": 7.2, "hop": 0, "fields": {"name_t": "Payments Service", "type_s": "service"}},
{"id": "team-core", "score": 3.6, "hop": 1, "via": "svc-pay", "fields": {"name_t": "Core Team", "type_s": "team"}},
{"id": "ch1", "score": 2.1, "hop": 2, "via": "team-core", "fields": {}}
],
"facets": {"types": {"buckets": [{"val": "service", "count": 9}, {"val": "team", "count": 4}]}}}
#How it works
seedsis a search, or a list of node ids. Its matches start the walk, and their search scores are their starting scores (ids start at 1, or at the group'sweight). Use any query, including a kNN search over entity names ("language": "es"with an ESknnbody), or several weighted groups combined into one ranked list.- Each hop expands the nodes the previous hop reached for the first time. A node is reached once, at its first hop, and is never revisited, so the walk cannot loop.
- A node's score is the sum (or, with
"propagate": "max", the best) over the nodes that reached it oftheir score x decay x edge weight. Adjacency edges weigh 1. With the default sum, a node many seeds point at outranks one reached once. - Every hop can cap its work: how many edges each node may follow, how many new nodes survive the hop, and which hubs are too connected to expand.
- The reached nodes come back best first, seeds included unless you exclude them, each with how many hops away it is and which node reached it.
totalcounts every node reached, andfacetsandsearchrun over all of them, not just the returned page.min_hophides the nodes nearer than that (from hits,total, facets andsearch) while they still take part in the walk and the scores;include_seeds: falseismin_hop: 1for the seeds alone.
#Request
| Field | Meaning |
|---|---|
seeds | The seed search: query, language, filters, limit (default 10), sort; or ids, a list of node ids. Or an array of up to 10 such groups, each with a weight (default 1) multiplying its scores; the group limits add up. sort is rejected with ids or weight. For vector seeds use "language": "es" and an ES knn search body as query. |
hops | Up to 3 hop objects, applied in order (below). |
propagate | sum (default) or max. |
rank | spread (default, the scores above) or ppr (personalized PageRank, below). |
ppr | PageRank options: alpha (damping, the probability of continuing the walk rather than restarting at a seed; default 0.5, HippoRAG's value; the web-graph 0.85 spreads much wider), iterations (default 50), tolerance (default 1e-6), undirected (default true), reset_field (a numeric field scaling each seed's restart weight, below). |
limit | How many nodes to return (default 10; -1 for your plan's maximum). |
include_seeds | Return the seeds too (default true). |
min_hop | Hide nodes nearer than this many hops (0 to the number of hops) from the hits, total, facets and search. They still traverse and score. |
fields | The fields to return for each node. |
scores | Return scores (default true). |
edges | true returns, with each node, the edge that reached it (below). |
subgraph | true returns every traversed edge of the reached subgraph under edges in the response (below), at most max_edges of them (default and maximum 100000; traversing more is a 429). |
budget | {"nodes", "edges", "edge_cost"}: keep a connected subgraph of bounded size around the seeds before ranking (below). At least one key. |
timeout_ms | Wall-clock budget, counted from the seed search. Once spent, no further hop runs, PPR stops where it is, and what was reached so far comes back with "timed_out": true. |
filters | Restrict every node the walk may reach, seeds included, for example an ACL or a tenant filter. |
facets, metrics | Analytics over every reached node. Same syntax as Facets and aggregations. |
search | A second search restricted to the reached nodes: query, language, filters, limit, fields, sort (kNN through "language": "es"). Returned as search. |
max_nodes | Safety cap on nodes reached (default and maximum 100000). Exceeding it is a 429. |
A hop over an adjacency field:
| Field | Meaning |
|---|---|
field | The adjacency field. |
direction | out (default: the node's own values), in (nodes whose field holds this node's id) or both. |
filter | Which reached nodes to keep: an expression or an array that must all match. |
decay | Score multiplier for this hop (default 1). |
max_per_node | Follow at most this many edges from each node. |
max_frontier | Keep only the best-scored new nodes after the hop. |
max_degree | Do not expand nodes with more edges than this (hubs). |
A hop over edge documents replaces field with edges:
{"edges": {"src": "src_s", "dst": "dst_s", "weight": "weight_f",
"filter": ["type_s:WORKS_ON", "valid_from_dt:<=2025-06-01", "valid_to_dt:>=2025-06-01"],
"fields": ["source_chunk_s", "type_s"]},
"direction": "out", "max_per_node": 20, "decay": 0.5}
edges field | Meaning |
|---|---|
src, dst | The fields holding the edge's endpoint ids (default src_s and dst_s). out follows src to dst, in dst to src. |
weight | A numeric field multiplied into the score. max_per_node keeps each node's heaviest edges. |
filter | Which edge documents count: edge type, validity at a point in time, ACL. |
fields | Edge fields returned as evidence with "edges": true. |
#Results
Each hit has the usual id, score and fields, and:
| Field | Meaning |
|---|---|
hop | 0 for a seed, else the hop that first reached the node. |
via | The id of the node that contributed most to its score. Absent on seeds. |
edge | With "edges": true: the link from via. For an edge document, {"id", "weight", ...requested fields}; for an adjacency field, {"field": "related_ss"}. |
Following via back to a seed shows why a node was returned, and edge cites where the link came from, for example the passage it was extracted from.
The response also carries timed_out (true when timeout_ms cut the walk short) and, with "rank": "ppr", ppr: {"ran_iterations", "converged"}.
#The whole subgraph
"subgraph": true adds edges to the response: every edge the walk traversed, in traversal order, each physical edge once even when both ends reached it. An edge is {"from", "to", "via", "weight", "hop"} plus, for an edge document, its id and the requested evidence fields; from and to are in the stored direction (the node holding the adjacency value to the value, or src to dst), via is the adjacency field or edges, and hop is the hop that traversed it. Edges to nodes hidden by include_seeds or min_hop are included; edges to nodes dropped by max_frontier are not. max_edges bounds the list.
#A size budget
limit keeps the best nodes, which need not connect to each other or to the seeds. budget keeps a connected subgraph instead, before ranking and before anything is returned: starting from the seeds, it repeatedly adds the best-scored node adjacent to the kept set (attached by its heaviest edge) while at most nodes nodes and edges edges are kept and the node scores more than edge_cost (default 0); any edge budget left over takes the heaviest remaining edges among the kept nodes. The choice is greedy, not optimal, and with several seeds the result is a forest whose trees join where the neighborhoods meet. The hits, total, facets, search and the subgraph edges all cover the kept subgraph only; via and edge name the edge that attached each node. Seeds count toward nodes even when hidden.
#Personalized PageRank
With "rank": "ppr", WarpSearch first collects the subgraph the hops reach, then ranks it by personalized PageRank: a random walk that follows edges (weighted by edge weight) and restarts at the seeds in proportion to their scores. Scores sum to 1 over the reached nodes. PPR favors nodes that are well connected to several seeds over nodes that are merely close to one; HippoRAG uses it for multi-hop question answering. hop and via are reported as before, and ppr in the response reports the iterations run and whether the last one moved less than tolerance.
ppr.reset_field names a numeric field whose value multiplies each seed's restart weight (HippoRAG's node specificity: a phrase node weighted by the inverse of the number of passages it occurs in). A seed without a value keeps its weight, a negative value counts as 0, and when every weight is 0 the restart is uniform over the seeds.
#Recipe: GraphRAG passage retrieval
Find the entities a question names, walk to related entities and to the passages that mention them, and rank the passages:
{"seeds": {"query": "aliases_ss:(ledger OR payments)", "limit": 10},
"hops": [{"field": "related_ss", "direction": "both", "max_degree": 1000},
{"field": "mentions_ss", "direction": "in", "filter": "kind_s:chunk"}],
"rank": "ppr",
"include_seeds": false,
"filters": ["acl_ss:(eng OR all-staff)"],
"fields": ["id", "text_t"],
"limit": 20}
Feed the returned passages, with their via chains as context, to your model.
#Recipe: weighted seed groups
HippoRAG 2 seeds the walk with the entities an LLM confirmed, plus the passages a vector search found at a small weight. Both are one seeds array; ids need no query escaping:
{"seeds": [{"ids": ["ent:ledger", "ent:payments"]},
{"language": "es", "query": {"knn": {"field": "embedding_v", "query_vector": [0.1, 0.9, 0.0], "k": 5}},
"filters": [{"term": {"kind_s": "chunk"}}], "weight": 0.05}],
"hops": [{"field": "related_ss", "direction": "both"},
{"field": "mentions_ss", "direction": "in", "filter": "kind_s:chunk"}],
"rank": "ppr", "include_seeds": false, "limit": 20}
The same form continues a walk from the ids a previous call returned, after your model picked the ones worth following.
#Recipe: vector search inside a neighborhood
Restrict a kNN search to the graph around the seeds. The restriction applies inside the vector search, so recall holds:
{"seeds": {"ids": ["svc-pay"]},
"hops": [{"field": "related_ss", "direction": "both"}],
"limit": 0,
"search": {"language": "es",
"query": {"knn": {"field": "embedding_v", "query_vector": [0.1, 0.9, 0.0], "k": 5}},
"fields": ["id", "name_t"]}}
For one hop, the same works on /v1/search with a lookup filter.
#Recipe: the subgraph for visualization or triple lists
A client that draws the neighborhood, or a retriever that feeds an LLM a list of triples (SubgraphRAG and G-Retriever style), needs the edges, not only the nodes. subgraph returns every traversed edge, with edge-document evidence, beside the hits:
{"seeds": {"ids": ["svc-pay"]},
"hops": [{"field": "related_ss", "direction": "both"},
{"edges": {"weight": "weight_f", "filter": "kind_s:edge", "fields": ["type_s"]}, "direction": "both"}],
"subgraph": true, "max_edges": 2000,
"fields": ["id", "name_t"], "limit": -1}
Each edges entry has from, to, via, weight and hop, plus id and type_s for the edge documents, so (from, type_s, to) is a triple and the hits supply the node labels.
#Recipe: token-bounded context with budget
For a prompt that can hold about thirty nodes, ask for the best connected thirty rather than the best thirty: budget grows a subgraph from the seeds by score and stops at the caps, so every returned node links back to a seed through returned nodes.
{"seeds": {"query": "aliases_ss:(ledger OR payments)", "limit": 5},
"hops": [{"field": "related_ss", "direction": "both"},
{"field": "mentions_ss", "direction": "in", "filter": "kind_s:chunk"}],
"rank": "ppr",
"budget": {"nodes": 30, "edges": 40},
"subgraph": true, "fields": ["id", "name_t", "text_t"], "limit": -1}
The choice is greedy; with several seeds whose neighborhoods do not meet, the result is a forest.
#Recipe: HippoRAG node specificity with reset_field
HippoRAG weights each seed phrase by its specificity (the inverse of how many passages mention it), so a rare entity pulls the walk more than a common one. Store it on the node and name it in ppr.reset_field; the field goes through the same alias and allow-list resolution as any other.
{"seeds": {"query": "aliases_ss:(ledger OR payments)", "limit": 10},
"hops": [{"field": "related_ss", "direction": "both"},
{"field": "mentions_ss", "direction": "in", "filter": "kind_s:chunk"}],
"rank": "ppr", "ppr": {"alpha": 0.5, "reset_field": "specificity_f"},
"min_hop": 2, "fields": ["id", "text_t"], "limit": 20}
min_hop: 2 returns only the passages; the seeds and the related entities still shape the PageRank. The response's ppr says how many iterations ran and whether they converged.
#Graph paths
POST /v1/collections/{collection}/graph/paths finds how entities are connected:
curl -s https://api.warpsearch.io/v1/collections/kg/graph/paths \
-H "Authorization: Bearer $WARPSEARCH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "alice", "to": ["svc-pay", "svc-ledger"],
"edges": [
{"field": "related_ss"},
{"edges": {"weight": "weight_f", "filter": "type_s:(WORKS_ON OR OWNS)", "fields": ["source_chunk_s"]}}
],
"max_depth": 4, "k": 3,
"fields": ["name_t"]
}'
{"took_ms": 3, "collection": "kg",
"paths": [
{"nodes": ["alice", "svc-pay"], "length": 1, "cost": 1,
"edges": [{"from": "alice", "to": "svc-pay", "via": "edges", "id": "e1", "weight": 0.9, "source_chunk_s": "ch7"}]},
{"nodes": ["alice", "team-core", "svc-pay"], "length": 2, "cost": 2,
"edges": [{"from": "alice", "to": "team-core", "via": "related_ss"},
{"from": "team-core", "to": "svc-pay", "via": "related_ss"}]},
{"nodes": ["alice", "team-core", "svc-ledger"], "length": 2, "cost": 2,
"edges": [{"from": "alice", "to": "team-core", "via": "related_ss"},
{"from": "team-core", "to": "svc-ledger", "via": "related_ss"}]}
],
"documents": {"alice": {"name_t": "Alice"}, "team-core": {"name_t": "Core Team"},
"svc-pay": {"name_t": "Payments Service"}, "svc-ledger": {"name_t": "Ledger Service"}},
"truncated": false, "timed_out": false, "explored": 23}
| Field | Meaning |
|---|---|
from, to | A node id, or up to 10 ids each. The search runs from the whole from set to the whole to set in one call and returns the best k paths overall, not k per pair (sorted by cost, then length). Duplicate ids are ignored, a missing node is skipped, and a node in both sets is a zero-length path. |
edges | The edge kinds to walk: adjacency hops and edge-document hops, as in graph expand. Undirected unless a spec sets "direction": "out" or "in". decay and max_per_node are rejected here. A spec's own max_frontier caps the new nodes that spec may add to one level, so a high fan-out edge type (chunk mentions) cannot crowd out the others. |
max_depth | Longest path, in edges (default 4, at most 6). |
k | How many paths (default 1, at most 10): the shortest, then the next shortest without repeating one. |
weighted | Rank by the sum of -log(weight) instead of the number of edges, so strong links win over short weak ones. |
mode | shortest (default) or all: every simple path from a from node to a to node with min_depth to max_depth edges, shortest first and by node ids within a length; cost is the length. k and weighted are rejected with it. |
min_depth | mode: "all" only: shortest path length to include (default 1; 0 to max_depth). |
max_paths | mode: "all" only: how many paths to return (default 100, at most 10000). |
max_frontier | Cap on nodes per exploration level (default 1000). |
max_degree | Do not expand hubs with more edges than this. |
timeout_ms | Wall-clock budget. Once spent, the exploration stops and the paths found over what was explored come back with "timed_out": true. |
filters | Restrict the nodes a path may pass through, for example to what the caller may see. |
fields | Fields of every node on a returned path, under documents keyed by id, so names and titles need no second request. Nodes you may not read are absent. |
Each path lists its nodes in order and each edge it uses: via names the adjacency field or edges, and edge documents add their id, weight and requested fields as evidence. The search explores from both ends at once and stops when they meet (for one unweighted path) or at max_depth; in mode: "all" it explores to the full depth. A node past a frontier or degree cap is still reached, so it can end or join a path, but it is not expanded. truncated: true means a work cap cut the exploration short (a frontier or node cap, more than max_paths paths in mode: "all", or its internal cap on path prefixes), so a path may exist beyond it; timed_out: true means the same for timeout_ms. explored counts the nodes explored. The path search is one engine call and fields one more; a plan allows 20 per request.
#Recipe: all paths between two entities up to length 3
To list how two entities are related rather than only the closest link, ask for every simple path in a length range. The paths come shortest first, so the first ones are the direct links and the later ones the indirect ones.
{"from": "svc-pay", "to": "team-core",
"edges": [{"field": "related_ss"}, {"field": "mentions_ss"}],
"mode": "all", "min_depth": 1, "max_depth": 3, "max_paths": 200,
"fields": ["name_t"]}
truncated: true means more than max_paths paths exist; raise it (up to 10000), narrow the edge specs with a filter, or lower max_depth.
#Recipes with plain search
Many graph questions need no graph endpoint. All of these run on /v1/search:
| Question | Request |
|---|---|
Who points at team-core? | filters: ["related_ss:team-core"] |
Everything under platform | filters: ["ancestors_ss:platform"] |
| Head count per org | facets: {"orgs": {"field": "ancestors_ss"}} over people |
| A seed's neighbors, as ids with counts | facets: {"neighbors": {"field": "related_ss", "limit": -1}} over the seeds |
| A seed's neighbors, as documents | query: "lookup(id, from=id:=$seed, from_field=related_ss)" (warpsearch, vars: {"seed": "svc-pay"}) |
| Passages that mention an entity | filters: ["mentions_ss:svc-pay"] |
| Which entities a set of passages mention | facets: {"mentioned": {"field": "mentions_ss"}} over the passages |
| Rank entities by importance | a rescore with score * log1p(pagerank_f) |
| Facts valid on a date | filters: ["valid_from_dt:<=2025-06-01", "valid_to_dt:>=2025-06-01"] |
| Resolve an entity name | RRF over fuzzy aliases_ss, exact aliases and a name embedding, see Hybrid search |
#Access control
Graph requests follow the collection's access control like any search: row filters and field restrictions apply to every node a walk or a path may reach. A node the caller cannot see is not returned, not counted in total or facets, and not used as a step toward other nodes. For document-level permissions, store the allowed groups on each document (acl_ss) and filter with a lookup from the user's document; the filter stays small and cached however many groups the user has.
#MCP tools
Agents get three read-role tools over the same operations (see Agents). describe_collection first shows the adjacency fields.
| Tool | Arguments | Returns |
|---|---|---|
graph_neighbors | collection; ids or query (+ language); field or edges (src, dst, weight, filter, fields); direction (default both); depth 1 to 3 (default 1); limit (default 20); min_hop (for example 2 with depth 2 keeps only second-degree nodes); filter; fields; rank (spread or ppr) | nodes (id, score, hop, via, fields, edge), total, truncated (more nodes were reached than returned). Seeds are excluded. |
graph_paths | collection; from and to (arrays of 1 to 10 ids; the best k paths over all pairs); field or edges; direction; max_depth; k; weighted; mode (shortest or all); min_depth and max_paths (mode all); filter; fields | paths, documents, truncated, timed_out, explored, as above. |
graph_expand | collection and request, the full expand request as JSON text | The expand response. For weighted seed groups, per-hop decay and caps, min_hop, the full edge list (subgraph), a size budget, ppr.reset_field, timeout_ms, facets, metrics and a search inside the neighborhood. |
Every tool description links this guide, so an agent that only has the tool list can find the request shapes. Clause arguments are strings in the tool's language (Lucene by default; ES clauses are JSON objects as text). For example, the people who exchanged mail with a person in the Enron demo:
{"collection": "enron", "ids": ["person:jeff.skilling@enron.com"],
"field": "participant_ids_ss", "direction": "in", "filter": "kind:email", "limit": 20}
#Limits
| Limit | Value |
|---|---|
| Hops per graph expand | 3 |
| Path depth | 6 edges |
Paths per request (k) | 10 |
Nodes reached per request (max_nodes), edges returned with subgraph (max_edges), and an explicit max_frontier | 100000 by default |
Paths per request in mode: "all" (max_paths) | 10000 |
Seed groups, and from or to ids per side | 10 |
Engine calls per request (the path search, plus one for path fields) | 20 |
| PPR iterations | 1000 |
Seeds, returned nodes and the nested search | Your plan's max_limit; seed ids count as query clauses |
Distinct values per lookup | 65536 by default (max_values) |
| Scope | One dedicated collection per request |
Memory used by a walk counts against the request's memory budget like any search. Each engine call is metered like a search.
#Errors
| Status | Code | Cause |
|---|---|---|
400 | invalid_request | A malformed hop, seed group or path spec: an unknown parameter, ids together with query, a non-positive weight, a field that is not a keyword or id field, an adjacency field without an index followed inward, decay or max_per_node on a path edge, min_hop outside 0 to the number of hops, an empty budget, k or weighted with mode: "all", min_depth or max_paths without it, a negative timeout_ms. The message names the parameter, for example edge/hop 0: direction must be out, in or both. |
400 | invalid_request | A lookup resolving more than max_values distinct values, or mixing a string field with a numeric one, or a graph request on a shared collection with namespaced ids. |
413 | request_too_large | The graph request, with all its queries and filters, exceeds your plan's max_query_bytes. |
422 | limit_exceeded | More than 3 hops, max_depth above 6, k above 10, max_paths above 10000, max_nodes, max_edges or a max_frontier above 100000, PPR iterations above 1000, too many seed groups, endpoint ids or engine calls, or a limit above your plan. |
429 | resource_exhausted | A walk reaching more than max_nodes nodes, or traversing more than max_edges edges with subgraph. Lower max_frontier or max_degree, or set budget or timeout_ms. Paths never return 429 for work caps: they report truncated instead. |
#Not supported yet
- Hops across collections, and walks deeper than 3 hops (6 for paths) in one request.
- Cypher or GQL graph queries.
- Community detection and community summaries, and scheduled graph jobs such as computing PageRank priors.
- Entity and relation extraction, and entity merging.
Until then, chain graph requests from your application (the ids a request returns are the seeds of the next), and write computed priors back as fields.