K-NN search returning up to `k` results. `ef_search` controls the beam width at layer 0 (must be >= k). The returned results are sorted ascending by `exact_asymmetric_distance`.
(&self, query: &[f32], k: usize, ef_search: usize)
| 55 | /// |
| 56 | /// The returned results are sorted ascending by `exact_asymmetric_distance`. |
| 57 | pub fn search(&self, query: &[f32], k: usize, ef_search: usize) -> Vec<CodecSearchResult> { |
| 58 | if self.is_empty() { |
| 59 | return Vec::new(); |
| 60 | } |
| 61 | |
| 62 | let Some(ep) = self.entry_point else { |
| 63 | return Vec::new(); |
| 64 | }; |
| 65 | |
| 66 | let ef = ef_search.max(k); |
| 67 | |
| 68 | // Precompute the query forms used by the two phases. |
| 69 | let q_encoded = self.codec.encode(query); |
| 70 | let q_prepared = self.codec.prepare_query(query); |
| 71 | |
| 72 | // Phase 1: greedy descent through layers max_layer..1. |
| 73 | let mut cur_ep = ep; |
| 74 | for layer in (1..=self.max_layer).rev() { |
| 75 | cur_ep = self.greedy_nearest_search(&q_encoded, cur_ep, layer); |
| 76 | } |
| 77 | |
| 78 | // Phase 2: ef-wide beam search at layer 0. |
| 79 | let candidates = self.search_layer_0(&q_encoded, cur_ep, ef); |
| 80 | |
| 81 | // Rerank top ef_search candidates with exact asymmetric distance. |
| 82 | let mut reranked: Vec<(f32, u32)> = candidates |
| 83 | .into_iter() |
| 84 | .take(ef) |
| 85 | .map(|c| { |
| 86 | let asym = self |
| 87 | .codec |
| 88 | .exact_asymmetric_distance(&q_prepared, &self.nodes[c.idx as usize].quantized); |
| 89 | (asym, self.nodes[c.idx as usize].id) |
| 90 | }) |
| 91 | .collect(); |
| 92 | |
| 93 | reranked.sort_unstable_by(|a, b| a.0.total_cmp(&b.0)); |
| 94 | reranked.truncate(k); |
| 95 | |
| 96 | reranked |
| 97 | .into_iter() |
| 98 | .map(|(distance, id)| CodecSearchResult { id, distance }) |
| 99 | .collect() |
| 100 | } |
| 101 | |
| 102 | /// Greedy single-nearest descent at `layer` using the pre-encoded query. |
| 103 | fn greedy_nearest_search(&self, q_enc: &C::Quantized, ep_idx: u32, layer: usize) -> u32 { |