pub struct HnswIndex { /* private fields */ }Expand description
Hierarchical Navigable Small World graph index.
- FP32 construction for structural integrity
- Heuristic neighbor selection (Algorithm 4)
- Beam search with configurable ef parameter
Implementations§
Source§impl HnswIndex
impl HnswIndex
Sourcepub fn hnsw_neighbors_layer0(&self, node_id: u32) -> Vec<u32>
pub fn hnsw_neighbors_layer0(&self, node_id: u32) -> Vec<u32>
Return the layer-0 neighbor list of node_id, or an empty slice if
the node does not exist or has no layer-0 neighbors.
Used by LirePatcher for local topology-drift estimation.
Source§impl HnswIndex
impl HnswIndex
Sourcepub fn insert(&mut self, vector: Vec<f32>) -> Result<(), VectorError>
pub fn insert(&mut self, vector: Vec<f32>) -> Result<(), VectorError>
Insert a vector into the index.
- Assign a random layer using the exponential distribution
- Greedily descend from the entry point to the new node’s layer + 1
- At each layer from the node’s layer down to 0, search for nearest neighbors, select via the diversity heuristic, and add bidirectional edges
- Prune over-connected nodes to maintain the M/M0 invariant
Source§impl HnswIndex
impl HnswIndex
Sourcepub fn graph_checkpoint_to_bytes(&self) -> Result<Vec<u8>, VectorError>
pub fn graph_checkpoint_to_bytes(&self) -> Result<Vec<u8>, VectorError>
Serialize ONLY the graph topology (neighbors, entry point, params) to
rkyv bytes. Vector data is intentionally omitted — node_vectors is
filled with empty Vec<f32> placeholders.
Pair with [Self::from_graph_checkpoint] on restore. The same
RKHNS\0 magic and version byte are used so from_checkpoint can
decode the bytes, but the resulting index has empty node storage.
This is the Lite pagedb-segment write path: vectors live in the segment, graph topology lives in the B+ tree. Origin never calls this method.
Sourcepub fn checkpoint_to_bytes(&self) -> Result<Vec<u8>, VectorError>
pub fn checkpoint_to_bytes(&self) -> Result<Vec<u8>, VectorError>
Serialize the index to rkyv bytes (with magic header) for storage.
Magic header RKHNS\0 allows from_checkpoint to detect format.
Sourcepub fn from_checkpoint(bytes: &[u8]) -> Result<Option<HnswIndex>, VectorError>
pub fn from_checkpoint(bytes: &[u8]) -> Result<Option<HnswIndex>, VectorError>
Restore an index from a checkpoint snapshot.
Returns:
Ok(Some(index))— successfully decoded (rkyv format).Ok(None)— bytes do not start with theRKHNS\0magic header.Err(VectorError::UnsupportedVersion)— magic matchesRKHNS\0but the version byte is notHNSW_FORMAT_VERSION; the caller must reject the buffer.Err(VectorError::CheckpointDeserializationError)— magic and version matched but the rkyv payload itself failed to decode (structurally corrupt checkpoint).
Source§impl HnswIndex
impl HnswIndex
Sourcepub fn with_backing(
&mut self,
b: Arc<dyn VectorSegmentBacking>,
) -> Result<&mut HnswIndex, VectorError>
pub fn with_backing( &mut self, b: Arc<dyn VectorSegmentBacking>, ) -> Result<&mut HnswIndex, VectorError>
Attach a crate::segment_backing::VectorSegmentBacking to this index.
After this succeeds, dist_to_node falls back to the backing whenever an
F32 node’s local vector storage is empty. This is used by Lite’s
graph-checkpoint-only restore path: the graph topology is loaded from the
B+ tree blob, but vector data lives in a pagedb segment.
Origin never calls this — its node arenas are always populated.
§Errors
The backing is validated against this index BEFORE being attached, and is not attached at all when it cannot serve every node whose local storage is empty. An attached-but-unserviceable backing is the worst outcome available: the graph looks healthy, so search proceeds and then finds no vector for a node it must score. Callers should treat an error as “this segment is unusable — rebuild the index from the authoritative vectors, or leave the collection unloaded”, never as something to ignore.
VectorError::StoredDimensionMismatchif the backing’sdim()is not this index’sdim.VectorError::VectorUnavailableif the backing holds fewer vectors than the index has nodes, or if a node that needs the backing has no correctly-sized vector in it.
Source§impl HnswIndex
impl HnswIndex
Sourcepub fn compact(&mut self) -> usize
pub fn compact(&mut self) -> usize
Compact the index by removing all tombstoned nodes.
Returns the number of removed nodes. See compact_with_map for the
variant that also returns the old→new id remapping.
Sourcepub fn compact_with_map(&mut self) -> (usize, Vec<u32>)
pub fn compact_with_map(&mut self) -> (usize, Vec<u32>)
Compact and return both the removed count and the old→new id map.
id_map[old_local] = new_local, or u32::MAX if the node was
tombstoned (removed). Repairs edges so the entry point reaches every
remaining node.
Source§impl HnswIndex
impl HnswIndex
Sourcepub fn new(dim: usize, params: HnswParams) -> HnswIndex
pub fn new(dim: usize, params: HnswParams) -> HnswIndex
Create a new empty HNSW index.
Sourcepub fn with_seed(dim: usize, params: HnswParams, seed: u64) -> HnswIndex
pub fn with_seed(dim: usize, params: HnswParams, seed: u64) -> HnswIndex
Create with a specific RNG seed (for deterministic testing).
Sourcepub fn metric(&self) -> DistanceMetric
pub fn metric(&self) -> DistanceMetric
The distance metric this index was built with. Search-time metric overrides must match this; differing metrics require either rebuilding the index or a metric-aware re-rank pass.
pub fn params(&self) -> &HnswParams
pub fn dim(&self) -> usize
Sourcepub fn dtype(&self) -> VectorStorageDtype
pub fn dtype(&self) -> VectorStorageDtype
Storage dtype this index was constructed with.
pub fn entry_point(&self) -> Option<u32>
pub fn max_layer(&self) -> usize
Sourcepub fn memory_usage_bytes(&self) -> usize
pub fn memory_usage_bytes(&self) -> usize
Approximate memory usage in bytes (vector data + neighbor lists).
Source§impl HnswIndex
impl HnswIndex
pub fn len(&self) -> usize
pub fn live_count(&self) -> usize
pub fn tombstone_count(&self) -> usize
Sourcepub fn tombstone_ratio(&self) -> f64
pub fn tombstone_ratio(&self) -> f64
Tombstone ratio: fraction of nodes that are deleted.
pub fn is_empty(&self) -> bool
pub fn is_deleted(&self, id: u32) -> bool
pub fn undelete(&mut self, id: u32) -> bool
Source§impl HnswIndex
impl HnswIndex
Sourcepub fn get_vector(&self, id: u32) -> Option<&[f32]>
pub fn get_vector(&self, id: u32) -> Option<&[f32]>
Returns a &[f32] view of the stored vector for node id.
Returns Some only when the index dtype is F32. For F16 or BF16
indexes this method returns None — use Self::get_vector_bytes
instead and decode via crate::dtype::cast_to_f32 if an f32 view is
needed.
In debug builds, calling this on a non-F32 index triggers a
debug_assert! to flag misuse early. In release builds the
debug_assert! is a no-op and None is returned silently.
Sourcepub fn get_vector_bytes(&self, id: u32) -> Option<&[u8]>
pub fn get_vector_bytes(&self, id: u32) -> Option<&[u8]>
Dtype-agnostic byte view of the stored vector for node id.
Returns None if id is out of range. Pair the returned slice with
Self::dtype to interpret the encoding.
Sourcepub fn get_vector_or_backing(&self, id: u32) -> Option<Cow<'_, [f32]>>
pub fn get_vector_or_backing(&self, id: u32) -> Option<Cow<'_, [f32]>>
Returns the stored f32 vector for node id, consulting the pagedb
segment backing when the node’s local storage is empty.
This is the rerank-safe accessor. It covers both cases that reading
node.storage directly gets wrong:
- Lite’s graph-checkpoint-only restore path: after
from_checkpoint+with_backing, per-node vectors are empty placeholders and the data must be fetched through the backing. - A narrower storage dtype (F16/BF16): the node holds encoded bytes, not
f32, so the vector is decoded into an owned
Cow.
Returns None when id is out of range, or the node has no local vector
and no backing supplies one. Decode failure also yields None — callers
needing the reason should use Self::materialize_vector.
Only available on non-WASM targets (the backing type requires mmap).
Sourcepub fn materialize_vector(&self, id: u32) -> Result<Vec<f32>, VectorError>
pub fn materialize_vector(&self, id: u32) -> Result<Vec<f32>, VectorError>
Materialize node id’s vector as an owned Vec<f32>, consulting the
segment backing when the node’s local storage is empty.
This is the authoritative accessor for every caller that copies vector
data out of the index — segment serialization, checkpointing, snapshot
export, parameter rebuilds. Reading node.storage directly is wrong on
the graph-checkpoint-only restore path, where per-node storage is an
empty placeholder and the real data lives in the attached backing.
§Errors
VectorError::VectorUnavailableifidis out of range, or local storage is empty and no backing provides the vector.VectorError::VectorDecodeFailedif dtype-encoded bytes cannot be decoded to f32.VectorError::StoredDimensionMismatchif the materialized vector’s length is notself.dim.
Sourcepub fn extract_vectors_and_surrogates(
&self,
) -> Result<(Vec<Vec<f32>>, Vec<u64>), VectorError>
pub fn extract_vectors_and_surrogates( &self, ) -> Result<(Vec<Vec<f32>>, Vec<u64>), VectorError>
Extract all node vectors as owned F32 vecs for segment serialization.
The second tuple element is always empty — HnswIndex has no surrogate
map. Surrogates live at the VectorCollection layer in Origin. Lite
passes an empty slice so write_vector_segment writes no surrogate block.
§Errors
Propagates Self::materialize_vector for the first node whose vector
cannot be materialized. Serializing an empty or partial payload would
write a segment whose header declares vectors it does not contain, so
this fails loudly instead.
Sourcepub fn export_vectors(&self) -> Result<Vec<Vec<f32>>, VectorError>
pub fn export_vectors(&self) -> Result<Vec<Vec<f32>>, VectorError>
Export all vectors as F32 for snapshot transfer.
For F32 indexes this is a clone. For F16/BF16 indexes each vector is decoded to F32 on the fly. Nodes whose local storage is empty are read through the attached segment backing.
§Errors
Propagates Self::materialize_vector for the first node whose vector
cannot be materialized. A caller copying vectors out of the index cannot
use an empty placeholder, so this reports the failure rather than
yielding one.
Source§impl HnswIndex
impl HnswIndex
Sourcepub fn search(
&self,
query: &[f32],
k: usize,
ef: usize,
) -> Result<Vec<SearchResult>, VectorError>
pub fn search( &self, query: &[f32], k: usize, ef: usize, ) -> Result<Vec<SearchResult>, VectorError>
K-NN search: find the k closest vectors to query.
ef controls the search beam width (higher = better recall, slower).
Must be >= k. Typical values: ef = 2k to 10k.
Returns VectorError::DimensionMismatch when query does not have
the index dimension.
Sourcepub fn search_filtered(
&self,
query: &[f32],
k: usize,
ef: usize,
filter: &RoaringBitmap,
) -> Result<Vec<SearchResult>, VectorError>
pub fn search_filtered( &self, query: &[f32], k: usize, ef: usize, filter: &RoaringBitmap, ) -> Result<Vec<SearchResult>, VectorError>
Filtered K-NN search with Roaring bitmap pre-filtering.
Sourcepub fn search_filtered_offset(
&self,
query: &[f32],
k: usize,
ef: usize,
filter: &RoaringBitmap,
id_offset: u32,
) -> Result<Vec<SearchResult>, VectorError>
pub fn search_filtered_offset( &self, query: &[f32], k: usize, ef: usize, filter: &RoaringBitmap, id_offset: u32, ) -> Result<Vec<SearchResult>, VectorError>
Filtered K-NN search where the bitmap is keyed in a shifted ID space.
id_offset is added to local node IDs before testing filter.contains.
Used by multi-segment collections where the bitmap holds GLOBAL ids
and each segment’s HNSW nodes are numbered starting at base_id.
Sourcepub fn search_with_bitmap_bytes(
&self,
query: &[f32],
k: usize,
ef: usize,
bitmap_bytes: &[u8],
) -> Result<Vec<SearchResult>, VectorError>
pub fn search_with_bitmap_bytes( &self, query: &[f32], k: usize, ef: usize, bitmap_bytes: &[u8], ) -> Result<Vec<SearchResult>, VectorError>
Deserialize a Roaring bitmap from bytes and perform filtered search.
Sourcepub fn search_with_bitmap_bytes_offset(
&self,
query: &[f32],
k: usize,
ef: usize,
bitmap_bytes: &[u8],
id_offset: u32,
) -> Result<Vec<SearchResult>, VectorError>
pub fn search_with_bitmap_bytes_offset( &self, query: &[f32], k: usize, ef: usize, bitmap_bytes: &[u8], id_offset: u32, ) -> Result<Vec<SearchResult>, VectorError>
Deserialize a Roaring bitmap and search with an ID offset applied
before testing membership. See search_filtered_offset for rationale.
Bytes that do not decode fail with
VectorError::InvalidFilterBitmap: an unfiltered search would
return rows the filter excludes.
Auto Trait Implementations§
impl !Freeze for HnswIndex
impl !RefUnwindSafe for HnswIndex
impl !Sync for HnswIndex
impl !UnwindSafe for HnswIndex
impl Send for HnswIndex
impl Unpin for HnswIndex
impl UnsafeUnpin for HnswIndex
Blanket Implementations§
Source§impl<T> ArchivePointee for T
impl<T> ArchivePointee for T
Source§type ArchivedMetadata = ()
type ArchivedMetadata = ()
Source§fn pointer_metadata(
_: &<T as ArchivePointee>::ArchivedMetadata,
) -> <T as Pointee>::Metadata
fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> LayoutRaw for T
impl<T> LayoutRaw for T
Source§fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
Source§impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
Source§unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
Source§fn resolve_niched(out: Place<NichedOption<T, N1>>)
fn resolve_niched(out: Place<NichedOption<T, N1>>)
out indicating that a T is niched.Source§impl<T> Paint for Twhere
T: ?Sized,
impl<T> Paint for Twhere
T: ?Sized,
Source§fn fg(&self, value: Color) -> Painted<&T>
fn fg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the foreground set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like red() and
green(), which have the same functionality but are
pithier.
§Example
Set foreground color to white using fg():
use yansi::{Paint, Color};
painted.fg(Color::White);Set foreground color to white using white().
use yansi::Paint;
painted.white();Source§fn bright_black(&self) -> Painted<&T>
fn bright_black(&self) -> Painted<&T>
Source§fn bright_red(&self) -> Painted<&T>
fn bright_red(&self) -> Painted<&T>
Source§fn bright_green(&self) -> Painted<&T>
fn bright_green(&self) -> Painted<&T>
Source§fn bright_yellow(&self) -> Painted<&T>
fn bright_yellow(&self) -> Painted<&T>
Source§fn bright_blue(&self) -> Painted<&T>
fn bright_blue(&self) -> Painted<&T>
Source§fn bright_magenta(&self) -> Painted<&T>
fn bright_magenta(&self) -> Painted<&T>
Source§fn bright_cyan(&self) -> Painted<&T>
fn bright_cyan(&self) -> Painted<&T>
Source§fn bright_white(&self) -> Painted<&T>
fn bright_white(&self) -> Painted<&T>
Source§fn bg(&self, value: Color) -> Painted<&T>
fn bg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the background set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like on_red() and
on_green(), which have the same functionality but
are pithier.
§Example
Set background color to red using fg():
use yansi::{Paint, Color};
painted.bg(Color::Red);Set background color to red using on_red().
use yansi::Paint;
painted.on_red();Source§fn on_primary(&self) -> Painted<&T>
fn on_primary(&self) -> Painted<&T>
Source§fn on_magenta(&self) -> Painted<&T>
fn on_magenta(&self) -> Painted<&T>
Source§fn on_bright_black(&self) -> Painted<&T>
fn on_bright_black(&self) -> Painted<&T>
Source§fn on_bright_red(&self) -> Painted<&T>
fn on_bright_red(&self) -> Painted<&T>
Source§fn on_bright_green(&self) -> Painted<&T>
fn on_bright_green(&self) -> Painted<&T>
Source§fn on_bright_yellow(&self) -> Painted<&T>
fn on_bright_yellow(&self) -> Painted<&T>
Source§fn on_bright_blue(&self) -> Painted<&T>
fn on_bright_blue(&self) -> Painted<&T>
Source§fn on_bright_magenta(&self) -> Painted<&T>
fn on_bright_magenta(&self) -> Painted<&T>
Source§fn on_bright_cyan(&self) -> Painted<&T>
fn on_bright_cyan(&self) -> Painted<&T>
Source§fn on_bright_white(&self) -> Painted<&T>
fn on_bright_white(&self) -> Painted<&T>
Source§fn attr(&self, value: Attribute) -> Painted<&T>
fn attr(&self, value: Attribute) -> Painted<&T>
Enables the styling Attribute value.
This method should be used rarely. Instead, prefer to use
attribute-specific builder methods like bold() and
underline(), which have the same functionality
but are pithier.
§Example
Make text bold using attr():
use yansi::{Paint, Attribute};
painted.attr(Attribute::Bold);Make text bold using using bold().
use yansi::Paint;
painted.bold();Source§fn rapid_blink(&self) -> Painted<&T>
fn rapid_blink(&self) -> Painted<&T>
Source§fn quirk(&self, value: Quirk) -> Painted<&T>
fn quirk(&self, value: Quirk) -> Painted<&T>
Enables the yansi Quirk value.
This method should be used rarely. Instead, prefer to use quirk-specific
builder methods like mask() and
wrap(), which have the same functionality but are
pithier.
§Example
Enable wrapping using .quirk():
use yansi::{Paint, Quirk};
painted.quirk(Quirk::Wrap);Enable wrapping using wrap().
use yansi::Paint;
painted.wrap();Source§fn clear(&self) -> Painted<&T>
👎Deprecated since 1.0.1: renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
fn clear(&self) -> Painted<&T>
renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
Source§fn whenever(&self, value: Condition) -> Painted<&T>
fn whenever(&self, value: Condition) -> Painted<&T>
Conditionally enable styling based on whether the Condition value
applies. Replaces any previous condition.
See the crate level docs for more details.
§Example
Enable styling painted only when both stdout and stderr are TTYs:
use yansi::{Paint, Condition};
painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);Source§impl<T> Pointable for T
impl<T> Pointable for T
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.