Vector Database System Design Template
Vector search service: HNSW vs IVF-PQ sizing, re-ranking, recall vs latency tuning, filtered search by selectivity, inserts and deletes, sharding, failure modes
사용법: Use it when designing or choosing a vector database for semantic search, RAG or recommendations. Fill vector count, dimension, query rate and recall target in section 3 first, because memory per vector decides the index family. The main pitfall is trusting benchmark recall instead of measuring it against exact search on your own queries and filters.
미리보기
System Design: [Vector database name]
Reference design for a vector database that stores embeddings with metadata and answers approximate nearest neighbour (ANN) queries with filters: index choice between HNSW (Malkov and Yashunin, IEEE TPAMI 2020) and IVF with product quantization (Jégou, Douze and Schmid, IEEE TPAMI 2011), filtered search, inserts and deletes on a live index, sharding, replication, and the recall versus latency trade-off. It follows the structure of the System Design Document template, adds a 45-minute interview path, access-pattern and failure-mode tables and a cited "How real systems do it" box, and is pre-filled with a worked design to adapt. Replace every
[bracketed]value and every row marked Example; values marked Example are assumptions, not benchmarks. Recall and latency figures must come from your own measurements on your own data.
Document control
| Field | Value |
|---|---|
| Document ID | [SDD-VDB-001] |
| System / feature | [Vector search service] |
| Version | [0.1] |
| Status | [Draft / In review / Approved / Implemented / Superseded] |
| Owner | [@owner] |
| Author(s) | [@author] |
| Reviewers | [@reviewer-1], [@reviewer-2] |
| Last updated | YYYY-MM-DD |
| Classification | [Internal] |
| Difficulty | Advanced |
| Embedding model and dimension | [Model name, version, d = 768] |
| Related | [RAG design], [Search relevance evaluation], [ADR: index family] |
Approvals
| Role | Name | Decision | Date |
|---|---|---|---|
| Tech lead | [@name] | [Approved / Changes requested] | YYYY-MM-DD |
| Staff / principal engineer | [@name] | [Decision] | YYYY-MM-DD |
| ML / relevance owner | [@name] | [Decision] | YYYY-MM-DD |
| SRE / operations | [@name] | [Decision] | YYYY-MM-DD |
| Security and privacy | [@name] | [Decision] | YYYY-MM-DD |
Revision history
| Version | Date | Author | Change summary |
|---|---|---|---|
| 0.1 | YYYY-MM-DD | [@name] | First draft for design review |
| 0.2 | YYYY-MM-DD | [@name] | Example: Moved the large collection from HNSW to IVF-PQ with re-ranking after the memory estimate |
| 0.3 | YYYY-MM-DD | [@name] | Example: Added per-query filter strategy choice by estimated selectivity |
| 1.0 | YYYY-MM-DD | [@name] | Example: Approved |
Contents
1. Overview
1.1 Problem statement
[Example: Our document assistant stores 500 million passage embeddings in a general-purpose database extension with an HNSW index on one large machine. Memory is at 92%, index rebuilds take two days, and a query filtered to one customer's documents often returns fewer than 10 results because the filter runs after the index search. Deleted documents keep appearing in answers for hours, which is a privacy problem.]
1.2 Proposed solution
[Example: A dedicated vector service shards collections by vector ID across 8 shards with 2 replicas each. Large collections use an IVF index with product-quantized codes in memory and full vectors on local NVMe for re-ranking; small collections use HNSW in memory. Inserts go to a write-ahead log and an in-memory buffer that is searched exactly, then merge into the main index every hour. Deletes are tombstones applied at query time and removed by compaction. Each query picks a filter strategy from the estimated selectivity of its filter. Tenants are separate partitions, so a tenant filter never scans other tenants' data. Recall is measured continuously against exact search on sampled queries.]
1.3 Decisions requested from reviewers
| ID | Question | Recommended option | Section |
|---|---|---|---|
| Q-01 | Example: Index family for the 500-million-vector collection? | IVF-PQ with re-ranking from NVMe; HNSW only for collections that fit in memory | 3, 7.2 |
| Q-02 | Example: How to filter? | Strategy per query from estimated selectivity: pre-filter and exact scan, filtered traversal, or post-filter with over-fetch | 7.4 |
| Q-03 | Example: Freshness of inserts and deletes? | Visible within 1 s (buffer and tombstones), physically merged hourly | 7.5 |
| Q-04 | Example: Sharding key? | Hash of vector ID within a tenant partition; queries fan out to all shards | 7.6 |
| Q-05 | Example: Recall target and how it is checked? | Recall@10 at or above 0.95 against exact search on 1% sampled queries | 7.3, 9.3 |
| [Q-nn] | [Question] | [Option] | [Section] |
1.4 45-minute interview path
Use this order when the document serves an interview or a short design review. The written sections below are the long form of each step.
| Minutes | Cover | Output on the whiteboard |
|---|---|---|
| 0 to 5 | Scope: top-k similarity with filters, inserts and deletes, recall target; below-the-line items (2.3) | One query shape and the recall definition |
| 5 to 10 | Estimates: raw size, HNSW size, PQ size, query fan-out (section 3) | Four numbers, "HNSW does not fit in RAM at this scale, so compress and re-rank" consequence |
| 10 to 15 | API: upsert, delete, query with filter and k (section 4) | Three calls |
| 15 to 25 | High-level design: router, shards with segments, index builder, object storage (section 6) | One diagram |
| 25 to 40 | One deep dive: index choice and recall versus latency (default, 7.2 and 7.3), or filtered search (7.4), or updates and deletes (7.5) | Options, choice, reason |
| 40 to 45 | Failures (shard loss, recall drift after a model change), the 10x row in section 10 | Two failure rows |
Start the default deep dive with the naive answer, exact search (compare the query with every vector). Show its cost: 500 million x 768 multiply-adds per query. Then introduce HNSW, compute its memory, and move to IVF-PQ with re-ranking when the memory does not fit.
2. Requirements
2.1 Core functional requirements
| ID | Requirement | Priority |
|---|---|---|
| FR-01 | Example: Upsert vectors with an ID and metadata (tenant, language, created time, tags) | Must |
| FR-02 | Example: Query the top k (up to 100) by cosine similarity, with optional metadata filters | Must |
| FR-03 | Example: Delete by ID and by filter (all vectors of a document or tenant) | Must |
| FR-04 | Example: Collections with fixed dimension and metric; one embedding model version per collection | Must |
| FR-05 | Example: Hybrid search hook: return scores so a caller can fuse them with keyword results | Should |
| FR-06 | Example: Snapshot and restore a collection | Should |
| [FR-nn] | [Requirement] | [Must / Should / Could] |
2.2 Non-functional requirements
| ID | Quality | Target | Measured as |
|---|---|---|---|
| NFR-01 | Recall | Example: Recall@10 at or above 0.95 against exact search | Sampled live queries re-run on the exact path |
| NFR-02 | Latency | Example: p99 at or below 50 ms for k = 10 with typical filters | Router timing |
| NFR-03 | Throughput | Example: 2 000 queries/s at peak | Load test |
| NFR-04 | Freshness | Example: Upserts and deletes visible to queries within 1 s | Write-then-read probe |
| NFR-05 | Durability | Example: No acknowledged write lost | WAL replay test |
| NFR-06 | Tenant isolation | Example: A query never returns another tenant's vector | Partition audit and tests |
| [NFR-nn] | [Quality] | [Target] | [Measurement] |
2.3 Below the line (out of scope)
Name these explicitly so reviewers and interviewers do not pull the design toward them.
- [Example: generating embeddings (the caller sends vectors)]
- [Example: keyword search and rank fusion (see Full-Text Search Engine System Design (
system-design/design-full-text-search))] - [Example: document chunking and prompt assembly (see Enterprise RAG Search System Design (
system-design/design-enterprise-rag-search))] - [Example: GPU-based search]
- [Item deferred, with the release that will take it]
3. Capacity estimation
3.1 Assumptions
| Input | Symbol | Value | Source |
|---|---|---|---|
| Vectors in the largest collection | Example: 500 million | Corpus size x growth | |
| Dimension | Example: 768, float32 | Embedding model | |
| Peak queries per second | Example: 2 000 | Product forecast | |
| Inserts per day | Example: 5 million | Ingestion pipeline | |
| Deletes per day | Example: 1 million | Document lifecycle | |
| HNSW links parameter | Example: 32 | 7.2 | |
| PQ sub-quantizers, 8 bits each | Example: 96 bytes per vector | 7.2 | |
| Usable memory per node | Example: 179 GB (70% of 256 GB) | Instance type | |
| Shards | Example: 8 | 7.6 |
3.2 Memory by index family
Raw vectors:
HNSW, using the Faiss wiki estimate of bytes per vector:
IVF-PQ codes plus an 8-byte ID:
PQ compresses each vector times. The full vectors stay on NVMe (192 GB per shard) for re-ranking. Consequence: HNSW for this collection would need 20 large-memory nodes with two replicas; IVF-PQ fits in a fraction of one node's memory per shard, so the cost moves from RAM to NVMe reads.
3.3 Work per query
Each shard holds million vectors and an IVF with lists (the Faiss wiki suggests this list count for 10 to 100 million vectors). Probing lists scans:
Each code is scored with a lookup table of bytes (about 98 KB per query per shard). Each shard then re-ranks its best 100 candidates with full vectors read from NVMe: 100 reads of 3 KB, one 4 KB page each. With 2 replicas sharing the 2 000 queries/s:
That is within one data-centre NVMe drive's random-read capability, but not with much headroom, which is why re-rank depth is a tuning knob in 7.3.
3.4 Writes
Inserts average per second (about 7.2 per shard) and deletes about 12 per second. An hour of inserts per shard is about 26 042 vectors (80 MB), which an exact scan covers in about 2 ms at an assumed 20 GFLOP/s, so a flat buffer is enough for fresh data (7.5).
3.5 Summary
| Quantity | Estimate | Design consequence |
|---|---|---|
| Raw vectors | 1.54 TB | Stored on NVMe and object storage, not in RAM |
| HNSW in memory | 1.66 TB (about 10 nodes per replica) | Used only for collections that fit in memory |
| IVF-PQ codes | 52 GB total, 6.5 GB per shard | Large collection uses IVF-PQ |
| Re-rank reads | 100 000 random reads/s per replica | NVMe per node, re-rank depth tuned |
| Inserts | about 58/s | Flat buffer plus hourly merge |
4. API design
4.1 Endpoints
| Method and path | Purpose | Notes |
|---|---|---|
PUT /v1/collections/{c} | Create a collection with dimension, metric, model version and index profile | Dimension and metric immutable |
POST /v1/collections/{c}/upsert | Insert or replace up to 1 000 vectors | Returns a write sequence number |
POST /v1/collections/{c}/delete | Delete by IDs or by filter | Returns a write sequence number |
POST /v1/collections/{c}/query | Top-k with filter and search parameters | Optional min_seq for read-your-writes |
POST /v1/collections/{c}/snapshots | Create a snapshot | Stored in object storage |
Errors use problem details (RFC 9457). A query with a vector of the wrong
dimension returns 400; a query against a collection whose model version
differs from the caller's declared version returns 409.
4.2 Query example
{"vector": [0.0132, -0.0871, 0.0419], "k": 10, "filter": {"and": [{"tenant": {"eq": "t_2207"}}, {"lang": {"in": ["en", "de"]}}, {"created_at": {"gte": "2026-01-01"}}]}, "params": {"nprobe": 64, "rerank": 100}, "min_seq": 88412093, "include": ["score", "metadata"]}
The vector is shortened here to three values; a real request carries all 768.
{"results": [{"id": "doc-7731#p4", "score": 0.8412, "metadata": {"lang": "en"}}, {"id": "doc-0918#p1", "score": 0.8377, "metadata": {"lang": "de"}}], "strategy": "filtered_traversal", "shards": 8, "took_ms": 23}
5. Data model
5.1 Entities
A collection is split into partitions (one per tenant), each partition into shards, and each shard into segments: one growing buffer and several sealed, indexed segments.
5.2 Storage choices
| Data | Store | Key | Why |
|---|---|---|---|
| Write-ahead log | Example: Replicated log, one partition per shard | Sequence number | Durability before acknowledgement, replay after crash |
| PQ codes and IVF lists | Shard memory, persisted to local disk and object storage | List ID, then vector ID | Scanned on every query |
| Full vectors | Local NVMe, copy in object storage | Vector ID to page offset | Re-ranking reads |
| Metadata and filter indexes | Columnar per segment with bitmap and range indexes | Vector ID | Fast bitmap for any filter |
| Tombstones | Bitmap per segment | Row offset | Applied at search, cleared at compaction |
| Catalog (collections, shards, segments) | Example: Consensus-backed metadata store | Collection ID | Small, strongly consistent |
5.3 Access patterns
| Access pattern | Frequency | Key or index that serves it | Partition key rationale |
|---|---|---|---|
Top-k query with tenant filter | 2 000/s at peak | Tenant partition, then IVF lists on every shard | Tenant partition removes other tenants' data before any distance is computed |
Top-k with a selective metadata filter | Part of the above | Segment bitmap index on the filtered fields | Selectivity estimate picks the strategy (7.4) |
| Upsert | about 58/s | WAL by shard (hash of vector ID) | Hashing spreads writes and sizes evenly |
| Delete by ID | about 12/s | Vector ID to segment and row lookup | Same shard as the insert |
| Delete a whole document or tenant | Rare | Metadata index, or drop the tenant partition | Dropping a partition is instant and certain |
| Rebuild or compact a segment | Hourly to weekly | Segment ID | Segments are the unit of rebuild |
6. High-level design
| Component | Responsibility | Scales by |
|---|---|---|
| Query router | Fan out to all shards of the partition, merge top-k, enforce timeouts | Stateless instances |
| Filter planner | Estimate selectivity, choose strategy and search parameters | In router |
| Write API and WAL | Validate, assign sequence number, persist before acknowledging | Log partitions per shard |
| Shard replica | Apply WAL, keep buffer and segments, answer local top-k | Shards and replicas |
| Index builder and compactor | Merge buffers into the main index, remove tombstoned rows, retrain when needed | Background workers |
| Catalog | Collections, shard map, segment list and versions | Consensus group |
7. Detailed design
The deep dives in this section, each with options, choice and reason:
| Deep dive | Options considered | Choice | Reason | Section |
|---|---|---|---|---|
| Index family | Exact (flat); HNSW; IVF-flat; IVF-PQ with re-rank; disk-based graph | IVF-PQ with re-rank for large, HNSW for small | Memory at 500 million vectors | 7.2 |
| Recall versus latency | Fixed parameters; per-collection tuning; per-query budget | Per-collection profile with per-query override | Different collections, different trade-offs | 7.3 |
| Filtering | Post-filter; pre-filter and exact scan; filtered traversal; partitioning | Planner chooses by selectivity; tenants as partitions | No single strategy wins across selectivities | 7.4 |
| Updates | Rebuild index; in-place insert; buffer and merge | Buffer, tombstones, hourly merge, compaction | Freshness without index churn | 7.5 |
7.1 Exact search as the baseline
Exact search compares the query with every vector. For one shard of 62.5 million vectors at that is about GFLOP per query, seconds of CPU time. It stays in the design for two jobs: searching the small growing buffer, and producing the ground truth that recall is measured against (NFR-01).
7.2 Index families
| Family | How it works | Memory per vector at | Updates | Fits |
|---|---|---|---|---|
| Flat (exact) | Scan all vectors | 3 072 B | Trivial | Small sets, ground truth |
| HNSW | Layered proximity graph; greedy search from the top layer down | 3 328 B with | Inserts incremental; deletes need tombstones (the Faiss wiki notes HNSW cannot remove vectors) | Collections that fit in RAM; lowest latency at high recall |
| IVF-flat | k-means lists; scan the closest lists | 3 072 B + ID | Inserts go to the nearest list | Memory somewhat constrained |
| IVF-PQ plus re-rank | Lists of compressed codes; re-rank the best candidates with full vectors | 104 B in RAM, 3 072 B on NVMe | Inserts encode with the trained codebooks | Hundreds of millions of vectors |
| Disk-based graph (DiskANN family) | Graph and full vectors on SSD, compressed vectors in RAM | Compressed codes in RAM | Supported with care | Billion scale per node |
HNSW in brief (Malkov and Yashunin, 2020): each vector gets a random top
layer drawn with an exponentially decaying probability; with the usual
normalisation , the share of vectors that reach layer 1 or
above is (about 3.1% for ), and the number of layers grows with
, about 5.2 for one shard of 62.5 million vectors. Search
starts at the top layer and descends greedily, then explores
efSearch candidates on the bottom layer. Larger efSearch gives higher
recall and higher latency.
Product quantization in brief (Jégou, Douze and Schmid, 2011): the vector is split into sub-vectors, each replaced by the index of its nearest centroid in a 256-entry codebook, so a 768-dimension float vector becomes 96 bytes. Distances to a query are computed from a per-query lookup table (asymmetric distance computation), which is why the codes never need to be decompressed. PQ distances are approximate, so the best candidates are re-ranked with the full vectors.
Choice: the 500-million-vector collection uses IVF with lists per shard, PQ with 96 bytes per vector, and re-ranking of 100 candidates per shard from NVMe. Collections under about 20 million vectors (about 67 GB in HNSW) use HNSW in memory. Training needs at least million sample vectors per shard (Faiss wiki guidance of 30 to 256 times the list count); the codebooks are trained once per collection version.
7.3 Recall versus latency
Three knobs move the trade-off: (lists scanned), re-rank depth,
and for HNSW efSearch. Fill the measured columns from your own benchmark
with the exact path as ground truth:
| Codes scanned per shard | Codes scanned in total | Recall@10 | p99 latency | |
|---|---|---|---|---|
| 16 | 3 815 | 30 518 | [measure] | [measure] |
| 32 | 7 629 | 61 035 | [measure] | [measure] |
| 64 (default) | 15 259 | 122 070 | [measure] | [measure] |
| 128 | 30 518 | 244 141 | [measure] | [measure] |
Pick the smallest setting that meets NFR-01 on the 5th percentile of per-query recall, not only the mean: average recall can hide a class of queries (for example short queries or a rare language) that fail badly. Re-check after every embedding model change, every codebook retrain and every large shift in the data.
7.4 Filtered search
With filter selectivity (the share of vectors that pass), a post-filter must fetch about candidates to keep results. For = 500 million and 8 shards:
| Selectivity | Candidates for with post-filter | Matching vectors per shard | Exact scan of matches per shard (at 20 GFLOP/s) | Strategy |
|---|---|---|---|---|
| 0.5 | 20 | 31 250 000 | far too slow | Post-filter with small over-fetch |
| 0.1 | 100 | 6 250 000 | far too slow | Filtered traversal (bitmap checked during search) |
| 0.01 | 1 000 | 625 000 | 48 ms | Filtered traversal, larger |
| 0.001 | 10 000 | 62 500 | 4.8 ms | Pre-filter by bitmap, then exact scan |
The planner estimates from per-segment field statistics and picks the strategy; the response reports which one ran so slow queries can be explained. Graph indexes lose connectivity when most nodes fail the filter, which is why research such as Filtered-DiskANN (WWW 2023) and ACORN (SIGMOD 2024) builds filter awareness into the graph. Tenants are never a filter: each tenant is a partition, so the most common and most important filter costs nothing and cannot leak (NFR-06).
The thresholds 0.002 and 0.3 are Example values; set them from a benchmark on your data.
7.5 Inserts, deletes and freshness
- An upsert is written to the shard's WAL and acknowledged with its sequence number.
- Each replica applies the WAL to its growing buffer (flat, searched exactly) within 1 s. A replaced ID gets a tombstone in its old segment.
- Every hour the builder encodes the buffer (about 26 000 vectors per shard) with the existing codebooks and appends the codes to their IVF lists in a new segment version; the buffer is then cleared. Queries switch to the new version atomically.
- A delete sets a tombstone bit immediately, so the vector disappears from results within 1 s (NFR-04). Compaction rewrites a segment when its deleted share passes 20%; at 1 million deletes a day spread evenly over 500 million vectors that takes about 100 days, but deleting a tenant drops its partition at once.
- Codebooks are retrained when recall on the sampled queries drifts below target, by building a new collection version in the background.
min_seq gives read-your-writes: a replica that has not applied that
sequence number waits up to 200 ms or the router tries another replica.
7.6 Sharding and replication
Vectors are assigned to shards by hash of their ID inside each tenant
partition, so every shard holds a similar slice of every large tenant and
queries fan out to all shards. Fan-out multiplies the work per query, but it
keeps shard sizes even and lets any shard answer for any query. Each shard
has 2 replicas behind the router; the router sends each query to one replica
per shard, hedges after the shard's p95 latency, and merges the top-k lists.
The tail latency of a query is the slowest shard's latency, so per-shard p99
must sit well below the end-to-end target.
7.7 How real systems do it
How real systems do it (paraphrased, not copied). The Milvus paper (Wang and others, "Milvus: A Purpose-Built Vector Data Management System", SIGMOD 2021) describes inserts held in memory and flushed as immutable segments when a size threshold is reached or every second, small segments merged into larger ones under a tiered policy, deletes handled out of place and removed at merge time, and indexes built only for large segments. Each query runs on a snapshot of the current segments, so writes do not disturb running queries. For attribute filters the paper compares attribute-first scans, attribute bitmaps checked during vector search, vector-first search followed by an attribute check, and a cost-based choice between them, and adds a partition-based method on frequently filtered attributes that its experiments found faster than the cost-based one. The Faiss wiki "Guidelines to choose an index" gives the memory estimate used in 3.2 and list-count guidance by dataset size. Read the originals in 12.3; this box keeps only the general ideas.
8. Scalability and performance
| Concern | Approach | Limit before redesign |
|---|---|---|
| Query rate | Add replicas per shard | NVMe random reads for re-rank (3.3) |
| Collection size | Add shards; codes are 104 B per vector | Training time for codebooks and list count |
| Fan-out tail latency | Hedged requests, per-shard timeouts, partial results flagged | About 32 shards before tail latency dominates |
| Filters | Planner and bitmap indexes | Filters on high-cardinality fields without statistics |
| Writes | WAL per shard, hourly merge | Merge time once buffers exceed an hour of inserts |
Latency budget for a query (target p99 50 ms):
| Step | Budget |
|---|---|
| Router, planner, fan-out | 3 ms |
| Coarse quantizer and list scan per shard | 12 ms |
| Re-rank (100 NVMe reads in parallel) | 8 ms |
| Growing buffer exact scan | 2 ms |
| Merge across shards and return | 3 ms |
| Headroom for the slowest shard | 22 ms |
9. Reliability, security and operations
9.1 Failure modes
| Component | Failure | Detection | Blast radius | Mitigation | RTO |
|---|---|---|---|---|---|
| Shard replica | Node lost | Health check | Half the capacity of one shard | Router uses the other replica; rebuild from object storage and WAL | Example: 20 min to restore the replica |
| Both replicas of a shard | Lost together | Router errors | One eighth of results missing | Return partial results flagged partial: true; restore from snapshot | Example: 30 min |
| NVMe drive | Slow or failing | Re-rank latency per node | One replica | Drain node; skip re-rank and serve PQ-only results with a flag | Example: 5 min |
| Index builder | Merge fails | Buffer age above 2 h | Buffer grows, query latency rises | Alert; buffer is still searched exactly | Example: 1 h |
| Embedding model | New version mixed with old | Model version check on query | Wrong neighbours across the collection | Collection pinned to one model version; new version is a new collection | Example: immediate rejection |
| Recall | Drift after data shift | Sampled recall below target | Answer quality | Raise temporarily; retrain codebooks | Example: 1 day |
| [Component] | [Failure] | [Signal] | [Scope] | [Mitigation] | [Time] |
9.2 Security and privacy
| Threat | Control |
|---|---|
| Cross-tenant leakage | Tenant partitions; tenant taken from the authenticated principal, never from the request body |
| Deleted personal data still retrievable | Tombstones within 1 s; compaction and snapshot expiry documented for erasure requests |
| Embedding inversion (reconstructing text from vectors) | Treat vectors as sensitive as the source text; encrypt at rest; restrict raw vector export |
| Abuse of expensive queries | Caps on k, and filter complexity per tenant; per-tenant rate limits |
9.3 Observability
| Signal | Metric or log | Alert threshold |
|---|---|---|
| Recall | Recall@10 on 1% sampled queries re-run exactly | Below 0.95 for 1 h |
| Latency | p99 end to end and per shard | Above 50 ms for 10 min |
| Filter strategy mix | Share of queries per strategy | Sudden shift |
| Freshness | Write-to-visible probe | Above 1 s |
| Buffer and tombstones | Buffer age, deleted share per segment | Buffer older than 2 h |
9.4 Cost estimate
| Item | Unit cost | Quantity | Monthly cost |
|---|---|---|---|
| Shard nodes with NVMe | [$/node-month] | Example: 16 | [$] |
| Router instances | [$/instance-month] | Example: 6 | [$] |
| Object storage for segments and snapshots | [$/GB-month] | Example: 3 TB | [$] |
| Re-embedding a collection | [$/GPU-hour] | Example: 28 GPU-hours for 500 million vectors at 5 000/s per GPU | [$] |
| Total | [$] |
10. Trade-offs and alternatives
| Decision | Options | Chosen | Why | What we give up |
|---|---|---|---|---|
| Index for large collection | HNSW in RAM; IVF-PQ with re-rank; disk graph | IVF-PQ with re-rank | 52 GB of codes instead of 1.66 TB of graph | Higher latency than HNSW at the same recall; training step |
| Database | Vector extension in the main relational database; dedicated service | Dedicated service | Scale and index control | Second system to operate; joins with business data are the caller's job |
| Filtering | One strategy; planner per query | Planner per query | Selectivity varies by orders of magnitude | Planner needs statistics and testing |
| Freshness | Rebuild nightly; buffer and merge | Buffer and merge | Visible within 1 s | Merge machinery and tombstones |
| Sharding | By tenant; by hash of ID | Hash within tenant partitions | Even shards, any tenant size | Fan-out to every shard |
| What changes at 10x / 0.1x | 10x (5 billion vectors): 520 GB of codes and 15.4 TB of full vectors, about 80 shards at today's 6.5 GB of codes each, so fan-out tail latency forces a two-level route (coarse routing to a subset of shards) or a disk-based graph per node. 0.1x (50 million vectors): about 166 GB in HNSW, above the 20-million HNSW limit in 7.2 and 93% of one node's usable memory, so either HNSW across 2 shards or IVF-PQ in one shard (5.2 GB of codes) with no fan-out | Review at each doubling of vectors | Memory and fan-out grow first | [Note] |
| [Decision] | [Options] | [Chosen] | [Why] | [Cost] |
11. Delivery plan and risks
11.1 Milestones
| Milestone | Scope | Exit criterion | Target date |
|---|---|---|---|
| M1 | Exact path, WAL, buffer, ground-truth harness | Recall harness reports on sampled queries | YYYY-MM-DD |
| M2 | IVF-PQ shards with re-rank, shadow traffic | Recall@10 at or above 0.95 and p99 at or below 50 ms in shadow | YYYY-MM-DD |
| M3 | Filter planner, tenant partitions | No cross-tenant result in audit; filtered recall at target | YYYY-MM-DD |
| M4 | Cutover, deletes within 1 s, compaction | Erasure test passes end to end | YYYY-MM-DD |
11.2 Rollout and rollback
[Example: Dual-write to the old and new stores, compare top-10 overlap on shadow queries for 14 days, then move read traffic per tenant in steps. Rollback points reads back to the old store while dual writes continue.]
11.3 Risks
| ID | Risk | Likelihood | Impact | Mitigation | Owner |
|---|---|---|---|---|---|
| R-01 | Example: Recall on real queries lower than on the benchmark set | Medium | High | Sample live queries for the harness from day one | [@name] |
| R-02 | Example: Embedding model upgrade forces full re-index | High | Medium | Collection per model version; re-embedding budget planned | [@name] |
| R-03 | Example: NVMe read rate becomes the bottleneck | Medium | Medium | Re-rank depth tuning; more replicas | [@name] |
| [R-nn] | [Risk] | [L / M / H] | [L / M / H] | [Mitigation] | [@name] |
12. Appendices
12.1 Open questions
| ID | Question | Owner | Due |
|---|---|---|---|
| OQ-01 | Example: Do we need multi-vector documents (one vector per passage, results grouped by document)? | [@name] | YYYY-MM-DD |
| OQ-02 | Example: Is a disk-based graph worth evaluating before 10x? | [@name] | YYYY-MM-DD |
| [OQ-nn] | [Question] | [@name] | YYYY-MM-DD |
12.2 Glossary
| Term | Meaning |
|---|---|
| ANN | Approximate nearest neighbour search: trades exactness for speed |
| Recall@k | Share of the true top-k (from exact search) that the approximate search returns |
| HNSW | Hierarchical navigable small world graph index |
| IVF | Inverted file index: vectors grouped into lists by nearest k-means centroid |
| PQ | Product quantization: vectors compressed into codes of sub-vector centroid indexes |
| Number of IVF lists scanned per query | |
efSearch | HNSW candidate list size during search |
| Tombstone | Mark that hides a deleted vector until compaction removes it |
| Selectivity | Share of vectors that pass a filter |
| [Term] | [Meaning] |
12.3 References
| Reference | Use |
|---|---|
| Malkov, Y. A. and Yashunin, D. A. "Efficient and Robust Approximate Nearest Neighbor Search Using Hierarchical Navigable Small World Graphs", IEEE TPAMI 42(4), 824 to 836, 2020, doi:10.1109/TPAMI.2018.2889473 | HNSW in 7.2 |
| Jégou, H., Douze, M. and Schmid, C. "Product Quantization for Nearest Neighbor Search", IEEE TPAMI 33(1), 117 to 128, 2011, doi:10.1109/TPAMI.2010.57 | PQ in 7.2 |
| Douze, M. and others. "The Faiss Library", IEEE Transactions on Big Data 12(2), 346 to 361, 2026, doi:10.1109/TBDATA.2025.3618474 | Index families |
| Faiss wiki, "Guidelines to choose an index", checked 2026-10-30 | Memory formula in 3.2, list counts in 3.3 and 7.2 |
| Wang, J. and others. "Milvus: A Purpose-Built Vector Data Management System", SIGMOD 2021, 2614 to 2627, doi:10.1145/3448016.3457550 | 7.5, 7.7 |
| Subramanya, S. J. and others. "DiskANN: Fast Accurate Billion-point Nearest Neighbor Search on a Single Node", NeurIPS 2019 | Disk-based graph in 7.2 |
| Gollapudi, S. and others. "Filtered-DiskANN: Graph Algorithms for Approximate Nearest Neighbor Search with Filters", WWW 2023, doi:10.1145/3543507.3583552 | 7.4 |
| Patel, L., Kraft, P., Guestrin, C. and Zaharia, M. "ACORN: Performant and Predicate-Agnostic Search Over Vector Embeddings and Structured Data", Proceedings of the ACM on Management of Data 2(3) (SIGMOD 2024), 2024, doi:10.1145/3654923 | 7.4 |
Enterprise RAG Search System Design (system-design/design-enterprise-rag-search) | Main consumer of this service |
RAG System Design (ai-data/rag-system-design) | Retrieval quality and evaluation |
Full-Text Search Engine System Design (system-design/design-full-text-search) | Keyword side of hybrid search |
Recommendation System Design (system-design/design-recommendation-system) | Candidate retrieval by embeddings |
Back-of-Envelope Estimation and Capacity Model (system-design/back-of-envelope-estimation) | Method for section 3 |
Standard and licence note
Based on the published research cited in 12.3 (HNSW, product quantization, filtered ANN search, the Milvus and Faiss papers) and on common industry practice for vector search services. No standard governs this design. The papers and the Faiss wiki are paraphrased only; no text, figures or code were copied. Capacity figures are computed from the stated example inputs, and recall and latency must be measured on your own data. Original text written for this collection. Template licence: MIT.
관련 템플릿
Ad Click Aggregation System Design Template (Reference Design)
45-minute path, click dedupe, event-time windows, exactly-once counting, exact and Count-Min top-K, batch reconciliation for billing, failure modes, 10x row
시스템 설계Zanzibar-Style Authorization Service System Design Template
Relationship-based authorization service: relation tuples, namespace config, Check/Expand/List/Watch APIs, consistency tokens, caching, sharding, failure modes
시스템 설계CDC Pipeline System Design Template
CDC pipeline: log-based capture, watermark chunked snapshot, per-key order, schema evolution, outbox, search, cache and warehouse sinks, replay