v3/implementation/adrs/ADR-077-diskann-vector-backend.md
Status: Implemented
Date: 2026-04-07
Branch: feat/diskann-vector-backend
ruflo's vector search uses three backends with different tradeoffs. With @ruvector/[email protected] now published (5-platform native binaries), we have a Vamana graph-based SSD-friendly alternative to HNSW.
| Backend | Insert | Build | Search | QPS | Recall@10 | Memory |
|---|---|---|---|---|---|---|
| DiskANN | 0.57ms | 1,324ms | 16.5ms | 6,048 | 1.000 | -1.1MB* |
| HNSW | 4,662ms | 0ms | 12.7ms | 7,850 | 0.120 | 0.5MB |
| Cosine-JS | 0.89ms | 0ms | 64.6ms | 1,548 | 1.000 | 0.4MB |
| Backend | Insert | Build | Search | QPS | Recall@10 | Memory |
|---|---|---|---|---|---|---|
| DiskANN | 2.12ms | 15,955ms | 20ms | 2,501 | 0.874 | 0.9MB |
| HNSW | 24,614ms | 0ms | 8.9ms | 5,636 | 0.026 | 1.0MB |
| Cosine-JS | 6.84ms | 0ms | 155ms | 323 | 1.000 | 1.0MB |
*Negative memory = GC reclaimed during benchmark
Add @ruvector/diskann as an optional backend with automatic fallback:
DiskANN (native, Vamana graph) → HNSW (@ruvector/router) → Cosine-JS (pure JS)
| Dataset size | Recommended backend | Reason |
|---|---|---|
| < 500 vectors | Cosine-JS | Perfect recall, fast enough |
| 500 - 50K vectors | DiskANN | High recall + reasonable QPS |
| > 50K vectors | DiskANN with PQ | SSD-friendly, sub-linear memory |
v3/@claude-flow/cli/src/ruvector/diskann-backend.ts — unified backend with auto-selection, fallback chain, benchmark utilityimport { insertVector, searchVectors, buildIndex, benchmark } from './ruvector/diskann-backend.js';
// Insert vectors
await insertVector('doc-1', embedding, { dim: 384 });
await insertVector('doc-2', embedding2, { dim: 384 });
// Build index (required for DiskANN)
await buildIndex({ dim: 384 });
// Search
const results = await searchVectors(queryEmbedding, 10, { dim: 384 });
// → [{ id: 'doc-1', distance: 0.02, score: 0.98 }, ...]
// Benchmark
const bench = await benchmark({ dim: 384, vectorCount: 1000, k: 10 });
pqSubspaces parameter for memory compressionsave(dir) / DiskAnn.load(dir) for persistent indexesinsertBatch() for bulk loadingsearchAsync() for non-blocking queries