SmallWorld Class

Definition

Namespace: HNSW.Net

public class SmallWorld<TItem, TDistance>

Type parameters

TItem : The item stored in the graph (for example float[]).

TDistance : The numeric distance type returned by the distance function. Any numeric struct that implements IComparable<TDistance> works (float, int, …).

The Hierarchical Navigable Small World graph. A single SmallWorld<TItem, TDistance> builds the index, grows it with new items, and answers k-NN queries. It is generic over both the item type and the distance type, so it works with float[] embeddings, byte[] fingerprints, or any custom record.

Remarks

The layering of the HNSW graph is handled internally — add items, ask for neighbours. The graph supports incremental inserts but not per-item deletion; see Building a graph for the soft-delete and rebuild patterns.

The type is thread-safe by default: a reader-writer lock lets many KNNSearch calls run concurrently while serialising mutations such as AddItems. Pass threadSafe: false to the constructor to drop the lock when you have your own synchronisation or only ever query a fully-built graph. See Thread safety.

Constructors

Name Description
SmallWorld(distance, generator, parameters, threadSafe) Creates an empty graph with a distance function, a random generator, and parameters.

Constructor

public SmallWorld(
    Func<TItem, TItem, TDistance> distance,
    IProvideRandomValues generator,
    SmallWorldParameters parameters,
    bool threadSafe = true)

Creates an empty graph. distance is the metric used everywhere the library compares items — smaller must mean closer. generator supplies the randomness for level assignment; pass DefaultRandomGenerator.Instance. parameters is the SmallWorldParameters configuration. Set threadSafe: false to skip the internal reader-writer lock. See Distance functions.

Methods

Name Description
AddItems(items) Inserts a batch of items and returns the integer IDs assigned to them.
AddItems(items, progressReporter) Inserts a batch of items while reporting progress through an IProgressReporter.
KNNSearch(item, k, filterItem, cancellationToken) Returns up to k items closest to the query under the distance function.
GetItem(id) Returns the item stored for a given integer ID.
SerializeGraph(stream) Writes the graph structure (parameters and edges) to a stream.
DeserializeGraph(items, distance, generator, stream, threadSafe) Static. Rebuilds a graph from a stream and the original items.

AddItems

public IReadOnlyList<int> AddItems(IReadOnlyList<TItem> items)

Inserts one batch of items into the graph and returns the integer IDs HNSW assigns to each input. The IDs are returned from KNNSearch and used everywhere the library refers to an item; they are stable for the lifetime of the graph. Call AddItems again to grow the same graph — there is no separate index/query mode. See Building a graph.

AddItems (with progress)

public IReadOnlyList<int> AddItems(
    IReadOnlyList<TItem> items,
    IProgressReporter progressReporter)

Same as AddItems(items), but calls IProgressReporter.Progress from the inserting thread as the batch is processed. total is the count for this call, not the cumulative graph size. See Progress reporting.

KNNSearch

public IList<KNNSearchResult> KNNSearch(
    TItem item,
    int k,
    Func<TItem, bool> filterItem = null,
    CancellationToken cancellationToken = default)

Returns up to k items judged closest to item under the distance function, each as a KNNSearchResult. The list is not pre-sorted — sort by Distance for ranked output. Pass filterItem to keep only candidates that satisfy a predicate; the cancellationToken is only checked when a filter is supplied. See k-NN search and Filtering.

GetItem

public TItem GetItem(int id)

Returns the item stored for the integer ID returned by AddItems. Takes a read lock when the graph is thread-safe.

SerializeGraph

public void SerializeGraph(Stream stream)

Writes the graph structure — parameters and edges — to any Stream as a MessagePack blob with an HNSW header. The vectors themselves are not stored; re-supply them on load. See Serialization.

DeserializeGraph

public static (SmallWorld<TItem, TDistance> graph, int[] missing) DeserializeGraph(
    IReadOnlyList<TItem> items,
    Func<TItem, TItem, TDistance> distance,
    IProvideRandomValues generator,
    Stream stream,
    bool threadSafe = true)

Static factory that rebuilds a graph from a stream. Pass the original items in the same order, the same distance function used at build time, and a random generator. Returns the graph plus a missing array listing any items the file references that weren't supplied — normally empty. InitialDistanceCacheSize is reset to 0 on load. See Serialization and Thread safety.

Properties

Name Description
Parameters The live SmallWorldParameters. Change EfSearch between queries here.
Items A copy of the stored items, taken under a read lock.
UnsafeItems The underlying item list, returned directly with no lock.

Parameters

public SmallWorldParameters Parameters { get; }

The SmallWorldParameters the graph was built with. EfSearch is the runtime dial — assign Parameters.EfSearch between queries to trade recall against latency without rebuilding.

Items

public IReadOnlyList<TItem> Items { get; }

Returns a copy of the stored items under a read lock. Safe to enumerate even while a writer adds more items, at the cost of an allocation. See Thread safety.

UnsafeItems

public IReadOnlyList<TItem> UnsafeItems { get; }

Returns the underlying item list directly, with no lock. Cheap, but you must guarantee no AddItems runs concurrently — enumerating it during a mutation throws. See Thread safety.

Nested types

Name Description
KNNSearchResult A single search hit: ID, item, and distance.

KNNSearchResult

public struct KNNSearchResult

A single result returned by KNNSearch. Exposes Id — the integer ID assigned by AddItems; Item — the original TItem reference; and Distance — the numeric distance from the query.

Applies to

HNSW.Net — see Parameters, Distance functions, and the guides.

© 2026 Curiosity. All rights reserved.