elasticsearch_dsl/search/queries/compound/
bool_query.rs

1use crate::search::*;
2use crate::util::*;
3
4/// A query that matches documents matching boolean combinations of other queries.
5/// The bool query maps to Lucene BooleanQuery.
6/// It is built using one or more boolean clauses, each clause with a typed occurrence.
7///
8/// The bool query takes a more-matches-is-better approach, so the score from each matching must or should clause will be added together to provide the final _score for each document.
9///
10/// To create bool query:
11/// ```
12/// # use elasticsearch_dsl::queries::*;
13/// # use elasticsearch_dsl::queries::params::*;
14/// # let query =
15/// Query::bool()
16///    .must(Query::term("test1", 1))
17///    .must(Query::term("test2", 2))
18///    .should(Query::term("test1", 3))
19///    .should(Query::term("test2", 4))
20///    .filter(Query::term("test1", 5))
21///    .filter(Query::term("test2", 6))
22///    .must_not(Query::term("test1", 7))
23///    .must_not(Query::term("test2", 8))
24///    .minimum_should_match("2")
25///    .boost(1.3)
26///    .name("test");
27/// ```
28/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html>
29#[derive(Debug, Default, Clone, PartialEq, Serialize)]
30#[serde(remote = "Self")]
31pub struct BoolQuery {
32    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
33    must: QueryCollection,
34
35    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
36    filter: QueryCollection,
37
38    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
39    should: QueryCollection,
40
41    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
42    must_not: QueryCollection,
43
44    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
45    minimum_should_match: Option<String>,
46
47    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
48    boost: Option<f32>,
49
50    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
51    _name: Option<String>,
52}
53
54impl Query {
55    /// Creates an instance of [`BoolQuery`]
56    pub fn bool() -> BoolQuery {
57        BoolQuery::default()
58    }
59}
60
61impl BoolQuery {
62    /// The clause (query) must appear in matching documents and will contribute to the score.
63    pub fn must<T>(mut self, query: T) -> Self
64    where
65        T: IntoIterator,
66        T::Item: Into<Query>,
67    {
68        self.must.extend(query);
69        self
70    }
71
72    /// The clause (query) should appear in the matching document.
73    pub fn should<T>(mut self, query: T) -> Self
74    where
75        T: IntoIterator,
76        T::Item: Into<Query>,
77    {
78        self.should.extend(query);
79        self
80    }
81
82    /// The clause (query) must appear in matching documents.
83    /// However unlike must the score of the query will be ignored.
84    /// Filter clauses are executed in [filter context](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html),
85    /// meaning that scoring is ignored and clauses are considered for caching.
86    pub fn filter<T>(mut self, query: T) -> Self
87    where
88        T: IntoIterator,
89        T::Item: Into<Query>,
90    {
91        self.filter.extend(query);
92        self
93    }
94
95    /// The clause (query) must not appear in the matching documents.
96    /// Clauses are executed in [filter context](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html)
97    /// meaning that scoring is ignored and clauses are considered for caching.
98    /// Because scoring is ignored, a score of `0` for all documents is returned.
99    pub fn must_not<T>(mut self, query: T) -> Self
100    where
101        T: IntoIterator,
102        T::Item: Into<Query>,
103    {
104        self.must_not.extend(query);
105        self
106    }
107
108    /// You can use the `minimum_should_match` parameter to specify the number
109    /// or percentage of should clauses returned documents must match.
110    ///
111    /// If the `bool` query includes at least one `should` clause and no
112    /// `must` or `filter` clauses, the default value is `1`.
113    /// Otherwise, the default value is `0`.
114    ///
115    /// For other valid values, see the
116    /// [minimum_should_match parameter](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-minimum-should-match.html).
117    pub fn minimum_should_match<T>(mut self, minimum_should_match: T) -> Self
118    where
119        T: ToString,
120    {
121        self.minimum_should_match = Some(minimum_should_match.to_string());
122        self
123    }
124
125    add_boost_and_name!();
126}
127
128impl ShouldSkip for BoolQuery {
129    fn should_skip(&self) -> bool {
130        self.must.should_skip()
131            && self.filter.should_skip()
132            && self.should.should_skip()
133            && self.must_not.should_skip()
134    }
135}
136
137serialize_with_root!("bool": BoolQuery);
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142
143    #[test]
144    fn serialization() {
145        assert_serialize_query(Query::bool(), json!({ "bool": {} }));
146
147        assert_serialize_query(
148            Query::bool()
149                .must([Query::term("test1", 1), Query::term("test2", 2)])
150                .should([Query::term("test1", 3), Query::term("test2", 4)])
151                .filter([Query::term("test1", 5), Query::term("test2", 6)])
152                .must_not([Query::term("test1", 7), Query::term("test2", 8)])
153                .minimum_should_match("2")
154                .boost(1.3)
155                .name("test"),
156            json!({
157                "bool": {
158                    "must":[
159                        { "term": { "test1": {"value": 1} } },
160                        { "term": { "test2": {"value": 2} } },
161                    ],
162                    "should":[
163                        { "term": { "test1": {"value": 3} } },
164                        { "term": { "test2": {"value": 4} } },
165                    ],
166                    "filter":[
167                        { "term": { "test1": {"value": 5} } },
168                        { "term": { "test2": {"value": 6} } },
169                    ],
170                    "must_not":[
171                        { "term": { "test1": {"value": 7} } },
172                        { "term": { "test2": {"value": 8} } },
173                    ],
174                    "minimum_should_match": "2",
175                    "boost": 1.3,
176                    "_name":"test"
177                }
178            }),
179        );
180
181        assert_serialize_query(
182            Query::bool()
183                .must(Query::term("test1", 1))
184                .must(Query::term("test2", 2))
185                .should(Query::term("test1", 3))
186                .should(Query::term("test2", 4))
187                .filter(Query::term("test1", 5))
188                .filter(Query::term("test2", 6))
189                .must_not(Query::term("test1", 7))
190                .must_not(Query::term("test2", 8))
191                .minimum_should_match("2")
192                .boost(1.3)
193                .name("test"),
194            json!({
195                "bool": {
196                    "must":[
197                        { "term": { "test1": {"value": 1} } },
198                        { "term": { "test2": {"value": 2} } },
199                    ],
200                    "should":[
201                        { "term": { "test1": {"value": 3} } },
202                        { "term": { "test2": {"value": 4} } },
203                    ],
204                    "filter":[
205                        { "term": { "test1": {"value": 5} } },
206                        { "term": { "test2": {"value": 6} } },
207                    ],
208                    "must_not":[
209                        { "term": { "test1": {"value": 7} } },
210                        { "term": { "test2": {"value": 8} } },
211                    ],
212                    "minimum_should_match": "2",
213                    "boost": 1.3,
214                    "_name":"test"
215                }
216            }),
217        );
218    }
219}