Skip to main content

apache_datasketches/hll/
union.rs

1// apache-datasketches/src/hll/union.rs
2use crate::error::SketchError;
3use crate::hll::sketch::{HllSketch, TargetHllType};
4use apache_datasketches_sys::hll::ffi as sys;
5use cxx::UniquePtr;
6
7/// Merges multiple [`HllSketch`]es into one, e.g. combining per-shard or
8/// per-day counts into a total distinct count across all of them.
9pub struct HllUnion {
10    inner: UniquePtr<sys::HllUnionShim>,
11}
12
13unsafe impl Send for HllUnion {}
14
15impl HllUnion {
16    /// Creates a new, empty union with the given maximum `lg_config_k`
17    /// (`4..=21`) — the union's result will use at most this `lg_config_k`,
18    /// even if a merged-in sketch used a larger one. Returns
19    /// [`SketchError::InvalidConfig`] if `lg_max_k` is out of range.
20    pub fn new(lg_max_k: u8) -> Result<Self, SketchError> {
21        let inner = sys::new_hll_union(lg_max_k)
22            .map_err(|e| SketchError::InvalidConfig(e.what().to_string()))?;
23        Ok(Self { inner })
24    }
25
26    /// Merges the given sketch's state into this union.
27    pub fn update_sketch(&mut self, sketch: &HllSketch) {
28        self.inner.pin_mut().update_sketch(&sketch.inner);
29    }
30
31    /// Adds a `u64` value directly to the union, as if it were added to
32    /// every sketch merged into it.
33    pub fn update_u64(&mut self, value: u64) {
34        self.inner.pin_mut().update_u64(value);
35    }
36
37    /// Adds an `i64` value directly to the union. See [`Self::update_u64`].
38    pub fn update_i64(&mut self, value: i64) {
39        self.inner.pin_mut().update_i64(value);
40    }
41
42    /// Adds an `f64` value directly to the union. See [`Self::update_u64`].
43    pub fn update_f64(&mut self, value: f64) {
44        self.inner.pin_mut().update_f64(value);
45    }
46
47    /// Adds a string value directly to the union. See [`Self::update_u64`].
48    pub fn update_str(&mut self, value: &str) {
49        self.inner.pin_mut().update_str(value);
50    }
51
52    /// Adds an arbitrary byte slice directly to the union. See
53    /// [`Self::update_u64`].
54    pub fn update_bytes(&mut self, value: &[u8]) {
55        self.inner.pin_mut().update_bytes(value);
56    }
57
58    /// Returns the current merged result as a standalone [`HllSketch`] of
59    /// the given [`TargetHllType`].
60    pub fn get_result(&self, tgt_type: TargetHllType) -> HllSketch {
61        let inner = self.inner.get_result(tgt_type.into());
62        HllSketch { inner }
63    }
64
65    /// Serializes `get_result(tgt_type)` in compact form. A union has no
66    /// serializable state of its own upstream (only the result sketch
67    /// does) — to resume accumulating after deserializing, use
68    /// `HllSketch::deserialize` and feed the sketch back in via
69    /// `update_sketch`.
70    pub fn serialize_compact(&self, tgt_type: TargetHllType) -> Vec<u8> {
71        self.inner
72            .serialize_compact(tgt_type.into())
73            .as_slice()
74            .to_vec()
75    }
76
77    /// Serializes `get_result(tgt_type)` in updatable form. See
78    /// [`Self::serialize_compact`] for why `HllUnion` has no `deserialize`.
79    pub fn serialize_updatable(&self, tgt_type: TargetHllType) -> Vec<u8> {
80        self.inner
81            .serialize_updatable(tgt_type.into())
82            .as_slice()
83            .to_vec()
84    }
85
86    /// Returns the current estimate of the number of distinct items merged
87    /// into this union so far.
88    pub fn get_estimate(&self) -> f64 {
89        self.inner.get_estimate()
90    }
91
92    /// Returns the lower bound of the confidence interval around
93    /// [`Self::get_estimate`]. See [`HllSketch::get_lower_bound`] for the
94    /// meaning of `num_std_dev`.
95    pub fn get_lower_bound(&self, num_std_dev: u8) -> Result<f64, SketchError> {
96        self.inner
97            .get_lower_bound(num_std_dev)
98            .map_err(|e| SketchError::InvalidConfig(e.what().to_string()))
99    }
100
101    /// Returns the upper bound of the confidence interval around
102    /// [`Self::get_estimate`]. See [`HllSketch::get_lower_bound`] for the
103    /// meaning of `num_std_dev`.
104    pub fn get_upper_bound(&self, num_std_dev: u8) -> Result<f64, SketchError> {
105        self.inner
106            .get_upper_bound(num_std_dev)
107            .map_err(|e| SketchError::InvalidConfig(e.what().to_string()))
108    }
109
110    /// Returns `true` if no sketch or item has been merged into this union.
111    pub fn is_empty(&self) -> bool {
112        self.inner.is_empty()
113    }
114
115    /// Resets this union to its initial, empty state.
116    pub fn reset(&mut self) {
117        self.inner.pin_mut().reset();
118    }
119}