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}