Vorcyc.Quiver 3.2.1

dotnet add package Vorcyc.Quiver --version 3.2.1
                    
NuGet\Install-Package Vorcyc.Quiver -Version 3.2.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Vorcyc.Quiver" Version="3.2.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Vorcyc.Quiver" Version="3.2.1" />
                    
Directory.Packages.props
<PackageReference Include="Vorcyc.Quiver" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Vorcyc.Quiver --version 3.2.1
                    
#r "nuget: Vorcyc.Quiver, 3.2.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Vorcyc.Quiver@3.2.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Vorcyc.Quiver&version=3.2.1
                    
Install as a Cake Addin
#tool nuget:?package=Vorcyc.Quiver&version=3.2.1
                    
Install as a Cake Tool

Vorcyc Quiver 3.2.1

Vorcyc Quiver 3.2.1

A pure .NET embedded vector database โ€” zero native dependencies, runs in-process, no standalone database server deployment required.

๐Ÿ“– Github Repo (full documention)

Quiver draws on EF Core's DbContext design pattern, allowing developers to define entities and indexing strategies through declarative attributes such as [QuiverKey], [QuiverVector], and [QuiverIndex], with the framework automatically completing model discovery, index construction, and persistence management at runtime.


๐Ÿ› What's Fixed in 3.2.1

v3.2.1 is fully backward-compatible with all previous data files.

Fix Description
EntityPageCache thread-safety Fixed a data race in LazyPaging mode: concurrent reads via Parallel.ForEach (e.g., multiple threads calling Find / Search simultaneously) could corrupt the internal LRU structures (_loadedPages, _lru, _lruNodes). All LRU-mutating paths are now protected by an internal Lock (_pageLock). FullMemory mode is unaffected.

๐Ÿ†• What's New in 3.2.0

v3.2.0 is fully backward-compatible with all previous data files.

Feature Description
CompactMemory() / CompactMemoryAsync() Call on any QuiverSet<T> to flush dirty pages and evict all in-memory pages on demand.
CompactAllMemoryAsync() Call on QuiverDbContext to compact every collection at once.

Both methods are no-op in FullMemory mode. Vector index structures always remain in memory.


๐Ÿ†• What's New in 3.1.0

v3.1.0 is fully backward-compatible with v1.x, v2.x, and v3.0.0 data files โ€” no migration needed.

Breaking Changes

Change Before (v3.0.0) After (v3.1.0)
VectorStorageMode removed VectorStorage = VectorStorageMode.MemoryMapped โ€” optional mmap vector arena via MmapVectorStore Removed entirely. Vectors are always stored on the GC heap (HeapVectorStore). The LazyPaging entity cache already bounds memory; a separate mmap layer is redundant.
QuiverSet constructor simplified Accepted DistanceMetric defaultMetric parameter The defaultMetric parameter is removed. Each vector field declares its metric independently via [QuiverVector(dim, metric)].

Migrating from v3.0.0: Remove VectorStorage = VectorStorageMode.MemoryMapped from your QuiverDbOptions if present. No other changes required.


What's New in 3.0.0

v3.0.0 is fully backward-compatible with v1.x and v2.x data files.

Category Change
Lazy-loading page cache EntityCache = EntityCacheMode.LazyPaging โ€” entity objects loaded on demand in fixed-size pages, evicted by LRU when memory ceiling is reached
Bounded memory MaxCachedPages ร— PageSize ร— entity size caps working-set size regardless of total dataset size
Vector indexes stay resident HNSW / IVF / KDTree topology structures always in memory; search performance is unaffected
IsLazyLoading property QuiverSet<T>.IsLazyLoading reflects the current caching mode

What's New in 2.0.0

v2.0.0 is fully backward-compatible with v1.x data files โ€” no migration needed.

Category Change
Architecture SimilarityFunc delegate โ†’ ISimilarity<T> static abstract interface (JIT-inlined, zero dispatch overhead)
Binary-first storage Primary storage is always binary. JSON/XML are export/import-only side channels (ExportAsync / ImportAsync)
New Metrics 6 new: Manhattan, Chebyshev, Pearson, Hamming, Jaccard, Canberra โ€” plus the original 3 (Cosine / Euclidean / DotProduct), totaling 9 built-in
Custom Similarity [QuiverVector(128, CustomSimilarity = typeof(MySim))] โ€” plug in any ISimilarity<float> struct
SIMD All 9 metrics use Vector<float> / TensorPrimitives SIMD, auto-adapts to SSE4/AVX2/AVX-512

  • Code-First Declarative Modeling โ€” Annotate entity classes with attributes; the framework auto-discovers and registers QuiverSet<T> collections via reflection โ€” zero configuration.
  • Multiple ANN Index Algorithms โ€” Built-in Flat (brute-force), HNSW, IVF, and KDTree indexes, covering small-scale exact search to million-scale approximate search.
  • 9 Distance Metrics + Custom Similarity โ€” Cosine, Euclidean, DotProduct, Manhattan, Chebyshev, Pearson, Hamming, Jaccard, Canberra. Or plug in your own ISimilarity<float>.
  • Binary-First Persistence โ€” Primary storage is always high-performance binary. JSON and XML are available as export/import side channels (ExportAsync / ImportAsync) for readable backups and interoperability. WAL incremental persistence reduces complexity from O(N) to O(ฮ”).
  • Concurrency Safe โ€” QuiverSet<T> uses ReaderWriterLockSlim internally; concurrent reads and writes are safe out-of-the-box.
  • SIMD Accelerated โ€” All similarity implementations use TensorPrimitives + Vector<float> SIMD, auto-adapting to SSE4/AVX2/AVX-512.
  • Lazy-loading Page Cache โ€” Optional EntityCache = EntityCacheMode.LazyPaging with LRU eviction and MaxCachedPages / PageSize controls. Entity objects load on demand; vector indexes remain resident for full search performance.
  • CompactMemory โ€” CompactMemory() / CompactMemoryAsync() on QuiverSet<T> and CompactAllMemoryAsync() on QuiverDbContext flush dirty pages and release all cached pages on demand.
  • Schema Migration โ€” Property rename and value transform via ConfigureMigration<T>(). Adding/removing fields requires no configuration.

Typical Use Cases: Semantic search ยท RAG ยท Face recognition ยท Image-to-image search ยท Recommendation systems ยท Multimodal retrieval


๐Ÿš€ Quick Start

1. Define Entity

using Vorcyc.Quiver;

public class Document
{
    [QuiverKey]
    public string Id { get; set; } = string.Empty;

    public string Title { get; set; } = string.Empty;

    public string Category { get; set; } = string.Empty;

    [QuiverVector(384, DistanceMetric.Cosine)]
    public float[] Embedding { get; set; } = [];
}

2. Define Database Context

public class MyDocumentDb : QuiverDbContext
{
    public QuiverSet<Document> Documents { get; set; } = null!;

    public MyDocumentDb() : base(new QuiverDbOptions
    {
        DatabasePath = "documents.vdb",
        DefaultMetric = DistanceMetric.Cosine
    })
    { }
}

3. Use It

await using var db = new MyDocumentDb();
await db.LoadAsync();

// Add
db.Documents.Add(new Document
{
    Id = "doc-001",
    Title = "Introduction to Vector Databases",
    Category = "Tutorial",
    Embedding = new float[384] // embedding vector from your model
});

// Search Top-5
float[] queryVector = new float[384];
var results = db.Documents.Search(e => e.Embedding, queryVector, topK: 5);

foreach (var r in results)
    Console.WriteLine($"{r.Entity.Title} โ€” {r.Similarity:F4}");

// Auto-saved on DisposeAsync

๐Ÿ“ Distance Metrics

Metric Range Use Case
Cosine [-1, 1] Text embeddings, semantic search
Euclidean (0, 1] Spatial coordinates, physical distances
DotProduct $(-\infty, +\infty)$ Pre-normalized vectors, MIPS
Manhattan (0, 1] Sparse features, recommendation systems
Chebyshev (0, 1] Feature deviation detection, grid distances
Pearson [-1, 1] Text embeddings (de-biased), TF-IDF, ratings
Hamming [0, 1] Binary hash codes, LSH, SimHash fingerprints
Jaccard [0, 1] BoW/TF-IDF sparse features, histograms
Canberra [0, 1] Sparse data (weight-sensitive), chemical fingerprints

Or define your own: [QuiverVector(128, CustomSimilarity = typeof(MyMetric))]


๐Ÿ—‚๏ธ Index Types

Index Search Speed Accuracy Best For
Flat O(nร—d) 100% < 10K entries, exact search
HNSW O(log n) ~95-99%+ 10Kโ€“10M, universal preferred
IVF O(n/kร—d) ~90-99% 100K+, high throughput
KDTree O(log n) 100% < 10K, dimensions < 20
// HNSW example
[QuiverVector(768, DistanceMetric.Cosine)]
[QuiverIndex(VectorIndexType.HNSW, M = 32, EfConstruction = 300, EfSearch = 100)]
public float[] Embedding { get; set; } = [];

// IVF example
[QuiverVector(128, DistanceMetric.Cosine)]
[QuiverIndex(VectorIndexType.IVF, NumClusters = 100, NumProbes = 15)]
public float[] Feature { get; set; } = [];

๐Ÿ”ง CRUD Operations

// Add
db.Documents.Add(entity);
db.Documents.AddRange(batch);          // Atomic two-phase commit
await db.Documents.AddRangeAsync(batch);

// Upsert (insert or update, single write lock)
db.Documents.Upsert(entity);

// Remove
db.Documents.Remove(entity);           // By entity (matched by key)
db.Documents.RemoveByKey("doc-001");   // By key directly

// Find
Document? doc = db.Documents.Find("doc-001"); // O(1)

// Exists
bool exists = db.Documents.Exists("doc-001");              // By key, O(1)
bool hasTutorial = db.Documents.Exists(e => e.Category == "Tutorial"); // By predicate, O(n) short-circuit

// Clear
db.Documents.Clear();

// Count
int count = db.Documents.Count;

// Top-K
var results = db.Documents.Search(e => e.Embedding, queryVector, topK: 10);

// Threshold
var results = db.Documents.SearchByThreshold(e => e.Embedding, queryVector, threshold: 0.85f);

// Filtered
var results = db.Documents.Search(
    e => e.Embedding, queryVector, topK: 10,
    filter: e => e.Category == "Tutorial",
    overFetchMultiplier: 4);

// Top-1
var best = db.Documents.SearchTop1(e => e.Embedding, queryVector);

// Async (all methods have Async variants)
var results = await db.Documents.SearchAsync(e => e.Embedding, queryVector, topK: 10, ct);

// Default field shorthand (single vector field entities)
var results = db.Documents.Search(queryVector, topK: 5);

๐Ÿ’พ Persistence

await db.SaveAsync();           // Full binary snapshot
await db.SaveChangesAsync();    // WAL incremental, O(ฮ”)
await db.CompactAsync();        // Full snapshot + clear WAL
await db.LoadAsync();           // Load snapshot + replay WAL

// Export / Import side channels
await db.ExportAsync("backup.json", ExportFormat.Json);
await db.ImportAsync("backup.json", ExportFormat.Json);
Storage Role Description
Binary Primary (always) Smallest size, fastest I/O, zero-copy via MemoryMarshal
Json Export/Import only Human-readable via ExportAsync / ImportAsync
Xml Export/Import only Compatible format via ExportAsync / ImportAsync

WAL Mode

var options = new QuiverDbOptions
{
    DatabasePath = "mydata.vdb",
    EnableWal = true,
    WalCompactionThreshold = 10_000,
    WalFlushToDisk = true
};

๐Ÿ”„ Schema Migration

When entity structures evolve, Quiver handles differences transparently during LoadAsync.

Automatic (zero config):

  • New field added โ†’ gets CLR default value
  • Old field removed โ†’ silently skipped

Property Renaming & Value Transform:

public class MyDb : QuiverDbContext
{
    public QuiverSet<Document> Documents { get; set; } = null!;

    public MyDb() : base(new QuiverDbOptions { DatabasePath = "my.db" })
    {
        ConfigureMigration<Document>(m => m
            .RenameProperty("OldTitle", "Title")
            .TransformValue("Score", v => v is int i ? (double)i : v));
    }
}
Scenario Handling Config Required
Add field Default value โŒ None
Remove field Silently skipped โŒ None
Rename field RenameProperty() โœ… Yes
Change type/format TransformValue() โœ… Yes

โš™๏ธ Configuration

Property Type Default Description
DatabasePath string? null Storage path; null = in-memory mode
DefaultMetric DistanceMetric Cosine Default distance metric
EntityCache EntityCacheMode FullMemory FullMemory (always resident) / LazyPaging (LRU page cache, requires DatabasePath)
EnableWal bool false Enable WAL incremental persistence
WalCompactionThreshold int 10,000 Auto-compact threshold
WalFlushToDisk bool true fsync after WAL write
MaxCachedPages int 16 Max pages in memory per QuiverSet
PageSize int 512 Entities per page

๐Ÿ”’ Concurrency

QuiverSet<T> uses ReaderWriterLockSlim:

  • Read operations (Search / Find / Exists / Count) โ€” shared lock, parallel execution โœ…
  • Write operations (Add / Upsert / Remove / Clear) โ€” exclusive lock ๐Ÿ”’

No external locking needed.


โ™ป๏ธ Lifecycle

// Recommended: await using (auto-save on dispose)
await using var db = new MyDocumentDb();
await db.LoadAsync();
// ... use db ...
// Scope ends โ†’ DisposeAsync โ†’ auto-save โ†’ release resources
Disposal Auto-Save Recommended
DisposeAsync() โœ… Yes โœ… Use with await using
Dispose() โŒ No Manual control scenarios
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.2.1 101 5/9/2026
3.2.0 91 5/6/2026
3.1.0 93 5/5/2026
3.0.0 94 5/5/2026
2.0.0 114 4/15/2026
1.2.2 134 4/4/2026
1.1.2 171 3/30/2026
1.1.1 147 3/30/2026
1.1.0 142 3/30/2026
1.0.1 146 3/30/2026
1.0.0 157 3/29/2026