opensearch_dsl/search/queries/full_text/query_string_query.rs
1use crate::{search::*, util::*};
2
3/// Returns documents that match a provided text, number, date or boolean value.
4/// The provided text is analyzed before matching.
5///
6/// The `match` query is the standard query for performing a full-text search,
7/// including options for fuzzy matching.
8///
9/// To create a Match query with numeric values:
10/// ```
11/// # use opensearch_dsl::queries::*;
12/// # use opensearch_dsl::queries::params::*;
13/// # let query =
14/// Query::query_string("(new york city) OR (big apple)")
15/// .boost(2)
16/// .name("test");
17/// ```
18/// <https://www.elastic.co/guide/en/opensearch/reference/current/query-dsl-query-string-query.html>
19#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
20#[serde(remote = "Self")]
21pub struct QueryStringQuery {
22 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
23 query: Text,
24
25 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
26 default_field: Option<String>,
27
28 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
29 allow_leading_wildcard: Option<bool>,
30
31 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
32 analyze_wildcard: Option<bool>,
33
34 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
35 analyzer: Option<String>,
36
37 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
38 auto_generate_synonyms_phrase_query: Option<bool>,
39
40 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
41 default_operator: Option<Operator>,
42
43 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
44 enable_position_increments: Option<bool>,
45
46 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
47 fields: Vec<String>,
48
49 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
50 fuzziness: Option<Fuzziness>,
51
52 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
53 fuzzy_max_expansions: Option<u32>,
54
55 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
56 fuzzy_prefix_length: Option<u32>,
57
58 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
59 fuzzy_transpositions: Option<bool>,
60
61 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
62 lenient: Option<bool>,
63
64 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
65 max_determinized_states: Option<u32>,
66
67 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
68 minimum_should_match: Option<String>,
69
70 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
71 quote_analyzer: Option<String>,
72
73 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
74 phrase_slop: Option<u32>,
75
76 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
77 quote_field_suffix: Option<String>,
78
79 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
80 rewrite: Option<Rewrite>,
81
82 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
83 time_zone: Option<String>,
84
85 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
86 boost: Option<f32>,
87
88 #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
89 _name: Option<String>,
90}
91
92impl Query {
93 /// Creates an instance of [`QueryStringQuery`]
94 ///
95 /// - `query` - Query string you wish to parse and use for search. See
96 /// [Simple query string syntax](https://www.elastic.co/guide/en/opensearch/reference/current/query-dsl-simple-query-string-query.html#simple-query-string-syntax).
97 pub fn query_string<S>(query: S) -> QueryStringQuery
98 where
99 S: Into<Text>,
100 {
101 QueryStringQuery {
102 query: query.into(),
103 fields: vec![],
104 default_operator: None,
105 analyze_wildcard: None,
106 analyzer: None,
107 auto_generate_synonyms_phrase_query: None,
108 fuzzy_transpositions: None,
109 fuzzy_max_expansions: None,
110 fuzzy_prefix_length: None,
111 quote_field_suffix: None,
112 lenient: None,
113 minimum_should_match: None,
114 allow_leading_wildcard: None,
115 default_field: None,
116 enable_position_increments: None,
117 fuzziness: None,
118 max_determinized_states: None,
119 phrase_slop: None,
120 quote_analyzer: None,
121 rewrite: None,
122 time_zone: None,
123 boost: None,
124 _name: None,
125 }
126 }
127}
128
129impl QueryStringQuery {
130 add_boost_and_name!();
131
132 /// Default field you wish to search if no field is provided in the query
133 /// string.
134 ///
135 /// Defaults to the `index.query.default_field` index setting, which has a
136 /// default value of `*`. The `*` value extracts all fields that are
137 /// eligible for term queries and filters the metadata fields. All
138 /// extracted fields are then combined to build a query if no `prefix`
139 /// is specified.
140 ///
141 /// Searching across all eligible fields does not include
142 /// [nested documents](https://www.elastic.co/guide/en/opensearch/reference/current/nested.html).
143 /// Use a [`nested` query](crate::NestedQuery) to search those documents.
144 ///
145 /// For mappings with a large number of fields, searching across all
146 /// eligible fields could be expensive.
147 ///
148 /// There is a limit on the number of fields that can be queried at once.
149 /// It is defined by the `indices.query.bool.max_clause_count`
150 /// [search setting](https://www.elastic.co/guide/en/opensearch/reference/current/search-settings.html),
151 /// which defaults to 1024.
152 pub fn default_field<S>(mut self, default_field: S) -> Self
153 where
154 S: ToString,
155 {
156 self.default_field = Some(default_field.to_string());
157 self
158 }
159
160 /// If `true`, the wildcard characters `*` and `?` are allowed as the first
161 /// character of the query string.
162 ///
163 /// Defaults to `true`.
164 pub fn allow_leading_wildcard(mut self, allow_leading_wildcard: bool) -> Self {
165 self.allow_leading_wildcard = Some(allow_leading_wildcard);
166 self
167 }
168
169 /// If `true`, the query attempts to analyze wildcard terms in the query
170 /// string.
171 ///
172 /// Defaults to `false`.
173 pub fn analyze_wildcard(mut self, analyze_wildcard: bool) -> Self {
174 self.analyze_wildcard = Some(analyze_wildcard);
175 self
176 }
177
178 /// [Analyzer](https://www.elastic.co/guide/en/opensearch/reference/current/analysis.html)
179 /// used to convert text in the query string into tokens. Defaults to the
180 /// [index-time analyzer](https://www.elastic.co/guide/en/opensearch/reference/current/specify-analyzer.html#specify-index-time-analyzer)
181 /// mapped for the `default_field`. If no analyzer is mapped, the index’s
182 /// default analyzer is used.
183 pub fn analyzer<T>(mut self, analyzer: T) -> Self
184 where
185 T: ToString,
186 {
187 self.analyzer = Some(analyzer.to_string());
188 self
189 }
190
191 /// If `true`, the parser creates a
192 /// [`match_phrase`](https://www.elastic.co/guide/en/opensearch/reference/current/query-dsl-match-query-phrase.html)
193 /// query for each
194 /// [multi-position token](https://www.elastic.co/guide/en/opensearch/reference/current/token-graphs.html#token-graphs-multi-position-tokens).
195 ///
196 /// Defaults to `true`. For examples, see
197 /// [Multi-position tokens](https://www.elastic.co/guide/en/opensearch/reference/current/query-dsl-simple-query-string-query.html#simple-query-string-synonyms).
198 pub fn auto_generate_synonyms_phrase_query(
199 mut self,
200 auto_generate_synonyms_phrase_query: bool,
201 ) -> Self {
202 self.auto_generate_synonyms_phrase_query = Some(auto_generate_synonyms_phrase_query);
203 self
204 }
205
206 /// Default boolean logic used to interpret text in the query string if no
207 /// operators are specified.
208 pub fn default_operator(mut self, default_operator: Operator) -> Self {
209 self.default_operator = Some(default_operator);
210 self
211 }
212
213 /// If `true`, enable position increments in queries constructed from a
214 /// `query_string` search.
215 ///
216 /// Defaults to `true`.
217 pub fn enable_position_increments(mut self, enable_position_increments: bool) -> Self {
218 self.enable_position_increments = Some(enable_position_increments);
219 self
220 }
221
222 /// Array of fields you wish to search.
223 ///
224 /// You can use this parameter query to search across multiple fields. See
225 /// [Search multiple fields](https://www.elastic.co/guide/en/opensearch/reference/current/query-dsl-query-string-query.html#query-string-multi-field).
226 pub fn fields<I>(mut self, fields: I) -> Self
227 where
228 I: IntoIterator,
229 I::Item: ToString,
230 {
231 self.fields = fields.into_iter().map(|x| x.to_string()).collect();
232 self
233 }
234
235 /// Maximum edit distance allowed for fuzzy matching. For fuzzy syntax, see
236 /// [`Fuzziness`].
237 pub fn fuzziness<T>(mut self, fuzziness: T) -> Self
238 where
239 T: Into<Fuzziness>,
240 {
241 self.fuzziness = Some(fuzziness.into());
242 self
243 }
244
245 /// Maximum number of terms to which the query expands for fuzzy matching.
246 ///
247 /// Defaults to `50`.
248 pub fn fuzzy_max_expansions(mut self, fuzzy_max_expansions: u32) -> Self {
249 self.fuzzy_max_expansions = Some(fuzzy_max_expansions);
250 self
251 }
252
253 /// Number of beginning characters left unchanged for fuzzy matching.
254 ///
255 /// Defaults to `0`.
256 pub fn fuzzy_prefix_length(mut self, fuzzy_prefix_length: u32) -> Self {
257 self.fuzzy_prefix_length = Some(fuzzy_prefix_length);
258 self
259 }
260
261 /// If `true`, edits for fuzzy matching include transpositions of two
262 /// adjacent characters (ab → ba).
263 ///
264 /// Defaults to `true`.
265 pub fn fuzzy_transpositions(mut self, fuzzy_transpositions: bool) -> Self {
266 self.fuzzy_transpositions = Some(fuzzy_transpositions);
267 self
268 }
269
270 /// If `true`, format-based errors, such as providing a text `query`
271 /// value for a
272 /// [numeric](https://www.elastic.co/guide/en/opensearch/reference/current/number.html)
273 /// field, are ignored.
274 ///
275 /// Defaults to `false`.
276 pub fn lenient(mut self, lenient: bool) -> Self {
277 self.lenient = Some(lenient);
278 self
279 }
280
281 /// Maximum number of
282 /// [automaton states](https://en.wikipedia.org/wiki/Deterministic_finite_automaton)
283 /// required for the query.
284 ///
285 /// Default is `10000`.
286 ///
287 /// OpenSearch uses [Apache Lucene](https://lucene.apache.org/core/)
288 /// internally to parse regular expressions. Lucene converts each regular
289 /// expression to a finite automaton containing a number of determinized
290 /// states.
291 ///
292 /// You can use this parameter to prevent that conversion from
293 /// unintentionally consuming too many resources. You may need to increase
294 /// this limit to run complex regular expressions.
295 pub fn max_determinized_states(mut self, max_determinized_states: u32) -> Self {
296 self.max_determinized_states = Some(max_determinized_states);
297 self
298 }
299
300 /// Minimum number of clauses that must match for a document to be returned.
301 /// See the `minimum_should_match` parameter for valid values and more
302 /// information.
303 pub fn minimum_should_match<T>(mut self, minimum_should_match: T) -> Self
304 where
305 T: ToString,
306 {
307 self.minimum_should_match = Some(minimum_should_match.to_string());
308 self
309 }
310
311 /// [Analyzer](https://www.elastic.co/guide/en/opensearch/reference/current/analysis.html)
312 /// used to convert quoted text in the query string into tokens.
313 ///
314 /// Defaults to the
315 /// [`search_quote_analyzer`](https://www.elastic.co/guide/en/opensearch/reference/current/analyzer.html#search-quote-analyzer)
316 /// mapped for the `default_field`.
317 ///
318 /// For quoted text, this parameter overrides the analyzer specified in the
319 /// `analyzer` parameter.
320 pub fn quote_analyzer<S>(mut self, quote_analyzer: S) -> Self
321 where
322 S: ToString,
323 {
324 self.quote_analyzer = Some(quote_analyzer.to_string());
325 self
326 }
327
328 /// Maximum number of positions allowed between matching tokens for
329 /// phrases.
330 ///
331 /// Defaults to `0`. If `0`, exact phrase matches are required. Transposed
332 /// terms have a slop of `2`.
333 pub fn phrase_slop(mut self, phrase_slop: u32) -> Self {
334 self.phrase_slop = Some(phrase_slop);
335 self
336 }
337
338 /// Suffix appended to quoted text in the query string.
339 ///
340 /// You can use this suffix to use a different analysis method for exact
341 /// matches. See
342 /// [Mixing exact search with stemming](https://www.elastic.co/guide/en/opensearch/reference/current/mixing-exact-search-with-stemming.html).
343 pub fn quote_field_suffix<S>(mut self, quote_field_suffix: S) -> Self
344 where
345 S: ToString,
346 {
347 self.quote_field_suffix = Some(quote_field_suffix.to_string());
348 self
349 }
350
351 /// Method used to rewrite the query. For valid values and more
352 /// information, see the [`rewrite` parameter](Rewrite).
353 pub fn rewrite(mut self, rewrite: Rewrite) -> Self {
354 self.rewrite = Some(rewrite);
355 self
356 }
357
358 /// [Coordinated Universal Time (UTC) offset](https://en.wikipedia.org/wiki/List_of_UTC_time_offsets)
359 /// or [IANA time zone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)
360 /// used to convert `date` values in the query string to UTC.
361 ///
362 /// Valid values are ISO 8601 UTC offsets, such as `+01:00` or `-08:00`,
363 /// and IANA time zone IDs, such as `America/Los_Angeles`.
364 pub fn time_zone<S>(mut self, time_zone: S) -> Self
365 where
366 S: ToString,
367 {
368 self.time_zone = Some(time_zone.to_string());
369 self
370 }
371}
372
373impl ShouldSkip for QueryStringQuery {
374 fn should_skip(&self) -> bool {
375 self.query.should_skip()
376 }
377}
378
379serialize_with_root!("query_string": QueryStringQuery);
380deserialize_with_root!("query_string": QueryStringQuery);
381
382#[cfg(test)]
383mod tests {
384 use super::*;
385
386 #[test]
387 fn serialization() {
388 assert_serialize_query(
389 Query::query_string("search text"),
390 json!({
391 "query_string": {
392 "query": "search text",
393 }
394 }),
395 );
396
397 assert_serialize_query(
398 Query::query_string("search text")
399 .fields(["database"])
400 .default_operator(Operator::And)
401 .analyze_wildcard(true)
402 .analyzer("search_time_analyzer")
403 .auto_generate_synonyms_phrase_query(true)
404 .fuzzy_max_expansions(20)
405 .fuzzy_prefix_length(3)
406 .fuzzy_transpositions(false)
407 .lenient(true)
408 .minimum_should_match("22")
409 .quote_field_suffix("s")
410 .boost(2)
411 .name("test"),
412 json!({
413 "query_string": {
414 "query": "search text",
415 "fields": ["database"],
416 "default_operator": "AND",
417 "analyze_wildcard": true,
418 "analyzer": "search_time_analyzer",
419 "auto_generate_synonyms_phrase_query": true,
420 "fuzzy_max_expansions": 20,
421 "fuzzy_prefix_length": 3,
422 "fuzzy_transpositions": false,
423 "lenient": true,
424 "minimum_should_match": "22",
425 "quote_field_suffix": "s",
426 "boost": 2.0,
427 "_name": "test",
428 }
429 }),
430 );
431 }
432}