Antarys

|

Antarys

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 edges

This 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:

MetricDescriptionUse Case
MetricCosineCosine similarityText embeddings, normalized vectors
MetricEuclideanL2 distanceGeneral purpose, unnormalized data
MetricDotProductDot product similarityPre-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.

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)
}

Find all vectors within a distance threshold:

results, err := db.RadiusSearch(
    "documents",
    queryVector,
    0.5,  // Maximum distance
)

Find vectors within a distance range:

results, err := db.RangeSearch(
    "documents",
    queryVector,
    0.2,  // Minimum distance
    0.8,  // Maximum distance
)

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
)

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 quantization

Memory-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.5

Available Models

IDModelDimensionsDescription
1BGE-Base-EN768Base English model
2BGE-Base-EN-v1.5768Improved base model
3BGE-Small-EN384Fast English model
4BGE-Small-EN-v1.5384Default, balanced performance
5BGE-Small-ZH-v1.5512Chinese 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

  1. Vector Cache: Hot vector data
  2. Metadata Cache: Associated metadata
  3. Query Cache: Recent search results
  4. 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 extensions

Write-Ahead Log (WAL):

Automatic WAL management for durability:

// WAL is automatically managed
// Configure via database initialization options

Performance Tuning

Worker Pool

Control parallel processing:

// Initialize with custom worker pool size
db, err := antarys.NewDB(path, cacheSize, 32)  // 32 workers

Batch 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 processor

Query Optimization

The query optimizer tracks query patterns and adapts:

// Automatic query optimization is enabled by default
// Monitors execution time and adjusts search parameters

Building 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 implementation

Custom 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)  // Fast

Connection 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.