Skip to content

Commit b32bf33

Browse files
authored
Query all vectors when multivectors are in place (#177)
1 parent fc6632e commit b32bf33

1 file changed

Lines changed: 55 additions & 28 deletions

File tree

‎src/search/from_args.rs‎

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ use qdrant_client::Qdrant;
88
use qdrant_client::qdrant::shard_key::Key;
99
use qdrant_client::qdrant::{
1010
IdfParamsBuilder, PrefetchQueryBuilder, QuantizationSearchParamsBuilder, Query,
11-
QueryBatchPointsBuilder, QueryPointsBuilder, SearchParams, SearchParamsBuilder, SparseIndices,
12-
VectorInput,
11+
QueryBatchPointsBuilder, QueryPointsBuilder, SearchParams, SearchParamsBuilder, VectorInput,
1312
};
1413
use rand::Rng;
1514
use rand::RngExt;
@@ -60,10 +59,7 @@ impl SearchProcessor {
6059
}
6160
}
6261

63-
fn get_sparse_queries(
64-
&self,
65-
rng: &mut impl Rng,
66-
) -> Vec<(Vec<f32>, Option<SparseIndices>, Option<String>)> {
62+
fn get_sparse_queries(&self, rng: &mut impl Rng) -> Vec<(VectorInput, Option<String>)> {
6763
if let Some(sparsity) = self.args.sparse_vectors {
6864
let name = format!(
6965
"{}_sparse",
@@ -77,19 +73,15 @@ impl SearchProcessor {
7773
let sparse_vector_tuples = random_sparse_vector(rng, vocab_size, length);
7874
let (indices, values): (Vec<_>, Vec<_>) =
7975
sparse_vector_tuples.into_iter().unzip();
80-
let sparse_indices = SparseIndices { data: indices };
81-
(values, Some(sparse_indices), Some(name.clone()))
76+
(VectorInput::new_sparse(indices, values), Some(name.clone()))
8277
})
8378
.collect()
8479
} else {
8580
panic!("No sparse vectors configured")
8681
}
8782
}
8883

89-
fn get_dense_queries(
90-
&self,
91-
rng: &mut impl Rng,
92-
) -> Vec<(Vec<f32>, Option<SparseIndices>, Option<String>)> {
84+
fn get_dense_queries(&self, rng: &mut impl Rng) -> Vec<(VectorInput, Option<String>)> {
9385
let name = if self.args.vectors_per_point > 1 {
9486
let name = random_vector_name(rng, self.args.vectors_per_point);
9587
Some(name)
@@ -101,20 +93,26 @@ impl SearchProcessor {
10193

10294
(0..self.args.search_batch_size)
10395
.map(|_| {
104-
(
105-
random_dense_vector(rng, self.args.dim, is_uint),
106-
None,
107-
name.clone(),
108-
)
96+
// With --multivector-size, query with as many sub-vectors as each point holds.
97+
let vector = match self.args.multivector_size {
98+
Some(count) => VectorInput::new_multi(
99+
(0..count)
100+
.map(|_| random_dense_vector(rng, self.args.dim, is_uint))
101+
.collect::<Vec<_>>(),
102+
),
103+
None => {
104+
VectorInput::new_dense(random_dense_vector(rng, self.args.dim, is_uint))
105+
}
106+
};
107+
(vector, name.clone())
109108
})
110109
.collect()
111110
}
112111

113112
fn create_request_builder(
114113
&self,
115114
query_filter: Option<qdrant_client::qdrant::Filter>,
116-
query_vectors: Vec<f32>,
117-
sparse_indices: Option<SparseIndices>,
115+
vector: VectorInput,
118116
vector_name: Option<String>,
119117
search_params: SearchParamsBuilder,
120118
) -> QueryPointsBuilder {
@@ -134,12 +132,6 @@ impl SearchProcessor {
134132
request_builder = request_builder.filter(filter);
135133
}
136134

137-
let vector = if let Some(sparse_indices) = sparse_indices {
138-
VectorInput::new_sparse(sparse_indices.data, query_vectors)
139-
} else {
140-
VectorInput::new_dense(query_vectors)
141-
};
142-
143135
let query = Query::new_nearest(vector);
144136

145137
if let Some(prefetch_limit) = self.args.prefetch {
@@ -246,11 +238,10 @@ impl SearchProcessor {
246238

247239
let query_points: Vec<_> = query_batch
248240
.into_iter()
249-
.map(|(query_vectors, sparse_indices, vector_name)| {
241+
.map(|(vector, vector_name)| {
250242
self.create_request_builder(
251243
query_filter.clone(),
252-
query_vectors,
253-
sparse_indices,
244+
vector,
254245
vector_name,
255246
search_params.clone(),
256247
)
@@ -395,3 +386,39 @@ impl Processor for SearchProcessor {
395386
self.args.search_batch_size
396387
}
397388
}
389+
390+
#[cfg(test)]
391+
mod tests {
392+
use clap::Parser;
393+
use qdrant_client::qdrant::vector_input::Variant;
394+
395+
use super::*;
396+
397+
fn processor(extra: &[&str]) -> SearchProcessor {
398+
let mut argv = vec!["bfb", "--dim", "8"];
399+
argv.extend_from_slice(extra);
400+
let args = Args::parse_from(argv);
401+
SearchProcessor::new(args, Arc::new(AtomicBool::new(false)), vec![], vec![])
402+
}
403+
404+
#[test]
405+
fn dense_query_without_multivector() {
406+
let queries = processor(&[]).get_dense_queries(&mut rand::rng());
407+
match &queries[0].0.variant {
408+
Some(Variant::Dense(v)) => assert_eq!(v.data.len(), 8),
409+
other => panic!("expected a dense query, got {other:?}"),
410+
}
411+
}
412+
413+
#[test]
414+
fn multivector_query_matches_multivector_size() {
415+
let queries = processor(&["--multivector-size", "4"]).get_dense_queries(&mut rand::rng());
416+
match &queries[0].0.variant {
417+
Some(Variant::MultiDense(m)) => {
418+
assert_eq!(m.vectors.len(), 4);
419+
assert!(m.vectors.iter().all(|v| v.data.len() == 8));
420+
}
421+
other => panic!("expected a multivector query, got {other:?}"),
422+
}
423+
}
424+
}

0 commit comments

Comments
 (0)