elasticsearch_dsl/search/queries/compound/dis_max_query.rs
1use crate::search::*;
2use crate::util::*;
3
4/// Returns documents matching one or more wrapped queries, called query clauses or clauses.
5///
6/// If a returned document matches multiple query clauses, the `dis_max` query assigns the document
7/// the highest relevance score from any matching clause, plus a tie breaking increment for any
8/// additional matching subqueries.
9///
10/// You can use the `dis_max` to search for a term in fields mapped with different
11/// [boost](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-boost.html)
12/// factors.
13///
14/// To create disjunction max query:
15/// ```
16/// # use elasticsearch_dsl::queries::*;
17/// # use elasticsearch_dsl::queries::params::*;
18/// # let query =
19/// Query::dis_max()
20/// .query(Query::r#match("t1", "text"))
21/// .query(Query::r#match("t2", "text"))
22/// .tie_breaker(0.5)
23/// .boost(3)
24/// .name("test");
25/// ```
26/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-dis-max-query.html>
27#[derive(Debug, Default, Clone, PartialEq, Serialize)]
28#[serde(remote = "Self")]
29pub struct DisMaxQuery {
30 queries: QueryCollection,
31
32 #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
33 tie_breaker: Option<f32>,
34
35 #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
36 boost: Option<f32>,
37
38 #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
39 _name: Option<String>,
40}
41
42impl Query {
43 /// Creates an instance of [`DisMaxQuery`]
44 pub fn dis_max() -> DisMaxQuery {
45 DisMaxQuery::default()
46 }
47}
48
49impl DisMaxQuery {
50 /// Contains one or more query clauses. Returned documents
51 /// **must match one or more** of these queries. If a document matches multiple queries,
52 /// Elasticsearch uses the highest
53 /// [relevance score](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html)
54 pub fn query<T>(mut self, query: T) -> Self
55 where
56 T: IntoIterator,
57 T::Item: Into<Query>,
58 {
59 self.queries.extend(query);
60 self
61 }
62
63 /// Floating point number between `0` and `1.0` used to increase the
64 /// [relevance scores](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html#relevance-scores)
65 /// of documents matching multiple query clauses. Defaults to `0.0`.
66 ///
67 /// You can use the `tie_breaker` value to assign higher relevance scores to
68 /// documents that contain the same term in multiple fields than documents that
69 /// contain this term in only the best of those multiple fields, without
70 /// confusing this with the better case of two different terms in the multiple
71 /// fields.
72 ///
73 /// If a document matches multiple clauses, the `dis_max` query calculates
74 /// the relevance score for the document as follows:
75 /// 1. Take the relevance score from a matching clause with the highest score.
76 /// 2. Multiply the score from any other matching clauses by the tie_breaker value.
77 /// 3. Add the highest score to the multiplied scores.
78 ///
79 /// If the `tie_breaker` value is greater than `0.0`, all matching clauses
80 /// count, but the clause with the highest score counts most.
81 pub fn tie_breaker(mut self, tie_breaker: f32) -> Self {
82 self.tie_breaker = Some(tie_breaker);
83 self
84 }
85
86 add_boost_and_name!();
87}
88
89impl ShouldSkip for DisMaxQuery {
90 fn should_skip(&self) -> bool {
91 self.queries.should_skip()
92 }
93}
94
95serialize_with_root!("dis_max": DisMaxQuery);
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn serialization() {
103 assert_serialize_query(
104 Query::dis_max()
105 .query(Query::r#match("t1", "text"))
106 .query(Query::r#match("t2", "text")),
107 json!({
108 "dis_max": {
109 "queries": [
110 {
111 "match": {
112 "t1": {
113 "query": "text"
114 }
115 }
116 },
117 {
118 "match": {
119 "t2": {
120 "query": "text"
121 }
122 }
123 }
124 ]
125 }
126 }),
127 );
128
129 assert_serialize_query(
130 Query::dis_max().query([Query::r#match("t1", "text"), Query::r#match("t2", "text")]),
131 json!({
132 "dis_max": {
133 "queries": [
134 {
135 "match": {
136 "t1": {
137 "query": "text"
138 }
139 }
140 },
141 {
142 "match": {
143 "t2": {
144 "query": "text"
145 }
146 }
147 }
148 ]
149 }
150 }),
151 );
152
153 assert_serialize_query(
154 Query::dis_max()
155 .query(Query::r#match("t1", "text"))
156 .query(Query::r#match("t2", "text"))
157 .tie_breaker(0.5)
158 .boost(3)
159 .name("test"),
160 json!({
161 "dis_max": {
162 "queries": [
163 {
164 "match": {
165 "t1": {
166 "query": "text"
167 }
168 }
169 },
170 {
171 "match": {
172 "t2": {
173 "query": "text"
174 }
175 }
176 }
177 ],
178 "tie_breaker": 0.5,
179 "boost": 3.0,
180 "_name": "test"
181 }
182 }),
183 );
184 }
185}