Embeddings embeddingindex save - CyrilB1531/lodestar GitHub Wiki

Development build. This page describes main, not a released package. The latest published Lodestar.Embeddings is 0.8.0 — read its documentation.

Home › Embeddings › Vector search

EmbeddingIndex.Save

Writes the index — configuration, ids and the vector block — out as UTF-8 JSON.

public void Save(Stream destination)
public void Save(string path)

Parameters — destination is a writable stream, flushed but never disposed: the caller owns it. path is a file to create or overwrite, written UTF-8 without a byte-order mark.

Returns — nothing.

Exceptions — ArgumentException when the stream cannot be written to, refused before the vectors and ids are checked (#1641), and when an id is beyond what the JSON writer can write — the writer's own, as 0.8.0 raised it, refused before the first byte, once the writer has accepted the stream or the file is open (#1618, #1646). IndexOutOfRangeException, the writer's own as well, for a string whose escaped form passes its buffer, as 0.8.0 raised it. ArgumentNullException when destination or path is null. InvalidDataException when any stored vector holds a non-finite component; the message names the item and the component. InvalidOperationException when the vector block, base64-encoded, is longer than the one array a load decodes it into — refused before the path is opened, so a file it would replace is left whole (#1322). IOException from the stream or file system.

Example — a round trip through memory, ids and all.

using Lodestar.Embeddings.Search;

var index = new EmbeddingIndex(dimension: 2);
index.Add(new float[] { 1f, 0f }, "east");

using var buffer = new MemoryStream();
index.Save(buffer);
buffer.Position = 0;

EmbeddingIndex restored = EmbeddingIndex.Load(buffer);
string label = restored.GetId(0)!;  // => east

Remarks — vectors are written as base64 raw little-endian bits, not as decimal text, so a reload scores bit for bit what the original scored. A decimal round trip that lost the last bit of a float would change scores by an amount too small to notice and too large to be nothing.

A non-finite component is refused here though Add accepted it. A NaN in memory is a wrong score you can still find; in a file it becomes a wrong score that outlives the code that made it, scoring NaN against every query the reloaded index is ever given.

The path overload checks for that before it opens the file. Truncating a good artifact and then refusing to write is the failure mode that would cost you the index you already had, so the check comes first and a refused save leaves the existing file untouched.

An index past 1,000,000 vectors saves, but loads only with a raised MaxArrayLength: a load holds the vector count to ArtifactLoadOptions' MaxArrayLength, whose default is 1,000,000. Save does not check it, since the ceiling is the reader's to choose.

The stream overload leaves destination open, so an index can be one entry inside a larger archive.

Applies to — net10.0, netstandard2.0.

See also — EmbeddingIndex.Load, EmbeddingIndex.SaveAsync, EmbeddingIndex.