Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions datasketches/src/countmin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,25 @@
//!
//! The Count-Min sketch provides approximate frequency counts for streaming data
//! with configurable relative error and confidence bounds.
//!
//! # Usage
//!
//! ```rust
//! # use datasketches::countmin::CountMinSketch;
//! let mut sketch = CountMinSketch::new(5, 256);
//! sketch.update("apple");
//! sketch.update_with_weight("banana", 3);
//! assert!(sketch.estimate("banana") >= 3);
//! ```
//!
//! # Configuration Helpers
//!
//! ```rust
//! # use datasketches::countmin::CountMinSketch;
//! let buckets = CountMinSketch::suggest_num_buckets(0.01);
//! let hashes = CountMinSketch::suggest_num_hashes(0.99);
//! let _sketch = CountMinSketch::new(hashes, buckets);
//! ```

mod serialization;

Expand Down
90 changes: 90 additions & 0 deletions datasketches/src/countmin/sketch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ impl CountMinSketch {
///
/// Panics if `num_hashes` is 0, `num_buckets` is less than 3, or the
/// total table size exceeds the supported limit.
///
/// # Examples
///
/// ```rust
/// # use datasketches::countmin::CountMinSketch;
/// let sketch = CountMinSketch::new(4, 128);
/// assert_eq!(sketch.num_buckets(), 128);
/// ```
pub fn new(num_hashes: u8, num_buckets: u32) -> Self {
Self::with_seed(num_hashes, num_buckets, DEFAULT_UPDATE_SEED)
}
Expand All @@ -64,6 +72,14 @@ impl CountMinSketch {
///
/// Panics if `num_hashes` is 0, `num_buckets` is less than 3, or the
/// total table size exceeds the supported limit.
///
/// # Examples
///
/// ```rust
/// # use datasketches::countmin::CountMinSketch;
/// let sketch = CountMinSketch::with_seed(4, 64, 42);
/// assert_eq!(sketch.seed(), 42);
/// ```
pub fn with_seed(num_hashes: u8, num_buckets: u32, seed: u64) -> Self {
let entries = entries_for_config(num_hashes, num_buckets);
Self::make(num_hashes, num_buckets, seed, entries)
Expand Down Expand Up @@ -127,11 +143,29 @@ impl CountMinSketch {
}

/// Updates the sketch with a single occurrence of the item.
///
/// # Examples
///
/// ```rust
/// # use datasketches::countmin::CountMinSketch;
/// let mut sketch = CountMinSketch::new(4, 128);
/// sketch.update("apple");
/// assert!(sketch.estimate("apple") >= 1);
/// ```
pub fn update<T: Hash>(&mut self, item: T) {
self.update_with_weight(item, 1);
}

/// Updates the sketch with the given item and weight.
///
/// # Examples
///
/// ```rust
/// # use datasketches::countmin::CountMinSketch;
/// let mut sketch = CountMinSketch::new(4, 128);
/// sketch.update_with_weight("banana", 3);
/// assert!(sketch.estimate("banana") >= 3);
/// ```
pub fn update_with_weight<T: Hash>(&mut self, item: T, weight: i64) {
if weight == 0 {
return;
Expand All @@ -147,6 +181,15 @@ impl CountMinSketch {
}

/// Returns the estimated frequency of the given item.
///
/// # Examples
///
/// ```rust
/// # use datasketches::countmin::CountMinSketch;
/// let mut sketch = CountMinSketch::new(4, 128);
/// sketch.update_with_weight("pear", 2);
/// assert!(sketch.estimate("pear") >= 2);
/// ```
pub fn estimate<T: Hash>(&self, item: T) -> i64 {
let num_buckets = self.num_buckets as usize;
let mut min = i64::MAX;
Expand Down Expand Up @@ -178,6 +221,20 @@ impl CountMinSketch {
/// # Panics
///
/// Panics if the sketches have incompatible configurations.
///
/// # Examples
///
/// ```rust
/// # use datasketches::countmin::CountMinSketch;
/// let mut left = CountMinSketch::new(4, 128);
/// let mut right = CountMinSketch::new(4, 128);
///
/// left.update("apple");
/// right.update_with_weight("banana", 2);
///
/// left.merge(&right);
/// assert!(left.estimate("banana") >= 2);
/// ```
pub fn merge(&mut self, other: &CountMinSketch) {
if std::ptr::eq(self, other) {
panic!("Cannot merge a sketch with itself.");
Expand All @@ -195,6 +252,17 @@ impl CountMinSketch {
}

/// Serializes this sketch into the DataSketches Count-Min format.
///
/// # Examples
///
/// ```rust
/// # use datasketches::countmin::CountMinSketch;
/// # let mut sketch = CountMinSketch::new(4, 128);
/// # sketch.update("apple");
/// let bytes = sketch.serialize();
/// let decoded = CountMinSketch::deserialize(&bytes).unwrap();
/// assert!(decoded.estimate("apple") >= 1);
/// ```
pub fn serialize(&self) -> Vec<u8> {
let header_size = PREAMBLE_LONGS_SHORT as usize * LONG_SIZE_BYTES;
let payload_size = if self.is_empty() {
Expand Down Expand Up @@ -227,11 +295,33 @@ impl CountMinSketch {
}

/// Deserializes a sketch from bytes using the default seed.
///
/// # Examples
///
/// ```rust
/// # use datasketches::countmin::CountMinSketch;
/// # let mut sketch = CountMinSketch::new(4, 64);
/// # sketch.update("apple");
/// # let bytes = sketch.serialize();
/// let decoded = CountMinSketch::deserialize(&bytes).unwrap();
/// assert!(decoded.estimate("apple") >= 1);
/// ```
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
Self::deserialize_with_seed(bytes, DEFAULT_UPDATE_SEED)
}

/// Deserializes a sketch from bytes using the provided seed.
///
/// # Examples
///
/// ```rust
/// # use datasketches::countmin::CountMinSketch;
/// # let mut sketch = CountMinSketch::with_seed(4, 64, 7);
/// # sketch.update("apple");
/// # let bytes = sketch.serialize();
/// let decoded = CountMinSketch::deserialize_with_seed(&bytes, 7).unwrap();
/// assert!(decoded.estimate("apple") >= 1);
/// ```
pub fn deserialize_with_seed(bytes: &[u8], seed: u64) -> Result<Self, Error> {
fn make_error(tag: &'static str) -> impl FnOnce(std::io::Error) -> Error {
move |_| Error::insufficient_data(tag)
Expand Down
10 changes: 10 additions & 0 deletions datasketches/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ impl fmt::Display for ErrorKind {
}

/// Error is the error struct returned by all datasketches functions.
///
/// # Examples
///
/// ```
/// # use datasketches::error::Error;
/// # use datasketches::error::ErrorKind;
/// let err = Error::new(ErrorKind::InvalidArgument, "bad input");
/// assert_eq!(err.kind(), ErrorKind::InvalidArgument);
/// assert_eq!(err.message(), "bad input");
/// ```
pub struct Error {
kind: ErrorKind,
message: String,
Expand Down
24 changes: 24 additions & 0 deletions datasketches/src/frequencies/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,30 @@
//!
//! For background, see the Java documentation:
//! <https://apache.github.io/datasketches-java/9.0.0/org/apache/datasketches/frequencies/FrequentItemsSketch.html>
//!
//! # Usage
//!
//! ```rust
//! # use datasketches::frequencies::ErrorType;
//! # use datasketches::frequencies::FrequentItemsSketch;
//! let mut sketch = FrequentItemsSketch::<i64>::new(64);
//! sketch.update_with_count(1, 3);
//! sketch.update(2);
//! let rows = sketch.frequent_items(ErrorType::NoFalseNegatives);
//! assert!(rows.iter().any(|row| *row.item() == 1));
//! ```
//!
//! # Serialization
//!
//! ```rust
//! # use datasketches::frequencies::FrequentItemsSketch;
//! let mut sketch = FrequentItemsSketch::<i64>::new(64);
//! sketch.update_with_count(42, 2);
//!
//! let bytes = sketch.serialize();
//! let decoded = FrequentItemsSketch::<i64>::deserialize(&bytes).unwrap();
//! assert!(decoded.estimate(&42) >= 2);
//! ```

mod reverse_purge_item_hash_map;
mod serialization;
Expand Down
Loading