Skip to content

HNSW: efConstruction does not scale with corpus size — recall plateaus at 1M vectors regardless of search ef #2180

Closed

Description

@kriszyp

Priority: P1

Summary

efConstruction defaults to 100 and never scales with corpus size, while the search-side ef auto-scales (AUTO_EF_BASE/AUTO_EF_MAX in HierarchicalNavigableSmallWorld.ts). At 1M vectors this becomes the recall bottleneck: recall@10 drops to 0.935 and cannot be recovered by any amount of search-side ef — the missing neighbours are unreachable in the graph, because the edge-selection candidate list stayed at 100 while the corpus grew 10×.

Found while extending #2125's scaling benchmark to 1M vectors (full data in the PR thread).

Evidence

All runs on benchmarks/hnsw-scale.js (768-dim, int8, calibrated Gaussian-mixture corpus at d(nn)/d(rand) ≈ 0.65 — the harder-contrast regime, matching the corpus the reporter of #2069 measured). Fixed seed, so the A/B graphs below index the identical corpus with identical level assignments.

Recall@10 (raw / candidate-set) across the sweep, ef = auto (pinned at AUTO_EF_MAX 512 from ~13K nodes up):

N 100K 250K 500K 1M
recall@10 0.980 / 0.997 0.978 / 0.988 0.978 / 0.987 0.935 / 0.943

Ruling out the search side — sweeping ef over the same 1M graph:

ef 512 768 1024 1536
recall@10 set 0.943 0.962 0.963 0.967
p50 8.7ms 18.1ms 25.6ms 41.8ms

Recall plateaus ~0.96 at 4.7× the latency: not an ef ceiling.

Attribution at 1M, ef 512:

build config recall@10 raw / set p50 visited build
efC=100, int8 (default) 0.935 / 0.943 8.9ms 3,948 63 min
efC=100, float32 0.952 / 0.952 — 3,596 71 min
efC=200, int8 0.985 / 0.997 7.2ms 3,110 110 min

efConstruction 200 fully restores 100K-level recall — and the queries get faster at the same ef (3,110 nodes visited vs 3,948; better edges route more directly). Quantization contributes ~1.5 points; construction quality is the dominant term.

Proposed fix

Auto-scale efConstruction with graph size when it is not explicitly configured, mirroring the existing search-side auto-scale — evaluated at insert time from the same node count the search side already resolves. An explicitly configured efConstruction stays authoritative. The cost is build time (1.77× at 1M for efC 200), paid only by tables that actually grow large; small tables see no change.

Caveats

Generated by Claude Fable 5.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:performancePerformance, latency, throughputarea:searchVector search, HNSW, full-text searchenhancementNew feature or request

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions