Skip to main content

opensearch_dsl/search/queries/full_text/
simple_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::simple_query_string("\"fried eggs\" +(eggplant | potato) -frittata")
15///   .boost(2)
16///   .name("test");
17/// ```
18/// <https://www.elastic.co/guide/en/opensearch/reference/current/query-dsl-simple-query-string-query.html>
19#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
20#[serde(remote = "Self")]
21pub struct SimpleQueryStringQuery {
22    #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
23    query: Text,
24
25    #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
26    fields: Vec<String>,
27
28    #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
29    default_operator: Option<Operator>,
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(
41        default,
42        skip_serializing_if = "ShouldSkip::should_skip",
43        serialize_with = "join_with_pipe"
44    )]
45    flags: Vec<SimpleQueryStringQueryFlags>,
46
47    #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
48    fuzzy_max_expansions: Option<u32>,
49
50    #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
51    fuzzy_prefix_length: Option<u32>,
52
53    #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
54    fuzzy_transpositions: Option<bool>,
55
56    #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
57    lenient: Option<bool>,
58
59    #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
60    minimum_should_match: Option<String>,
61
62    #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
63    quote_field_suffix: Option<String>,
64
65    #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
66    boost: Option<f32>,
67
68    #[serde(default, skip_serializing_if = "ShouldSkip::should_skip")]
69    _name: Option<String>,
70}
71
72impl Query {
73    /// Creates an instance of [`SimpleQueryStringQuery`]
74    ///
75    /// - `query` - Query string you wish to parse and use for search. See
76    /// [Simple query string syntax](https://www.elastic.co/guide/en/opensearch/reference/current/query-dsl-simple-query-string-query.html#simple-query-string-syntax).
77    pub fn simple_query_string<S>(query: S) -> SimpleQueryStringQuery
78    where
79        S: Into<Text>,
80    {
81        SimpleQueryStringQuery {
82            query: query.into(),
83            fields: vec![],
84            default_operator: None,
85            analyze_wildcard: None,
86            analyzer: None,
87            auto_generate_synonyms_phrase_query: None,
88            fuzzy_transpositions: None,
89            fuzzy_max_expansions: None,
90            flags: vec![],
91            fuzzy_prefix_length: None,
92            quote_field_suffix: None,
93            lenient: None,
94            minimum_should_match: None,
95            boost: None,
96            _name: None,
97        }
98    }
99}
100
101impl SimpleQueryStringQuery {
102    add_boost_and_name!();
103
104    /// Array of fields you wish to search.
105    ///
106    /// This field accepts wildcard expressions. You also can boost relevance
107    /// scores for matches to particular fields using a caret (`^`) notation.
108    /// See
109    /// [Wildcards and per-field boosts in the fields parameter](https://www.elastic.co/guide/en/opensearch/reference/current/query-dsl-simple-query-string-query.html#simple-query-string-boost)
110    /// for examples.
111    ///
112    /// Defaults to the `index.query.default_field` index setting, which has a
113    /// default value of `*`. The `*` value extracts all fields that are
114    /// eligible to term queries and filters the metadata fields. All extracted
115    /// fields are then combined to build a query if no `prefix` is specified.
116    pub fn fields<I>(mut self, fields: I) -> Self
117    where
118        I: IntoIterator,
119        I::Item: ToString,
120    {
121        self.fields = fields.into_iter().map(|x| x.to_string()).collect();
122        self
123    }
124
125    /// Default boolean logic used to interpret text in the query string if no
126    /// operators are specified.
127    pub fn default_operator(mut self, default_operator: Operator) -> Self {
128        self.default_operator = Some(default_operator);
129        self
130    }
131
132    /// If `true`, the query attempts to analyze wildcard terms in the query
133    /// string.
134    ///
135    /// Defaults to `false`.
136    pub fn analyze_wildcard(mut self, analyze_wildcard: bool) -> Self {
137        self.analyze_wildcard = Some(analyze_wildcard);
138        self
139    }
140
141    /// [Analyzer](https://www.elastic.co/guide/en/opensearch/reference/current/analysis.html)
142    /// used to convert text in the query string into tokens. Defaults to the
143    /// [index-time analyzer](https://www.elastic.co/guide/en/opensearch/reference/current/specify-analyzer.html#specify-index-time-analyzer)
144    /// mapped for the `default_field`. If no analyzer is mapped, the index’s
145    /// default analyzer is used.
146    pub fn analyzer<T>(mut self, analyzer: T) -> Self
147    where
148        T: ToString,
149    {
150        self.analyzer = Some(analyzer.to_string());
151        self
152    }
153
154    /// If `true`, the parser creates a
155    /// [`match_phrase`](https://www.elastic.co/guide/en/opensearch/reference/current/query-dsl-match-query-phrase.html)
156    /// query for each
157    /// [multi-position token](https://www.elastic.co/guide/en/opensearch/reference/current/token-graphs.html#token-graphs-multi-position-tokens).
158    ///
159    /// Defaults to `true`. For examples, see
160    /// [Multi-position tokens](https://www.elastic.co/guide/en/opensearch/reference/current/query-dsl-simple-query-string-query.html#simple-query-string-synonyms).
161    pub fn auto_generate_synonyms_phrase_query(
162        mut self,
163        auto_generate_synonyms_phrase_query: bool,
164    ) -> Self {
165        self.auto_generate_synonyms_phrase_query = Some(auto_generate_synonyms_phrase_query);
166        self
167    }
168
169    /// List of enabled operators for the simple query string syntax.
170    ///
171    /// Defaults to [ALL](SimpleQueryStringQueryFlags::All) (all operators).
172    /// See [Limit operators](SimpleQueryStringQueryFlags) for valid values.
173    pub fn flags<I>(mut self, flags: I) -> Self
174    where
175        I: IntoIterator<Item = SimpleQueryStringQueryFlags>,
176    {
177        self.flags.extend(flags);
178        self
179    }
180
181    /// Maximum number of terms to which the query expands for fuzzy matching.
182    ///
183    /// Defaults to `50`.
184    pub fn fuzzy_max_expansions(mut self, fuzzy_max_expansions: u32) -> Self {
185        self.fuzzy_max_expansions = Some(fuzzy_max_expansions);
186        self
187    }
188
189    /// Number of beginning characters left unchanged for fuzzy matching.
190    ///
191    /// Defaults to `0`.
192    pub fn fuzzy_prefix_length(mut self, fuzzy_prefix_length: u32) -> Self {
193        self.fuzzy_prefix_length = Some(fuzzy_prefix_length);
194        self
195    }
196
197    /// If `true`, edits for fuzzy matching include transpositions of two
198    /// adjacent characters (ab → ba).
199    ///
200    /// Defaults to `true`.
201    pub fn fuzzy_transpositions(mut self, fuzzy_transpositions: bool) -> Self {
202        self.fuzzy_transpositions = Some(fuzzy_transpositions);
203        self
204    }
205
206    /// If `true`, format-based errors, such as providing a text `query`
207    /// value for a
208    /// [numeric](https://www.elastic.co/guide/en/opensearch/reference/current/number.html)
209    /// field, are ignored.
210    ///
211    /// Defaults to `false`.
212    pub fn lenient(mut self, lenient: bool) -> Self {
213        self.lenient = Some(lenient);
214        self
215    }
216
217    /// Minimum number of clauses that must match for a document to be returned.
218    /// See the `minimum_should_match` parameter for valid values and more
219    /// information.
220    pub fn minimum_should_match<T>(mut self, minimum_should_match: T) -> Self
221    where
222        T: ToString,
223    {
224        self.minimum_should_match = Some(minimum_should_match.to_string());
225        self
226    }
227
228    /// Suffix appended to quoted text in the query string.
229    ///
230    /// You can use this suffix to use a different analysis method for exact
231    /// matches. See
232    /// [Mixing exact search with stemming](https://www.elastic.co/guide/en/opensearch/reference/current/mixing-exact-search-with-stemming.html).
233    pub fn quote_field_suffix<S>(mut self, quote_field_suffix: S) -> Self
234    where
235        S: ToString,
236    {
237        self.quote_field_suffix = Some(quote_field_suffix.to_string());
238        self
239    }
240}
241
242impl ShouldSkip for SimpleQueryStringQuery {
243    fn should_skip(&self) -> bool {
244        self.query.should_skip()
245    }
246}
247
248serialize_with_root!("simple_query_string": SimpleQueryStringQuery);
249deserialize_with_root!("simple_query_string": SimpleQueryStringQuery);
250
251#[cfg(test)]
252mod tests {
253    use super::*;
254
255    #[test]
256    fn serialization() {
257        assert_serialize_query(
258            Query::simple_query_string("search text"),
259            json!({
260                "simple_query_string": {
261                    "query": "search text",
262                }
263            }),
264        );
265
266        assert_serialize_query(
267            Query::simple_query_string("search text")
268                .fields(["database"])
269                .default_operator(Operator::And)
270                .analyze_wildcard(true)
271                .analyzer("search_time_analyzer")
272                .auto_generate_synonyms_phrase_query(true)
273                .flags([
274                    SimpleQueryStringQueryFlags::And,
275                    SimpleQueryStringQueryFlags::Escape,
276                ])
277                .fuzzy_max_expansions(20)
278                .fuzzy_prefix_length(3)
279                .fuzzy_transpositions(false)
280                .lenient(true)
281                .minimum_should_match("22")
282                .quote_field_suffix("s")
283                .boost(2)
284                .name("test"),
285            json!({
286                "simple_query_string": {
287                    "query": "search text",
288                    "fields": ["database"],
289                    "default_operator": "AND",
290                    "analyze_wildcard": true,
291                    "analyzer": "search_time_analyzer",
292                    "auto_generate_synonyms_phrase_query": true,
293                    "flags": "AND|ESCAPE",
294                    "fuzzy_max_expansions": 20,
295                    "fuzzy_prefix_length": 3,
296                    "fuzzy_transpositions": false,
297                    "lenient": true,
298                    "minimum_should_match": "22",
299                    "quote_field_suffix": "s",
300                    "boost": 2.0,
301                    "_name": "test",
302                }
303            }),
304        );
305    }
306}