pub struct HnswService { /* private fields */ }Expand description
Kernel service wrapping the HNSW vector store.
All mutable access to the inner HnswStore is serialized through a
Mutex. Atomic counters track insert and search operations for
observability without requiring the lock.
Implementations§
Source§impl HnswService
impl HnswService
Sourcepub fn new(config: HnswServiceConfig) -> HnswService
pub fn new(config: HnswServiceConfig) -> HnswService
Create a new service with the given configuration.
Sourcepub fn set_chain_manager(&mut self, cm: Arc<ChainManager>)
pub fn set_chain_manager(&mut self, cm: Arc<ChainManager>)
Set the chain manager for exochain event logging.
Sourcepub fn set_governance_engine(&mut self, engine: Arc<GovernanceEngine>)
pub fn set_governance_engine(&mut self, engine: Arc<GovernanceEngine>)
Set the governance engine for gating destructive operations.
Sourcepub fn insert(&self, id: String, embedding: Vec<f32>, metadata: Value)
pub fn insert(&self, id: String, embedding: Vec<f32>, metadata: Value)
Insert an embedding with associated metadata (upsert semantics).
Sourcepub fn current_epoch(&self) -> u64
pub fn current_epoch(&self) -> u64
Return the current monotonic epoch.
Sourcepub fn search(&self, query: &[f32], top_k: usize) -> Vec<HnswSearchResult>
pub fn search(&self, query: &[f32], top_k: usize) -> Vec<HnswSearchResult>
Search for the top_k nearest embeddings to query.
Sourcepub fn search_batch(
&self,
queries: &[&[f32]],
top_k: usize,
) -> Vec<Vec<HnswSearchResult>>
pub fn search_batch( &self, queries: &[&[f32]], top_k: usize, ) -> Vec<Vec<HnswSearchResult>>
Batch search: acquire the lock once, perform all queries, release.
This avoids per-query mutex acquisition overhead when processing multiple embeddings in a single tick (e.g., DEMOCRITUS loop).
Sourcepub fn insert_multi_key(
&self,
primary_id: String,
keys: &[MultiKey],
metadata: Value,
max_keys: usize,
)
pub fn insert_multi_key( &self, primary_id: String, keys: &[MultiKey], metadata: Value, max_keys: usize, )
Insert an entity with multiple search keys.
Each key generates a separate embedding entry in the store, all
sharing the same primary_id prefix. The stored ID has the form
"{primary_id}::{key_type}". This allows the entity to be found
via different query formulations (name, context, description, etc.).
Keys beyond max_keys are silently dropped.
Sourcepub fn search_dedup(&self, query: &[f32], top_k: usize) -> Vec<HnswSearchResult>
pub fn search_dedup(&self, query: &[f32], top_k: usize) -> Vec<HnswSearchResult>
Search with deduplication by primary entity ID.
Because multi-key insertion stores several embeddings for one entity,
a single query may match multiple keys of the same entity. This
method searches for top_k * 3 candidates, deduplicates by
stripping the "::key_type" suffix, and returns up to top_k
unique entities. The best (highest) score among duplicates is kept.
Sourcepub fn insert_count(&self) -> u64
pub fn insert_count(&self) -> u64
Total number of insert operations since service creation.
Sourcepub fn search_count(&self) -> u64
pub fn search_count(&self) -> u64
Total number of search operations since service creation.
Sourcepub fn clear(&self) -> Result<(), String>
pub fn clear(&self) -> Result<(), String>
Replace the inner store with a fresh, empty instance.
Useful for calibration cleanup. Counters are not reset.
Returns Err if the governance engine denies the bulk destruction.
Sourcepub fn config(&self) -> &HnswServiceConfig
pub fn config(&self) -> &HnswServiceConfig
Borrow the service configuration.
Sourcepub fn save_to_file(&self, path: &Path) -> Result<(), Error>
pub fn save_to_file(&self, path: &Path) -> Result<(), Error>
Persist the HNSW store to a JSON file.
Delegates to the underlying HnswStore::save. The HNSW index
graph is not serialized; it will be rebuilt on load.
Sourcepub fn load_from_file(path: &Path) -> Result<HnswService, Error>
pub fn load_from_file(path: &Path) -> Result<HnswService, Error>
Load an HNSW store from a JSON file and create a new service.
Delegates to HnswStore::load. The HNSW index is rebuilt
from the saved entries. Counters start at zero.
Note: chain logging for hnsw.load requires calling
[set_chain_manager] after construction; use
[load_from_file_logged] when a chain manager is available.
Sourcepub fn load_from_file_logged(
path: &Path,
cm: Arc<ChainManager>,
) -> Result<HnswService, Error>
pub fn load_from_file_logged( path: &Path, cm: Arc<ChainManager>, ) -> Result<HnswService, Error>
Load an HNSW store from a JSON file with chain logging.
Same as [load_from_file] but emits an hnsw.load chain event.
Trait Implementations§
Source§impl Debug for HnswService
impl Debug for HnswService
Source§impl SystemService for HnswService
impl SystemService for HnswService
Source§fn service_type(&self) -> ServiceType
fn service_type(&self) -> ServiceType
Source§fn start<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<(), Box<dyn Error + Sync + Send>>> + Send + 'async_trait>>where
'life0: 'async_trait,
HnswService: 'async_trait,
fn start<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<(), Box<dyn Error + Sync + Send>>> + Send + 'async_trait>>where
'life0: 'async_trait,
HnswService: 'async_trait,
Source§fn stop<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<(), Box<dyn Error + Sync + Send>>> + Send + 'async_trait>>where
'life0: 'async_trait,
HnswService: 'async_trait,
fn stop<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<(), Box<dyn Error + Sync + Send>>> + Send + 'async_trait>>where
'life0: 'async_trait,
HnswService: 'async_trait,
Source§fn health_check<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = HealthStatus> + Send + 'async_trait>>where
'life0: 'async_trait,
HnswService: 'async_trait,
fn health_check<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = HealthStatus> + Send + 'async_trait>>where
'life0: 'async_trait,
HnswService: 'async_trait,
Source§fn liveness_check<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ProbeResult> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn liveness_check<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ProbeResult> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
Source§fn readiness_check<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ProbeResult> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn readiness_check<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ProbeResult> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
Auto Trait Implementations§
impl !Freeze for HnswService
impl RefUnwindSafe for HnswService
impl Send for HnswService
impl Sync for HnswService
impl Unpin for HnswService
impl UnsafeUnpin for HnswService
impl UnwindSafe for HnswService
Blanket Implementations§
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
Source§impl<T> GetSetFdFlags for T
impl<T> GetSetFdFlags for T
Source§fn get_fd_flags(&self) -> Result<FdFlags, Error>where
T: AsFilelike,
fn get_fd_flags(&self) -> Result<FdFlags, Error>where
T: AsFilelike,
self file descriptor.Source§fn new_set_fd_flags(&self, fd_flags: FdFlags) -> Result<SetFdFlags<T>, Error>where
T: AsFilelike,
fn new_set_fd_flags(&self, fd_flags: FdFlags) -> Result<SetFdFlags<T>, Error>where
T: AsFilelike,
Source§fn set_fd_flags(&mut self, set_fd_flags: SetFdFlags<T>) -> Result<(), Error>where
T: Sized + AsFilelike,
fn set_fd_flags(&mut self, set_fd_flags: SetFdFlags<T>) -> Result<(), Error>where
T: Sized + AsFilelike,
self file descriptor. Read moreSource§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 more