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