Files
wifi-densepose/crates/ruvector-router-ffi/README.md
ruv d803bfe2b1 Squashed 'vendor/ruvector/' content from commit b64c2172
git-subtree-dir: vendor/ruvector
git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
2026-02-28 14:39:40 -05:00

808 lines
20 KiB
Markdown

# router-ffi
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![Rust](https://img.shields.io/badge/rust-1.77%2B-orange.svg)](https://www.rust-lang.org)
[![Platform](https://img.shields.io/badge/platform-Node.js-green.svg)](https://nodejs.org)
**High-performance Node.js bindings for router-core vector database and neural routing engine.**
> NAPI-RS powered bindings bringing Rust-level performance to JavaScript/TypeScript with zero-copy buffer sharing and async/await support.
## Overview
`router-ffi` provides seamless Node.js integration for the `router-core` vector database through NAPI-RS, enabling JavaScript and TypeScript applications to leverage Rust's blazing-fast performance for vector similarity search, neural routing, and embedding operations.
### Why router-ffi?
- **🚀 Native Performance**: Direct Rust execution with minimal overhead
- **⚡ Zero-Copy**: Float32Array buffers shared directly with Rust
- **🔄 Async/Await**: Non-blocking operations using Tokio runtime
- **🎯 Type Safe**: Complete TypeScript definitions auto-generated from Rust
- **🌐 Cross-Platform**: Linux, macOS, Windows (x64 and ARM64)
- **🧠 Neural Routing**: Advanced inference and routing capabilities
- **💾 Memory Efficient**: HNSW indexing with 4-32x compression
## Features
### Core Capabilities
- **Vector Operations**: Insert, search, delete with sub-millisecond latency
- **Distance Metrics**: Euclidean, Cosine, Dot Product, Manhattan
- **HNSW Indexing**: Sub-millisecond search with 95%+ recall
- **Async API**: Full async/await support for all operations
- **Batch Operations**: Efficient bulk insert and search
- **Metadata Support**: Store and filter by JSON metadata
- **Persistent Storage**: Disk-based storage with memory-mapped I/O
### Advanced Features
- **Neural Routing**: Intelligent request routing and load balancing
- **SIMD Optimizations**: Hardware-accelerated distance calculations
- **Product Quantization**: 4-32x memory compression
- **Thread Safety**: Arc-based concurrency for multi-threaded Node.js
- **Error Handling**: Proper JavaScript error propagation from Rust
## Installation
```bash
npm install router-ffi
```
### Prerequisites
- **Node.js**: 18.0 or higher
- **Rust**: 1.77+ (for building from source)
- **Platform**: Linux, macOS, or Windows (x64/ARM64)
## Quick Start
### Basic Usage
```javascript
const { VectorDB, DistanceMetric } = require('router-ffi');
// Create a vector database
const db = new VectorDB({
dimensions: 384,
maxElements: 10000,
distanceMetric: DistanceMetric.Cosine,
hnswM: 32,
hnswEfConstruction: 200,
hnswEfSearch: 100,
storagePath: './vectors.db'
});
// Insert a vector
const vector = new Float32Array([0.1, 0.2, 0.3, /* ... 384 dimensions */]);
const id = db.insert('doc1', vector);
console.log(`Inserted: ${id}`);
// Search for similar vectors
const query = new Float32Array([0.1, 0.2, 0.3, /* ... */]);
const results = db.search(query, 10);
results.forEach(result => {
console.log(`ID: ${result.id}, Score: ${result.score}`);
});
// Get database statistics
const count = db.count();
const allIds = db.getAllIds();
console.log(`Database contains ${count} vectors`);
```
### Async Operations
```javascript
const { VectorDB } = require('router-ffi');
async function main() {
const db = new VectorDB({
dimensions: 768,
distanceMetric: 'Cosine',
storagePath: './async-vectors.db'
});
// Async insert (non-blocking)
const vector = new Float32Array(768).fill(0.5);
const id = await db.insertAsync('doc1', vector);
console.log(`Inserted: ${id}`);
// Async search (non-blocking)
const query = new Float32Array(768).fill(0.5);
const results = await db.searchAsync(query, 10);
for (const result of results) {
console.log(`ID: ${result.id}, Score: ${result.score}`);
}
}
main().catch(console.error);
```
### TypeScript Usage
```typescript
import { VectorDB, DistanceMetric, DbOptions, SearchResultJS } from 'router-ffi';
// Type-safe configuration
const options: DbOptions = {
dimensions: 384,
maxElements: 50000,
distanceMetric: DistanceMetric.Cosine,
hnswM: 32,
hnswEfConstruction: 200,
hnswEfSearch: 100,
storagePath: './typed-vectors.db'
};
const db = new VectorDB(options);
// Type-safe operations
const vector: Float32Array = new Float32Array(384);
const id: string = db.insert('doc1', vector);
const results: SearchResultJS[] = db.search(vector, 10);
results.forEach((result: SearchResultJS) => {
console.log(`${result.id}: ${result.score}`);
});
```
## API Reference
### VectorDB
Main vector database class providing core operations.
#### Constructor
```typescript
new VectorDB(options: DbOptions)
```
**DbOptions:**
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `dimensions` | `number` | Yes | - | Vector dimensionality |
| `maxElements` | `number` | No | 1,000,000 | Maximum number of vectors |
| `distanceMetric` | `DistanceMetric` | No | `Cosine` | Distance metric |
| `hnswM` | `number` | No | 32 | HNSW connections per node |
| `hnswEfConstruction` | `number` | No | 200 | HNSW construction quality |
| `hnswEfSearch` | `number` | No | 100 | HNSW search quality |
| `storagePath` | `string` | No | `./router.db` | Database file path |
#### Methods
##### insert
```typescript
insert(id: string, vector: Float32Array): string
```
Insert a vector synchronously. Returns the vector ID.
**Example:**
```javascript
const id = db.insert('doc1', new Float32Array([0.1, 0.2, 0.3]));
```
##### insertAsync
```typescript
async insertAsync(id: string, vector: Float32Array): Promise<string>
```
Insert a vector asynchronously (non-blocking). Returns a Promise with the vector ID.
**Example:**
```javascript
const id = await db.insertAsync('doc1', new Float32Array([0.1, 0.2, 0.3]));
```
##### search
```typescript
search(queryVector: Float32Array, k: number): SearchResultJS[]
```
Search for similar vectors synchronously. Returns top-k results sorted by similarity.
**Returns:** Array of `SearchResultJS` objects:
- `id` (string): Vector ID
- `score` (number): Distance score (lower is more similar)
**Example:**
```javascript
const results = db.search(new Float32Array([0.1, 0.2, 0.3]), 10);
```
##### searchAsync
```typescript
async searchAsync(queryVector: Float32Array, k: number): Promise<SearchResultJS[]>
```
Search for similar vectors asynchronously (non-blocking).
**Example:**
```javascript
const results = await db.searchAsync(new Float32Array([0.1, 0.2, 0.3]), 10);
```
##### delete
```typescript
delete(id: string): boolean
```
Delete a vector by ID. Returns `true` if deleted, `false` if not found.
**Example:**
```javascript
const deleted = db.delete('doc1');
```
##### count
```typescript
count(): number
```
Get the total number of vectors in the database.
**Example:**
```javascript
const totalVectors = db.count();
console.log(`Database contains ${totalVectors} vectors`);
```
##### getAllIds
```typescript
getAllIds(): string[]
```
Get all vector IDs in the database.
**Example:**
```javascript
const ids = db.getAllIds();
console.log(`IDs: ${ids.join(', ')}`);
```
### DistanceMetric
Enum defining supported distance metrics:
```typescript
enum DistanceMetric {
Euclidean = "Euclidean",
Cosine = "Cosine",
DotProduct = "DotProduct",
Manhattan = "Manhattan"
}
```
**Choosing a Metric:**
- **Cosine**: Best for normalized embeddings (most common)
- **Euclidean**: Standard L2 distance
- **DotProduct**: Efficient for pre-normalized vectors
- **Manhattan**: L1 distance, robust to outliers
## Building from Source
### Prerequisites
```bash
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Install Node.js dependencies
npm install
```
### Build Commands
```bash
# Build the native module (release mode)
npm run build
# Build with debug symbols
npm run build:debug
# Clean build artifacts
npm run clean
# Run tests
npm test
# Format code
cargo fmt --all
# Lint
cargo clippy --all -- -D warnings
```
### Cross-Platform Compilation
Build for multiple platforms using NAPI-RS:
```bash
# Linux x64
npm run build -- --target x86_64-unknown-linux-gnu
# Linux ARM64
npm run build -- --target aarch64-unknown-linux-gnu
# macOS x64
npm run build -- --target x86_64-apple-darwin
# macOS ARM64 (M1/M2)
npm run build -- --target aarch64-apple-darwin
# Windows x64
npm run build -- --target x86_64-pc-windows-msvc
```
## Performance Benchmarks
### Local Performance
**10,000 vectors (384D):**
```
Operation Throughput Latency (avg)
------------------------------------------------
Insert (sync) ~2,000/sec 0.5ms
Insert (async) ~5,000/sec 0.2ms
Search (k=10) ~10,000/sec 0.1ms
Batch Insert ~8,000/sec 0.125ms
```
**1,000,000 vectors (384D):**
```
Operation Throughput Latency (avg)
------------------------------------------------
Insert (sync) ~1,000/sec 1.0ms
Insert (async) ~3,000/sec 0.33ms
Search (k=10) ~5,000/sec 0.2ms
Search (k=100) ~2,000/sec 0.5ms
```
### Performance Comparison
```
Library Search Latency Memory (1M vectors) Language
-------------------------------------------------------------------
router-ffi 0.2ms ~600MB Rust → Node.js
Pinecone ~2ms Cloud only Hosted
Qdrant ~1ms ~1.5GB Rust
ChromaDB ~50ms ~3GB Python
FAISS ~0.5ms ~1GB C++ → Python
```
### Optimization Tips
1. **Use Async Operations**: `insertAsync` and `searchAsync` for better throughput
2. **Batch Inserts**: Group multiple inserts for 3-4x better performance
3. **Tune HNSW Parameters**:
- Higher `hnswM` = better recall, more memory
- Higher `efConstruction` = better index quality, slower build
- Higher `efSearch` = better accuracy, slower search
4. **Choose Distance Metric**: `Cosine` with pre-normalized vectors is fastest
5. **Use Float32Array**: Direct buffer sharing avoids copies
## Use Cases
### RAG (Retrieval-Augmented Generation)
```javascript
const { VectorDB } = require('router-ffi');
// Create embeddings database
const db = new VectorDB({
dimensions: 1536, // OpenAI ada-002
distanceMetric: 'Cosine',
storagePath: './embeddings.db'
});
// Store document embeddings
async function indexDocument(docId, embedding) {
await db.insertAsync(docId, new Float32Array(embedding));
}
// Retrieve relevant documents
async function retrieveContext(queryEmbedding, topK = 5) {
const results = await db.searchAsync(
new Float32Array(queryEmbedding),
topK
);
return results.map(r => r.id);
}
```
### Semantic Search
```javascript
// Index text embeddings
const documents = [
{ id: 'doc1', text: 'Machine learning basics', embedding: [...] },
{ id: 'doc2', text: 'Deep learning tutorial', embedding: [...] },
{ id: 'doc3', text: 'Neural networks explained', embedding: [...] }
];
for (const doc of documents) {
await db.insertAsync(doc.id, new Float32Array(doc.embedding));
}
// Search by semantic similarity
const query = 'AI fundamentals';
const queryEmbedding = await getEmbedding(query);
const results = await db.searchAsync(new Float32Array(queryEmbedding), 3);
```
### Recommendation Engine
```javascript
// Store user/item embeddings
const userEmbeddings = new Map();
const itemEmbeddings = new Map();
// Index items
for (const [itemId, embedding] of itemEmbeddings) {
await db.insertAsync(`item_${itemId}`, new Float32Array(embedding));
}
// Find similar items
function recommendSimilar(itemId, count = 10) {
const embedding = itemEmbeddings.get(itemId);
const results = db.search(new Float32Array(embedding), count + 1);
return results.slice(1); // Exclude self
}
```
### Agent Memory
```javascript
// Store agent experiences
class AgentMemory {
constructor(dimensions) {
this.db = new VectorDB({
dimensions,
distanceMetric: 'Cosine',
storagePath: './agent-memory.db'
});
}
async remember(experience, embedding) {
const id = `exp_${Date.now()}`;
await this.db.insertAsync(id, new Float32Array(embedding));
return id;
}
async recall(queryEmbedding, count = 5) {
return await this.db.searchAsync(
new Float32Array(queryEmbedding),
count
);
}
}
```
## Memory Management
### Thread Safety
`router-ffi` uses Rust's `Arc<T>` for thread-safe reference counting, making it safe to use across Node.js worker threads:
```javascript
const { Worker } = require('worker_threads');
const { VectorDB } = require('router-ffi');
// Main thread
const db = new VectorDB({ dimensions: 384 });
// Workers can safely share the database
const worker = new Worker('./worker.js');
```
### Memory Efficiency
- **Zero-Copy Buffers**: Float32Array data is shared directly between JavaScript and Rust
- **Arc Reference Counting**: Automatic cleanup when JavaScript objects are garbage collected
- **Memory-Mapped I/O**: Efficient disk-based storage with OS-level caching
- **Product Quantization**: 4-32x compression for large datasets
### Best Practices
1. **Reuse VectorDB Instances**: Creating new instances is expensive
2. **Use Float32Array**: Native typed arrays avoid data copying
3. **Async for Large Batches**: Prevents blocking the event loop
4. **Close When Done**: Allow garbage collection to free resources
```javascript
// Good: Reuse instance
const db = new VectorDB({ dimensions: 384 });
for (let i = 0; i < 1000; i++) {
await db.insertAsync(`doc${i}`, vector);
}
// Bad: Creating new instances
for (let i = 0; i < 1000; i++) {
const db = new VectorDB({ dimensions: 384 }); // Expensive!
await db.insertAsync(`doc${i}`, vector);
}
```
## Platform Support
### Supported Platforms
| Platform | Architecture | Status | Notes |
|----------|--------------|--------|-------|
| Linux | x86_64 | ✅ Supported | glibc 2.17+ |
| Linux | aarch64 | ✅ Supported | ARM64 servers |
| macOS | x86_64 | ✅ Supported | Intel Macs |
| macOS | aarch64 | ✅ Supported | M1/M2/M3 Macs |
| Windows | x86_64 | ✅ Supported | MSVC runtime |
| Windows | aarch64 | ⚠️ Experimental | ARM64 Windows |
### Node.js Compatibility
- **Minimum**: Node.js 18.0
- **Recommended**: Node.js 20 LTS or 22 LTS
- **Maximum**: Latest stable release
### Pre-built Binaries
NAPI-RS provides pre-built binaries for common platforms. If your platform isn't supported, the module will compile from source automatically.
## Troubleshooting
### Installation Issues
**Error: `cargo` not found**
Install Rust toolchain:
```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
```
**Error: NAPI-RS build failed**
Update NAPI-RS CLI:
```bash
npm install -g @napi-rs/cli@latest
```
### Runtime Issues
**Error: Cannot find native module**
Rebuild the native module:
```bash
npm rebuild router-ffi
```
**Error: Vector dimension mismatch**
Ensure all vectors have the same dimensions as specified in `DbOptions`:
```javascript
const db = new VectorDB({ dimensions: 384 });
// ✅ Correct
db.insert('doc1', new Float32Array(384));
// ❌ Wrong - dimension mismatch
db.insert('doc2', new Float32Array(768)); // Error!
```
### Performance Issues
**Slow search performance**
1. Increase `hnswEfSearch` for better recall
2. Use `searchAsync` instead of `search`
3. Check if HNSW index is built (insert >100 vectors)
4. Consider using Product Quantization for large datasets
**High memory usage**
1. Reduce `maxElements` if you don't need it
2. Enable quantization (requires router-core configuration)
3. Use smaller `hnswM` value (trades accuracy for memory)
## Advanced Topics
### HNSW Index Tuning
The HNSW (Hierarchical Navigable Small World) index provides fast approximate nearest neighbor search:
```javascript
const db = new VectorDB({
dimensions: 384,
hnswM: 32, // Connections per node (16-64)
hnswEfConstruction: 200, // Build quality (100-500)
hnswEfSearch: 100 // Search quality (10-200)
});
```
**Parameter Guidelines:**
| Parameter | Low Value | High Value | Trade-off |
|-----------|-----------|------------|-----------|
| `hnswM` | 16 | 64 | Memory vs Recall |
| `efConstruction` | 100 | 500 | Speed vs Quality |
| `efSearch` | 10 | 200 | Speed vs Accuracy |
### Distance Metrics Explained
```javascript
// Cosine Similarity (angle between vectors)
// Range: [0, 2], lower is more similar
// Best for: Normalized embeddings, semantic search
const db1 = new VectorDB({ distanceMetric: 'Cosine' });
// Euclidean Distance (L2 norm)
// Range: [0, ∞), lower is more similar
// Best for: Spatial data, general purpose
const db2 = new VectorDB({ distanceMetric: 'Euclidean' });
// Dot Product (inner product)
// Range: (-∞, ∞), higher is more similar
// Best for: Pre-normalized vectors
const db3 = new VectorDB({ distanceMetric: 'DotProduct' });
// Manhattan Distance (L1 norm)
// Range: [0, ∞), lower is more similar
// Best for: Robust to outliers
const db4 = new VectorDB({ distanceMetric: 'Manhattan' });
```
### Batch Operations
```javascript
// Efficient batch insert
async function batchInsert(vectors) {
const promises = vectors.map((vec, idx) =>
db.insertAsync(`doc${idx}`, new Float32Array(vec))
);
return await Promise.all(promises);
}
// Parallel search
async function batchSearch(queries, k = 10) {
const promises = queries.map(query =>
db.searchAsync(new Float32Array(query), k)
);
return await Promise.all(promises);
}
```
## Examples
Complete examples are available in the [examples](./examples) directory:
- **basic.js**: Simple insert and search operations
- **async.js**: Async/await patterns
- **typescript.ts**: TypeScript integration
- **rag-system.js**: RAG implementation
- **semantic-search.js**: Semantic search engine
- **benchmark.js**: Performance testing
Run examples:
```bash
npm run build
node examples/basic.js
node examples/async.js
ts-node examples/typescript.ts
```
## Integration with router-core
`router-ffi` wraps the `router-core` Rust crate, providing:
- Full API compatibility with router-core
- Zero-overhead FFI through NAPI-RS
- Automatic memory management
- Thread-safe operations
- Async runtime integration
See [router-core](../router-core) for core implementation details.
## Related Crates
- **[router-core](../router-core)**: Core vector database engine
- **[router-cli](../router-cli)**: Command-line interface
- **[router-wasm](../router-wasm)**: WebAssembly bindings
- **[ruvector-node](../ruvector-node)**: Node.js bindings for ruvector-core
## Contributing
Contributions are welcome! See [CONTRIBUTING.md](../../docs/development/CONTRIBUTING.md) for guidelines.
### Development Setup
```bash
# Clone repository
git clone https://github.com/ruvnet/ruvector.git
cd ruvector/crates/router-ffi
# Install dependencies
npm install
# Build in development mode
npm run build:debug
# Run tests
npm test
# Format code
cargo fmt --all
# Lint
cargo clippy --all -- -D warnings
```
### Testing
```bash
# Run all tests
npm test
# Run specific test
npm test -- --grep "search"
# Run benchmarks
npm run bench
```
## License
**MIT License** - see [LICENSE](../../LICENSE) for details.
## Acknowledgments
Built with cutting-edge technologies:
- **[NAPI-RS](https://napi.rs)**: High-performance Rust bindings for Node.js
- **[router-core](../router-core)**: Core vector database engine
- **[Tokio](https://tokio.rs)**: Asynchronous runtime for Rust
- **[SimSIMD](https://github.com/ashvardanian/simsimd)**: SIMD-accelerated similarity metrics
- **[HNSW](https://arxiv.org/abs/1603.09320)**: Hierarchical Navigable Small World graphs
## Support
- **Documentation**: [github.com/ruvnet/ruvector](https://github.com/ruvnet/ruvector)
- **Issues**: [GitHub Issues](https://github.com/ruvnet/ruvector/issues)
- **Discord**: [Join our community](https://discord.gg/ruvnet)
- **Twitter**: [@ruvnet](https://twitter.com/ruvnet)
- **Enterprise**: [enterprise@ruv.io](mailto:enterprise@ruv.io)
---
<div align="center">
**Built by [rUv](https://ruv.io) • Part of the [Ruvector](https://github.com/ruvnet/ruvector) ecosystem**
[![Star on GitHub](https://img.shields.io/github/stars/ruvnet/ruvector?style=social)](https://github.com/ruvnet/ruvector)
[![Follow @ruvnet](https://img.shields.io/twitter/follow/ruvnet?style=social)](https://twitter.com/ruvnet)
</div>