elasticsearch_dsl/search/queries/specialized/
rank_feature_query.rs

1use crate::search::*;
2use crate::util::*;
3use serde::Serialize;
4
5/// Boosts the relevance score of documents based on the numeric value of a `rank_feature` or
6/// `rank_features` field.
7///
8/// To create a rank feature query:
9/// ```
10/// # use elasticsearch_dsl::queries::*;
11/// # use elasticsearch_dsl::queries::params::*;
12/// # let query =
13/// Query::rank_feature("test");
14/// ```
15/// To apply mathematical functions:
16/// ```
17/// # use elasticsearch_dsl::queries::*;
18/// # use elasticsearch_dsl::queries::params::*;
19/// # let query =
20/// Query::rank_feature("test").saturation();
21/// # let query =
22/// Query::rank_feature("test").saturation().pivot(2.2);
23/// # let query =
24/// Query::rank_feature("test").logarithm(3.0);
25/// # let query =
26/// Query::rank_feature("test").sigmoid(1.0, 2.0);
27/// # let query =
28/// Query::rank_feature("test").linear();
29/// ```
30/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-rank-feature-query.html>
31#[derive(Debug, Clone, PartialEq, Serialize)]
32#[serde(remote = "Self")]
33pub struct RankFeatureQuery {
34    field: String,
35
36    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
37    boost: Option<f32>,
38
39    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
40    _name: Option<String>,
41}
42
43/// Boosts the relevance score of documents based on the numeric value of a `rank_feature` or
44/// `rank_features` field.
45///
46/// To create a rank feature query:
47/// ```
48/// # use elasticsearch_dsl::queries::*;
49/// # use elasticsearch_dsl::queries::params::*;
50/// # let query =
51/// Query::rank_feature("test");
52/// ```
53/// To apply mathematical functions:
54/// ```
55/// # use elasticsearch_dsl::queries::*;
56/// # use elasticsearch_dsl::queries::params::*;
57/// # let query =
58/// Query::rank_feature("test").saturation();
59/// # let query =
60/// Query::rank_feature("test").saturation().pivot(2.2);
61/// # let query =
62/// Query::rank_feature("test").logarithm(3.0);
63/// # let query =
64/// Query::rank_feature("test").sigmoid(1.0, 2.0);
65/// # let query =
66/// Query::rank_feature("test").linear();
67/// ```
68/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-rank-feature-query.html>
69#[derive(Debug, Clone, PartialEq, Serialize)]
70#[serde(remote = "Self")]
71pub struct RankFeatureSaturationQuery {
72    field: String,
73
74    saturation: Saturation,
75
76    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
77    boost: Option<f32>,
78
79    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
80    _name: Option<String>,
81}
82
83/// Boosts the relevance score of documents based on the numeric value of a `rank_feature` or
84/// `rank_features` field.
85///
86/// To create a rank feature query:
87/// ```
88/// # use elasticsearch_dsl::queries::*;
89/// # use elasticsearch_dsl::queries::params::*;
90/// # let query =
91/// Query::rank_feature("test");
92/// ```
93/// To apply mathematical functions:
94/// ```
95/// # use elasticsearch_dsl::queries::*;
96/// # use elasticsearch_dsl::queries::params::*;
97/// # let query =
98/// Query::rank_feature("test").saturation();
99/// # let query =
100/// Query::rank_feature("test").saturation().pivot(2.2);
101/// # let query =
102/// Query::rank_feature("test").logarithm(3.0);
103/// # let query =
104/// Query::rank_feature("test").sigmoid(1.0, 2.0);
105/// # let query =
106/// Query::rank_feature("test").linear();
107/// ```
108/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-rank-feature-query.html>
109#[derive(Debug, Clone, PartialEq, Serialize)]
110#[serde(remote = "Self")]
111pub struct RankFeatureLogarithmQuery {
112    field: String,
113
114    log: Logarithm,
115
116    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
117    boost: Option<f32>,
118
119    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
120    _name: Option<String>,
121}
122
123/// Boosts the relevance score of documents based on the numeric value of a `rank_feature` or
124/// `rank_features` field.
125///
126/// To create a rank feature query:
127/// ```
128/// # use elasticsearch_dsl::queries::*;
129/// # use elasticsearch_dsl::queries::params::*;
130/// # let query =
131/// Query::rank_feature("test");
132/// ```
133/// To apply mathematical functions:
134/// ```
135/// # use elasticsearch_dsl::queries::*;
136/// # use elasticsearch_dsl::queries::params::*;
137/// # let query =
138/// Query::rank_feature("test").saturation();
139/// # let query =
140/// Query::rank_feature("test").saturation().pivot(2.2);
141/// # let query =
142/// Query::rank_feature("test").logarithm(3.0);
143/// # let query =
144/// Query::rank_feature("test").sigmoid(1.0, 2.0);
145/// # let query =
146/// Query::rank_feature("test").linear();
147/// ```
148/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-rank-feature-query.html>
149#[derive(Debug, Clone, PartialEq, Serialize)]
150#[serde(remote = "Self")]
151pub struct RankFeatureSigmoidQuery {
152    field: String,
153
154    sigmoid: Sigmoid,
155
156    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
157    boost: Option<f32>,
158
159    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
160    _name: Option<String>,
161}
162
163/// Boosts the relevance score of documents based on the numeric value of a `rank_feature` or
164/// `rank_features` field.
165///
166/// To create a rank feature query:
167/// ```
168/// # use elasticsearch_dsl::queries::*;
169/// # use elasticsearch_dsl::queries::params::*;
170/// # let query =
171/// Query::rank_feature("test");
172/// ```
173/// To apply mathematical functions:
174/// ```
175/// # use elasticsearch_dsl::queries::*;
176/// # use elasticsearch_dsl::queries::params::*;
177/// # let query =
178/// Query::rank_feature("test").saturation();
179/// # let query =
180/// Query::rank_feature("test").saturation().pivot(2.2);
181/// # let query =
182/// Query::rank_feature("test").logarithm(3.0);
183/// # let query =
184/// Query::rank_feature("test").sigmoid(1.0, 2.0);
185/// # let query =
186/// Query::rank_feature("test").linear();
187/// ```
188/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-rank-feature-query.html>
189#[derive(Debug, Clone, PartialEq, Serialize)]
190#[serde(remote = "Self")]
191pub struct RankFeatureLinearQuery {
192    field: String,
193
194    linear: Linear,
195
196    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
197    boost: Option<f32>,
198
199    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
200    _name: Option<String>,
201}
202
203#[derive(Debug, Clone, PartialEq, Serialize)]
204struct Saturation {
205    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
206    pivot: Option<f64>,
207}
208
209#[derive(Debug, Clone, PartialEq, Serialize)]
210struct Logarithm {
211    scaling_factor: f64,
212}
213
214#[derive(Debug, Clone, PartialEq, Serialize)]
215struct Sigmoid {
216    pivot: f64,
217    exponent: f64,
218}
219
220#[derive(Debug, Clone, PartialEq, Serialize)]
221struct Linear {}
222
223impl Query {
224    /// Creates an instance of [`RankFeatureQuery`]
225    ///
226    /// - `field` - `rank_feature` or `rank_features` field used to boost relevance scores
227    pub fn rank_feature<T>(field: T) -> RankFeatureQuery
228    where
229        T: ToString,
230    {
231        RankFeatureQuery {
232            field: field.to_string(),
233            boost: None,
234            _name: None,
235        }
236    }
237}
238
239impl RankFeatureQuery {
240    /// The `saturation` function gives a score equal to `S / (S + pivot)`, where `S` is the value
241    /// of the rank feature field and `pivot` is a configurable pivot value so that the result will
242    /// be less than `0.5` if `S` is less than pivot and greater than `0.5` otherwise.
243    /// Scores are always `(0,1)`.
244    ///
245    /// If the rank feature has a negative score impact then the function will be computed as
246    /// `pivot / (S + pivot)`, which decreases when `S` increases.
247    ///
248    /// If a `pivot` value is not provided, Elasticsearch computes a default value equal to the
249    /// approximate geometric mean of all rank feature values in the index. We recommend using this
250    /// default value if you haven’t had the opportunity to train a good pivot value.
251    pub fn saturation(self) -> RankFeatureSaturationQuery {
252        RankFeatureSaturationQuery {
253            field: self.field,
254            boost: self.boost,
255            _name: self._name,
256            saturation: Saturation { pivot: None },
257        }
258    }
259
260    /// The `log` function gives a score equal to `log(scaling_factor + S)`, where `S` is the value
261    /// of the rank feature field and `scaling_factor` is a configurable scaling factor.
262    /// Scores are unbounded.
263    ///
264    /// This function only supports rank features that have a positive score impact.
265    pub fn logarithm(self, scaling_factor: f64) -> RankFeatureLogarithmQuery {
266        RankFeatureLogarithmQuery {
267            field: self.field,
268            boost: self.boost,
269            _name: self._name,
270            log: Logarithm { scaling_factor },
271        }
272    }
273
274    /// The `sigmoid` function is an extension of `saturation` which adds a configurable exponent.
275    /// Scores are computed as `S^exp^ / (S^exp^ + pivot^exp^)`. Like for the `saturation` function,
276    /// `pivot` is the value of `S` that gives a score of `0.5` and scores are `(0,1)`.
277    ///
278    /// The `exponent` must be positive and is typically in `[0.5, 1]`. A good value should be
279    /// computed via training. If you don’t have the opportunity to do so, we recommend you use the
280    /// `saturation` function instead.
281    pub fn sigmoid(self, pivot: f64, exponent: f64) -> RankFeatureSigmoidQuery {
282        RankFeatureSigmoidQuery {
283            field: self.field,
284            boost: self.boost,
285            _name: self._name,
286            sigmoid: Sigmoid { pivot, exponent },
287        }
288    }
289
290    /// The `linear` function is the simplest function, and gives a score equal to the indexed
291    /// value of `S`, where `S` is the value of the rank feature field. If a rank feature field is
292    /// indexed with `"positive_score_impact": true`, its indexed value is equal to `S` and rounded
293    /// to preserve only 9 significant bits for the precision. If a rank feature field is indexed
294    /// with `"positive_score_impact": false`, its indexed value is equal to `1/S` and rounded to
295    /// preserve only 9 significant bits for the precision.
296    pub fn linear(self) -> RankFeatureLinearQuery {
297        RankFeatureLinearQuery {
298            field: self.field,
299            boost: self.boost,
300            _name: self._name,
301            linear: Linear {},
302        }
303    }
304
305    add_boost_and_name!();
306}
307
308impl RankFeatureSaturationQuery {
309    /// Sets pivot value
310    pub fn pivot<T>(mut self, pivot: T) -> Self
311    where
312        T: Into<f64>,
313    {
314        self.saturation.pivot = Some(pivot.into());
315        self
316    }
317
318    add_boost_and_name!();
319}
320
321impl RankFeatureLogarithmQuery {
322    add_boost_and_name!();
323}
324
325impl RankFeatureSigmoidQuery {
326    add_boost_and_name!();
327}
328
329impl RankFeatureLinearQuery {
330    add_boost_and_name!();
331}
332
333impl ShouldSkip for RankFeatureQuery {}
334impl ShouldSkip for RankFeatureSaturationQuery {}
335impl ShouldSkip for RankFeatureLogarithmQuery {}
336impl ShouldSkip for RankFeatureSigmoidQuery {}
337impl ShouldSkip for RankFeatureLinearQuery {}
338
339serialize_with_root!("rank_feature": RankFeatureQuery);
340serialize_with_root!("rank_feature": RankFeatureSaturationQuery);
341serialize_with_root!("rank_feature": RankFeatureLogarithmQuery);
342serialize_with_root!("rank_feature": RankFeatureSigmoidQuery);
343serialize_with_root!("rank_feature": RankFeatureLinearQuery);
344
345#[cfg(test)]
346mod tests {
347    use super::*;
348
349    #[test]
350    fn serialization() {
351        assert_serialize_query(
352            Query::rank_feature("test"),
353            json!({
354                "rank_feature": {
355                    "field": "test",
356                }
357            }),
358        );
359
360        assert_serialize_query(
361            Query::rank_feature("test").boost(2).name("query"),
362            json!({
363                "rank_feature": {
364                    "field": "test",
365                    "boost": 2.0,
366                    "_name": "query",
367                }
368            }),
369        );
370
371        assert_serialize_query(
372            Query::rank_feature("test")
373                .saturation()
374                .boost(2)
375                .name("query"),
376            json!({
377                "rank_feature": {
378                    "field": "test",
379                    "boost": 2.0,
380                    "_name": "query",
381                    "saturation": {},
382                }
383            }),
384        );
385
386        assert_serialize_query(
387            Query::rank_feature("test")
388                .saturation()
389                .pivot(2.2)
390                .boost(2)
391                .name("query"),
392            json!({
393                "rank_feature": {
394                    "field": "test",
395                    "boost": 2.0,
396                    "_name": "query",
397                    "saturation": {
398                        "pivot": 2.2,
399                    },
400                }
401            }),
402        );
403
404        assert_serialize_query(
405            Query::rank_feature("test")
406                .logarithm(2.2)
407                .boost(2)
408                .name("query"),
409            json!({
410                "rank_feature": {
411                    "field": "test",
412                    "boost": 2.0,
413                    "_name": "query",
414                    "log": {
415                        "scaling_factor": 2.2
416                    },
417                }
418            }),
419        );
420
421        assert_serialize_query(
422            Query::rank_feature("test")
423                .sigmoid(2.2, 3.3)
424                .boost(2)
425                .name("query"),
426            json!({
427                "rank_feature": {
428                    "field": "test",
429                    "boost": 2.0,
430                    "_name": "query",
431                    "sigmoid": {
432                        "pivot": 2.2,
433                        "exponent": 3.3,
434                    },
435                }
436            }),
437        );
438
439        assert_serialize_query(
440            Query::rank_feature("test").linear().boost(2).name("query"),
441            json!({
442                "rank_feature": {
443                    "field": "test",
444                    "boost": 2.0,
445                    "_name": "query",
446                    "linear": {},
447                }
448            }),
449        );
450    }
451}