graph: extract current_metrics() from health_report
health_report() had a hidden write side effect — it saved a metrics snapshot to disk while appearing to be a pure query (returns String). Extract the pure computation into current_metrics(), make the save explicit. daily_check() now uses current_metrics() too, eliminating duplicated metric computation.
This commit is contained in:
parent
2f455ba29d
commit
9eaf5e6690
1 changed files with 33 additions and 24 deletions
57
src/graph.rs
57
src/graph.rs
|
|
@ -504,7 +504,7 @@ fn label_propagation(
|
||||||
/// A snapshot of graph topology metrics, for tracking evolution over time
|
/// A snapshot of graph topology metrics, for tracking evolution over time
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct MetricsSnapshot {
|
pub struct MetricsSnapshot {
|
||||||
pub timestamp: f64,
|
pub timestamp: i64,
|
||||||
pub date: String,
|
pub date: String,
|
||||||
pub nodes: usize,
|
pub nodes: usize,
|
||||||
pub edges: usize,
|
pub edges: usize,
|
||||||
|
|
@ -548,14 +548,39 @@ pub fn save_metrics_snapshot(snap: &MetricsSnapshot) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Health report: summary of graph metrics
|
/// Compute current graph metrics as a snapshot (no side effects).
|
||||||
|
pub fn current_metrics(graph: &Graph) -> MetricsSnapshot {
|
||||||
|
let now = crate::store::now_epoch();
|
||||||
|
let date = crate::store::format_datetime_space(now);
|
||||||
|
MetricsSnapshot {
|
||||||
|
timestamp: now,
|
||||||
|
date,
|
||||||
|
nodes: graph.nodes().len(),
|
||||||
|
edges: graph.edge_count(),
|
||||||
|
communities: graph.community_count(),
|
||||||
|
sigma: graph.small_world_sigma(),
|
||||||
|
alpha: graph.degree_power_law_exponent(),
|
||||||
|
gini: graph.degree_gini(),
|
||||||
|
avg_cc: graph.avg_clustering_coefficient(),
|
||||||
|
avg_path_length: graph.avg_path_length(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Health report: summary of graph metrics.
|
||||||
|
/// Saves a metrics snapshot as a side effect (callers who want pure
|
||||||
|
/// computation should use `current_metrics` + `save_metrics_snapshot`).
|
||||||
pub fn health_report(graph: &Graph, store: &Store) -> String {
|
pub fn health_report(graph: &Graph, store: &Store) -> String {
|
||||||
let n = graph.nodes().len();
|
let snap = current_metrics(graph);
|
||||||
let e = graph.edge_count();
|
save_metrics_snapshot(&snap);
|
||||||
let avg_cc = graph.avg_clustering_coefficient();
|
|
||||||
let avg_pl = graph.avg_path_length();
|
let n = snap.nodes;
|
||||||
let sigma = graph.small_world_sigma();
|
let e = snap.edges;
|
||||||
let communities = graph.community_count();
|
let avg_cc = snap.avg_cc;
|
||||||
|
let avg_pl = snap.avg_path_length;
|
||||||
|
let sigma = snap.sigma;
|
||||||
|
let alpha = snap.alpha;
|
||||||
|
let gini = snap.gini;
|
||||||
|
let communities = snap.communities;
|
||||||
|
|
||||||
// Community sizes
|
// Community sizes
|
||||||
let mut comm_sizes: HashMap<u32, usize> = HashMap::new();
|
let mut comm_sizes: HashMap<u32, usize> = HashMap::new();
|
||||||
|
|
@ -576,10 +601,6 @@ pub fn health_report(graph: &Graph, store: &Store) -> String {
|
||||||
degrees.iter().sum::<usize>() as f64 / n as f64
|
degrees.iter().sum::<usize>() as f64 / n as f64
|
||||||
};
|
};
|
||||||
|
|
||||||
// Topology metrics
|
|
||||||
let alpha = graph.degree_power_law_exponent();
|
|
||||||
let gini = graph.degree_gini();
|
|
||||||
|
|
||||||
// Low-CC nodes: poorly integrated
|
// Low-CC nodes: poorly integrated
|
||||||
let low_cc = graph.nodes().iter()
|
let low_cc = graph.nodes().iter()
|
||||||
.filter(|k| graph.clustering_coefficient(k) < 0.1)
|
.filter(|k| graph.clustering_coefficient(k) < 0.1)
|
||||||
|
|
@ -588,18 +609,6 @@ pub fn health_report(graph: &Graph, store: &Store) -> String {
|
||||||
// Category breakdown
|
// Category breakdown
|
||||||
let cats = store.category_counts();
|
let cats = store.category_counts();
|
||||||
|
|
||||||
// Snapshot current metrics and log
|
|
||||||
let now = crate::store::now_epoch();
|
|
||||||
let date = crate::store::format_datetime_space(now);
|
|
||||||
let snap = MetricsSnapshot {
|
|
||||||
timestamp: now,
|
|
||||||
date: date.clone(),
|
|
||||||
nodes: n, edges: e, communities,
|
|
||||||
sigma, alpha, gini, avg_cc,
|
|
||||||
avg_path_length: avg_pl,
|
|
||||||
};
|
|
||||||
save_metrics_snapshot(&snap);
|
|
||||||
|
|
||||||
// Load history for deltas
|
// Load history for deltas
|
||||||
let history = load_metrics_history();
|
let history = load_metrics_history();
|
||||||
let prev = if history.len() >= 2 {
|
let prev = if history.len() >= 2 {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue