///|
/// Maintenance operations for ANN indices
/// - HNSW compaction: Remove deleted entries and rebuild the graph
/// - IVF retraining: Recompute centroids and reassign vectors
///|
/// Compact HNSW index by removing tombstoned entries and rebuilding
/// Returns the number of removed entries
pub fn hnsw_compact_and_rebuild(
state : HNSWState,
store : @store.CoreStore,
) -> (HNSWState, Int) {
let n = store.size()
if n == 0 {
return (state, 0)
}
// Count alive vectors
let mut alive = 0
for i in 0..= state.tombstone.length() || !state.tombstone[i] {
alive = alive + 1
}
}
if alive == n {
return (state, 0)
}
// Create new HNSW state (use default seed 42 for rebuild)
let new_state = HNSWState::new(
@types.HNSWParams::{
m: state.m,
ef_construction: state.ef_construction,
ef_search: state.ef_search,
level_mult: state.level_mult,
seed: 42UL,
allow_replace_deleted: state.allow_replace_deleted,
},
state.metric,
if alive > 0 {
alive
} else {
1
},
)
// Re-add non-tombstoned vectors, mark skipped as tombstoned
for i in 0.. Int {
if store.size() == 0 {
return 0
}
// Train new centroids
ivf_train(state, store, iterations~)
// Clear existing lists
for list in state.lists {
list.clear()
}
state.id_to_list.clear()
// Reassign all vectors to new centroids using ivf_assign (no bootstrap)
let mut reassigned = 0
for i in 0.. IVFState {
let state = IVFState::new(params, metric, store.dim)
if store.size() > 0 {
ivf_train(state, store, iterations~)
// Use ivf_assign to assign vectors to trained centroids (no bootstrap)
for i in 0.. HNSWState {
let cap = if store.size() > 0 { store.size() } else { 1 }
let state = HNSWState::new(params, metric, cap)
for i in 0.. (Int, Int) {
let n = store.size()
let mut dead = 0
for i in 0..