ann_router.backends.hnsw module

HNSW backend (hnswlib) — best recall/latency for a stable, in-memory corpus.

Hierarchical Navigable Small World graphs give the best recall-per-millisecond of the in-memory engines when the corpus rarely changes: the graph is built once and traversed cheaply. The catch — and the reason the router only picks it for static corpora — is deletion: hnswlib deletes via tombstones (mark_deleted), which degrade the graph over time and are never truly reclaimed without a rebuild. So this adapter advertises supports_remove as tombstone-only and the policy keeps dynamic workloads on turbovec instead.

Consumes: hnswlib (optional, pip install 'ann-router[hnsw]'). Produces: HNSWIndex.

Author: Warith Harchaoui <warith.harchaoui@deraison.ai>

class ann_router.backends.hnsw.HNSWIndex(dim, metric='cosine', **kwargs)[source]

Bases: ANNIndex

hnswlib-backed graph index tuned for high recall on a fixed corpus.

Build knobs (M, ef_construction) and the query knob (ef) are passed through and default to values that hit ~0.95+ recall on typical 768-d embeddings. The index is grown to max_elements lazily and doubled on overflow so streaming add still works within the “stable corpus” caveat.

Parameters:
  • dim (int) – Embedding dimensionality.

  • metric ({"cosine", "l2", "ip"}, optional) – Distance metric. Defaults to "cosine".

  • M (int, optional) – Graph out-degree. Defaults to 16.

  • ef_construction (int, optional) – Build-time search width. Defaults to 200.

  • ef (int, optional) – Query-time search width (recall/latency trade). Defaults to 64.

  • kwargs (object)

Examples

>>> HNSWIndex.capabilities().name
'hnsw'
add(vectors)[source]

Append vectors with the next contiguous ids.

Parameters:

vectors (numpy.ndarray) – Shape (m, dim).

Return type:

None

add_with_ids(vectors, ids)[source]

Append vectors with explicit ids, growing capacity if needed.

Parameters:
  • vectors (numpy.ndarray) – Shape (m, dim).

  • ids (numpy.ndarray) – Shape (m,) integer ids.

Return type:

None

build(vectors, ids=None)[source]

Build the graph from an initial corpus.

Parameters:
  • vectors (numpy.ndarray) – Shape (n, dim).

  • ids (numpy.ndarray, optional) – Shape (n,); defaults to range(n).

Returns:

self.

Return type:

HNSWIndex

classmethod capabilities()[source]

Return the HNSW capability descriptor (remove is tombstone-only).

Return type:

Capabilities

classmethod is_available()[source]

Return True if hnswlib is importable.

Examples

>>> isinstance(HNSWIndex.is_available(), bool)
True
Return type:

bool

load(path)[source]

Load a graph written by save().

Parameters:

path (str) – Source path produced by save().

Returns:

self, populated from disk.

Return type:

HNSWIndex

remove(ids)[source]

Tombstone the given ids (graph is not reclaimed — rebuild for that).

Parameters:

ids (numpy.ndarray) – Shape (m,) integer ids to tombstone.

Return type:

None

save(path)[source]

Persist the graph via hnswlib’s native serialiser.

Parameters:

path (str) – Destination file path.

Return type:

None

search(queries, k)[source]

Return approximate top-k neighbours per query.

Parameters:
  • queries (numpy.ndarray) – Shape (q, dim).

  • k (int) – Neighbours per query.

Returns:

  • ids (numpy.ndarray) – Shape (q, k) neighbour ids.

  • distances (numpy.ndarray) – Shape (q, k) distances under the index metric.

Return type:

tuple[ndarray, ndarray]