Guide
Prefiltering ranks only the nodes or edges that a traversal reaches, instead of a whole
index. Use it when graph membership is a correctness boundary, such as “documents this
user may access” or “products reachable from this category.” It works the same way for
vector and full-text search.
For why filtering before ranking matters, see
Filtered vector search.
How it works
Every prefiltered search runs in the same order: graph traversal → exact candidate membership → ranking → top k.- The traversal is authoritative. A result outside the candidate set is never returned, even when approximate index structures accelerate ranking.
- Output IDs are a deduplicated subset of the input IDs.
- Each selected row keeps its bindings, path, and sack, with
$distance(vector) or$score(text) attached. - Empty input returns without opening the index.
- A tenant-partitioned index requires the same tenant value used to build the candidate stream.
Vector prefiltering
This request finds the projects a user owns, ranks that exact set by embedding distance, and returns the top five. It requires an active three-dimensional cosine vector index onProject.embedding.
Full-text search prefiltering
This request finds the documents a user can read, ranks that exact set for"graph databases", and returns the top five. It requires an active
text index on Document.body.
SDK methods
Rust, TypeScript, and Python pick the node or edge wire operation from the current stream. Go has separate node and edge methods.Result limits
Unpublished changes
Prefiltered searches follow the request’s search consistency. A candidate whose indexed vector or text changed in a committed write that the index worker has not published yet is superseded: the search drops that candidate’s published index rows up front and ranks its newest committed value instead, or leaves it out when that write removed the value.strong(the default) treats every superseded candidate this way. Unlike a whole-index search, a prefiltered search never fails withindex_backpressurebecause of superseded results; only the limits above apply. A prefiltered text search still fails withindex_backpressurewhen its partition holds more unpublished text than astrongtext search may analyze, since its BM25 statistics cover every unpublished document, and a prefiltered vector search fails the same way when its index holds more unpublished vector work than astrongsearch may score. That work counts every tenant partition of the index, so with a lowered bound another tenant’s backlog can fail the search even when its own candidates have nothing unpublished.eventualdoes this for the oldest unpublished work within its per-search budget and ranks the remaining candidates by their last published values until publication.
Checklist
- Create a compatible index for the candidate label and property. Vector queries must match the index dimension exactly.
- Pass the same tenant value as the index when it is tenant-partitioned.
- Project
$distanceor$scorebefore traversing away from a ranked hit. - Bound the candidate traversal when its size can grow without application limits.
Next steps
Vector indexes
Create the dimensioned index used for ranking.
Text indexes
Create the BM25 index used for full-text ranking.
Traversals
Build the candidate set by following relationships.
Project search results
Preserve ranked hit metadata before continuing a traversal.