Documentation
¶
Overview ¶
Package qdrant provides a modular, dependency-injected client for the Qdrant vector database.
The qdrant package is designed to simplify interaction with Qdrant in Go applications, offering a clean, testable abstraction layer for common vector database operations such as collection management, embedding insertion, similarity search, and deletion. It integrates seamlessly with the fx dependency injection framework and supports builder-style configuration.
Core Features:
- Managed Qdrant client lifecycle with Fx integration
- Config struct supporting environment and YAML loading
- Automatic health checks on client initialization
- Safe, batched insertion of embeddings with configurable batch size
- Vector similarity search with abstracted SearchResult interface
- Type-safe collection creation and existence checks
- Support for payload metadata and optional vector retrieval
- Extensible abstraction layer for alternate vector stores (e.g., Pinecone, Postgres)
Basic Usage:
import "github.com/Aleph-Alpha/std/v1/qdrant"
// Create a new client
client, err := qdrant.NewQdrantClient(qdrant.QdrantParams{
Config: &qdrant.Config{
Endpoint: "localhost:6334",
ApiKey: "",
Collection: "documents",
},
})
if err != nil {
log.Fatal(err)
}
// Insert single embedding
input := qdrant.EmbeddingInput{
ID: "doc_1",
Vector: []float32{0.12, 0.43, 0.85},
Meta: map[string]any{"title": "My Document"},
}
if err := client.Insert(ctx, input); err != nil {
log.Fatal(err)
}
// Batch insert embeddings
batch := []qdrant.EmbeddingInput{input1, input2, input3}
if err := client.BatchInsert(ctx, batch); err != nil {
log.Fatal(err)
}
// Perform similarity search
results, err := client.Search(ctx, queryVector, 5)
for _, res := range results {
fmt.Printf("ID=%s Score=%.4f\n", res.GetID(), res.GetScore())
}
FX Module Integration:
The package exposes an Fx module for automatic dependency injection:
app := fx.New( qdrant.FXModule, // other modules... ) app.Run()
Abstractions:
The package defines a lightweight SearchResultInterface that encapsulates search results via methods such as GetID(), GetScore(), GetMeta(), and GetCollectionName(). The underlying concrete type remains SearchResult, allowing both strong typing internally and loose coupling externally.
Example:
type SearchResultInterface interface {
GetID() string
GetScore() float32
GetMeta() map[string]*qdrant.Value
GetCollectionName() string
}
type SearchResult struct { /* implements SearchResultInterface */ }
// Function signature:
func (c *QdrantClient) Search(ctx context.Context, vector []float32, topK int) ([]SearchResultInterface, error)
Configuration:
Qdrant can be configured via environment variables or YAML:
QDRANT_ENDPOINT=http://localhost:6334 QDRANT_API_KEY=your-api-key QDRANT_COLLECTION=documents
Performance Considerations:
The BatchInsert method automatically splits large embedding inserts into smaller upserts (default batch size = 500). This minimizes memory usage and avoids timeouts when ingesting large datasets.
Thread Safety:
All exported methods on QdrantClient are safe for concurrent use by multiple goroutines.
Testing:
For testing and mocking, application code should depend on the public interface types (e.g., SearchResultInterface, EmbeddingInput) instead of concrete Qdrant structs. This allows replacing the QdrantClient with in-memory or mock implementations in tests.
Example Mock:
type MockResult struct {
id string
score float32
meta map[string]any
}
func (m MockResult) GetID() string { return m.id }
func (m MockResult) GetScore() float32 { return m.score }
func (m MockResult) GetMeta() map[string]any { return m.meta }
Package Layout:
qdrant/ ├── setup.go // Qdrant client implementation ├── utils.go // Shared types and interfaces └── config.go // Configuration and Fx module definitions
Index ¶
- Variables
- func RegisterQdrantLifecycle(lc fx.Lifecycle, client *QdrantClient)
- type Collection
- type Config
- func (c *Config) WithApiKey(key string) *Config
- func (c *Config) WithCompatibilityCheck(enabled bool) *Config
- func (c *Config) WithCompression(enabled bool) *Config
- func (c *Config) WithConnectTimeout(d time.Duration) *Config
- func (c *Config) WithKeepAlive(enabled bool) *Config
- func (c *Config) WithTimeout(d time.Duration) *Config
- type Embedding
- type EmbeddingInput
- type QdrantClient
- func (c *QdrantClient) BatchInsert(ctx context.Context, inputs []EmbeddingInput) error
- func (c *QdrantClient) Close() error
- func (c *QdrantClient) Delete(ctx context.Context, ids []string) error
- func (c *QdrantClient) EnsureCollection(ctx context.Context, name string) error
- func (c *QdrantClient) GetCollection(ctx context.Context, name string) (*Collection, error)
- func (c *QdrantClient) Insert(ctx context.Context, input EmbeddingInput) error
- func (c *QdrantClient) ListCollections(ctx context.Context) ([]string, error)
- func (c *QdrantClient) Search(ctx context.Context, vector []float32, topK int) ([]SearchResultInterface, error)
- type QdrantParams
- type SearchResult
- type SearchResultInterface
Constants ¶
This section is empty.
Variables ¶
var FXModule = fx.Module("qdrant", fx.Provide( NewQdrantClient, ), fx.Invoke(RegisterQdrantLifecycle), )
FXModule defines the Fx module for the Qdrant client.
This module integrates the Qdrant client into an Fx-based application by providing the client factory and registering its lifecycle hooks.
The module:
- Provides the NewQdrantClient factory function to the dependency injection container, making the client available to other components.
- Provides the NewEmbeddingsStore function, which wraps the client into a higher-level abstraction.
- Invokes RegisterQdrantLifecycle to handle startup/shutdown of the client.
Usage:
app := fx.New(
qdrant.FXModule,
// other modules...
)
Dependencies required by this module: - A qdrant.Config instance must be available in the dependency injection container.
Functions ¶
func RegisterQdrantLifecycle ¶
func RegisterQdrantLifecycle(lc fx.Lifecycle, client *QdrantClient)
RegisterQdrantLifecycle handles startup/shutdown of the Qdrant client. It ensures proper resource cleanup and logging.
OnStart:
- Performs a Qdrant health check to verify connectivity.
- Logs a success message once the client is ready.
OnStop:
- Ensures the Qdrant client is closed exactly once.
- Logs a shutdown message.
Types ¶
type Collection ¶
type Config ¶
type Config struct {
// Hostname of the Qdrant server, e.g. "localhost".
Endpoint string `yaml:"endpoint" env:"QDRANT_ENDPOINT"`
// gRPC port of the Qdrant server. Defaults to 6334.
Port int `yaml:"port" env:"QDRANT_PORT"`
// Optional authentication token for secured deployments.
ApiKey string `yaml:"api_key" env:"QDRANT_API_KEY"`
// Default collection name this client operates on.
Collection string `yaml:"collection" env:"QDRANT_COLLECTION"`
// Maximum request duration before timing out.
Timeout time.Duration `yaml:"timeout" env:"QDRANT_TIMEOUT"`
// Connection establishment timeout.
ConnectTimeout time.Duration `yaml:"connect_timeout" env:"QDRANT_CONNECT_TIMEOUT"`
// Whether to keep idle connections open for reuse.
KeepAlive bool `yaml:"keep_alive" env:"QDRANT_KEEP_ALIVE"`
// Enable gzip compression for requests.
Compression bool `yaml:"compression" env:"QDRANT_COMPRESSION"`
// Whether to perform version compatibility checks between client and server.
CheckCompatibility bool `yaml:"check_compatibility" env:"QDRANT_CHECK_COMPATIBILITY"`
}
Config holds connection and behavior settings for the Qdrant client.
It is intentionally minimal, readable, and easy to override from environment variables, YAML, or programmatically via helper methods.
Example (programmatic):
cfg := qdrant.DefaultConfig()
cfg.Endpoint = "http://localhost:6334"
cfg.ApiKey = os.Getenv("QDRANT_API_KEY")
cfg.Timeout = 10 * time.Second
Example (builder style):
cfg := qdrant.FromEndpoint("http://localhost:6334").
WithApiKey(os.Getenv("QDRANT_API_KEY")).
WithTimeout(10 * time.Second)
func DefaultConfig ¶
func DefaultConfig() *Config
DefaultConfig provides sensible defaults for most use cases.
func FromEndpoint ¶
FromEndpoint returns a default config pre-filled with a specific endpoint.
func (*Config) WithApiKey ¶
Builder-style helpers (optional, ergonomic)
func (*Config) WithCompatibilityCheck ¶
func (*Config) WithCompression ¶
func (*Config) WithKeepAlive ¶
type Embedding ¶
type Embedding struct {
ID string // Unique identifier (same as Qdrant point ID)
Vector []float32 // Vector representation of the embedding
Meta map[string]any // Optional metadata associated with the embedding
}
Embedding represents a dense embedding vector.
func NewEmbedding ¶
func NewEmbedding(input EmbeddingInput) Embedding
NewEmbedding converts a high-level EmbeddingInput into the internal Embedding type. Having this builder allows for future validation or normalization logic. For now, it performs a shallow copy.
type EmbeddingInput ¶
type EmbeddingInput struct {
ID string // Unique identifier for the embedding (e.g., document ID)
Vector []float32 // Dense vector representation of the embedding
Meta map[string]any // Optional metadata associated with the embedding
}
EmbeddingInput is the type the application provides to insert embeddings. Keeps the app decoupled from internal Qdrant SDK structs.
type QdrantClient ¶
type QdrantClient struct {
// contains filtered or unexported fields
}
func NewQdrantClient ¶
func NewQdrantClient(p QdrantParams) (*QdrantClient, error)
NewQdrantClient ────────────────────────────────────────────────────────────── NewQdrantClient ──────────────────────────────────────────────────────────────
NewQdrantClient constructs a new instance of QdrantClient and validates connectivity via a health check.
The Qdrant Go SDK creates lightweight gRPC connections, so this method performs an immediate health check to fail fast if the service is unreachable.
Example:
client, _ := qdrant.NewQdrantClient(qdrant.QdrantParams{Config: cfg})
func (*QdrantClient) BatchInsert ¶
func (c *QdrantClient) BatchInsert(ctx context.Context, inputs []EmbeddingInput) error
BatchInsert ────────────────────────────────────────────────────────────── BatchInsert ──────────────────────────────────────────────────────────────
BatchInsert efficiently inserts multiple embeddings in batches to reduce network overhead.
This method is safe to call for large datasets — it will automatically split inserts into smaller chunks (`defaultBatchSize`) and perform multiple upserts sequentially.
Logs batch indices and collection name for debugging.
func (*QdrantClient) Close ¶
func (c *QdrantClient) Close() error
Close ────────────────────────────────────────────────────────────── Close ──────────────────────────────────────────────────────────────
Close gracefully shuts down the Qdrant client.
Since the official Qdrant Go SDK doesn’t maintain persistent connections, this is currently a no-op. It exists for lifecycle symmetry and future safety.
func (*QdrantClient) Delete ¶
func (c *QdrantClient) Delete(ctx context.Context, ids []string) error
Delete ────────────────────────────────────────────────────────────── Delete ──────────────────────────────────────────────────────────────
Delete removes embeddings from a collection by their IDs.
It constructs a `DeletePoints` request containing a list of `PointId`s, waits synchronously for completion, and logs the operation status.
func (*QdrantClient) EnsureCollection ¶
func (c *QdrantClient) EnsureCollection(ctx context.Context, name string) error
EnsureCollection ────────────────────────────────────────────────────────────── EnsureCollection ──────────────────────────────────────────────────────────────
EnsureCollection verifies if a given collection exists, and creates it if missing.
It’s safe to call this multiple times — if the collection already exists, the function exits early. This pattern simplifies startup logic for embedding services that may bootstrap their own Qdrant collections.
func (*QdrantClient) GetCollection ¶
func (c *QdrantClient) GetCollection(ctx context.Context, name string) (*Collection, error)
func (*QdrantClient) Insert ¶
func (c *QdrantClient) Insert(ctx context.Context, input EmbeddingInput) error
Insert ────────────────────────────────────────────────────────────── Insert ──────────────────────────────────────────────────────────────
Insert adds a single embedding to Qdrant.
Internally, it reuses the BatchInsert logic to ensure consistent handling of payload serialization and error management.
func (*QdrantClient) ListCollections ¶
func (c *QdrantClient) ListCollections(ctx context.Context) ([]string, error)
ListCollections ────────────────────────────────────────────────────────────── ListCollections ──────────────────────────────────────────────────────────────
ListCollections retrieves all existing collections from Qdrant and returns their names as a string slice. This can be extended to preload metadata using GetCollection for each name if needed.
Example:
names, err := client.ListCollections(ctx)
if err != nil {
log.Fatalf("failed to list collections: %v", err)
}
log.Printf("Found collections: %v", names)
func (*QdrantClient) Search ¶
func (c *QdrantClient) Search(ctx context.Context, vector []float32, topK int) ([]SearchResultInterface, error)
Search ────────────────────────────────────────────────────────────── Search ──────────────────────────────────────────────────────────────
Search performs a similarity search in the configured collection.
Parameters:
- vector — the query embedding to search against.
- topK — maximum number of nearest results to return.
Returns:
A slice of `SearchResultInterface` instances representing the most similar stored embeddings.
Logs the total count of hits for observability.
type QdrantParams ¶
QdrantParams defines dependencies needed to construct the Qdrant client.
type SearchResult ¶
type SearchResult struct {
ID string
Score float32
Meta map[string]*qdrant.Value
Vector []float32
Collection string
}
SearchResult holds results from a similarity search.
func (SearchResult) GetCollectionName ¶
func (r SearchResult) GetCollectionName() string
GetCollectionName returns the name of the collection from which the result originated.
func (SearchResult) GetID ¶
func (r SearchResult) GetID() string
GetID returns the result's unique identifier.
func (SearchResult) GetMeta ¶
func (r SearchResult) GetMeta() map[string]*qdrant.Value
GetMeta returns the metadata stored with the vector.
func (SearchResult) GetScore ¶
func (r SearchResult) GetScore() float32
GetScore returns the similarity score associated with the result.
func (SearchResult) GetVector ¶
func (r SearchResult) GetVector() []float32
GetVector returns the dense embedding vector if available.
func (SearchResult) HasVector ¶
func (r SearchResult) HasVector() bool
HasVector reports whether the result contains a non-empty vector payload.
type SearchResultInterface ¶
type SearchResultInterface interface {
GetID() string // Unique result identifier
GetScore() float32 // Similarity score
GetMeta() map[string]*qdrant.Value // Metadata associated with the result
GetVector() []float32 // Optional embedding vector
HasVector() bool // Whether a vector payload is present
GetCollectionName() string // Name of the Qdrant collection
}
SearchResultInterface is the public interface for search results. It provides a consistent way to access search results regardless of the underlying implementation.