Documentation
¶
Overview ¶
Package qdrantgrpc provides Qdrant-compatible gRPC APIs for NornicDB.
This package enables existing Qdrant SDKs (Python, Go, Rust, etc.) to connect to NornicDB without modification by implementing the upstream Qdrant protobuf contract (package `qdrant`, pinned to v1.16.x).
NornicDB does not expose any additional “compat” gRPC contract for Qdrant. The only public Qdrant surface is the upstream Qdrant protobuf contract.
Integration with NornicDB Search ¶
This package integrates with the existing search.Service to ensure:
- Points added via Qdrant gRPC are searchable via /nornicdb/search
- Points added via Cypher are searchable via Qdrant gRPC
- A single unified vector index is maintained
Compatibility ¶
The upstream Qdrant SDK surface currently implements the core methods used by qdrant-client (Python) and other SDKs for typical vector workloads:
- Collections: Create, Get, List, Delete, Update, CollectionExists
- Points: Upsert, Get, Delete, Count, Search, Scroll, payload ops, vector ops
Additional upstream Qdrant RPCs can be added incrementally as needed.
Data Model Mapping ¶
- Qdrant Collection → NornicDB database namespace (collection = database)
- Qdrant Point → NornicDB Node with embeddings in NamedEmbeddings (supports named vectors)
- Qdrant Payload → NornicDB Node properties
- Qdrant PointId → NornicDB NodeID (prefixed: qdrant:point:<id>, scoped by database namespace)
Feature Flag ¶
The Qdrant gRPC endpoint is controlled by a feature flag:
- Environment: NORNICDB_QDRANT_GRPC_ENABLED=true
- Config: config.Features.QdrantGRPCEnabled = true
Usage ¶
// Create server with NornicDB storage and search
cfg := qdrantgrpc.DefaultConfig()
srv, err := qdrantgrpc.NewServer(cfg, storage, registry, searchService, authenticator)
if err != nil {
log.Fatal(err)
}
// Start listening
if err := srv.Start(); err != nil {
log.Fatal(err)
}
defer srv.Stop()
ELI12 ¶
Think of this like a translator at a restaurant:
- Qdrant SDKs "speak Qdrant language" (their API)
- NornicDB "speaks NornicDB language" (its internal API)
- This server translates between them so they can communicate
- When a Qdrant client asks to store a vector, we translate it to NornicDB format
- When NornicDB returns results, we translate back to Qdrant format
Package qdrantgrpc - In-memory vector index cache for Qdrant gRPC searches.
DEPRECATED: This endpoint-specific indexing cache is being phased out in favor of the unified IndexRegistry and NamedEmbeddings data model. The cache is kept as a fallback during migration but will be removed once IndexRegistry integration is stable.
This cache maintains per-collection, per-vector-name indexes to avoid falling back to storage scans when Qdrant collection dimensions differ from the DB's default embedding dimensions.
Index ¶
- Constants
- Variables
- type CollectionMeta
- type CollectionStore
- type CollectionsService
- func (s *CollectionsService) CollectionExists(ctx context.Context, req *qpb.CollectionExistsRequest) (*qpb.CollectionExistsResponse, error)
- func (s *CollectionsService) Create(ctx context.Context, req *qpb.CreateCollection) (*qpb.CollectionOperationResponse, error)
- func (s *CollectionsService) Delete(ctx context.Context, req *qpb.DeleteCollection) (*qpb.CollectionOperationResponse, error)
- func (s *CollectionsService) Get(ctx context.Context, req *qpb.GetCollectionInfoRequest) (*qpb.GetCollectionInfoResponse, error)
- func (s *CollectionsService) List(ctx context.Context, req *qpb.ListCollectionsRequest) (*qpb.ListCollectionsResponse, error)
- func (s *CollectionsService) Update(ctx context.Context, req *qpb.UpdateCollection) (*qpb.CollectionOperationResponse, error)
- type Config
- type DatabaseAccessChecker
- type PointsService
- func (s *PointsService) ClearPayload(ctx context.Context, req *qpb.ClearPayloadPoints) (*qpb.PointsOperationResponse, error)
- func (s *PointsService) Count(ctx context.Context, req *qpb.CountPoints) (*qpb.CountResponse, error)
- func (s *PointsService) CreateFieldIndex(ctx context.Context, req *qpb.CreateFieldIndexCollection) (*qpb.PointsOperationResponse, error)
- func (s *PointsService) Delete(ctx context.Context, req *qpb.DeletePoints) (*qpb.PointsOperationResponse, error)
- func (s *PointsService) DeleteFieldIndex(ctx context.Context, req *qpb.DeleteFieldIndexCollection) (*qpb.PointsOperationResponse, error)
- func (s *PointsService) DeletePayload(ctx context.Context, req *qpb.DeletePayloadPoints) (*qpb.PointsOperationResponse, error)
- func (s *PointsService) DeleteVectors(ctx context.Context, req *qpb.DeletePointVectors) (*qpb.PointsOperationResponse, error)
- func (s *PointsService) Get(ctx context.Context, req *qpb.GetPoints) (*qpb.GetResponse, error)
- func (s *PointsService) OverwritePayload(ctx context.Context, req *qpb.SetPayloadPoints) (*qpb.PointsOperationResponse, error)
- func (s *PointsService) Query(ctx context.Context, req *qpb.QueryPoints) (*qpb.QueryResponse, error)
- func (s *PointsService) QueryBatch(ctx context.Context, req *qpb.QueryBatchPoints) (*qpb.QueryBatchResponse, error)
- func (s *PointsService) Recommend(ctx context.Context, req *qpb.RecommendPoints) (*qpb.RecommendResponse, error)
- func (s *PointsService) RecommendBatch(ctx context.Context, req *qpb.RecommendBatchPoints) (*qpb.RecommendBatchResponse, error)
- func (s *PointsService) Scroll(ctx context.Context, req *qpb.ScrollPoints) (*qpb.ScrollResponse, error)
- func (s *PointsService) Search(ctx context.Context, req *qpb.SearchPoints) (*qpb.SearchResponse, error)
- func (s *PointsService) SearchBatch(ctx context.Context, req *qpb.SearchBatchPoints) (*qpb.SearchBatchResponse, error)
- func (s *PointsService) SearchGroups(ctx context.Context, req *qpb.SearchPointGroups) (*qpb.SearchGroupsResponse, error)
- func (s *PointsService) SetPayload(ctx context.Context, req *qpb.SetPayloadPoints) (*qpb.PointsOperationResponse, error)
- func (s *PointsService) UpdateVectors(ctx context.Context, req *qpb.UpdatePointVectors) (*qpb.PointsOperationResponse, error)
- func (s *PointsService) Upsert(ctx context.Context, req *qpb.UpsertPoints) (*qpb.PointsOperationResponse, error)
- type SearchServiceProvider
- type Server
- func (s *Server) Addr() string
- func (s *Server) AllowDatabaseAccess(ctx context.Context, database string, write bool) error
- func (s *Server) CollectionStore() CollectionStore
- func (s *Server) IsRunning() bool
- func (s *Server) RegisterAdditionalServices(fn func(*grpc.Server)) error
- func (s *Server) Start() error
- func (s *Server) Stop()
- func (s *Server) VisibleDatabases(ctx context.Context, candidates []string) ([]string, error)
- type SnapshotsService
- func (s *SnapshotsService) Create(ctx context.Context, req *qpb.CreateSnapshotRequest) (*qpb.CreateSnapshotResponse, error)
- func (s *SnapshotsService) CreateFull(ctx context.Context, req *qpb.CreateFullSnapshotRequest) (*qpb.CreateSnapshotResponse, error)
- func (s *SnapshotsService) Delete(ctx context.Context, req *qpb.DeleteSnapshotRequest) (*qpb.DeleteSnapshotResponse, error)
- func (s *SnapshotsService) DeleteFull(ctx context.Context, req *qpb.DeleteFullSnapshotRequest) (*qpb.DeleteSnapshotResponse, error)
- func (s *SnapshotsService) List(ctx context.Context, req *qpb.ListSnapshotsRequest) (*qpb.ListSnapshotsResponse, error)
- func (s *SnapshotsService) ListFull(ctx context.Context, req *qpb.ListFullSnapshotsRequest) (*qpb.ListSnapshotsResponse, error)
Constants ¶
const (
// QdrantPointLabel is the label used to identify Qdrant point nodes within a collection database.
QdrantPointLabel = "QdrantPoint"
)
Variables ¶
var ( // ErrCollectionNotFound indicates the requested Qdrant collection does not exist. // This includes databases that exist but do not contain the required _collection_meta node. ErrCollectionNotFound = errors.New("collection not found") // ErrInvalidCollection indicates the collection database exists but does not satisfy the metadata contract. ErrInvalidCollection = errors.New("invalid collection metadata") )
Functions ¶
This section is empty.
Types ¶
type CollectionMeta ¶
type CollectionMeta struct {
Name string
Dimensions int
Distance qpb.Distance
Status qpb.CollectionStatus
}
CollectionMeta holds metadata about a Qdrant collection.
In the collection=database model, this metadata is stored in the collection database as the required `_collection_meta` node.
type CollectionStore ¶
type CollectionStore interface {
Create(ctx context.Context, name string, dims int, distance qpb.Distance) error
Open(ctx context.Context, name string) (storage.Engine, *CollectionMeta, error)
GetMeta(ctx context.Context, name string) (*CollectionMeta, error)
List(ctx context.Context) ([]string, error)
Drop(ctx context.Context, name string) error
Exists(name string) bool
PointCount(ctx context.Context, name string) (int64, error)
}
CollectionStore maps Qdrant collections to NornicDB database namespaces.
The implementation enforces the required _collection_meta node contract and does not support legacy layouts (shared namespace + label filtering).
func NewDatabaseCollectionStore ¶
func NewDatabaseCollectionStore(dbManager *multidb.DatabaseManager, vecIndex *vectorIndexCache) (CollectionStore, error)
NewDatabaseCollectionStore creates a CollectionStore backed by DatabaseManager namespaces.
type CollectionsService ¶
type CollectionsService struct {
qpb.UnimplementedCollectionsServer
// contains filtered or unexported fields
}
CollectionsService implements the Qdrant Collections gRPC service.
func NewCollectionsService ¶
func NewCollectionsService(collections CollectionStore, vecIndex *vectorIndexCache, checker DatabaseAccessChecker) *CollectionsService
NewCollectionsService creates a new Collections service.
func (*CollectionsService) CollectionExists ¶
func (s *CollectionsService) CollectionExists(ctx context.Context, req *qpb.CollectionExistsRequest) (*qpb.CollectionExistsResponse, error)
func (*CollectionsService) Create ¶
func (s *CollectionsService) Create(ctx context.Context, req *qpb.CreateCollection) (*qpb.CollectionOperationResponse, error)
func (*CollectionsService) Delete ¶
func (s *CollectionsService) Delete(ctx context.Context, req *qpb.DeleteCollection) (*qpb.CollectionOperationResponse, error)
func (*CollectionsService) Get ¶
func (s *CollectionsService) Get(ctx context.Context, req *qpb.GetCollectionInfoRequest) (*qpb.GetCollectionInfoResponse, error)
func (*CollectionsService) List ¶
func (s *CollectionsService) List(ctx context.Context, req *qpb.ListCollectionsRequest) (*qpb.ListCollectionsResponse, error)
func (*CollectionsService) Update ¶
func (s *CollectionsService) Update(ctx context.Context, req *qpb.UpdateCollection) (*qpb.CollectionOperationResponse, error)
Update acknowledges the update request if the collection exists. NornicDB manages tuning parameters internally.
type Config ¶
type Config struct {
// ListenAddr is the address to listen on (e.g., ":6334")
ListenAddr string
// AllowVectorMutations controls whether Qdrant points operations are allowed to
// directly set/update/delete stored vectors.
//
// When NornicDB-managed embeddings are enabled, operators typically want to
// prevent external clients from overwriting embeddings via the Qdrant API.
// In that mode, vector mutation endpoints return FailedPrecondition.
//
// When NornicDB-managed embeddings are disabled, set this to true to allow
// Qdrant clients to fully manage vectors.
AllowVectorMutations bool
// MaxVectorDim is the maximum allowed vector dimension
MaxVectorDim int
// MaxBatchPoints is the maximum points per upsert batch
MaxBatchPoints int
// MaxPayloadBytes is the maximum payload size per point
MaxPayloadBytes int
// MaxTopK is the maximum results per search
MaxTopK int
// MaxFilterClauses is the maximum filter conditions
MaxFilterClauses int
// RequestTimeout is the default deadline for requests
RequestTimeout time.Duration
// MaxConcurrentStreams per connection
MaxConcurrentStreams uint32
// MaxRecvMsgSize in bytes
MaxRecvMsgSize int
// MaxSendMsgSize in bytes
MaxSendMsgSize int
// EnableReflection enables gRPC server reflection
EnableReflection bool
// SnapshotDir is the directory for storing snapshots
SnapshotDir string
// EmbedQuery, when set, allows the Qdrant Query API to accept text/inference
// inputs (e.g. VectorInput.Document) and have NornicDB embed the query text.
//
// If nil, those query variants return FailedPrecondition.
EmbedQuery func(ctx context.Context, text string) ([]float32, error)
// MethodPermissions optionally overrides the default RBAC requirements for
// specific RPCs.
//
// Keys are of the form "<Service>/<Method>", using the short gRPC service name:
// - "Collections/Create"
// - "Points/Upsert"
// - "Snapshots/List"
// - "ServerReflection/ServerReflectionInfo"
//
// If a request's method is not found in either this map or the built-in
// defaults, the request is denied (default-deny).
MethodPermissions map[string]auth.Permission
// DatabaseAccessModeResolver, when set, enables per-database (per-collection) RBAC.
// Collection name = database name. Called with the principal's roles from context;
// CanAccessDatabase(collectionName) is checked before opening the collection.
DatabaseAccessModeResolver func(roles []string) auth.DatabaseAccessMode
// ResolvedAccessResolver, when set, is used for write RPCs: ResolvedAccess.Write
// for (roles, collectionName) must be true or the request is denied.
ResolvedAccessResolver func(roles []string, dbName string) auth.ResolvedAccess
}
Config holds configuration for the Qdrant gRPC server.
func DefaultConfig ¶
func DefaultConfig() *Config
DefaultConfig returns sensible defaults for the Qdrant gRPC server.
type DatabaseAccessChecker ¶
type DatabaseAccessChecker interface {
// AllowDatabaseAccess returns nil if the principal in ctx may access the database (read-only if write is false, write if write is true).
AllowDatabaseAccess(ctx context.Context, database string, write bool) error
// VisibleDatabases returns the subset of candidates that the principal may see (e.g. for List filtering).
VisibleDatabases(ctx context.Context, candidates []string) ([]string, error)
}
DatabaseAccessChecker is used by Points, Collections, and Snapshots services to enforce per-database (per-collection) RBAC. Collection name = database name.
type PointsService ¶
type PointsService struct {
qpb.UnimplementedPointsServer
// contains filtered or unexported fields
}
PointsService implements the upstream Qdrant Points gRPC service (package `qdrant`). It stores points as NornicDB nodes and (optionally) indexes them via search.Service.
func NewPointsService ¶
func NewPointsService(config *Config, collections CollectionStore, searchProvider SearchServiceProvider, vecIndex *vectorIndexCache, checker DatabaseAccessChecker) *PointsService
func (*PointsService) ClearPayload ¶
func (s *PointsService) ClearPayload(ctx context.Context, req *qpb.ClearPayloadPoints) (*qpb.PointsOperationResponse, error)
func (*PointsService) Count ¶
func (s *PointsService) Count(ctx context.Context, req *qpb.CountPoints) (*qpb.CountResponse, error)
func (*PointsService) CreateFieldIndex ¶
func (s *PointsService) CreateFieldIndex(ctx context.Context, req *qpb.CreateFieldIndexCollection) (*qpb.PointsOperationResponse, error)
func (*PointsService) Delete ¶
func (s *PointsService) Delete(ctx context.Context, req *qpb.DeletePoints) (*qpb.PointsOperationResponse, error)
func (*PointsService) DeleteFieldIndex ¶
func (s *PointsService) DeleteFieldIndex(ctx context.Context, req *qpb.DeleteFieldIndexCollection) (*qpb.PointsOperationResponse, error)
func (*PointsService) DeletePayload ¶
func (s *PointsService) DeletePayload(ctx context.Context, req *qpb.DeletePayloadPoints) (*qpb.PointsOperationResponse, error)
func (*PointsService) DeleteVectors ¶
func (s *PointsService) DeleteVectors(ctx context.Context, req *qpb.DeletePointVectors) (*qpb.PointsOperationResponse, error)
func (*PointsService) Get ¶
func (s *PointsService) Get(ctx context.Context, req *qpb.GetPoints) (*qpb.GetResponse, error)
func (*PointsService) OverwritePayload ¶
func (s *PointsService) OverwritePayload(ctx context.Context, req *qpb.SetPayloadPoints) (*qpb.PointsOperationResponse, error)
func (*PointsService) Query ¶
func (s *PointsService) Query(ctx context.Context, req *qpb.QueryPoints) (*qpb.QueryResponse, error)
Query implements Qdrant's universal query API for the most common variant: Query(nearest = VectorInput).
This enables text/inference-shaped queries via VectorInput.Document when Config.EmbedQuery is provided.
func (*PointsService) QueryBatch ¶
func (s *PointsService) QueryBatch(ctx context.Context, req *qpb.QueryBatchPoints) (*qpb.QueryBatchResponse, error)
func (*PointsService) Recommend ¶
func (s *PointsService) Recommend(ctx context.Context, req *qpb.RecommendPoints) (*qpb.RecommendResponse, error)
func (*PointsService) RecommendBatch ¶
func (s *PointsService) RecommendBatch(ctx context.Context, req *qpb.RecommendBatchPoints) (*qpb.RecommendBatchResponse, error)
func (*PointsService) Scroll ¶
func (s *PointsService) Scroll(ctx context.Context, req *qpb.ScrollPoints) (*qpb.ScrollResponse, error)
func (*PointsService) Search ¶
func (s *PointsService) Search(ctx context.Context, req *qpb.SearchPoints) (*qpb.SearchResponse, error)
func (*PointsService) SearchBatch ¶
func (s *PointsService) SearchBatch(ctx context.Context, req *qpb.SearchBatchPoints) (*qpb.SearchBatchResponse, error)
func (*PointsService) SearchGroups ¶
func (s *PointsService) SearchGroups(ctx context.Context, req *qpb.SearchPointGroups) (*qpb.SearchGroupsResponse, error)
func (*PointsService) SetPayload ¶
func (s *PointsService) SetPayload(ctx context.Context, req *qpb.SetPayloadPoints) (*qpb.PointsOperationResponse, error)
func (*PointsService) UpdateVectors ¶
func (s *PointsService) UpdateVectors(ctx context.Context, req *qpb.UpdatePointVectors) (*qpb.PointsOperationResponse, error)
func (*PointsService) Upsert ¶
func (s *PointsService) Upsert(ctx context.Context, req *qpb.UpsertPoints) (*qpb.PointsOperationResponse, error)
Upsert inserts or overwrites points. If a point exists, its payload/vectors are replaced.
type SearchServiceProvider ¶
SearchServiceProvider returns a search service configured for the provided database namespace. When nil, Qdrant point writes still persist but do not update NornicDB search indexes.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the Qdrant-compatible gRPC server.
func NewServer ¶
func NewServer(config *Config, collections CollectionStore, baseStorage storage.Engine, searchProvider SearchServiceProvider, authenticator *auth.Authenticator) (*Server, error)
NewServer creates a new Qdrant gRPC server.
Parameters:
- config: Server configuration (use DefaultConfig() for sensible defaults)
- collections: Collection store (maps collections to database namespaces)
- baseStorage: Base storage engine (un-namespaced); used for full snapshots/backups
- searchProvider: Optional per-database search service provider
- authenticator: Authentication for gRPC requests (can be nil if auth disabled)
Returns the server instance ready to Start().
func NewServerWithDatabaseManager ¶
func NewServerWithDatabaseManager(config *Config, dbManager *multidb.DatabaseManager, baseStorage storage.Engine, searchProvider SearchServiceProvider, authenticator *auth.Authenticator) (*Server, error)
NewServerWithPersistentRegistry creates a server with a persistent collection registry. This is the recommended way to create a production Qdrant gRPC server.
The persistent registry:
- Persists collection metadata to storage
- Loads existing collections on startup
The search service (if provided):
- Indexes points for unified vector search
- Enables cross-endpoint search (Qdrant gRPC + /nornicdb/search)
Example:
storage := badger.NewEngine("./data")
searchSvc := search.NewService(storage)
authenticator := auth.NewAuthenticator(auth.DefaultAuthConfig())
srv, registry, err := qdrantgrpc.NewServerWithPersistentRegistry(nil, storage, searchSvc, authenticator)
if err != nil {
log.Fatal(err)
}
defer registry.Close()
srv.Start()
NewServerWithDatabaseManager wires a Qdrant gRPC server against NornicDB's DatabaseManager.
Collections are created as database namespaces and must contain the required _collection_meta node.
func (*Server) AllowDatabaseAccess ¶
AllowDatabaseAccess implements DatabaseAccessChecker. Returns PermissionDenied if the principal may not access the database.
func (*Server) CollectionStore ¶
func (s *Server) CollectionStore() CollectionStore
CollectionStore returns the configured collection store.
func (*Server) RegisterAdditionalServices ¶
RegisterAdditionalServices registers additional gRPC services on the same server. This must be called before Start().
type SnapshotsService ¶
type SnapshotsService struct {
qpb.UnimplementedSnapshotsServer
// contains filtered or unexported fields
}
SnapshotsService implements the Qdrant Snapshots gRPC service. It maps to NornicDB's storage.Snapshot and BadgerEngine.Backup functionality.
func NewSnapshotsService ¶
func NewSnapshotsService(config *Config, collections CollectionStore, baseStorage storage.Engine, snapshotDir string, checker DatabaseAccessChecker) *SnapshotsService
NewSnapshotsService creates a new Snapshots service. snapshotDir is the directory where snapshots will be stored.
func (*SnapshotsService) Create ¶
func (s *SnapshotsService) Create(ctx context.Context, req *qpb.CreateSnapshotRequest) (*qpb.CreateSnapshotResponse, error)
Create creates a new snapshot of a collection. Maps to: Export collection nodes as JSON snapshot
func (*SnapshotsService) CreateFull ¶
func (s *SnapshotsService) CreateFull(ctx context.Context, req *qpb.CreateFullSnapshotRequest) (*qpb.CreateSnapshotResponse, error)
CreateFull creates a full storage snapshot (all collections). Maps to: BadgerEngine.Backup or WAL.CreateSnapshot for all data
func (*SnapshotsService) Delete ¶
func (s *SnapshotsService) Delete(ctx context.Context, req *qpb.DeleteSnapshotRequest) (*qpb.DeleteSnapshotResponse, error)
Delete removes a snapshot. Maps to: Delete snapshot file
func (*SnapshotsService) DeleteFull ¶
func (s *SnapshotsService) DeleteFull(ctx context.Context, req *qpb.DeleteFullSnapshotRequest) (*qpb.DeleteSnapshotResponse, error)
DeleteFull removes a full storage snapshot. Maps to: Delete full snapshot file
func (*SnapshotsService) List ¶
func (s *SnapshotsService) List(ctx context.Context, req *qpb.ListSnapshotsRequest) (*qpb.ListSnapshotsResponse, error)
List lists all snapshots for a collection. Maps to: List files in collection snapshot directory
func (*SnapshotsService) ListFull ¶
func (s *SnapshotsService) ListFull(ctx context.Context, req *qpb.ListFullSnapshotsRequest) (*qpb.ListSnapshotsResponse, error)
ListFull lists all full storage snapshots. Maps to: List files in full snapshot directory