velesdb_core/collection/search/
sparse.rs1use super::resolve;
9use crate::collection::types::Collection;
10use crate::error::{Error, Result};
11use crate::fusion::FusionStrategy;
12use crate::point::SearchResult;
13use crate::sparse_index::{search::sparse_search, SparseVector, DEFAULT_SPARSE_INDEX_NAME};
14
15impl Collection {
16 pub fn sparse_search_default(
22 &self,
23 query: &SparseVector,
24 k: usize,
25 ) -> Result<Vec<SearchResult>> {
26 self.sparse_search_named(query, k, DEFAULT_SPARSE_INDEX_NAME)
27 }
28
29 pub fn sparse_search_named(
35 &self,
36 query: &SparseVector,
37 k: usize,
38 index_name: &str,
39 ) -> Result<Vec<SearchResult>> {
40 let indexes = self.sparse_indexes.read();
41 let index = indexes
42 .get(index_name)
43 .ok_or_else(|| resolve::sparse_index_not_found(index_name))?;
44 let results = sparse_search(index, query, k);
45 drop(indexes);
50 Ok(self.resolve_sparse_results(&results, k))
51 }
52
53 pub fn hybrid_sparse_search(
62 &self,
63 dense_vector: &[f32],
64 sparse_query: &SparseVector,
65 k: usize,
66 strategy: &FusionStrategy,
67 ) -> Result<Vec<SearchResult>> {
68 self.hybrid_sparse_search_inner(
69 dense_vector,
70 sparse_query,
71 k,
72 strategy,
73 None,
74 DEFAULT_SPARSE_INDEX_NAME,
75 )
76 }
77
78 pub fn hybrid_sparse_search_with_filter(
87 &self,
88 dense_vector: &[f32],
89 sparse_query: &SparseVector,
90 k: usize,
91 strategy: &FusionStrategy,
92 filter: &crate::filter::Filter,
93 ) -> Result<Vec<SearchResult>> {
94 self.hybrid_sparse_search_inner(
95 dense_vector,
96 sparse_query,
97 k,
98 strategy,
99 Some(filter),
100 DEFAULT_SPARSE_INDEX_NAME,
101 )
102 }
103
104 pub fn hybrid_sparse_search_named(
113 &self,
114 dense_vector: &[f32],
115 sparse_query: &SparseVector,
116 k: usize,
117 strategy: &FusionStrategy,
118 index_name: &str,
119 ) -> Result<Vec<SearchResult>> {
120 self.hybrid_sparse_search_inner(dense_vector, sparse_query, k, strategy, None, index_name)
121 }
122
123 pub fn hybrid_sparse_search_named_with_filter(
132 &self,
133 dense_vector: &[f32],
134 sparse_query: &SparseVector,
135 k: usize,
136 strategy: &FusionStrategy,
137 index_name: &str,
138 filter: &crate::filter::Filter,
139 ) -> Result<Vec<SearchResult>> {
140 self.hybrid_sparse_search_inner(
141 dense_vector,
142 sparse_query,
143 k,
144 strategy,
145 Some(filter),
146 index_name,
147 )
148 }
149
150 fn hybrid_sparse_search_inner(
152 &self,
153 dense_vector: &[f32],
154 sparse_query: &SparseVector,
155 k: usize,
156 strategy: &FusionStrategy,
157 filter: Option<&crate::filter::Filter>,
158 index_name: &str,
159 ) -> Result<Vec<SearchResult>> {
160 let candidate_k = k.saturating_mul(2).max(k.saturating_add(10));
161
162 let (dense_results, sparse_results) =
163 self.execute_both_branches(dense_vector, sparse_query, index_name, candidate_k, filter);
164
165 if dense_results.is_empty() && sparse_results.is_empty() {
166 return Ok(Vec::new());
167 }
168 if dense_results.is_empty() {
169 let scored: Vec<(u64, f32)> = sparse_results
170 .iter()
171 .map(|sd| (sd.doc_id, sd.score))
172 .collect();
173 return Ok(self.resolve_fused_results(&scored, k));
174 }
175 if sparse_results.is_empty() {
176 return Ok(self.resolve_fused_results(&dense_results, k));
177 }
178
179 let sparse_tuples: Vec<(u64, f32)> = sparse_results
180 .iter()
181 .map(|sd| (sd.doc_id, sd.score))
182 .collect();
183
184 let fused = strategy
185 .fuse(vec![dense_results, sparse_tuples])
186 .map_err(|e| Error::Config(format!("Fusion error: {e}")))?;
187
188 Ok(self.resolve_fused_results(&fused, k))
189 }
190}