velesdb_core/collection/search/
sparse.rs1use crate::collection::types::Collection;
9use crate::error::{Error, Result};
10use crate::fusion::FusionStrategy;
11use crate::point::SearchResult;
12use crate::sparse_index::{search::sparse_search, SparseVector, DEFAULT_SPARSE_INDEX_NAME};
13
14impl Collection {
15 pub fn sparse_search_default(
21 &self,
22 query: &SparseVector,
23 k: usize,
24 ) -> Result<Vec<SearchResult>> {
25 self.sparse_search_named(query, k, DEFAULT_SPARSE_INDEX_NAME)
26 }
27
28 pub fn sparse_search_named(
34 &self,
35 query: &SparseVector,
36 k: usize,
37 index_name: &str,
38 ) -> Result<Vec<SearchResult>> {
39 let indexes = self.sparse_indexes.read();
40 let index = indexes.get(index_name).ok_or_else(|| {
41 Error::Config(format!(
42 "Sparse index '{}' not found",
43 if index_name.is_empty() {
44 "<default>"
45 } else {
46 index_name
47 }
48 ))
49 })?;
50 let results = sparse_search(index, query, k);
51 drop(indexes);
56 Ok(self.resolve_sparse_results(&results, k))
57 }
58
59 pub fn hybrid_sparse_search(
68 &self,
69 dense_vector: &[f32],
70 sparse_query: &SparseVector,
71 k: usize,
72 strategy: &FusionStrategy,
73 ) -> Result<Vec<SearchResult>> {
74 let candidate_k = k.saturating_mul(2).max(k + 10);
75
76 let (dense_results, sparse_results) = self.execute_both_branches(
77 dense_vector,
78 sparse_query,
79 DEFAULT_SPARSE_INDEX_NAME,
80 candidate_k,
81 None,
82 );
83
84 if dense_results.is_empty() && sparse_results.is_empty() {
85 return Ok(Vec::new());
86 }
87 if dense_results.is_empty() {
88 let scored: Vec<(u64, f32)> = sparse_results
89 .iter()
90 .map(|sd| (sd.doc_id, sd.score))
91 .collect();
92 return Ok(self.resolve_fused_results(&scored, k));
93 }
94 if sparse_results.is_empty() {
95 return Ok(self.resolve_fused_results(&dense_results, k));
96 }
97
98 let sparse_tuples: Vec<(u64, f32)> = sparse_results
99 .iter()
100 .map(|sd| (sd.doc_id, sd.score))
101 .collect();
102
103 let fused = strategy
104 .fuse(vec![dense_results, sparse_tuples])
105 .map_err(|e| Error::Config(format!("Fusion error: {e}")))?;
106
107 Ok(self.resolve_fused_results(&fused, k))
108 }
109}