Engine Reference
Complete reference for Antarys vector database engine architecture, APIs, and extension capabilities
Engine Reference
Complete technical reference for building with and extending Antarys. This guide covers the core engine architecture, database operations, indexing strategies, and extension points.
Architecture Overview
Antarys is designed around a cache-friendly, contiguous memory layout that minimizes pointer chasing and thread contention. The engine separates concerns into distinct, composable layers.
Core Data Layout
Traditional HNSW implementations use pointer-based node structures:
nodes = [
Node0: {vector=[...], links={0:[1,2],1:[3]}},
Node1: {vector=[...], links={0:[0,2]}},
]Antarys uses separated, contiguous arrays:
vectors = [v0..., v1..., v2..., ...] // Cache-aligned float arrays
edges = [1,2, 0,2, 0,1, ...] // Flat edge list
offsets = [0,2,4,6,...] // Index into edgesThis design enables:
- Sequential memory access patterns
- Better CPU cache utilization
- Lock-free read operations
- Index-based O(1) lookups instead of pointer dereferencing
Component Architecture
┌─────────────────────────────────────────┐
│ Database API Layer │
│ (Collections, CRUD, Query Interface) │
└─────────────────────────────────────────┘
│
┌─────────────────────────────────────────┐
│ Index & Query Engines │
│ (HNSW, Quantization, Batch Query) │
└─────────────────────────────────────────┘
│
┌─────────────────────────────────────────┐
│ Storage & Cache Layer │
│ (PebbleDB, FastCache, Adaptive Cache) │
└─────────────────────────────────────────┘Database Operations
Initialization
Create a database instance with custom configuration:
import "github.com/antarys-ai/antarys"
// Basic initialization
db, err := antarys.NewDB(
"./data", // Storage path
1024*1024*100, // Cache size (bytes)
16, // Worker pool size
)
if err != nil {
return err
}
defer db.Close()Collection Management
Collections are isolated vector spaces with specific dimensionality and distance metrics.
Create Collection:
err := db.CreateCollection(
"documents", // Collection name
384, // Vector dimensions
antarys.MetricCosine, // Distance metric
)Available Metrics:
| Metric | Description | Use Case |
|---|---|---|
MetricCosine | Cosine similarity | Text embeddings, normalized vectors |
MetricEuclidean | L2 distance | General purpose, unnormalized data |
MetricDotProduct | Dot product similarity | Pre-normalized vectors |
List Collections:
collections, err := db.ListCollections()
for _, col := range collections {
fmt.Printf("%s: %d vectors, %d dimensions\n",
col.Name, col.VectorCount, col.Dimensions)
}Delete Collection:
err := db.DeleteCollection("documents")Vector Operations
Insert Single Vector:
err := db.Upsert("documents", &antarys.VectorInput{
ID: "doc_001",
Vector: []float32{0.1, 0.2, 0.3, ...},
Metadata: map[string]interface{}{
"title": "Introduction to Vector Databases",
"category": "technical",
"year": 2024,
},
})Batch Insert:
vectors := []*antarys.VectorInput{
{ID: "doc_001", Vector: vec1, Metadata: meta1},
{ID: "doc_002", Vector: vec2, Metadata: meta2},
// ... more vectors
}
err := db.BatchUpsert("documents", vectors)Optimized Batch Insert:
Uses adaptive batching and parallel processing:
err := db.BatchUpsertOptimized("documents", vectors)
// View batch performance statistics
stats := db.GetBatchStats()
fmt.Printf("Throughput: %.2f vectors/sec\n", stats["throughput"])Retrieve Vector:
vector, metadata, err := db.Get("documents", "doc_001")
if err != nil {
return err
}
// Access metadata
title := metadata["title"].(string)Delete Vector:
err := db.Delete("documents", "doc_001")Query Operations
Antarys supports multiple query types beyond standard k-NN search.
Top-K Search
Find K nearest neighbors:
results, err := db.Search(
"documents",
queryVector,
10, // K results
)
for _, result := range results {
fmt.Printf("ID: %s, Distance: %.4f\n",
result.ID, result.Distance)
fmt.Printf("Metadata: %v\n", result.Metadata)
}Radius Search
Find all vectors within a distance threshold:
results, err := db.RadiusSearch(
"documents",
queryVector,
0.5, // Maximum distance
)Range Search
Find vectors within a distance range:
results, err := db.RangeSearch(
"documents",
queryVector,
0.2, // Minimum distance
0.8, // Maximum distance
)Recommendation Search
Combine positive and negative examples:
positive := [][]float32{vec1, vec2} // Similar to these
negative := [][]float32{vec3} // Dissimilar to these
results, err := db.RecommendSearch(
"documents",
positive,
negative,
10, // K results
)Discovery Search
Find diverse results (exploration mode):
results, err := db.DiscoverSearch(
"documents",
queryVector,
10, // K diverse results
)Index Configuration
HNSW Parameters
Control index building and search behavior:
config := &antarys.IndexDenseConfig{
Collection: "documents",
Dimensions: 384,
MetricKind: antarys.MetricCosine,
Connectivity: 16, // Graph connectivity (M)
ExpansionAdd: 128, // Candidate list size for insertion
ExpansionSearch: 64, // Candidate list size for search
}Parameter Guidelines:
- Connectivity (M): Higher values improve recall but increase memory and build time. Default: 16
- ExpansionAdd: Larger values improve index quality. Default: 128
- ExpansionSearch: Larger values improve search accuracy. Default: 64
Memory Optimization
Product Quantization:
Reduce memory footprint with minimal accuracy loss:
// Enable quantization for database
db.EnableQuantization(antarys.QuantPQ)
// Train quantizer with sample vectors
sampleVectors := [][]float32{...} // Representative samples
err := db.TrainQuantizer("documents", sampleVectors)Available Quantization Types:
antarys.QuantNone // No quantization
antarys.QuantPQ // Product quantization
antarys.QuantScalar // Scalar quantizationMemory-Mapped Storage:
Use mmap for large datasets that exceed RAM:
db.EnableMmap()Segment-Based Architecture
Enable fine-grained locking for write-heavy workloads:
db.EnableSegments()
// Compact segments to improve performance
err := db.CompactSegments("documents")
// View segment statistics
stats, err := db.GetSegmentStats("documents")Embedding Generation
Antarys includes built-in text embedding generation using ONNX Runtime.
Setup
Download required dependencies:
# Download ONNX Runtime for your platform
antarys download onnx
# Download embedding model
antarys download embedding 4 # BGE-Small-EN-v1.5Available Models
| ID | Model | Dimensions | Description |
|---|---|---|---|
| 1 | BGE-Base-EN | 768 | Base English model |
| 2 | BGE-Base-EN-v1.5 | 768 | Improved base model |
| 3 | BGE-Small-EN | 384 | Fast English model |
| 4 | BGE-Small-EN-v1.5 | 384 | Default, balanced performance |
| 5 | BGE-Small-ZH-v1.5 | 512 | Chinese language model |
Using Embedding Service
import "github.com/antarys-ai/antarys"
// Initialize service
service, err := antarys.NewEmbeddingService(
antarys.BGESmallENV15,
os.Getenv("HOME") + "/.antarys",
)
if err != nil {
return err
}
defer service.Close()
// Generate query embedding
queryEmbed, err := service.GenerateQuery("What is vector search?")
// Generate passage embeddings (batch)
texts := []string{
"Vector search enables semantic similarity",
"HNSW is an approximate nearest neighbor algorithm",
}
embeddings, err := service.GeneratePassage(texts, 256)Caching System
Antarys implements a multi-tier caching strategy for optimal performance.
Cache Layers
- Vector Cache: Hot vector data
- Metadata Cache: Associated metadata
- Query Cache: Recent search results
- Adaptive Cache: Automatic cache policy selection (LRU, LFU, ARC)
Cache Operations
Prewarm Cache:
Preload frequently accessed vectors:
ids := []string{"doc_001", "doc_002", "doc_003"}
err := db.PrewarmCache("documents", ids)View Cache Statistics:
stats := db.GetCacheStats()
fmt.Printf("Hit rate: %.2f%%\n", stats["hit_rate"])
fmt.Printf("Evictions: %d\n", stats["evictions"])Reset Cache:
db.ResetCache()Snapshot & Backup
Create point-in-time snapshots for backup and recovery.
Create Snapshot
snapshot, err := db.CreateSnapshot("backup-2024-11-01")
if err != nil {
return err
}
fmt.Printf("Snapshot ID: %s\n", snapshot.ID)
fmt.Printf("Created at: %s\n", snapshot.Timestamp)List Snapshots
snapshots, err := db.ListSnapshots()
for _, snap := range snapshots {
fmt.Printf("%s: %s (%d bytes)\n",
snap.ID, snap.Name, snap.Size)
}Restore Snapshot
err := db.RestoreSnapshot("backup-2024-11-01")Delete Snapshot
err := db.DeleteSnapshot("backup-2024-11-01")Storage Layer
Antarys uses PebbleDB (LSM-tree based storage) for persistence.
Storage Operations
Direct Storage Access:
// Advanced: Access underlying storage
// Most operations should use the high-level DB API
// Custom key-value operations possible for extensionsWrite-Ahead Log (WAL):
Automatic WAL management for durability:
// WAL is automatically managed
// Configure via database initialization optionsPerformance Tuning
Worker Pool
Control parallel processing:
// Initialize with custom worker pool size
db, err := antarys.NewDB(path, cacheSize, 32) // 32 workersBatch Configuration
Customize batch processing behavior:
config := &antarys.BatchConfig{
MaxBatchSize: 1000,
MinBatchSize: 10,
AutoTune: true,
FlushInterval: time.Second,
Compression: false,
ParallelWorkers: 16,
}
// Apply to new batch processorQuery Optimization
The query optimizer tracks query patterns and adapts:
// Automatic query optimization is enabled by default
// Monitors execution time and adjusts search parametersBuilding Custom Solutions
Antarys is designed to be extended. Here are common patterns for building custom vector databases.
Custom Distance Metrics
Implement custom distance functions:
// Define custom metric
type CustomMetric struct{}
func (m *CustomMetric) Distance(a, b []float32) float32 {
// Your custom distance logic
return distance
}
// Use with custom index implementationCustom Index Types
Build specialized indexes:
// Create index with custom configuration
index, err := antarys.NewIndexDense(dbPath, &antarys.IndexDenseConfig{
Collection: "custom",
Dimensions: dimensions,
MetricKind: metric,
Connectivity: 32, // Custom connectivity
ExpansionAdd: 256, // Custom expansion
ExpansionSearch: 128,
})Distributed Architecture
Extend for distributed deployment:
Shard Collections
Partition vectors across multiple instances:
// Implement consistent hashing for ID-based sharding
shard := hashID(vectorID) % numShards
// Route to appropriate instance
db := shards[shard]
db.Upsert(collection, vector)Aggregate Search Results
Merge results from multiple shards:
// Query all shards in parallel
var wg sync.WaitGroup
results := make([][]SearchResult, numShards)
for i, db := range shards {
wg.Add(1)
go func(idx int, database *DB) {
defer wg.Done()
results[idx], _ = database.Search(collection, query, k)
}(i, db)
}
wg.Wait()
// Merge and re-rank
finalResults := mergeAndRank(results, k)Implement Replication
Add redundancy for fault tolerance:
// Write to primary and replicas
primary.Upsert(collection, vector)
for _, replica := range replicas {
go replica.Upsert(collection, vector)
}Custom Query Types
Extend the query engine:
// Implement custom query logic
type CustomQueryEngine struct {
index *antarys.IndexDense
}
func (qe *CustomQueryEngine) HybridSearch(
textQuery string,
filters map[string]interface{},
k int,
) ([]SearchResult, error) {
// 1. Generate embedding
// 2. Apply filters
// 3. Execute vector search
// 4. Re-rank with custom scoring
return results, nil
}API Integration Patterns
HTTP Server
Build a REST API:
import (
"encoding/json"
"net/http"
"github.com/gorilla/mux"
)
func main() {
db, _ := antarys.NewDB("./data", cacheSize, workers)
defer db.Close()
r := mux.NewRouter()
r.HandleFunc("/collections", createCollection).Methods("POST")
r.HandleFunc("/vectors", upsertVector).Methods("POST")
r.HandleFunc("/search", searchVectors).Methods("POST")
http.ListenAndServe(":8080", r)
}
func searchVectors(w http.ResponseWriter, r *http.Request) {
var req SearchRequest
json.NewDecoder(r.Body).Decode(&req)
results, err := db.Search(
req.Collection,
req.Query,
req.K,
)
json.NewEncoder(w).Encode(results)
}gRPC Server
High-performance RPC interface:
service VectorDB {
rpc Search(SearchRequest) returns (SearchResponse);
rpc Upsert(UpsertRequest) returns (UpsertResponse);
rpc BatchUpsert(stream UpsertRequest) returns (UpsertResponse);
}Error Handling
Common error patterns and handling:
import "errors"
// Check for specific errors
if errors.Is(err, antarys.ErrCollectionNotFound) {
// Handle missing collection
}
if errors.Is(err, antarys.ErrInvalidDimensions) {
// Handle dimension mismatch
}
// Validate before operations
if len(vector) != expectedDim {
return fmt.Errorf("expected %d dimensions, got %d",
expectedDim, len(vector))
}Monitoring & Observability
Database Statistics
// Collection stats
collections, _ := db.ListCollections()
for _, col := range collections {
fmt.Printf("Collection: %s\n", col.Name)
fmt.Printf(" Vectors: %d\n", col.VectorCount)
fmt.Printf(" Dimensions: %d\n", col.Dimensions)
}
// Cache statistics
cacheStats := db.GetCacheStats()
fmt.Printf("Cache hit rate: %.2f%%\n", cacheStats["hit_rate"])
// Batch statistics
batchStats := db.GetBatchStats()
fmt.Printf("Batch throughput: %.2f/sec\n", batchStats["throughput"])Performance Metrics
Track query performance:
start := time.Now()
results, err := db.Search(collection, query, k)
duration := time.Since(start)
fmt.Printf("Query time: %v\n", duration)
fmt.Printf("Results: %d\n", len(results))
fmt.Printf("QPS: %.2f\n", 1.0/duration.Seconds())Best Practices
Vector Normalization
Normalize vectors for cosine similarity:
func normalize(vec []float32) []float32 {
var norm float32
for _, v := range vec {
norm += v * v
}
norm = float32(math.Sqrt(float64(norm)))
normalized := make([]float32, len(vec))
for i, v := range vec {
normalized[i] = v / norm
}
return normalized
}
// Use before insertion with MetricCosine
normalizedVec := normalize(rawVector)
db.Upsert(collection, &VectorInput{
ID: id,
Vector: normalizedVec,
})Batch Operations
Prefer batch operations for better throughput:
// Instead of individual inserts
for _, vec := range vectors {
db.Upsert(collection, vec) // Slow
}
// Use batch insert
db.BatchUpsertOptimized(collection, vectors) // FastConnection Pooling
Reuse database instances:
// Initialize once
var db *antarys.DB
func init() {
db, _ = antarys.NewDB(path, cacheSize, workers)
}
// Use across application
func handler() {
results, _ := db.Search(collection, query, k)
}Resource Cleanup
Always close resources:
db, err := antarys.NewDB(path, cacheSize, workers)
if err != nil {
return err
}
defer db.Close()
service, err := antarys.NewEmbeddingService(model, cacheDir)
if err != nil {
return err
}
defer service.Close()Dependencies
Antarys maintains minimal dependencies:
require (
github.com/VictoriaMetrics/fastcache v1.13.0
github.com/cockroachdb/pebble v1.1.5
github.com/gorilla/mux v1.8.1
github.com/schollz/progressbar/v3 v3.18.0
github.com/sugarme/tokenizer v0.3.0
)Dependency Roles:
- fastcache: High-performance in-memory cache
- pebble: LSM-tree based persistent storage
- mux: HTTP routing (examples only)
- progressbar: Download progress display
- tokenizer: Text tokenization for embeddings
Limitations & Future Work
Current Limitations
- No built-in distributed coordination
- Filter predicates not yet exposed via HTTP API (engine supports them)
- Limited to supported platforms (macOS, Linux)
Planned Features
The following features are in development:
- Filtered search and payload indexing (HTTP API)
- Distributed architecture with coordination
- gRPC support for high-performance RPC
- Comprehensive observability and monitoring
- Advanced resource management
- Hybrid and multi-modal search capabilities
- Multi-tenancy and security features
- Enhanced query optimization
- Advanced collection management
- Backup and recovery improvements
Filter Engine (In Progress)
The query engine already supports filters internally:
// Available internally, HTTP API coming soon
params := &QueryParams{
Type: QueryTopK,
K: 10,
// Filters: map[string]interface{}{ ... } // Coming soon
}Getting Help
For issues, questions, or contributions:
- Review the source code on GitHub
- Check existing issues and discussions
- Study the test files for usage examples
- Examine benchmark code for performance patterns
License
Antarys is open source and available under the Apache 2.0 license.