Skip to main content

qdrant_client/builders/
text_index_params_builder.rs

1use crate::qdrant::*;
2
3#[must_use]
4#[derive(Clone)]
5pub struct TextIndexParamsBuilder {
6    /// Tokenizer type
7    pub(crate) tokenizer: Option<i32>,
8    /// If true - all tokens will be lowercase
9    pub(crate) lowercase: Option<Option<bool>>,
10    /// Minimal token length
11    pub(crate) min_token_len: Option<Option<u64>>,
12    /// Maximal token length
13    pub(crate) max_token_len: Option<Option<u64>>,
14    /// If true - store index on disk.
15    pub(crate) on_disk: Option<Option<bool>>,
16    pub(crate) stopwords: Option<Option<StopwordsSet>>,
17    /// If true - support phrase matching.
18    pub(crate) phrase_matching: Option<Option<bool>>,
19    /// Set an algorithm for stemming.
20    pub(crate) stemmer: Option<Option<StemmingAlgorithm>>,
21    /// If true, normalize tokens by folding accented characters to ASCII (e.g., "ação" -> "acao"). Default: false.
22    pub(crate) ascii_folding: Option<Option<bool>>,
23    /// If true - enable HNSW index for this field.
24    pub(crate) enable_hnsw: Option<Option<bool>>,
25    /// Memory placement of the index.
26    pub(crate) memory: Option<Option<i32>>,
27    /// Index every object of this array as a separate entry.
28    pub(crate) nested: Option<Option<String>>,
29    /// Enable ranking points by BM25 over this field.
30    pub(crate) scoring: Option<Option<TextScoringParams>>,
31}
32
33impl TextIndexParamsBuilder {
34    pub fn new(tokenizer: TokenizerType) -> Self {
35        let mut builder = Self::create_empty();
36        builder.tokenizer = Some(tokenizer.into());
37        builder
38    }
39
40    /// Tokenizer type
41    pub fn tokenizer(self, value: i32) -> Self {
42        let mut new = self;
43        new.tokenizer = Option::Some(value);
44        new
45    }
46    /// If true - all tokens will be lowercase
47    pub fn lowercase(self, value: bool) -> Self {
48        let mut new = self;
49        new.lowercase = Option::Some(Option::Some(value));
50        new
51    }
52    /// Minimal token length
53    pub fn min_token_len(self, value: u64) -> Self {
54        let mut new = self;
55        new.min_token_len = Option::Some(Option::Some(value));
56        new
57    }
58    /// Maximal token length
59    pub fn max_token_len(self, value: u64) -> Self {
60        let mut new = self;
61        new.max_token_len = Option::Some(Option::Some(value));
62        new
63    }
64    /// If true - store index on disk.
65    ///
66    /// Deprecated since 1.19.0, use [`memory`](Self::memory) instead.
67    pub fn on_disk(self, value: bool) -> Self {
68        let mut new = self;
69        new.on_disk = Option::Some(Option::Some(value));
70        new
71    }
72
73    /// Stopwords for a single language for the text index
74    pub fn stopwords_language(self, language: String) -> Self {
75        let mut new = self;
76        let stopwords_set = StopwordsSet {
77            languages: vec![language],
78            custom: vec![],
79        };
80        new.stopwords = Some(Some(stopwords_set));
81        new
82    }
83
84    /// Stopwords for the text index
85    pub fn stopwords(self, stopwords_set: StopwordsSet) -> Self {
86        let mut new = self;
87        new.stopwords = Some(Some(stopwords_set));
88        new
89    }
90
91    /// If true - support phrase matching. Default is false.
92    pub fn phrase_matching(self, phrase_matching: bool) -> Self {
93        let mut new = self;
94        new.phrase_matching = Some(Some(phrase_matching));
95        new
96    }
97
98    /// Set snowball stemmer with the provided language
99    pub fn snowball_stemmer(self, language: String) -> Self {
100        let mut new: TextIndexParamsBuilder = self;
101        let stemmer = StemmingAlgorithm {
102            stemming_params: Some(stemming_algorithm::StemmingParams::Snowball(
103                SnowballParams { language },
104            )),
105        };
106        new.stemmer = Some(Some(stemmer));
107        new
108    }
109
110    /// Explicitly disable stemming, overriding the language default
111    pub fn disabled_stemmer(self) -> Self {
112        let mut new = self;
113        let stemmer = StemmingAlgorithm {
114            stemming_params: Some(stemming_algorithm::StemmingParams::Disabled(
115                DisabledStemmer {},
116            )),
117        };
118        new.stemmer = Some(Some(stemmer));
119        new
120    }
121
122    /// Set an algorithm for stemming.
123    pub fn stemmer(self, stemming_params: stemming_algorithm::StemmingParams) -> Self {
124        let mut new = self;
125        let stemmer = StemmingAlgorithm {
126            stemming_params: Some(stemming_params),
127        };
128        new.stemmer = Some(Some(stemmer));
129        new
130    }
131
132    /// If true, normalize tokens by folding accented characters to ASCII (e.g., "ação" -> "acao"). Default: false.
133    pub fn ascii_folding(self, value: bool) -> Self {
134        let mut new = self;
135        new.ascii_folding = Option::Some(Option::Some(value));
136        new
137    }
138
139    /// If true - enable HNSW index for this field.
140    pub fn enable_hnsw(self, value: bool) -> Self {
141        let mut new = self;
142        new.enable_hnsw = Option::Some(Option::Some(value));
143        new
144    }
145
146    /// Memory placement of the index.
147    /// Overrides the deprecated `on_disk` flag if both are set.
148    pub fn memory<VALUE: core::convert::Into<i32>>(self, value: VALUE) -> Self {
149        let mut new = self;
150        new.memory = Option::Some(Option::Some(value.into()));
151        new
152    }
153    /// Index every object of this array as a separate entry, e.g. `offers` for the field `offers[].title`.
154    /// The field must be inside the array's elements.
155    pub fn nested(self, value: impl Into<String>) -> Self {
156        let mut new = self;
157        new.nested = Option::Some(Option::Some(value.into()));
158        new
159    }
160
161    /// Enable ranking points by BM25 over this field, see [`Query::new_text`].
162    /// Changing it rebuilds the index.
163    /// Default: disabled.
164    pub fn scoring<VALUE: core::convert::Into<TextScoringParams>>(self, value: VALUE) -> Self {
165        let mut new = self;
166        new.scoring = Option::Some(Option::Some(value.into()));
167        new
168    }
169
170    /// Enable BM25 ranking over this field, see [`Query::new_text`].
171    /// Changing it rebuilds the index.
172    pub fn bm25_scoring(self) -> Self {
173        self.scoring(TextScoringType::Bm25)
174    }
175
176    #[allow(deprecated)]
177    fn build_inner(self) -> Result<TextIndexParams, TextIndexParamsBuilderError> {
178        Ok(TextIndexParams {
179            tokenizer: match self.tokenizer {
180                Some(value) => value,
181                None => {
182                    return Result::Err(core::convert::Into::into(
183                        ::derive_builder::UninitializedFieldError::from("tokenizer"),
184                    ));
185                }
186            },
187            lowercase: self.lowercase.unwrap_or_default(),
188            min_token_len: self.min_token_len.unwrap_or_default(),
189            max_token_len: self.max_token_len.unwrap_or_default(),
190            on_disk: self.on_disk.unwrap_or_default(),
191            stopwords: self.stopwords.unwrap_or_default(),
192            phrase_matching: self.phrase_matching.unwrap_or_default(),
193            stemmer: self.stemmer.unwrap_or_default(),
194            ascii_folding: self.ascii_folding.unwrap_or_default(),
195            enable_hnsw: self.enable_hnsw.unwrap_or_default(),
196            memory: self.memory.unwrap_or_default(),
197            nested: self.nested.unwrap_or_default(),
198            scoring: self.scoring.unwrap_or_default(),
199        })
200    }
201
202    /// Create an empty builder, with all fields set to `None` or `PhantomData`.
203    fn create_empty() -> Self {
204        Self {
205            tokenizer: Default::default(),
206            lowercase: Default::default(),
207            min_token_len: Default::default(),
208            max_token_len: Default::default(),
209            on_disk: Default::default(),
210            stopwords: Default::default(),
211            phrase_matching: Default::default(),
212            stemmer: Default::default(),
213            ascii_folding: Default::default(),
214            enable_hnsw: Default::default(),
215            memory: Default::default(),
216            nested: Default::default(),
217            scoring: Default::default(),
218        }
219    }
220}
221
222impl From<TextIndexParamsBuilder> for TextIndexParams {
223    fn from(value: TextIndexParamsBuilder) -> Self {
224        value.build_inner().unwrap_or_else(|_| {
225            panic!(
226                "Failed to convert {0} to {1}",
227                "TextIndexParamsBuilder", "TextIndexParams"
228            )
229        })
230    }
231}
232
233impl TextIndexParamsBuilder {
234    /// Builds the desired type. Can often be omitted.
235    pub fn build(self) -> TextIndexParams {
236        self.build_inner().unwrap_or_else(|_| {
237            panic!(
238                "Failed to build {0} into {1}",
239                "TextIndexParamsBuilder", "TextIndexParams"
240            )
241        })
242    }
243}
244
245#[non_exhaustive]
246#[derive(Debug)]
247pub enum TextIndexParamsBuilderError {
248    /// Uninitialized field
249    UninitializedField(&'static str),
250    /// Custom validation error
251    ValidationError(String),
252}
253
254// Implementing the Display trait for better error messages
255impl std::fmt::Display for TextIndexParamsBuilderError {
256    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
257        match self {
258            Self::UninitializedField(field) => {
259                write!(f, "`{field}` must be initialized")
260            }
261            Self::ValidationError(error) => write!(f, "{error}"),
262        }
263    }
264}
265
266// Implementing the Error trait
267impl std::error::Error for TextIndexParamsBuilderError {}
268
269// Implementing From trait for conversion from UninitializedFieldError
270impl From<derive_builder::UninitializedFieldError> for TextIndexParamsBuilderError {
271    fn from(error: derive_builder::UninitializedFieldError) -> Self {
272        Self::UninitializedField(error.field_name())
273    }
274}
275
276// Implementing From trait for conversion from String
277impl From<String> for TextIndexParamsBuilderError {
278    fn from(error: String) -> Self {
279        Self::ValidationError(error)
280    }
281}