Vector Search
Find semantically similar nodes using nearest-neighbor search over embeddings.
Vector search finds nodes that are semantically similar to a query vector. It
uses the current Omnigraph vector index implementation — an ivf_flat index
with L2 distance — over a Vector(N) field.
Schema setup
Declare a Vector(N) property with @index to enable vector search. N is
the embedding dimension.
node Person {
name: String @key
bio: String @index
embedding: Vector(1536) @index
}
node Document {
title: String @key
content: String
embedding: Vector(768) @index
}The @index annotation on a Vector(N) field causes Omnigraph to build the
current vector index for that column. Without it, nearest() queries on that
field are rejected at compile time.
If you want embeddings to be auto-generated from another field, use
@embed(source_property):
node Person {
name: String @key
bio: String @index
embedding: Vector(1536) @embed(bio) @index
}nearest() — vector similarity ranking
nearest(field, vector) appears in the order block and ranks results by
nearest-neighbor distance to the query vector. Because nearest() requires a
limit clause, pair them together.
query similar_people($vec: Vector(1536)) {
match {
$p: Person
}
return { $p.name, $p.bio }
order { nearest($p.embedding, $vec) }
limit 10
}Passing vector parameters
Vectors are passed as JSON arrays in the --params argument:
omnigraph read --uri ./my-graph \
--query queries.gq \
--name similar_people \
--params '{"vec": [0.021, -0.003, 0.118]}'In practice, you generate the query vector from an embedding model and pass it as a parameter.
Via the HTTP API:
curl -X POST http://localhost:8080/read \
-H "Content-Type: application/json" \
-d '{
"query_source": "query similar_people($vec: Vector(1536)) { match { $p: Person } return { $p.name, $p.bio } order { nearest($p.embedding, $vec) } limit 10 }",
"query_name": "similar_people",
"params": {"vec": [0.021, -0.003, 0.118]},
"branch": "main"
}'Filtering before ranking
Combine a match filter with nearest() in order to narrow the candidate
set before ranking.
query similar_active_people($vec: Vector(1536)) {
match {
$p: Person { status: "active" }
}
return { $p.name, $p.bio }
order { nearest($p.embedding, $vec) }
limit 10
}This first filters to active people, then ranks the filtered set by vector similarity.
Combining with traversal
Vector search composes with graph traversal. You can find semantically similar nodes and then follow edges to related entities:
query similar_people_at_company($vec: Vector(1536), $company: String) {
match {
$p: Person
$p worksAt $c: Company { name: $company }
}
return { $p.name, $p.bio, $c.name }
order { nearest($p.embedding, $vec) }
limit 10
}This finds people who work at a specific company, ranked by how similar their embedding is to the query vector.