Skip to content

Commit

Permalink
feat: add terms aggregation include, exclude
Browse files Browse the repository at this point in the history
  • Loading branch information
buinauskas committed Apr 8, 2024
1 parent f3f6786 commit 0a9ccca
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 2 deletions.
41 changes: 39 additions & 2 deletions src/search/aggregations/bucket/terms_aggregation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ struct TermsAggregationInner {

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

#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
include: Option<TermsInclude>,

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

impl Aggregation {
Expand All @@ -49,6 +55,8 @@ impl Aggregation {
order: Default::default(),
min_doc_count: None,
missing: None,
include: None,
exclude: None,
},
aggs: Aggregations::new(),
}
Expand Down Expand Up @@ -115,6 +123,24 @@ impl TermsAggregation {
self
}

/// The `include` parameter can be set to include only specific terms in the response.
pub fn include<T>(mut self, include: T) -> Self
where
T: Into<TermsInclude>,
{
self.terms.include = Some(include.into());
self
}

/// The `exclude` parameter can be set to exclude specific terms from the response.
pub fn exclude<T>(mut self, exclude: T) -> Self
where
T: Into<TermsExclude>,
{
self.terms.exclude = Some(exclude.into());
self
}

add_aggregate!();
}

Expand Down Expand Up @@ -155,15 +181,22 @@ mod tests {
.size(0)
.order(TermsOrder::ascending("test_order"))
.missing(123)
.include(["mazda", "honda"])
.exclude("water_.*")
.aggregate(
"test_sub_agg",
Aggregation::terms("test_field2").size(3).missing(false),
Aggregation::terms("test_field2")
.size(3)
.missing(false)
.include([0, 20]),
),
json!({
"terms": {
"field": "test_field",
"size": 0,
"missing": 123,
"include": ["mazda", "honda"],
"exclude": "water_.*",
"order": [
{ "test_order": "asc" }
]
Expand All @@ -173,7 +206,11 @@ mod tests {
"terms": {
"field": "test_field2",
"size": 3,
"missing": false
"missing": false,
"include": {
"partition": 0,
"num_partitions": 20
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/search/aggregations/params/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
mod aggregation_name;
mod gap_policy;
mod rate_mode;
mod terms_exclude;
mod terms_include;
mod terms_order;

pub use self::aggregation_name::*;
pub use self::gap_policy::*;
pub use self::rate_mode::*;
pub use self::terms_exclude::*;
pub use self::terms_include::*;
pub use self::terms_order::*;
61 changes: 61 additions & 0 deletions src/search/aggregations/params/terms_exclude.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use crate::util::ShouldSkip;

/// Filter the values for which buckets will be created.
#[derive(Debug, Clone, Serialize, PartialEq)]
#[serde(untagged)]
pub enum TermsExclude {
/// Filter buckets by their regular expression pattern.
///
/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html#_filtering_values_with_regular_expressions_2>
Regex(String),

/// Filter buckets by their exact value.
///
/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html#_filtering_values_with_exact_values_2>
Exact(Vec<String>),
}

impl ShouldSkip for TermsExclude {
fn should_skip(&self) -> bool {
match self {
Self::Regex(ref s) => s.is_empty(),
Self::Exact(ref v) => v.is_empty(),
}
}
}

impl From<String> for TermsExclude {
fn from(s: String) -> Self {
Self::Regex(s)
}
}

impl From<&str> for TermsExclude {
fn from(s: &str) -> Self {
Self::Regex(s.to_string())
}
}

impl From<Vec<String>> for TermsExclude {
fn from(v: Vec<String>) -> Self {
Self::Exact(v)
}
}

impl From<Vec<&str>> for TermsExclude {
fn from(v: Vec<&str>) -> Self {
Self::Exact(v.iter().map(|s| s.to_string()).collect())
}
}

impl From<&[&str]> for TermsExclude {
fn from(v: &[&str]) -> Self {
Self::Exact(v.iter().map(|s| s.to_string()).collect())
}
}

impl<const N: usize> From<[&str; N]> for TermsExclude {
fn from(value: [&str; N]) -> Self {
Self::Exact(value.iter().map(|s| s.to_string()).collect())
}
}
90 changes: 90 additions & 0 deletions src/search/aggregations/params/terms_include.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use crate::util::ShouldSkip;

/// Filter the values for which buckets will be created.
#[derive(Debug, Clone, Serialize, PartialEq)]
#[serde(untagged)]
pub enum TermsInclude {
/// Filter buckets by their regular expression pattern.
///
/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html#_filtering_values_with_regular_expressions_2>
Regex(String),

/// Filter buckets by their exact value.
///
/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html#_filtering_values_with_exact_values_2>
Exact(Vec<String>),

/// A number of partitions at query-time and processing only one partition in each request.
///
/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html#_filtering_values_with_partitions>
Partitions {
/// The partition number to return.
partition: u32,
/// The number of partitions to create.
num_partitions: u32,
},
}

impl ShouldSkip for TermsInclude {
fn should_skip(&self) -> bool {
match self {
Self::Regex(ref s) => s.is_empty(),
Self::Exact(ref v) => v.is_empty(),
Self::Partitions { .. } => false,
}
}
}

impl From<String> for TermsInclude {
fn from(s: String) -> Self {
Self::Regex(s)
}
}

impl From<&str> for TermsInclude {
fn from(s: &str) -> Self {
Self::Regex(s.to_string())
}
}

impl From<Vec<String>> for TermsInclude {
fn from(v: Vec<String>) -> Self {
Self::Exact(v)
}
}

impl From<Vec<&str>> for TermsInclude {
fn from(v: Vec<&str>) -> Self {
Self::Exact(v.iter().map(|s| s.to_string()).collect())
}
}

impl From<&[&str]> for TermsInclude {
fn from(v: &[&str]) -> Self {
Self::Exact(v.iter().map(|s| s.to_string()).collect())
}
}

impl<const N: usize> From<[&str; N]> for TermsInclude {
fn from(value: [&str; N]) -> Self {
Self::Exact(value.iter().map(|s| s.to_string()).collect())
}
}

impl From<(u32, u32)> for TermsInclude {
fn from(value: (u32, u32)) -> Self {
Self::Partitions {
partition: value.0,
num_partitions: value.1,
}
}
}

impl From<[u32; 2]> for TermsInclude {
fn from(value: [u32; 2]) -> Self {
Self::Partitions {
partition: value[0],
num_partitions: value[1],
}
}
}

0 comments on commit 0a9ccca

Please sign in to comment.