Recern Vector 0.4.0 · Measured 2026-11-02

Recall, latency and storage.

We measured the released Python package on full SIFT1M and GloVe-100: embedded f32 and int8 collections against faiss HNSW. Each search setting has three timed repetitions over the same 1,000 test queries. These results measure one query at a time, not an HTTP server or a hosted service.

Apple M3 Max · 36 GiB RAM · macOS 27.0.1 · Python 3.13.15
Recern Vector 0.4.0 · faiss-cpu 1.15.1 · NumPy 2.5.3 · h5py 3.16.0

7,712/s

queries/s on SIFT1M at recall ≥ 0.95

618/s

queries/s on GloVe-100 at recall ≥ 0.95

102.7s

to build the SIFT1M f32 index · 4 threads

Same recall target

Throughput at recall@10 ≥ 0.95

Each cell selects that engine’s fastest tested setting reaching the target. A missing result means the target was not reached within the measured ef sweep.

EngineSIFT1M · recall ≥ 0.95GloVe-100 · recall ≥ 0.95
Recern Vector 0.4.0 · f32HNSW · 0.4.07,712queries/s · ef=80618queries/s · ef=1280
Recern Vector 0.4.0 · int8HNSW · 0.4.03,565queries/s · ef=80246queries/s · ef=1280
faiss HNSW · f32HNSW · 1.15.16,605queries/s · ef=80356queries/s · ef=1280
The complete trade-off

Recall and single-query throughput

Both f32 and int8 are evaluated against the original dataset’s published neighbours. The int8 results include quantization loss. Query throughput is the median of three repeated loops, not a claim of concurrent serving capacity.

  • Recern f32 HNSW m=16
  • Recern int8 HNSW m=16
  • faiss f32 HNSW m=16
0.50.80.90.950.990.999101001k10kRecall@10, stretched toward 1.0 →Queries per second (log) →faiss f32Recern int8Recern f32
Recall@10 on the first 1,000 test queries; throughput of one query at a time from Python, on a log scale. The recall axis is stretched toward 1.0 so the high-recall region is readable; exact search sits at the right edge. Settings below recall 0.5 are not shown. The same numbers are in the tables below.
Three recall levels

Choose a target before comparing speed

QPS and p95 belong to the same selected setting. A higher ef can improve recall while reducing throughput; no interpolation or extrapolation is used.

SIFT1M · 1,000,000 × 128 · l2

EngineRecall ≥ 0.90Recall ≥ 0.95Recall ≥ 0.99
Recern Vector 0.4.0 · f32HNSW m=16 · ef construction=20014,681queries/s · ef=40p95 0.086 ms7,712queries/s · ef=80p95 0.164 ms4,083queries/s · ef=160p95 0.31 ms
Recern Vector 0.4.0 · int8HNSW m=16 · ef construction=2006,126queries/s · ef=40p95 0.2 ms3,565queries/s · ef=80p95 0.339 msnot reached
faiss HNSW · f32HNSW m=16 · ef construction=20012,903queries/s · ef=40p95 0.095 ms6,605queries/s · ef=80p95 0.192 ms3,802queries/s · ef=160p95 0.316 ms

GloVe-100 · 1,183,514 × 100 · cosine

EngineRecall ≥ 0.90Recall ≥ 0.95Recall ≥ 0.99
Recern Vector 0.4.0 · f32HNSW m=16 · ef construction=2002,251queries/s · ef=320p95 0.552 ms618queries/s · ef=1280p95 2 msnot reached
Recern Vector 0.4.0 · int8HNSW m=16 · ef construction=200930queries/s · ef=320p95 1.425 ms246queries/s · ef=1280p95 5.513 msnot reached
faiss HNSW · f32HNSW m=16 · ef construction=2001,623queries/s · ef=320p95 0.782 ms356queries/s · ef=1280p95 3.317 msnot reached
Index construction and files

Build time and storage

All three engines use 4 build threads, m=16 and ef construction=200. Build times are one index build per configuration. Recern save and checkpoint are recorded separately; faiss writes an index file and does not provide the same database/WAL durability semantics.

SIFT1M

EngineBuildSave / writeCheckpointReopenFile size
Recern Vector 0.4.0 · f32102.69 s5.46 s7.69 s5.53 s630.8 MiB
Recern Vector 0.4.0 · int8299.01 s2.39 s3.39 s2.74 s268.4 MiB
faiss HNSW · f3280.51 s0.13 s—0.1 s625.9 MiB

GloVe-100

EngineBuildSave / writeCheckpointReopenFile size
Recern Vector 0.4.0 · f32149.44 s5.19 s7.42 s5.63 s620.3 MiB
Recern Vector 0.4.0 · int8387.87 s2.52 s3.61 s3.04 s286.2 MiB
faiss HNSW · f32118.25 s0.16 s—0.1 s614.3 MiB

File size is the checkpoint plus any WAL for Recern, and the serialized index for faiss. Formats include different features and overhead. This is not peak RAM usage. ID preparation and faiss cosine normalization are outside the index build timer; Recern normalizes inputs inside its API.

Method and boundaries

What was measured

  • SIFT1M: 1,000,000 vectors, 128 dimensions, L2. GloVe-100: 1,183,514 vectors, 100 dimensions, cosine.
  • The first 1,000 test queries, k=10, with the published ANN-Benchmarks ground truth. Recern uses string IDs and faiss uses positional IDs.
  • ef: 10, 20, 40, 80, 160, 320, 640, 1280. Each repetition warms up on 100 queries, then uses a reproducibly shuffled query order. Search uses one thread and one caller.
  • Latency includes the Python call through returned IDs; recall calculation is outside the timer. p50 and p95 are medians of per-repetition percentiles.
  • Graphs are built once, then saved and reopened. Parallel graph construction can vary between runs. The reported throughput ranges below show query-loop variation, not build-to-build confidence intervals.
  • Measured on a desktop workstation, without process or CPU isolation. Other activity, OS scheduling and thermal conditions can affect the results.
  • No filters, document embedding model, metadata payload workload, HTTP, Qdrant, multi-client load, crash test or larger-than-memory operation is measured here.
Every measured setting

Inspect the raw measurements

The JSON files retain every repetition, dataset hashes, exact package versions and the installed native-binary hash.

SIFT1M · all ef settings and repeated-loop ranges
EngineefRecall@10QPSQPS rangep50 msp95 ms
Recern Vector 0.4.0 · f32100.753434,97531,591–36,2280.0270.041
Recern Vector 0.4.0 · f32200.863523,44220,359–24,6450.0410.059
Recern Vector 0.4.0 · f32400.943214,68112,728–14,9080.0680.086
Recern Vector 0.4.0 · f32800.98297,7127,501–8,2700.130.164
Recern Vector 0.4.0 · f321600.99564,0834,073–4,2100.2460.31
Recern Vector 0.4.0 · f323200.99862,2292,212–2,3840.450.565
Recern Vector 0.4.0 · f326400.99901,3211,267–1,3670.7640.978
Recern Vector 0.4.0 · f3212800.9991749743–7491.3741.625
Recern Vector 0.4.0 · int8100.749714,94314,492–15,1690.0650.094
Recern Vector 0.4.0 · int8200.85859,9299,838–9,9720.1010.13
Recern Vector 0.4.0 · int8400.93536,1266,070–6,1280.1680.2
Recern Vector 0.4.0 · int8800.97113,5653,527–3,5780.290.339
Recern Vector 0.4.0 · int81600.98461,9851,953–1,9900.5220.628
Recern Vector 0.4.0 · int83200.98681,1101,075–1,1190.931.145
Recern Vector 0.4.0 · int86400.9870632625–6361.6352.041
Recern Vector 0.4.0 · int812800.9870359356–3602.8793.644
faiss HNSW · f32100.698733,93233,141–34,1310.0290.041
faiss HNSW · f32200.828519,51518,223–22,0210.050.069
faiss HNSW · f32400.924512,90312,881–12,9450.0780.095
faiss HNSW · f32800.97566,6056,531–7,1170.1510.192
faiss HNSW · f321600.99383,8023,743–3,8030.2710.316
faiss HNSW · f323200.99811,9471,942–1,9500.5270.61
faiss HNSW · f326400.9990941939–9421.0911.248
faiss HNSW · f3212800.9991405399–4072.4982.869
Download SIFT1M JSON →

Dataset SHA-256: dd6f0a6ed6b7ebb8934680f861a33ed01ff33991eaee4fd60914d854a0ca5984

GloVe-100 · all ef settings and repeated-loop ranges
EngineefRecall@10QPSQPS rangep50 msp95 ms
Recern Vector 0.4.0 · f32100.522034,71733,756–35,5090.0270.042
Recern Vector 0.4.0 · f32200.641622,10421,614–22,1540.0430.065
Recern Vector 0.4.0 · f32400.739813,25413,098–13,2750.0730.105
Recern Vector 0.4.0 · f32800.81327,6837,659–7,7000.1280.172
Recern Vector 0.4.0 · f321600.87014,2184,157–4,2480.2380.299
Recern Vector 0.4.0 · f323200.91282,2512,235–2,2550.4490.552
Recern Vector 0.4.0 · f326400.94551,1541,067–1,1930.8721.094
Recern Vector 0.4.0 · f3212800.9699618600–6201.6482
Recern Vector 0.4.0 · int8100.519713,31211,146–13,5990.070.114
Recern Vector 0.4.0 · int8200.62898,6037,339–8,7090.110.173
Recern Vector 0.4.0 · int8400.73185,1595,079–5,3630.1850.291
Recern Vector 0.4.0 · int8800.80933,0763,029–3,1440.320.447
Recern Vector 0.4.0 · int81600.86441,7171,710–1,7650.5860.773
Recern Vector 0.4.0 · int83200.9052930925–9621.091.425
Recern Vector 0.4.0 · int86400.9357512510–5161.9882.548
Recern Vector 0.4.0 · int812800.9603246244–2464.1445.513
faiss HNSW · f32100.468928,23327,914–28,5540.0330.054
faiss HNSW · f32200.603617,59717,182–17,9000.0540.085
faiss HNSW · f32400.707110,64110,623–10,6900.090.136
faiss HNSW · f32800.79175,6375,560–6,0160.1740.243
faiss HNSW · f321600.85233,1923,188–3,2820.3130.399
faiss HNSW · f323200.90031,6231,548–1,6930.620.782
faiss HNSW · f326400.9371801794–8191.2611.53
faiss HNSW · f3212800.9619356336–3572.8373.317
Download GloVe-100 JSON →

Dataset SHA-256: 544af1d5e84e112cd4749571dcfd8ca109818a572f850af75a3a09e093a953c4

Reproduce

Run the same harness

The current harness records macOS hardware metadata. Use a fresh work directory for each run. Large datasets and indexes require several gigabytes of free disk space; compare machines and builds explicitly.

Benchmark script · Pinned requirements

# macOS, Python 3.13; run in a fresh directory
curl --fail --location -O https://recern.net/benchmarks/release_bench.py
curl --fail --location -O https://recern.net/benchmarks/requirements-0.4.0.txt
python3.13 -m venv .bench-venv
.bench-venv/bin/python -m pip install -r requirements-0.4.0.txt
mkdir bench-data
curl --fail --location https://ann-benchmarks.com/sift-128-euclidean.hdf5 -o bench-data/sift-128-euclidean.hdf5
curl --fail --location https://ann-benchmarks.com/glove-100-angular.hdf5 -o bench-data/glove-100-angular.hdf5

OPENBLAS_NUM_THREADS=1 VECLIB_MAXIMUM_THREADS=1 OMP_NUM_THREADS=4 \
  .bench-venv/bin/python release_bench.py sift --data-dir bench-data \
  --output results/sift.json --work work/sift --queries 1000 --repeats 3 --build-threads 4
OPENBLAS_NUM_THREADS=1 VECLIB_MAXIMUM_THREADS=1 OMP_NUM_THREADS=4 \
  .bench-venv/bin/python release_bench.py glove --data-dir bench-data \
  --output results/glove.json --work work/glove --queries 1000 --repeats 3 --build-threads 4

Harness SHA-256: 46d61eaffa74ee1ec11bd91b14c84637702c5a40eb6095eb5c0a276d15335aad

Earlier work

Keep historical results in context

The pre-0.2.0 report from 7 October 2026 compared the prototype with faiss, LanceDB and sqlite-vec using a different build protocol. It is preserved separately; it is not mixed into these release measurements.

Read the historical report →