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}