Skip to content

@saehrimnir/druidjs / HNSW

Class: HNSW<T> ​

Defined in: knn/HNSW.js:65

Hierarchical Navigable Small World (HNSW) graph for approximate nearest neighbor search.

HNSW builds a multi-layer graph structure where each layer is a navigable small world graph. The top layers serve as "highways" for fast traversal, while lower layers provide accuracy. Each element is assigned to a random level, allowing logarithmic search complexity.

Key parameters:

  • m: Controls the number of connections per element (affects accuracy/memory)
  • ef_construction: Controls the quality of the graph during construction (higher = better but slower)
  • ef: Controls the quality of search (higher = better recall but slower)

This is an approximate index. Recall above 95% is expected for any m; raise ef or ef_construction if a dataset needs more. Queries overtake the exact KDTree at around 10 000 points, so below a few thousand prefer spatial_tree, which is exact and quicker.

Based on:

  • "Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs" by Malkov & Yashunin (2016)
  • "Approximate Nearest Neighbor Search on High Dimensional Data" by Li et al. (2019)

Template ​

T

Example ​

ts
import * as druid from "@saehrimnir/druidjs";

const points = [[1, 2], [3, 4], [5, 6], [7, 8]];
const hnsw = new druid.HNSW(points, {
    metric: druid.euclidean,
    m: 16,
    ef_construction: 200
});

const query = [2, 3];
const neighbors = hnsw.search(query, 2);
// [{ element: [1, 2], index: 0, distance: 1.41 }, ...]

Extends ​

  • KNN

Type Parameters ​

Type ParameterDescription
T extends number[] | Float64Array

Constructors ​

Constructor ​

ts
new HNSW<T>(points: T[], parameters?: Partial<ParametersHNSW>): HNSW<T>;

Defined in: knn/HNSW.js:73

Creates a new HNSW index.

Parameters ​

ParameterTypeDescription
pointsT[]Initial points to add to the index
parameters?Partial<ParametersHNSW>Anything left out falls back to the documented default.

Returns ​

HNSW<T>

Overrides ​

ts
KNN.constructor

Properties ​

PropertyTypeDescriptionInherited fromDefined in
_efnumber--knn/HNSW.js:152
_ef_constructionnumber--knn/HNSW.js:145
_elementsT[]-KNN._elementsknn/KNN.js:16
_epnumber[] | null--knn/HNSW.js:171
_Lnumber--knn/HNSW.js:168
_mnumber--knn/HNSW.js:138
_m0number--knn/HNSW.js:159
_metricMetric--knn/HNSW.js:118
_mLnumber--knn/HNSW.js:162
_next_indexnumber--knn/HNSW.js:130
_parametersParametersHNSW-KNN._parametersknn/KNN.js:18
_randomizerRandomizerSeeded source of randomness shared by every index. Construction is randomized — the trees pick quickselect pivots from it — so the seed parameter is what makes a built index, and therefore its query results, reproducible.KNN._randomizerknn/KNN.js:28
_selectFunction--knn/HNSW.js:121
_type"array" | "typed"-KNN._typeknn/KNN.js:20

Accessors ​

num_layers ​

Get Signature ​

ts
get num_layers(): number;

Defined in: knn/HNSW.js:688

Get the number of layers in the graph.

Returns ​

number

Number of layers


size ​

Get Signature ​

ts
get size(): number;

Defined in: knn/HNSW.js:679

Get the number of elements in the index.

Returns ​

number

Number of elements

Methods ​

add() ​

ts
add(new_elements: T[]): HNSW<T>;

Defined in: knn/HNSW.js:201

Add multiple elements to the index.

Parameters ​

ParameterTypeDescription
new_elementsT[]Elements to add

Returns ​

HNSW<T>

This instance for chaining


addOne() ​

ts
addOne(element: T): HNSW<T>;

Defined in: knn/HNSW.js:191

Add a single element to the index.

Parameters ​

ParameterTypeDescription
elementTElement to add

Returns ​

HNSW<T>

This instance for chaining


get_element() ​

ts
get_element(index: number): T;

Defined in: knn/HNSW.js:698

Get an element by its index.

Parameters ​

ParameterTypeDescription
indexnumberElement index

Returns ​

T

The element at the given index


ts
search(q: T, K: number): Candidate<T>[];

Defined in: knn/HNSW.js:556

Searches for the K nearest neighbors to a query element in the HNSW graph.

Performs a multi-layer search starting from the entry point and traversing each layer as entry points for the next.

Parameters ​

ParameterTypeDescription
qTQuery element
KnumberNumber of nearest neighbors to return

Returns ​

Candidate<T>[]

K nearest neighbors with their distances

Overrides ​

ts
KNN.search

search_by_index() ​

ts
search_by_index(i: number, k?: number): {
  distance: number;
  element: T;
  index: number;
}[];

Defined in: knn/KNN.js:77

Searches the k nearest neighbors of the element stored at index i.

The queried element is never part of the result. It is trivially its own closest neighbor at distance 0, which is never what a caller asking "what is this point near?" wants, so every caller used to strip it back out — each in its own, subtly different way. Note the asymmetry with search: an arbitrary query point has no "self" to exclude, so there k means "k results", while here it means "k neighbors".

The self match is removed by index — not by position, and not by looking for a zero distance. Position is wrong because an approximate index may order ties differently or miss the element altogether (one extra candidate is requested to cover that), and a zero distance is wrong because genuine duplicate points share it and must survive.

Parameters ​

ParameterTypeDefault valueDescription
inumberundefinedIndex of the query element.
k?number5Number of neighbors to return. Default is 5

Returns ​

{ distance: number; element: T; index: number; }[]

The k nearest other elements, closest first. Empty when i is out of range.

Inherited from ​

ts
KNN.search_by_index

search_iter() ​

ts
search_iter(
   q: T, 
   K: number, 
   ef?: number | null): Generator<{
  candidates: {
     distance: number;
     element: T;
     index: number;
  }[];
  layer: number;
}, void, unknown>;

Defined in: knn/HNSW.js:638

Iterator for searching the HNSW graph layer by layer.

Yields intermediate results at each layer for debugging or visualization.

Parameters ​

ParameterTypeDefault valueDescription
qTundefinedQuery element
KnumberundefinedNumber of nearest neighbors to return
ef?number | nullnullSize of dynamic candidate list

Returns ​

Generator<{ candidates: { distance: number; element: T; index: number; }[]; layer: number; }, void, unknown>

Yields ​