elasticsearch_dsl/search/aggregations/metrics/
top_hits_aggregation.rs

1use crate::search::*;
2use crate::util::*;
3
4/// A `top_hits` metric aggregation keeps track of the most relevant document being aggregated.
5/// This aggregation is intended to be used as a sub aggregation,
6/// so that the top matching documents can be aggregated per bucket.
7///
8/// > We do not recommend using `top_hits` as a top-level aggregation.
9/// > If you want to group search hits, use the
10/// > [`collapse`](https://www.elastic.co/guide/en/elasticsearch/reference/current/collapse-search-results.html)
11/// > parameter instead.
12///
13/// The `top_hits` aggregation can effectively be used to group result sets
14/// by certain fields via a bucket aggregation. One or more bucket aggregations
15/// determines by which properties a result set get sliced into.
16///
17/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-top-hits-aggregation.html>
18#[derive(Debug, Clone, Serialize, PartialEq)]
19pub struct TopHitsAggregation {
20    top_hits: TopHitsAggregationInner,
21}
22
23#[derive(Debug, Clone, Serialize, PartialEq)]
24struct TopHitsAggregationInner {
25    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
26    _source: Option<SourceFilter>,
27
28    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
29    from: Option<u64>,
30
31    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
32    size: Option<u64>,
33
34    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
35    sort: SortCollection,
36}
37
38impl Aggregation {
39    /// Creates an instance of [`TopHitsAggregation`]
40    pub fn top_hits() -> TopHitsAggregation {
41        TopHitsAggregation {
42            top_hits: TopHitsAggregationInner {
43                _source: None,
44                from: None,
45                size: None,
46                sort: Default::default(),
47            },
48        }
49    }
50}
51
52impl TopHitsAggregation {
53    /// Indicates which source fields are returned for matching documents
54    pub fn source<T>(mut self, source: T) -> Self
55    where
56        T: Into<SourceFilter>,
57    {
58        self.top_hits._source = Some(source.into());
59        self
60    }
61
62    /// The offset from the first result you want to fetch.
63    pub fn from(mut self, from: u64) -> Self {
64        self.top_hits.from = Some(from);
65        self
66    }
67
68    /// The maximum number of top matching hits to return per bucket.
69    ///
70    /// By default the top three matching hits are returned.
71    pub fn size(mut self, size: u64) -> Self {
72        self.top_hits.size = Some(size);
73        self
74    }
75
76    /// A collection of sorting fields
77    pub fn sort<T>(mut self, sort: T) -> Self
78    where
79        T: IntoIterator,
80        T::Item: Into<Sort>,
81    {
82        self.top_hits.sort.extend(sort);
83        self
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn serialization() {
93        assert_serialize_aggregation(Aggregation::top_hits(), json!({ "top_hits": { } }));
94
95        assert_serialize_aggregation(
96            Aggregation::top_hits()
97                .source(false)
98                .from(2)
99                .size(10)
100                .sort(FieldSort::new("sort_field").order(SortOrder::Desc)),
101            json!({
102                "top_hits": {
103                    "_source": false,
104                    "from": 2,
105                    "size": 10,
106                    "sort": [
107                        { "sort_field": { "order": "desc" } }
108                    ]
109                }
110            }),
111        );
112    }
113}