mirror of
https://github.com/quickwit-oss/tantivy.git
synced 2026-01-06 17:22:54 +00:00
121 lines
3.7 KiB
Rust
121 lines
3.7 KiB
Rust
use std::fmt::Debug;
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use super::*;
|
|
use crate::aggregation::*;
|
|
|
|
/// A single-value metric aggregation that computes the maximum of numeric values that are
|
|
/// extracted from the aggregated documents.
|
|
/// See [super::SingleMetricResult] for return value.
|
|
///
|
|
/// # JSON Format
|
|
/// ```json
|
|
/// {
|
|
/// "max": {
|
|
/// "field": "score"
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
pub struct MaxAggregation {
|
|
/// The field name to compute the maximum on.
|
|
pub field: String,
|
|
/// 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. Examples in JSON format:
|
|
/// { "field": "my_numbers", "missing": "10.0" }
|
|
#[serde(default, deserialize_with = "deserialize_option_f64")]
|
|
pub missing: Option<f64>,
|
|
}
|
|
|
|
impl MaxAggregation {
|
|
/// Creates a new [`MaxAggregation`] instance from a field name.
|
|
pub fn from_field_name(field_name: String) -> Self {
|
|
Self {
|
|
field: field_name,
|
|
missing: None,
|
|
}
|
|
}
|
|
/// Returns the field name the aggregation is computed on.
|
|
pub fn field_name(&self) -> &str {
|
|
&self.field
|
|
}
|
|
}
|
|
|
|
/// Intermediate result of the maximum aggregation that can be combined with other intermediate
|
|
/// results.
|
|
#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
pub struct IntermediateMax {
|
|
stats: IntermediateStats,
|
|
}
|
|
|
|
impl IntermediateMax {
|
|
/// Creates a new [`IntermediateMax`] instance from a [`SegmentStatsCollector`].
|
|
pub(crate) fn from_collector(collector: SegmentStatsCollector) -> Self {
|
|
Self {
|
|
stats: collector.stats,
|
|
}
|
|
}
|
|
/// Merges the other intermediate result into self.
|
|
pub fn merge_fruits(&mut self, other: IntermediateMax) {
|
|
self.stats.merge_fruits(other.stats);
|
|
}
|
|
/// Computes the final maximum value.
|
|
pub fn finalize(&self) -> Option<f64> {
|
|
self.stats.finalize().max
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::aggregation::agg_req::Aggregations;
|
|
use crate::aggregation::tests::exec_request_with_query;
|
|
use crate::schema::{Schema, FAST};
|
|
use crate::{Index, IndexWriter};
|
|
|
|
#[test]
|
|
fn test_max_agg_with_missing() -> crate::Result<()> {
|
|
let mut schema_builder = Schema::builder();
|
|
let json = schema_builder.add_json_field("json", FAST);
|
|
let schema = schema_builder.build();
|
|
let index = Index::create_in_ram(schema);
|
|
let mut index_writer: IndexWriter = index.writer_for_tests().unwrap();
|
|
// => Segment with empty json
|
|
index_writer.add_document(doc!()).unwrap();
|
|
index_writer.commit().unwrap();
|
|
// => Segment with json, but no field partially_empty
|
|
index_writer
|
|
.add_document(doc!(json => json!({"different_field": "blue"})))
|
|
.unwrap();
|
|
index_writer.commit().unwrap();
|
|
//// => Segment with field partially_empty
|
|
index_writer
|
|
.add_document(doc!(json => json!({"partially_empty": 10.0})))
|
|
.unwrap();
|
|
index_writer.add_document(doc!())?;
|
|
index_writer.commit().unwrap();
|
|
|
|
let agg_req: Aggregations = serde_json::from_value(json!({
|
|
"my_stats": {
|
|
"max": {
|
|
"field": "json.partially_empty",
|
|
"missing": 100.0,
|
|
}
|
|
}
|
|
}))
|
|
.unwrap();
|
|
|
|
let res = exec_request_with_query(agg_req, &index, None)?;
|
|
|
|
assert_eq!(
|
|
res["my_stats"],
|
|
json!({
|
|
"value": 100.0,
|
|
})
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
}
|