rs_es/query/
full_text.rs

1/*
2 * Copyright 2016-2018 Ben Ashford
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//! Implementations of full-text ES queries
18
19use serde::{Serialize, Serializer};
20
21use crate::{
22    json::{NoOuter, ShouldSkip},
23    operations::search::highlight::Highlight,
24    units::JsonVal,
25};
26
27use super::{common::FieldBasedQuery, Flags, Fuzziness, MinimumShouldMatch, Query};
28
29/// MatchType - the type of Match query
30#[derive(Debug, Clone)]
31pub enum MatchType {
32    Boolean,
33    Phrase,
34    PhrasePrefix,
35}
36
37impl Serialize for MatchType {
38    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
39    where
40        S: Serializer,
41    {
42        use self::MatchType::*;
43        match self {
44            Boolean => "boolean",
45            Phrase => "phrase",
46            PhrasePrefix => "phrase_prefix",
47        }
48        .serialize(serializer)
49    }
50}
51
52/// Zero Terms Query
53
54#[derive(Debug)]
55pub enum ZeroTermsQuery {
56    None,
57    All,
58}
59
60impl Serialize for ZeroTermsQuery {
61    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
62    where
63        S: Serializer,
64    {
65        match self {
66            ZeroTermsQuery::None => "none",
67            ZeroTermsQuery::All => "all",
68        }
69        .serialize(serializer)
70    }
71}
72
73/// MatchQueryType - the type of the multi Match Query
74#[derive(Debug, Clone)]
75pub enum MatchQueryType {
76    BestFields,
77    MostFields,
78    CrossFields,
79    Phrase,
80    PhrasePrefix,
81}
82
83impl Serialize for MatchQueryType {
84    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
85    where
86        S: Serializer,
87    {
88        use self::MatchQueryType::*;
89        match self {
90            BestFields => "best_fields",
91            MostFields => "most_fields",
92            CrossFields => "cross_fields",
93            Phrase => "phrase",
94            PhrasePrefix => "phrase_prefix",
95        }
96        .serialize(serializer)
97    }
98}
99
100/// Match query
101
102#[derive(Debug, Serialize)]
103pub struct MatchQuery(FieldBasedQuery<MatchQueryInner, NoOuter>);
104
105#[derive(Debug, Default, Serialize)]
106pub struct MatchQueryInner {
107    query: JsonVal,
108    #[serde(skip_serializing_if = "ShouldSkip::should_skip", rename = "type")]
109    match_type: Option<MatchType>,
110    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
111    cutoff_frequency: Option<f64>,
112    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
113    lenient: Option<bool>,
114    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
115    analyzer: Option<String>,
116    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
117    boost: Option<f64>,
118    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
119    operator: Option<String>,
120    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
121    minimum_should_match: Option<MinimumShouldMatch>,
122    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
123    fuzziness: Option<Fuzziness>,
124    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
125    prefix_length: Option<u64>,
126    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
127    max_expansions: Option<u64>,
128    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
129    rewrite: Option<String>,
130    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
131    zero_terms_query: Option<ZeroTermsQuery>,
132    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
133    slop: Option<i64>,
134    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
135    highlight: Option<Highlight>,
136}
137
138impl Query {
139    pub fn build_match<A, B>(field: A, query: B) -> MatchQuery
140    where
141        A: Into<String>,
142        B: Into<JsonVal>,
143    {
144        MatchQuery(FieldBasedQuery::new(
145            field.into(),
146            MatchQueryInner {
147                query: query.into(),
148                ..Default::default()
149            },
150            NoOuter,
151        ))
152    }
153}
154
155impl MatchQuery {
156    add_inner_field!(with_type, match_type, MatchType);
157    add_inner_field!(with_cutoff_frequency, cutoff_frequency, f64);
158    add_inner_field!(with_lenient, lenient, bool);
159    add_inner_field!(with_analyzer, analyzer, String);
160    add_inner_field!(with_boost, boost, f64);
161    add_inner_field!(with_operator, operator, String);
162    add_inner_field!(
163        with_minimum_should_match,
164        minimum_should_match,
165        MinimumShouldMatch
166    );
167    add_inner_field!(with_fuzziness, fuzziness, Fuzziness);
168    add_inner_field!(with_prefix_length, prefix_length, u64);
169    add_inner_field!(with_max_expansions, max_expansions, u64);
170    add_inner_field!(with_rewrite, rewrite, String);
171    add_inner_field!(with_zero_terms_query, zero_terms_query, ZeroTermsQuery);
172    add_inner_field!(with_slop, slop, i64);
173    add_inner_field!(with_highlight, highlight, Highlight);
174
175    build!(Match);
176}
177
178/// Multi Match Query
179#[derive(Debug, Default, Serialize)]
180pub struct MultiMatchQuery {
181    fields: Vec<String>,
182    query: JsonVal,
183    #[serde(skip_serializing_if = "ShouldSkip::should_skip", rename = "type")]
184    match_type: Option<MatchQueryType>,
185    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
186    tie_breaker: Option<f64>,
187    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
188    analyzer: Option<String>,
189    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
190    boost: Option<f64>,
191    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
192    operator: Option<String>,
193    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
194    minimum_should_match: Option<MinimumShouldMatch>,
195    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
196    fuzziness: Option<Fuzziness>,
197    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
198    prefix_length: Option<u64>,
199    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
200    max_expansions: Option<u64>,
201    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
202    rewrite: Option<String>,
203    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
204    zero_terms_query: Option<ZeroTermsQuery>,
205    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
206    cutoff_frequency: Option<f64>,
207    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
208    slop: Option<i64>,
209    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
210    highlight: Option<Highlight>,
211}
212
213impl Query {
214    pub fn build_multi_match<A, B>(fields: A, query: B) -> MultiMatchQuery
215    where
216        A: Into<Vec<String>>,
217        B: Into<JsonVal>,
218    {
219        MultiMatchQuery {
220            fields: fields.into(),
221            query: query.into(),
222            ..Default::default()
223        }
224    }
225}
226
227impl MultiMatchQuery {
228    add_field!(with_type, match_type, MatchQueryType);
229    add_field!(with_tie_breaker, tie_breaker, f64);
230    add_field!(with_analyzer, analyzer, String);
231    add_field!(with_boost, boost, f64);
232    add_field!(with_operator, operator, String);
233    add_field!(
234        with_minimum_should_match,
235        minimum_should_match,
236        MinimumShouldMatch
237    );
238    add_field!(with_fuzziness, fuzziness, Fuzziness);
239    add_field!(with_prefix_length, prefix_length, u64);
240    add_field!(with_max_expansions, max_expansions, u64);
241    add_field!(with_rewrite, rewrite, String);
242    add_field!(with_zero_terms_query, zero_terms_query, ZeroTermsQuery);
243    add_field!(with_cutoff_frequency, cutoff_frequency, f64);
244    add_field!(with_slop, slop, i64);
245    add_field!(with_highlight, highlight, Highlight);
246
247    build!(MultiMatch);
248}
249
250/// Common terms query
251#[derive(Debug, Serialize)]
252pub struct CommonQuery(FieldBasedQuery<CommonQueryInner, NoOuter>);
253
254#[derive(Debug, Default, Serialize)]
255pub struct CommonQueryInner {
256    query: JsonVal,
257    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
258    cutoff_frequency: Option<f64>,
259    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
260    low_freq_operator: Option<String>,
261    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
262    high_freq_operator: Option<String>,
263    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
264    minimum_should_match: Option<MinimumShouldMatch>,
265    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
266    boost: Option<f64>,
267    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
268    analyzer: Option<String>,
269    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
270    disable_coord: Option<bool>,
271}
272
273impl Query {
274    pub fn build_common<A>(query: A) -> CommonQuery
275    where
276        A: Into<JsonVal>,
277    {
278        CommonQuery(FieldBasedQuery::new(
279            "body".to_owned(),
280            CommonQueryInner {
281                query: query.into(),
282                ..Default::default()
283            },
284            NoOuter,
285        ))
286    }
287}
288
289impl CommonQuery {
290    add_inner_field!(with_cutoff_frequency, cutoff_frequency, f64);
291    add_inner_field!(with_low_freq_operator, low_freq_operator, String);
292    add_inner_field!(with_high_freq_operator, high_freq_operator, String);
293    add_inner_field!(
294        with_minimum_should_match,
295        minimum_should_match,
296        MinimumShouldMatch
297    );
298    add_inner_field!(with_boost, boost, f64);
299    add_inner_field!(with_analyzer, analyzer, String);
300    add_inner_field!(with_disable_coord, disable_coord, bool);
301
302    build!(Common);
303}
304
305/// Query string query
306#[derive(Debug, Default, Serialize)]
307pub struct QueryStringQuery {
308    query: String,
309    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
310    default_field: Option<String>,
311    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
312    fields: Option<Vec<String>>,
313    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
314    default_operator: Option<String>,
315    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
316    analyzer: Option<String>,
317    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
318    allow_leading_wildcard: Option<bool>,
319    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
320    lowercase_expanded_terms: Option<bool>,
321    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
322    enable_position_increments: Option<bool>,
323    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
324    fuzzy_max_expansions: Option<u64>,
325    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
326    fuzziness: Option<Fuzziness>,
327    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
328    fuzzy_prefix_length: Option<u64>,
329    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
330    phrase_slop: Option<i64>,
331    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
332    boost: Option<f64>,
333    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
334    analyze_wildcard: Option<bool>,
335    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
336    auto_generate_phrase_queries: Option<bool>,
337    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
338    max_determined_states: Option<u64>,
339    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
340    minimum_should_match: Option<MinimumShouldMatch>,
341    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
342    lenient: Option<bool>,
343    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
344    locale: Option<String>,
345    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
346    time_zone: Option<String>,
347    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
348    use_dis_max: Option<bool>,
349}
350
351impl Query {
352    pub fn build_query_string<A: Into<String>>(query: A) -> QueryStringQuery {
353        QueryStringQuery {
354            query: query.into(),
355            ..Default::default()
356        }
357    }
358}
359
360impl QueryStringQuery {
361    add_field!(with_default_field, default_field, String);
362    add_field!(with_fields, fields, Vec<String>);
363    add_field!(with_default_operator, default_operator, String);
364    add_field!(with_analyzer, analyzer, String);
365    add_field!(with_allow_leading_wildcard, allow_leading_wildcard, bool);
366    add_field!(
367        with_lowercase_expanded_terms,
368        lowercase_expanded_terms,
369        bool
370    );
371    add_field!(
372        with_enable_position_increments,
373        enable_position_increments,
374        bool
375    );
376    add_field!(with_fuzzy_max_expansions, fuzzy_max_expansions, u64);
377    add_field!(with_fuzziness, fuzziness, Fuzziness);
378    add_field!(with_fuzzy_prefix_length, fuzzy_prefix_length, u64);
379    add_field!(with_phrase_slop, phrase_slop, i64);
380    add_field!(with_boost, boost, f64);
381    add_field!(with_analyze_wildcard, analyze_wildcard, bool);
382    add_field!(
383        with_auto_generate_phrase_queries,
384        auto_generate_phrase_queries,
385        bool
386    );
387    add_field!(with_max_determined_states, max_determined_states, u64);
388    add_field!(
389        with_minimum_should_match,
390        minimum_should_match,
391        MinimumShouldMatch
392    );
393    add_field!(with_lenient, lenient, bool);
394    add_field!(with_locale, locale, String);
395    add_field!(with_time_zone, time_zone, String);
396    add_field!(with_use_dis_max, use_dis_max, bool);
397
398    build!(QueryString);
399}
400
401/// Flags for the SimpleQueryString query
402#[derive(Debug)]
403pub enum SimpleQueryStringFlags {
404    All,
405    None,
406    And,
407    Or,
408    Not,
409    Prefix,
410    Phrase,
411    Precedence,
412    Escape,
413    Whitespace,
414    Fuzzy,
415    Near,
416    Slop,
417}
418
419impl AsRef<str> for SimpleQueryStringFlags {
420    fn as_ref(&self) -> &str {
421        match self {
422            SimpleQueryStringFlags::All => "ALL",
423            SimpleQueryStringFlags::None => "NONE",
424            SimpleQueryStringFlags::And => "AND",
425            SimpleQueryStringFlags::Or => "OR",
426            SimpleQueryStringFlags::Not => "NOT",
427            SimpleQueryStringFlags::Prefix => "PREFIX",
428            SimpleQueryStringFlags::Phrase => "PHRASE",
429            SimpleQueryStringFlags::Precedence => "PRECEDENCE",
430            SimpleQueryStringFlags::Escape => "ESCAPE",
431            SimpleQueryStringFlags::Whitespace => "WHITESPACE",
432            SimpleQueryStringFlags::Fuzzy => "FUZZY",
433            SimpleQueryStringFlags::Near => "NEAR",
434            SimpleQueryStringFlags::Slop => "SLOP",
435        }
436    }
437}
438
439/// SimpleQueryString query
440#[derive(Debug, Default, Serialize)]
441pub struct SimpleQueryStringQuery {
442    query: String,
443    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
444    fields: Option<Vec<String>>,
445    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
446    default_operator: Option<String>,
447    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
448    analyzer: Option<String>,
449    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
450    flags: Option<Flags<SimpleQueryStringFlags>>,
451    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
452    lowercase_expanded_terms: Option<bool>,
453    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
454    analyze_wildcard: Option<bool>,
455    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
456    locale: Option<String>,
457    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
458    lenient: Option<bool>,
459    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
460    minimum_should_match: Option<MinimumShouldMatch>,
461}
462
463impl Query {
464    pub fn build_simple_query_string<A: Into<String>>(query: A) -> SimpleQueryStringQuery {
465        SimpleQueryStringQuery {
466            query: query.into(),
467            ..Default::default()
468        }
469    }
470}
471
472impl SimpleQueryStringQuery {
473    add_field!(with_fields, fields, Vec<String>);
474    add_field!(with_default_operator, default_operator, String);
475    add_field!(with_analyzer, analyzer, String);
476    add_field!(with_flags, flags, Flags<SimpleQueryStringFlags>);
477    add_field!(
478        with_lowercase_expanded_terms,
479        lowercase_expanded_terms,
480        bool
481    );
482    add_field!(with_analyze_wildcard, analyze_wildcard, bool);
483    add_field!(with_locale, locale, String);
484    add_field!(with_lenient, lenient, bool);
485    add_field!(
486        with_minimum_should_match,
487        minimum_should_match,
488        MinimumShouldMatch
489    );
490
491    build!(SimpleQueryString);
492}