Skip to content

Commit

Permalink
Implement metrics aggregations (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
iamazy authored Oct 28, 2021
1 parent d6f4daa commit e1d2928
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/search/aggregations/metrics/avg_aggregation.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::util::*;
use crate::{Aggregation, Numeric};

/// A single-value metrics aggregation that computes the average of numeric values that are extracted
/// A `single-value` metrics aggregation that computes the average of numeric values that are extracted
/// from the aggregated documents. These values can be extracted either from specific numeric fields
/// in the documents.
///
Expand Down
72 changes: 72 additions & 0 deletions src/search/aggregations/metrics/max_aggregation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use crate::util::*;
use crate::{Aggregation, Numeric};

/// A `single-value` metrics aggregation that keeps track and returns the maximum value among the
/// numeric values extracted from the aggregated documents.
///
/// > The `min` and `max` aggregation operate on the `double` representation of the data. As a
/// consequence, the result may be approximate when running on longs whose absolute value is greater
/// than `2^53`.
///
/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-max-aggregation.html>
#[derive(Debug, Clone, Serialize, PartialEq)]
pub struct MaxAggregation {
#[serde(skip_serializing)]
pub(crate) name: String,
max: MaxAggregationInner,
}

#[derive(Debug, Clone, Serialize, PartialEq)]
struct MaxAggregationInner {
field: String,

#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
missing: Option<Numeric>,
}

impl Aggregation {
/// Creates an instance of [`MaxAggregation`]
///
/// - `name` - name of the aggregation
pub fn max(name: impl Into<String>, field: impl Into<String>) -> MaxAggregation {
MaxAggregation {
name: name.into(),
max: MaxAggregationInner {
field: field.into(),
missing: None,
},
}
}
}

impl MaxAggregation {
/// The `missing` parameter defines how documents that are missing a value should be treated. By
/// default they will be ignored but it is also possible to treat them as if they had a value.
pub fn missing(mut self, missing: impl Into<Numeric>) -> Self {
self.max.missing = Some(missing.into());
self
}
}

#[cfg(test)]
mod tests {
use super::*;

test_serialization! {
with_required_fields(
Aggregation::max("test_max", "test_field"),
json!({ "max": { "field": "test_field" } })
);

with_all_fields(
Aggregation::max("test_max", "test_field")
.missing(100.1),
json!({
"max": {
"field": "test_field",
"missing": 100.1
}
})
);
}
}
72 changes: 72 additions & 0 deletions src/search/aggregations/metrics/min_aggregation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use crate::util::*;
use crate::{Aggregation, Numeric};

/// A `single-value` metrics aggregation that keeps track and returns the minimum value among numeric
/// values extracted from the aggregated documents.
///
/// > The `min` and `max` aggregation operate on the `double` representation of the data. As a
/// consequence, the result may be approximate when running on longs whose absolute value is greater
/// than `2^53`.
///
/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-min-aggregation.html>
#[derive(Debug, Clone, Serialize, PartialEq)]
pub struct MinAggregation {
#[serde(skip_serializing)]
pub(crate) name: String,
min: MinAggregationInner,
}

#[derive(Debug, Clone, Serialize, PartialEq)]
struct MinAggregationInner {
field: String,

#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
missing: Option<Numeric>,
}

impl Aggregation {
/// Creates an instance of [`MinAggregation`]
///
/// - `name` - name of the aggregation
pub fn min(name: impl Into<String>, field: impl Into<String>) -> MinAggregation {
MinAggregation {
name: name.into(),
min: MinAggregationInner {
field: field.into(),
missing: None,
},
}
}
}

impl MinAggregation {
/// The `missing` parameter defines how documents that are missing a value should be treated. By
/// default they will be ignored but it is also possible to treat them as if they had a value.
pub fn missing(mut self, missing: impl Into<Numeric>) -> Self {
self.min.missing = Some(missing.into());
self
}
}

#[cfg(test)]
mod tests {
use super::*;

test_serialization! {
with_required_fields(
Aggregation::min("test_min", "test_field"),
json!({ "min": { "field": "test_field" } })
);

with_all_fields(
Aggregation::min("test_min", "test_field")
.missing(100.1),
json!({
"min": {
"field": "test_field",
"missing": 100.1
}
})
);
}
}
6 changes: 6 additions & 0 deletions src/search/aggregations/metrics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,14 @@
mod avg_aggregation;
mod cardinality_aggregation;
mod max_aggregation;
mod min_aggregation;
mod sum_aggregation;
mod top_hits_aggregation;

pub use self::avg_aggregation::*;
pub use self::cardinality_aggregation::*;
pub use self::max_aggregation::*;
pub use self::min_aggregation::*;
pub use self::sum_aggregation::*;
pub use self::top_hits_aggregation::*;
69 changes: 69 additions & 0 deletions src/search/aggregations/metrics/sum_aggregation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use crate::util::*;
use crate::{Aggregation, Numeric};

/// A `single-value` metrics aggregation that sums up numeric values that are extracted from the
/// aggregated documents. These values can be extracted either from specific numeric or histogram fields.
///
/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-sum-aggregation.html>
#[derive(Debug, Clone, Serialize, PartialEq)]
pub struct SumAggregation {
#[serde(skip_serializing)]
pub(crate) name: String,
sum: SumAggregationInner,
}

#[derive(Debug, Clone, Serialize, PartialEq)]
struct SumAggregationInner {
field: String,

#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
missing: Option<Numeric>,
}

impl Aggregation {
/// Creates an instance of [`SumAggregation`]
///
/// - `name` - name of the aggregation
pub fn sum(name: impl Into<String>, field: impl Into<String>) -> SumAggregation {
SumAggregation {
name: name.into(),
sum: SumAggregationInner {
field: field.into(),
missing: None,
},
}
}
}

impl SumAggregation {
/// The `missing` parameter defines how documents that are missing a value should be treated. By
/// default documents missing the value will be ignored but it is also possible to treat them
/// as if they had a value.
pub fn missing(mut self, missing: impl Into<Numeric>) -> Self {
self.sum.missing = Some(missing.into());
self
}
}

#[cfg(test)]
mod tests {
use super::*;

test_serialization! {
with_required_fields(
Aggregation::sum("test_sum", "test_field"),
json!({ "sum": { "field": "test_field" } })
);

with_all_fields(
Aggregation::sum("test_sum", "test_field")
.missing(100.1),
json!({
"sum": {
"field": "test_field",
"missing": 100.1
}
})
);
}
}
5 changes: 4 additions & 1 deletion src/search/aggregations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ aggregation!(Aggregation {
Terms(TermsAggregation),
TopHits(TopHitsAggregation),
Cardinality(CardinalityAggregation),
Avg(AvgAggregation)
Avg(AvgAggregation),
Max(MaxAggregation),
Min(MinAggregation),
Sum(SumAggregation),
});

/// Type alias for a collection of aggregations
Expand Down
4 changes: 2 additions & 2 deletions src/search/params/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
//! Value types accepted by leaf query clauses
mod geo_point;
mod scalar;
mod numeric;
mod scalar;
mod search;
mod units;

pub use self::geo_point::*;
pub use self::scalar::*;
pub use self::numeric::*;
pub use self::scalar::*;
pub use self::search::*;
pub use self::units::*;

0 comments on commit e1d2928

Please sign in to comment.