gRPC API

polign_db serves the same operations over gRPC (default localhost:23001) and HTTP at once — same database, two wire formats. The service is defined in proto/vectordb.proto.

The service

service VectorDB {
  rpc PutVector(PutVectorRequest) returns (PutVectorResponse);
  rpc PutVectors(PutVectorsRequest) returns (PutVectorsResponse);
  rpc GetVector(GetVectorRequest) returns (GetVectorResponse);
  rpc GetVectors(GetVectorsRequest) returns (GetVectorsResponse);
  rpc ListVectors(ListVectorsRequest) returns (ListVectorsResponse);
  rpc DeleteVector(DeleteVectorRequest) returns (DeleteVectorResponse);
  rpc SearchVectors(SearchVectorsRequest) returns (SearchVectorsResponse);

  // Collection admin — only for servers running the collections registry
  // (-byo-store); returns Unimplemented otherwise
  rpc CreateCollection(CreateCollectionRequest) returns (CreateCollectionResponse);
  rpc GetCollection(GetCollectionRequest) returns (GetCollectionResponse);
  rpc ListCollections(ListCollectionsRequest) returns (ListCollectionsResponse);
  rpc DeleteCollection(DeleteCollectionRequest) returns (DeleteCollectionResponse);
  rpc VerifyCollection(VerifyCollectionRequest) returns (VerifyCollectionResponse);
}

For everyday use you only need the first seven: collections are auto-created on the first PutVector, inferring their dimension from that vector, so most setups never make an explicit "create collection" call. The five collection-admin RPCs exist for servers that manage collections on customer-owned buckets (started with -byo-store) — on any other server they return UNIMPLEMENTED. PutVectors is the batch upsert: up to 5000 vectors per call, validated as a whole before anything is applied (an invalid batch writes nothing); chunk larger loads. GetVectors is its read-side twin — fetch many vectors by id in one call.

Go client (recommended)

For Go services, don't hand-roll stubs — polign_db ships a public client, github.com/Polign/polign_db/client, that wraps the gRPC API and maps status codes to sentinel errors so callers never import gRPC types.

import "github.com/Polign/polign_db/client"

c, err := client.Dial(ctx, "localhost:23001")   // client.WithGRPCDialOptions(...) for TLS
defer c.Close()

// Store an embedding (collection auto-created from the first vector's dimension)
c.Put(ctx, "docs", client.Vector{
    ID:       "doc-1",
    Values:   embedding,                  // []float32 from your model
    Metadata: map[string]string{"title": "Cats"},
})

// Nearest-neighbour search: k=10, ef=0 = server default
hits, _ := c.Search(ctx, "docs", queryEmbedding, 10, 0)
for _, h := range hits {
    fmt.Println(h.ID, h.Distance, h.Metadata)
}

// Typed metadata filters — eq/in/range/exists composed with and/or/not,
// built with the client's Filter constructors (no proto types needed)
hits, _ = c.Search(ctx, "docs", queryEmbedding, 10, 0, client.SearchOptions{
    FilterExpr: client.FilterOr(
        client.FilterEq("lang", "en"),
        client.FilterExists("lang", false),
    ),
})

// Also: PutBatch(ctx, coll, []Vector) — batch upsert, up to 5000 per RPC ·
// Get(ctx, coll, id) · GetBatch(ctx, coll, ids) · List(ctx, coll, limit, offset) ·
// Delete(ctx, coll, id)
if errors.Is(err, client.ErrNotFound) { /* ... */ }

From Python, the Python SDK's GrpcClient (the [grpc] extra) speaks this same API with stubs generated from the same proto — identical operations and error mapping as its HTTP client.

Calling it with grpcurl

The server does not register gRPC reflection, so point grpcurl at the proto file (from a polign_db checkout):

# Put (auto-creates the "docs" collection as 3-dimensional)
grpcurl -plaintext -import-path proto -proto vectordb.proto \
  -d '{"collection":"docs","vector":{"id":"a","values":[1,0,0],"metadata":{"label":"first"}}}' \
  localhost:23001 polign.v1.VectorDB/PutVector

# Batch upsert — up to 5000 vectors per call, validated as a whole
grpcurl -plaintext -import-path proto -proto vectordb.proto \
  -d '{"collection":"docs","vectors":[{"id":"b","values":[0,1,0]},{"id":"c","values":[0,0,1]}]}' \
  localhost:23001 polign.v1.VectorDB/PutVectors

# Nearest-neighbour search, restricted to matching metadata
grpcurl -plaintext -import-path proto -proto vectordb.proto \
  -d '{"collection":"docs","values":[0.9,0.1,0],"k":5,"filter":{"label":"first"}}' \
  localhost:23001 polign.v1.VectorDB/SearchVectors

# Richer predicates via the typed filter_expr tree (eq/in/range/exists + and/or/not)
grpcurl -plaintext -import-path proto -proto vectordb.proto \
  -d '{"collection":"docs","values":[0.9,0.1,0],"k":5,
       "filter_expr":{"cond":{"key":"ts","range":{"gte":"2026-01-01"}}}}' \
  localhost:23001 polign.v1.VectorDB/SearchVectors

# Hybrid search: vector + BM25 text, fused server-side
grpcurl -plaintext -import-path proto -proto vectordb.proto \
  -d '{"collection":"docs","values":[0.9,0.1,0],"text":"quick brown fox","k":5,
       "fusion":{"method":"linear","alpha":0.6}}' \
  localhost:23001 polign.v1.VectorDB/SearchVectors

Text and hybrid search read the object-store segment index, so they need the server started with -segment-stores and a persistor running — see the install & use guide.

SearchVectors options

FieldWhat it does
valuesThe query embedding. Omit it (and set text) for a pure BM25 search.
kHow many hits to return.
efSearch beam width override; 0 = server default. Larger = more accurate, slower.
filterLegacy metadata equality filter, AND across keys — exactly an AND of eq conditions. Applied in-graph on both the in-memory and cold paths.
filter_exprTyped filter expression tree: eq/in/range/exists conditions composed with and/or/not. Setting both filter and filter_expr is an error. The Go client builds it with the Filter constructors; the Python client converts its filter dict to it.
coldServe straight from object-storage segments instead of the in-memory index. Requires a segment store.
nprobeIVF probe-count override for cold queries; 0 = searcher default.
textBM25 query. Alone = text search; together with values = hybrid.
fusionHybrid fusion: method = "rrf" (default, rrf_k=60) or "linear" (alpha = vector-leg weight, default 0.5). Only valid when both legs are present.
rescoreAccuracy/speed dial for compressed (IVF-PQ) collections: 0 = server default (accuracy-first), > 0 = exact-rescore pool of that size, < 0 = fastest approximate ranking with no exact rescore. Other collection types ignore it.

Each SearchHit carries a distance (vector metric, smaller-is-closer) and a score (relevance, larger-is-better: BM25 on a text search, the fused score on a hybrid one, 0 on a pure vector search).

Errors

gRPC codeMeaning
NOT_FOUNDMissing vector or collection on GetVector.
INVALID_ARGUMENTBad request — including a query whose dimension doesn't match the collection's.
FAILED_PRECONDITIONWith placement enabled, this node doesn't own the resource; the message names the owner to redial.
UNIMPLEMENTEDA collection-admin RPC on a server that isn't running the collections registry (-byo-store).
UNAUTHENTICATED / PERMISSION_DENIEDMissing or wrong API key on a collection-admin RPC (only those calls require a key).
RESOURCE_EXHAUSTEDRate limit hit (servers started with -rate-limit).
INTERNALAnything else.

Regenerating the stubs

Generated code lives in internal/pb; other languages can generate their own client from the proto:

protoc --go_out=. --go_opt=module=github.com/Polign/polign_db \
       --go-grpc_out=. --go-grpc_opt=module=github.com/Polign/polign_db \
       proto/vectordb.proto
Which API is this?

This page is the gRPC wire API of polign_db. The same operations are also available over HTTP/JSON — from the command line, or with the curl examples in Install & deploy polign_db.