Skip to main content

cpc/
cpc.rs

1//! Standalone demo of the CPC (Compressed Probabilistic Counting) sketch
2//! and union APIs.
3//!
4//! Run with: `cargo run -p apache-datasketches --example cpc --features cpc`
5
6use apache_datasketches::cpc::{CpcSketch, CpcSketchBuilder, CpcUnionBuilder};
7
8fn main() {
9    // A sketch estimates the number of distinct items seen, using bounded
10    // memory regardless of how many items are added. `lg_k` (4..=26)
11    // trades memory for accuracy: higher values are more accurate but use
12    // more space.
13    let mut visitors_day1 = CpcSketchBuilder::new()
14        .lg_k(11)
15        .build()
16        .expect("valid lg_k");
17    for id in 0..10_000u64 {
18        visitors_day1.update_u64(id);
19    }
20
21    let mut visitors_day2 = CpcSketchBuilder::new()
22        .lg_k(11)
23        .build()
24        .expect("valid lg_k");
25    for id in 5_000..15_000u64 {
26        visitors_day2.update_u64(id);
27    }
28
29    println!(
30        "Day 1 unique visitors (estimate): {:.0}",
31        visitors_day1.get_estimate()
32    );
33    println!(
34        "Day 2 unique visitors (estimate): {:.0}",
35        visitors_day2.get_estimate()
36    );
37    println!(
38        "Day 1, 95% confidence interval: [{:.0}, {:.0}]",
39        visitors_day1.get_lower_bound(2).unwrap(),
40        visitors_day1.get_upper_bound(2).unwrap()
41    );
42
43    // CpcUnion merges multiple sketches into one, e.g. combining per-day
44    // counts into a total distinct count across both days.
45    let mut union = CpcUnionBuilder::new().lg_k(11).build().expect("valid lg_k");
46    union.update(&visitors_day1);
47    union.update(&visitors_day2);
48    let total_unique = union.get_result();
49    println!(
50        "Total unique visitors across both days (true count = 15000): {:.0}",
51        total_unique.get_estimate()
52    );
53
54    // Sketches can be serialized to bytes (e.g. to store or send over the
55    // network) and reconstructed later. CPC's serialized form is always
56    // compressed, so there's a single serialize()/deserialize() pair
57    // (unlike Theta, which has separate compressed/uncompressed formats).
58    let bytes = visitors_day1.serialize();
59    let restored = CpcSketch::deserialize(&bytes).expect("valid sketch bytes");
60    println!(
61        "serialized day-1 sketch to {} bytes and restored successfully (estimate {:.0})",
62        bytes.len(),
63        restored.get_estimate()
64    );
65}