dart_vector_index
Fast, zero-dependency, pure-Dart vector search and HNSW (Hierarchical Navigable Small World) index for on-device RAG (Retrieval Augmented Generation), semantic search, and AI embedding similarity on Flutter and Dart.
⚡ Why dart_vector_index?
Building on-device AI in Flutter (using local models like Gemma, Whisper, LLaMA, or cloud embeddings from OpenAI/Cohere) requires searching thousands of high-dimensional vectors in sub-millisecond time.
Most existing solutions force you into bulky C++ native binaries, heavy SQLite extensions, or remote cloud databases.
dart_vector_index is 100% pure Dart:
- Zero native dependencies: Runs seamlessly across Flutter (Android, iOS, Web, macOS, Windows, Linux), Dart CLI, Dart Frog, and server backends.
- $O(\log N)$ HNSW Graph Index: Fast approximate nearest-neighbor search with >99% recall.
- Exact Flat Index: Guaranteed 100% ground-truth brute force search for smaller datasets.
- 8-Bit Scalar Quantization (SQ8): Cuts mobile RAM usage by 75% (4x compression).
- Rich Predicate Filtering: Filter metadata by equality, numeric ranges, lists, tags, and composite
and/or/notboolean logic. - Atomic File Persistence: Save and restore your embedding knowledge base to disk with a single line of code.
🚀 Features
| Feature | Description |
|---|---|
| HNSW Graph Index | Multi-layer navigable small-world graph for $O(\log N)$ search across 100k+ embeddings. |
| Flat Brute-Force Index | Exact exhaustive search for guaranteed 100% recall. |
| Distance Metrics | Cosine, Euclidean ($L_2$), DotProduct, Manhattan ($L_1$), Chebyshev ($L_\infty$). |
| SQ8 Quantization | 4x RAM reduction by quantizing Float32 embeddings into Uint8 buffers. |
| Metadata Filtering | Declarative SQL-like filters (Filter.eq, Filter.gte, Filter.inList, Filter.and). |
| Atomic File Sync | Atomic disk serialization to prevent file corruption on mobile app termination. |
📦 Installation
Add dart_vector_index to your pubspec.yaml:
dependencies:
dart_vector_index: ^1.0.0
Or via terminal:
dart pub add dart_vector_index
🏁 Quick Start
import 'package:dart_vector_index/dart_vector_index.dart';
void main() {
// 1. Initialize an HNSW Vector Store
final store = VectorStore(
type: IndexType.hnsw,
metric: DistanceMetric.cosine,
);
// 2. Add embeddings with metadata
store.add(
id: 'doc_1',
vector: [0.95, 0.20, 0.05, 0.10],
metadata: {'title': 'On-Device AI in Flutter', 'category': 'tech'},
);
store.add(
id: 'doc_2',
vector: [0.10, 0.85, 0.90, 0.25],
metadata: {'title': 'Stock Market Technical Analysis', 'category': 'finance'},
);
// 3. Search for nearest neighbors
final queryVector = [0.92, 0.25, 0.08, 0.12];
final results = store.similaritySearch(queryVector, limit: 1);
for (final hit in results) {
print('Match: ${hit.id} (${(hit.score * 100).toStringAsFixed(1)}%)');
print('Title: ${hit.metadata['title']}');
}
}
🔍 Deep Dive & API Examples
1. Advanced Metadata Filtering
Prune search results before returning top-K candidates:
final results = store.search(
queryVector,
limit: 5,
filter: Filter.and([
Filter.eq('category', 'tech'),
Filter.gte('rating', 4.5),
Filter.inList('tags', ['flutter', 'ai']),
]),
);
Available filter operators:
Filter.eq(key, value)/Filter.neq(key, value)Filter.gt(key, num)/Filter.gte(key, num)/Filter.lt(key, num)/Filter.lte(key, num)Filter.inList(key, List values)Filter.contains(key, substringOrElement)Filter.tag(String tag)Filter.and(List<Filter> filters)/Filter.or(List<Filter> filters)/Filter.not(Filter filter)
2. 8-Bit Scalar Quantization (SQ8)
Compress 32-bit floats into 8-bit unsigned bytes for 4x memory savings on mobile:
final quantizer = ScalarQuantizer(minVal: -1.0, maxVal: 1.0);
// Quantize Float32List -> Uint8List
final quantized = quantizer.quantize(floatVector);
// Dequantize back to Float32List when needed
final restored = quantizer.dequantize(quantized);
3. File Persistence & Backup
Save your entire on-device knowledge base to a local JSON file atomically:
import 'dart:io';
// Save store to disk
final file = File('/path/to/documents_vector_db.json');
await store.saveToFile(file);
// Load store from disk
final restoredStore = await VectorStore.loadFromFile(file);
print('Loaded ${restoredStore.count} vectors.');
💖 Support the Project
If you find this project useful, consider supporting its active maintenance and future development:
📄 License
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
Maintained with ❤️ by Govind Tank.
Libraries
- dart_vector_index
- Fast, pure-Dart vector search & HNSW index for on-device RAG, semantic search, and embeddings.