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}