use processor::aggregation::{
Aggregator, AverageAggregator, CompositeAggregator, CountAggregator, MaxAggregator,
MinAggregator, PercentileAggregator, StandardDeviationAggregator, SumAggregator,
};
fn main() {
println!("=== Stream Aggregation Demo ===\n");
println!("1. Basic Aggregation - Request Latencies");
println!(" Computing various statistics on latency data\n");
basic_aggregation_example();
println!("\n{}\n", "=".repeat(60));
println!("2. Composite Aggregation - All Stats in One Pass");
println!(" Efficiently computing multiple statistics simultaneously\n");
composite_aggregation_example();
println!("\n{}\n", "=".repeat(60));
println!("3. Distributed Processing - Merging Partial Results");
println!(" Processing data across multiple workers and merging results\n");
distributed_processing_example();
println!("\n{}\n", "=".repeat(60));
println!("4. Time Window Aggregation - Tumbling Windows");
println!(" Simulating aggregation over 5-second time windows\n");
time_window_example();
println!("\n{}\n", "=".repeat(60));
println!("5. Real-World: API Endpoint Monitoring");
println!(" Tracking multiple metrics for an API endpoint\n");
api_monitoring_example();
}
fn basic_aggregation_example() {
let latencies = vec![
45.2, 48.1, 52.0, 49.5, 51.2, 150.0, 47.8, 50.1, 46.9, 200.0, 48.5, 49.2, 51.8, 500.0,
47.2,
];
let mut count = CountAggregator::new();
let mut avg = AverageAggregator::new();
let mut min = MinAggregator::new();
let mut max = MaxAggregator::new();
let mut p50 = PercentileAggregator::p50();
let mut p95 = PercentileAggregator::p95();
let mut p99 = PercentileAggregator::p99();
let mut stddev = StandardDeviationAggregator::new();
for &latency in &latencies {
count.update(latency).unwrap();
avg.update(latency).unwrap();
min.update(latency).unwrap();
max.update(latency).unwrap();
p50.update(latency).unwrap();
p95.update(latency).unwrap();
p99.update(latency).unwrap();
stddev.update(latency).unwrap();
}
println!(" Total Requests: {}", count.finalize().unwrap());
println!(" Average Latency: {:.2}ms", avg.finalize().unwrap());
println!(" Min Latency: {:.2}ms", min.finalize().unwrap());
println!(" Max Latency: {:.2}ms", max.finalize().unwrap());
println!(" P50 (Median): {:.2}ms", p50.finalize().unwrap());
println!(" P95: {:.2}ms", p95.finalize().unwrap());
println!(" P99: {:.2}ms", p99.finalize().unwrap());
println!(" Std Deviation: {:.2}ms", stddev.finalize().unwrap());
}
fn composite_aggregation_example() {
let latencies = vec![
45.2, 48.1, 52.0, 49.5, 51.2, 150.0, 47.8, 50.1, 46.9, 200.0, 48.5, 49.2, 51.8, 500.0,
47.2,
];
let mut composite = CompositeAggregator::new();
composite
.add_count("request_count")
.add_avg("avg_latency")
.add_min("min_latency")
.add_max("max_latency")
.add_p50("p50_latency")
.add_p95("p95_latency")
.add_p99("p99_latency")
.add_stddev("stddev_latency");
for latency in latencies {
composite.update(latency).unwrap();
}
let results = composite.finalize().unwrap();
println!(" Total Requests: {}", results.get_count("request_count").unwrap());
println!(" Average Latency: {:.2}ms", results.get_value("avg_latency").unwrap());
println!(" Min Latency: {:.2}ms", results.get_value("min_latency").unwrap());
println!(" Max Latency: {:.2}ms", results.get_value("max_latency").unwrap());
println!(" P50 (Median): {:.2}ms", results.get_value("p50_latency").unwrap());
println!(" P95: {:.2}ms", results.get_value("p95_latency").unwrap());
println!(" P99: {:.2}ms", results.get_value("p99_latency").unwrap());
println!(" Std Deviation: {:.2}ms", results.get_value("stddev_latency").unwrap());
println!("\n Performance benefit: Single pass vs 8 separate passes!");
}
fn distributed_processing_example() {
let worker1_data = vec![45.0, 50.0, 55.0, 60.0];
let worker2_data = vec![48.0, 52.0, 58.0, 62.0];
let worker3_data = vec![46.0, 51.0, 56.0, 61.0];
println!(" Worker 1: Processing {} requests", worker1_data.len());
let mut agg1 = AverageAggregator::new();
agg1.update_batch(&worker1_data).unwrap();
let worker1_avg = agg1.finalize().unwrap();
println!(" Local average: {:.2}ms", worker1_avg);
println!(" Worker 2: Processing {} requests", worker2_data.len());
let mut agg2 = AverageAggregator::new();
agg2.update_batch(&worker2_data).unwrap();
let worker2_avg = agg2.finalize().unwrap();
println!(" Local average: {:.2}ms", worker2_avg);
println!(" Worker 3: Processing {} requests", worker3_data.len());
let mut agg3 = AverageAggregator::new();
agg3.update_batch(&worker3_data).unwrap();
let worker3_avg = agg3.finalize().unwrap();
println!(" Local average: {:.2}ms", worker3_avg);
println!("\n Merging results from all workers...");
let mut combined = AverageAggregator::<f64>::new();
combined.merge(agg1.accumulator()).unwrap();
combined.merge(agg2.accumulator()).unwrap();
combined.merge(agg3.accumulator()).unwrap();
println!(" Combined total: {} requests", combined.count());
println!(" Global average: {:.2}ms", combined.finalize().unwrap());
}
fn time_window_example() {
struct Event {
timestamp: u64,
latency: f64,
}
let events = vec![
Event { timestamp: 1000, latency: 45.0 },
Event { timestamp: 1500, latency: 50.0 },
Event { timestamp: 2000, latency: 48.0 },
Event { timestamp: 3000, latency: 52.0 },
Event { timestamp: 4500, latency: 47.0 },
Event { timestamp: 6000, latency: 150.0 }, Event { timestamp: 7000, latency: 55.0 },
Event { timestamp: 8500, latency: 49.0 },
Event { timestamp: 9000, latency: 51.0 },
Event { timestamp: 11000, latency: 200.0 }, Event { timestamp: 12000, latency: 46.0 },
Event { timestamp: 13500, latency: 48.0 },
];
let window_size = 5000; let mut windows: std::collections::HashMap<u64, CompositeAggregator> =
std::collections::HashMap::new();
for event in events {
let window_id = event.timestamp / window_size;
let agg = windows.entry(window_id).or_insert_with(|| {
let mut comp = CompositeAggregator::new();
comp.add_count("count").add_avg("avg").add_max("max");
comp
});
agg.update(event.latency).unwrap();
}
let mut sorted_windows: Vec<_> = windows.iter().collect();
sorted_windows.sort_by_key(|(id, _)| **id);
for (window_id, agg) in sorted_windows {
let results = agg.finalize().unwrap();
let start_ms = window_id * window_size;
let end_ms = (window_id + 1) * window_size;
println!(
" Window [{:>5}ms - {:>5}ms]: count={}, avg={:.1}ms, max={:.1}ms",
start_ms,
end_ms,
results.get_count("count").unwrap(),
results.get_value("avg").unwrap(),
results.get_value("max").unwrap()
);
}
}
fn api_monitoring_example() {
println!(" Monitoring: POST /api/v1/completions");
struct ApiRequest {
latency_ms: f64,
tokens_used: f64,
cost_usd: f64,
}
let requests = vec![
ApiRequest { latency_ms: 1200.0, tokens_used: 150.0, cost_usd: 0.003 },
ApiRequest { latency_ms: 950.0, tokens_used: 120.0, cost_usd: 0.0024 },
ApiRequest { latency_ms: 2100.0, tokens_used: 250.0, cost_usd: 0.005 },
ApiRequest { latency_ms: 1100.0, tokens_used: 140.0, cost_usd: 0.0028 },
ApiRequest { latency_ms: 5200.0, tokens_used: 500.0, cost_usd: 0.010 }, ApiRequest { latency_ms: 1050.0, tokens_used: 135.0, cost_usd: 0.0027 },
ApiRequest { latency_ms: 1300.0, tokens_used: 160.0, cost_usd: 0.0032 },
ApiRequest { latency_ms: 980.0, tokens_used: 125.0, cost_usd: 0.0025 },
];
let mut latency_stats = CompositeAggregator::new();
latency_stats
.add_count("count")
.add_avg("avg")
.add_min("min")
.add_max("max")
.add_p50("p50")
.add_p95("p95");
let mut token_stats = CompositeAggregator::new();
token_stats.add_sum("total").add_avg("avg");
let mut cost_stats = CompositeAggregator::new();
cost_stats.add_sum("total").add_avg("avg");
for req in requests {
latency_stats.update(req.latency_ms).unwrap();
token_stats.update(req.tokens_used).unwrap();
cost_stats.update(req.cost_usd).unwrap();
}
let lat_results = latency_stats.finalize().unwrap();
let tok_results = token_stats.finalize().unwrap();
let cost_results = cost_stats.finalize().unwrap();
println!("\n Latency Metrics:");
println!(" Total Requests: {}", lat_results.get_count("count").unwrap());
println!(" Avg: {:.0}ms", lat_results.get_value("avg").unwrap());
println!(" Min: {:.0}ms", lat_results.get_value("min").unwrap());
println!(" Max: {:.0}ms", lat_results.get_value("max").unwrap());
println!(" P50: {:.0}ms", lat_results.get_value("p50").unwrap());
println!(" P95: {:.0}ms", lat_results.get_value("p95").unwrap());
println!("\n Token Usage:");
println!(" Total: {:.0} tokens", tok_results.get_value("total").unwrap());
println!(" Avg/Request: {:.0} tokens", tok_results.get_value("avg").unwrap());
println!("\n Cost Metrics:");
println!(" Total: ${:.4}", cost_results.get_value("total").unwrap());
println!(" Avg/Request: ${:.4}", cost_results.get_value("avg").unwrap());
println!("\n SLA Status:");
let p95_latency = lat_results.get_value("p95").unwrap();
let sla_threshold = 3000.0; if p95_latency < sla_threshold {
println!(" P95 Latency: WITHIN SLA ({:.0}ms < {:.0}ms)", p95_latency, sla_threshold);
} else {
println!(
" P95 Latency: EXCEEDS SLA ({:.0}ms > {:.0}ms)",
p95_latency, sla_threshold
);
}
}