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}