Skip to content
This repository was archived by the owner on Feb 18, 2026. It is now read-only.

Commit 5209dd3

Browse files
committed
chore(tpp): checkpoint
1 parent 6b79e05 commit 5209dd3

2 files changed

Lines changed: 257 additions & 1 deletion

File tree

_done/20260212-max-neighbors-sweep.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ make clean && make test # If code changed
104104
**Results (100k vectors, 256D, searchListSize=150):**
105105

106106
| maxDeg | Build(s) | Index(GB) | Recall@10 | QPS |
107-
|--------|----------|-----------|-----------|-----|
107+
| ------ | -------- | --------- | --------- | --- |
108108
| 24 | 577 | 2.78 | 56.0% | 234 |
109109
| 32 | 886 | 3.96 | 72.4% | 144 |
110110
| 48 | 1196 | 5.52 | 83.2% | 121 |
@@ -117,6 +117,7 @@ make clean && make test # If code changed
117117
**Decision:** Keep DEFAULT_MAX_NEIGHBORS=32. No code change. Auto-scaling search beam handles recall at scale.
118118

119119
**Action items:**
120+
120121
- [x] Document final results in experiment-003-max-neighbors.md ✅ DONE
121122
- [x] Update experiments/README.md index ✅ DONE
122123
- [x] Close this TPP (move to `_done/`)
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
# Deprecate sqlite-diskann and Migrate Assets to sqlite-vec
2+
3+
## Summary
4+
5+
Benchmarks show sqlite-diskann has prohibitive performance issues (2,268x slower builds, 74x larger indexes than sqlite-vec, similar QPS). Gracefully deprecate the npm package, archive the repository, and migrate valuable benchmark infrastructure and research findings to sqlite-vec.
6+
7+
## Current Phase
8+
9+
- [ ] Research & Planning
10+
- [ ] Test Design
11+
- [ ] Implementation Design
12+
- [ ] Test-First Development
13+
- [ ] Implementation
14+
- [ ] Integration
15+
- [ ] Cleanup & Documentation
16+
- [ ] Final Review
17+
18+
## Required Reading
19+
20+
- `benchmarks/src/harness.ts` - Multi-library comparison framework
21+
- `benchmarks/src/runners/usearch-runner.ts` - USearch integration
22+
- `experiments/README.md` - Experiment methodology
23+
- `experiments/experiment-005-100k-recall.md` - Post-mortem findings
24+
- `package.json` - npm package configuration
25+
- `../sqlite-vec/` - Target repository for migration
26+
27+
## Description
28+
29+
**Problem:** sqlite-diskann is not viable compared to alternatives:
30+
- Build time: 3626s vs 1.6s (sqlite-vec) = 2,268x slower
31+
- Index size: 7.5 GB vs 100 MB (sqlite-vec) = 74x larger
32+
- QPS: ~46 (same as sqlite-vec's brute force)
33+
- Only advantage: recall is good (93-100%), but not enough to offset costs
34+
35+
**Constraints:**
36+
- Package already published to npm (v0.1.2, 2 versions total)
37+
- Users may have installed it (minimize disruption)
38+
- Valuable assets should be preserved (benchmark infrastructure, research)
39+
- sqlite-vec has minimal benchmark infrastructure (just Rust micro-benchmarks)
40+
41+
**Success Criteria:**
42+
- [ ] New repo `node-vector-bench` created with benchmark infrastructure
43+
- [ ] npm package deprecated with clear explanation and guidance
44+
- [ ] Post-mortem narrative explains what happened and why
45+
- [ ] Experiment methodology preserved in new repo
46+
- [ ] sqlite-diskann repo archived with deprecation notice
47+
- [ ] All links work, no orphaned docs
48+
49+
## Tribal Knowledge
50+
51+
**npm Package Details:**
52+
- Package: `@photostructure/sqlite-diskann`
53+
- Current version: 0.1.2
54+
- Published: 5 days ago by GitHub Actions
55+
- Downloads: Unknown (likely minimal given recent publish)
56+
- Includes: prebuilds/, dist/, TypeScript bindings
57+
58+
**Benchmark Infrastructure:**
59+
- Self-contained in `benchmarks/` subdirectory with own package.json
60+
- Multi-library runner supporting diskann, vec, usearch
61+
- USearch integration provides HNSW comparison baseline
62+
- Profile-based configuration (JSON)
63+
- Ground truth computation and caching
64+
- Statistical metrics (recall@k, percentile latencies, QPS)
65+
- Multiple reporters (console table, JSON, markdown)
66+
- Dataset generation utilities
67+
68+
**Experiment Methodology:**
69+
- Template-driven documentation (`experiments/template.md`)
70+
- Hypothesis-driven testing approach
71+
- Structured experiment index
72+
- Guidelines document (`experiments/README.md`)
73+
- Valuable for any performance engineering work
74+
75+
**sqlite-vec Current State:**
76+
- Has `benchmarks/` directory but only Rust micro-benchmarks
77+
- Empty README.md in benchmarks/
78+
- No multi-library comparison infrastructure
79+
- Would benefit from this benchmark harness
80+
81+
**Key Findings to Preserve:**
82+
- Block size limitations (4KB → 2-3 edges max for 256D)
83+
- Graph fragmentation at scale
84+
- BLOB I/O overhead dominates
85+
- Write performance bottlenecks (profiling data)
86+
- Why DiskANN's advantages don't materialize in SQLite
87+
88+
## Solutions
89+
90+
### Option 1: Standalone Benchmark Repo (Recommended)
91+
92+
**Create new repo: `node-vector-bench`**
93+
- Implementation-agnostic vector search benchmarking framework
94+
- Multi-library runner supporting any vector library (diskann, vec, usearch, hnswlib, etc.)
95+
- Profile-based configuration, ground truth computation, statistical reporting
96+
- Experiment methodology and templates
97+
- Not tied to any specific implementation
98+
99+
**Migrate from sqlite-diskann:**
100+
- Benchmark harness (`benchmarks/src/`, `benchmarks/package.json`)
101+
- USearch runner (as reference competitor)
102+
- Add sqlite-vec runner (migrate from existing)
103+
- Experiment methodology (`experiments/template.md`, `experiments/README.md`)
104+
105+
**Deprecate sqlite-diskann:**
106+
- Publish v0.2.0 with deprecation notice and clear narrative of why it failed
107+
- Update package.json with `"deprecated"` field
108+
- Add prominent deprecation banner to README with link to post-mortem
109+
- Archive GitHub repo (read-only)
110+
- Keep public as learning resource
111+
112+
**Pros:**
113+
- Preserves valuable benchmark work in neutral location
114+
- Benefits entire Node.js vector search ecosystem
115+
- Not tied to any vendor or implementation
116+
- sqlite-vec can use it without inheriting diskann baggage
117+
- Clear migration path for users
118+
- Post-mortem becomes valuable reference
119+
120+
**Cons:**
121+
- Need to create new repo
122+
- Some work to make runners pluggable
123+
- Need to document runner interface
124+
125+
**Status:** Recommended approach
126+
127+
### Option 2: Migrate to sqlite-vec
128+
129+
**Pros:**
130+
- Simpler - one destination
131+
- sqlite-vec gets better benchmarks
132+
133+
**Cons:**
134+
- sqlite-vec already has its own benchmark infrastructure
135+
- Ties universal benchmark tool to specific implementation
136+
- Confusing to have diskann benchmarks in vec repo
137+
138+
**Status:** Rejected - standalone is cleaner
139+
140+
### Option 3: Minimal Deprecation
141+
142+
**Just deprecate without preserving anything:**
143+
144+
**Pros:**
145+
- Minimal effort
146+
147+
**Cons:**
148+
- Loses valuable benchmark infrastructure
149+
- Loses experiment methodology
150+
- Wastes months of research findings
151+
152+
**Status:** Rejected - too much value left on table
153+
154+
## Tasks
155+
156+
### Phase 1: Create node-vector-bench repo
157+
- [ ] Create new GitHub repo: `node-vector-bench`
158+
- [ ] Initialize with README explaining purpose
159+
- [ ] Set up package.json structure
160+
- [ ] Define runner interface
161+
162+
### Phase 2: Migrate benchmark infrastructure
163+
- [ ] Copy benchmark harness (`benchmarks/src/`)
164+
- [ ] Copy USearch runner
165+
- [ ] Copy benchmark profiles
166+
- [ ] Copy dataset utilities
167+
- [ ] Update imports for new structure
168+
- [ ] Test with USearch runner
169+
170+
### Phase 3: Add sqlite-vec runner
171+
- [ ] Copy sqlite-vec runner from sqlite-diskann
172+
- [ ] Test sqlite-vec runner in new repo
173+
- [ ] Verify benchmarks work end-to-end
174+
175+
### Phase 4: Migrate experiment methodology
176+
- [ ] Copy experiment template and README
177+
- [ ] Update paths in experiment docs
178+
- [ ] Link to node-vector-bench from experiments
179+
180+
### Phase 5: Deprecate sqlite-diskann npm package
181+
- [ ] Update package.json to v0.2.0
182+
- [ ] Add `"deprecated"` field with message
183+
- [ ] Update README with deprecation banner
184+
- [ ] Add post-mortem narrative to README
185+
- [ ] Publish final version to npm
186+
187+
### Phase 6: Archive sqlite-diskann repo
188+
- [ ] Add deprecation notice to README
189+
- [ ] Link to node-vector-bench
190+
- [ ] Link to post-mortem section
191+
- [ ] Update repo description
192+
- [ ] Archive repository on GitHub
193+
194+
**Verification:**
195+
196+
```bash
197+
# Test benchmark harness in sqlite-vec
198+
cd ../sqlite-vec/benchmarks
199+
npm install
200+
npm run bench -- profiles/quick.json
201+
202+
# Verify npm deprecation
203+
npm view @photostructure/sqlite-diskann
204+
205+
# Check archived repo status
206+
# (Manual GitHub UI check)
207+
```
208+
209+
## Post-mortem narrative
210+
211+
Draft for README deprecation notice and standalone document.
212+
213+
### Why we abandoned sqlite-diskann
214+
215+
We extracted the DiskANN implementation from libSQL into a standalone SQLite extension (Feb 9-10). The code worked, but benchmarks were bad. We spent the next week figuring out why and trying to fix it.
216+
217+
**The recall problem.** At 10k vectors, recall was 97%. At 100k, it dropped to 0-1%. We tuned `searchListSize`, `pruning_alpha`, and `MIN_DEGREE` with no effect. Turns out the default 4KB block size only fits 2-3 edges per node for 256D vectors (`(4096 - 1040) / 1040 = 2.9`). The graph fragmented into disconnected components. See `_done/20260210-diskann-recall-fix-investigation.md`.
218+
219+
**Fixing recall broke everything else.** Switching to auto-calculated 40KB blocks (Feb 11) restored recall to 98%. But 40KB per node means 7.5 GB indexes for 100k vectors (sqlite-vec uses 100 MB). Build time: 3626 seconds vs 1.6 seconds. See `experiment-005-100k-recall.md`.
220+
221+
**We tried to optimize build performance.** None of it worked well enough:
222+
223+
- **Parallel construction** (`_todo/20260210-parallel-graph-construction.md`): SQLite only allows one writer. Graph mutations can't be parallelized.
224+
- **BLOB caching** (`_todo/20260211-build-speed-optimization.md`): LRU cache with refcounting. 37% faster (707s to 445s for 25k). Still 1,667x slower than brute force.
225+
- **Batch insert API** (`_todo/20260211-serial-batch-insert.md`): Persistent cache across inserts, amortized SAVEPOINT overhead. 10-20% gain. We stopped benchmarking at that point.
226+
- **Lazy back-edges** (`_todo/20260212-lazy-back-edges.md`): Defer edge updates, batch repair at commit. Helped throughput but hurt recall at small scale. Complex code for marginal gains.
227+
- **Parameter sweeps** (`_done/20260212-max-neighbors-sweep.md`, experiments 002b-004): Tested `max_neighbors` from 24 to 64 and `searchListSize` from 100 to 500. Recall improved, build time didn't.
228+
229+
**The problem is architectural.** DiskANN assumes direct memory control: mmap the graph, traverse it cheaply. SQLite's BLOB I/O adds a 40KB read per graph hop. Each insert touches ~200 nodes, so that's 16 MB of I/O per insert. At 100k inserts, the cumulative BLOB I/O is around 800 TB. No amount of caching or batching fixes that.
230+
231+
**Final numbers (Feb 15):**
232+
233+
- Build: 3626s vs 1.6s (sqlite-vec), 2,268x slower
234+
- Index: 7.5 GB vs 100 MB, 74x larger
235+
- QPS: ~46, same as sqlite-vec brute force at 100k
236+
- Recall: 98% (the one metric that worked)
237+
238+
**Use `@photostructure/sqlite-vec` instead.** For datasets under 100k, brute force builds in 1.6 seconds with perfect recall. For datasets over 1M, use an external index like USearch with mmap.
239+
240+
See also: `_todo/` and `_done/` directories for full TPPs, `experiments/` for benchmark data.
241+
242+
## Notes
243+
244+
**Session 2026-02-15:**
245+
- User showed benchmark results: diskann loses on all metrics except recall
246+
- Build: 3626s vs 1.6s (sqlite-vec)
247+
- Index: 7.5GB vs 100MB (sqlite-vec)
248+
- QPS: ~46 (both libraries similar)
249+
- User requested help with deprecation and migration
250+
- Decision: Create standalone `node-vector-bench` repo (not migrate to sqlite-vec)
251+
- Reason: sqlite-vec has own benchmarks, standalone benefits whole ecosystem
252+
- Wrote post-mortem narrative summarizing optimization journey
253+
- Catalogued TPPs showing what was tried and why it failed
254+
- Catalogued assets: benchmark harness is valuable, experiment methodology is valuable
255+
- sqlite-vec has minimal benchmark infrastructure currently

0 commit comments

Comments
 (0)