Omnigraph
Search

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, query) appears in the order block and ranks results by nearest-neighbor distance to the query. The query argument can be either a Vector(N) parameter or a String. When you pass a string, the engine auto-embeds it using the configured runtime embedding client, so callers don't need their own embedding pipeline. 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
}

Searching by string (auto-embed)

Pass a string in place of a vector and the engine embeds it for you:

query similar_people_by_text($q: String) {
    match {
        $p: Person
    }
    return { $p.name, $p.bio }
    order { nearest($p.embedding, $q) }
    limit 10
}
omnigraph read --uri ./graph.omni \
    --query queries.gq \
    --name similar_people_by_text \
    --params '{"q": "machine learning researcher in NYC"}'

This is the most common shape in agent code: you have natural language, you want nearest neighbors, you don't want to maintain a separate embed step.

Passing vector parameters

If you already have an embedding vector. For example, because you computed it inside the agent. Pass it as a JSON array in --params:

omnigraph read --uri ./graph.omni \
    --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.

On this page