(
index: &HnswIndex,
query: &[f32],
neighbors_1hop: &[u32],
allowed: &RoaringBitmap,
ef: usize,
metric: nodedb_types::vector_distance::DistanceMetric,
visited: &mut HashSet
| 399 | /// adding to heaps only IDs that are in `allowed`. |
| 400 | #[allow(clippy::too_many_arguments)] |
| 401 | fn expand_blind( |
| 402 | index: &HnswIndex, |
| 403 | query: &[f32], |
| 404 | neighbors_1hop: &[u32], |
| 405 | allowed: &RoaringBitmap, |
| 406 | ef: usize, |
| 407 | metric: nodedb_types::vector_distance::DistanceMetric, |
| 408 | visited: &mut HashSet<u32>, |
| 409 | candidates: &mut BinaryHeap<Reverse<Candidate>>, |
| 410 | results: &mut BinaryHeap<Candidate>, |
| 411 | ) { |
| 412 | for &nb1 in neighbors_1hop { |
| 413 | // Mark 1-hop as visited so we do not double-score them later, |
| 414 | // but do not score them — that is the Blind heuristic. |
| 415 | visited.insert(nb1); |
| 416 | |
| 417 | for &nb2 in index.neighbors_at(nb1, 0) { |
| 418 | if !visited.insert(nb2) { |
| 419 | continue; |
| 420 | } |
| 421 | if index.is_deleted(nb2) { |
| 422 | continue; |
| 423 | } |
| 424 | if !allowed.contains(nb2) { |
| 425 | continue; |
| 426 | } |
| 427 | let d = dist(index, query, nb2, metric); |
| 428 | let nb2_cand = Candidate { dist: d, id: nb2 }; |
| 429 | let worst_dist = results.peek().map_or(f32::INFINITY, |w| w.dist); |
| 430 | if d < worst_dist || results.len() < ef { |
| 431 | candidates.push(Reverse(nb2_cand)); |
| 432 | } |
| 433 | results.push(nb2_cand); |
| 434 | if results.len() > ef { |
| 435 | results.pop(); |
| 436 | } |
| 437 | } |
| 438 | } |
| 439 | } |
| 440 | |
| 441 | /// Inline helper: distance from query to a stored node using the given metric. |
| 442 | #[inline] |
no test coverage detected