MCPcopy Create free account
hub / github.com/NodeDB-Lab/nodedb / patch

Method patch

nodedb-vector/src/delta/compaction.rs:83–154  ·  view source on GitHub ↗

Flush the delta buffer into the main HNSW. ## Steps 1. Drain tombstones → call `HnswIndex::delete` on each. 2. Drain fresh vectors → call `HnswIndex::insert` on each. 3. After each insert, estimate local topology drift for the newly assigned node and accumulate the overlap fraction. 4. If average overlap fraction < `drift_threshold`, increment `drift_subgraphs`. `k_neighbors` and `ef_constructi

(
        &mut self,
        _k_neighbors: usize,
        _ef_construction: usize,
    )

Source from the content-addressed store, hash-verified

81 /// current HNSW implementation derives its own neighbor count from
82 /// `HnswParams` stored on the index, so these values are informational.
83 pub fn patch(
84 &mut self,
85 _k_neighbors: usize,
86 _ef_construction: usize,
87 ) -> Result<PatchStats, VectorError> {
88 let mut stats = PatchStats::default();
89
90 // --- Step 1: Forward tombstones to the main HNSW ---
91 let tombstone_ids = self.delta.drain_tombstones();
92 for id in tombstone_ids {
93 if self.main.delete(id) {
94 stats.tombstoned_marked += 1;
95 }
96 }
97
98 // --- Step 2 + 3: Insert fresh vectors and estimate drift ---
99 let fresh = self.delta.drain_fresh();
100
101 // Collect the node IDs that will be assigned to freshly inserted nodes
102 // so we can measure neighborhood overlap after each insert.
103 // The HNSW appends nodes sequentially, so the new id = len() before insert.
104 let mut overlap_fractions: Vec<f32> = Vec::with_capacity(fresh.len());
105 // Track the set of recently-patched node ids for overlap estimation.
106 let mut patched_ids: std::collections::HashSet<u32> =
107 std::collections::HashSet::with_capacity(fresh.len());
108
109 for (user_id, vector) in fresh {
110 // Skip tombstoned fresh inserts — they were deleted before we
111 // could patch them.
112 if self.delta.is_tombstoned(user_id) {
113 continue;
114 }
115
116 // The HNSW uses its own internal monotonic IDs (insertion order).
117 // We record what the next id will be before the insert.
118 let new_internal_id = self.main.len() as u32;
119
120 self.main.insert(vector)?;
121 stats.patched += 1;
122
123 // --- Drift estimation (LIRE approximation) ---
124 // Inspect neighbors assigned to the new node at layer 0.
125 let neighbors_l0 = self.main.hnsw_neighbors_layer0(new_internal_id);
126
127 let overlap_fraction = if neighbors_l0.is_empty() {
128 // First node or isolated — perfect connectivity by definition.
129 1.0f32
130 } else {
131 // Count how many neighbors are themselves in the current
132 // patched-ids set (i.e., recently inserted into this batch).
133 let overlap = neighbors_l0
134 .iter()
135 .filter(|&&nid| patched_ids.contains(&nid))
136 .count();
137 overlap as f32 / neighbors_l0.len() as f32
138 };
139
140 overlap_fractions.push(overlap_fraction);

Calls 12

drain_tombstonesMethod · 0.80
drain_freshMethod · 0.80
hnsw_neighbors_layer0Method · 0.80
deleteMethod · 0.45
lenMethod · 0.45
is_tombstonedMethod · 0.45
insertMethod · 0.45
is_emptyMethod · 0.45
countMethod · 0.45
iterMethod · 0.45
containsMethod · 0.45
pushMethod · 0.45