hermes_core/query/vector/
dense.rs1use crate::dsl::Field;
4use crate::segment::SegmentReader;
5
6use super::VectorResultScorer;
7use super::combiner::MultiValueCombiner;
8use crate::query::traits::{CountFuture, Query, Scorer, ScorerFuture};
9
10pub const MAX_DENSE_NPROBE: usize = 4096;
16
17pub const MAX_DENSE_RERANK_FACTOR: f32 = 32.0;
22
23#[derive(Debug, Clone)]
25pub struct DenseVectorQuery {
26 pub field: Field,
28 pub vector: Vec<f32>,
30 pub nprobe: usize,
32 pub rerank_factor: f32,
34 pub combiner: MultiValueCombiner,
36}
37
38impl std::fmt::Display for DenseVectorQuery {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 write!(
41 f,
42 "Dense({}, dim={}, nprobe={}, rerank={})",
43 self.field.0,
44 self.vector.len(),
45 self.nprobe,
46 self.rerank_factor
47 )
48 }
49}
50
51impl DenseVectorQuery {
52 pub fn new(field: Field, vector: Vec<f32>) -> Self {
54 Self {
55 field,
56 vector,
57 nprobe: 32,
58 rerank_factor: 3.0,
59 combiner: MultiValueCombiner::Max,
60 }
61 }
62
63 pub fn with_nprobe(mut self, nprobe: usize) -> Self {
68 self.nprobe = nprobe;
69 self
70 }
71
72 pub fn with_rerank_factor(mut self, factor: f32) -> Self {
77 self.rerank_factor = factor;
78 self
79 }
80
81 pub fn with_combiner(mut self, combiner: MultiValueCombiner) -> Self {
83 self.combiner = combiner;
84 self
85 }
86}
87
88impl Query for DenseVectorQuery {
89 fn scorer<'a>(&self, reader: &'a SegmentReader, limit: usize) -> ScorerFuture<'a> {
90 let field = self.field;
91 let vector = self.vector.clone();
92 let nprobe = self.nprobe;
93 let rerank_factor = self.rerank_factor;
94 let combiner = self.combiner;
95 Box::pin(async move {
96 let results = reader
97 .search_dense_vector(field, &vector, limit, nprobe, rerank_factor, combiner)
98 .await?;
99
100 Ok(Box::new(VectorResultScorer::new(results, field.0)) as Box<dyn Scorer>)
101 })
102 }
103
104 #[cfg(feature = "sync")]
105 fn scorer_sync<'a>(
106 &self,
107 reader: &'a SegmentReader,
108 limit: usize,
109 ) -> crate::Result<Box<dyn Scorer + 'a>> {
110 let results = reader.search_dense_vector_sync(
111 self.field,
112 &self.vector,
113 limit,
114 self.nprobe,
115 self.rerank_factor,
116 self.combiner,
117 )?;
118 Ok(Box::new(VectorResultScorer::new(results, self.field.0)) as Box<dyn Scorer>)
119 }
120
121 fn count_estimate<'a>(&self, _reader: &'a SegmentReader) -> CountFuture<'a> {
122 Box::pin(async move { Ok(u32::MAX) })
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 #[test]
131 fn test_dense_vector_query_builder() {
132 let query = DenseVectorQuery::new(Field(0), vec![1.0, 2.0, 3.0])
133 .with_nprobe(64)
134 .with_rerank_factor(5.0);
135
136 assert_eq!(query.field, Field(0));
137 assert_eq!(query.vector.len(), 3);
138 assert_eq!(query.nprobe, 64);
139 assert_eq!(query.rerank_factor, 5.0);
140 }
141}