query: rich QueryResult + toolkit cleanup
QueryResult carries a fields map (BTreeMap<String, Value>) so callers don't re-resolve fields after queries run. Neighbors queries inject edge context (strength, rel_type) at construction time. New public API: - run_query(): parse + execute + format in one call - format_value(): format a Value for display - execute_parsed(): internal, avoids double-parse in run_query Removed: output_stages(), format_field() Simplified commands: - cmd_query, cmd_graph, cmd_link, cmd_list_keys all delegate to run_query - cmd_experience_mine uses existing find_current_transcript() Deduplication: - now_epoch() 3 copies → 1 (capnp_store's public fn) - hub_threshold → Graph::hub_threshold() method - eval_node + eval_edge → single eval() with closure for field resolution - compare() collapsed via Ordering (35 → 15 lines) Modernization: - 12 sites of partial_cmp().unwrap_or(Ordering::Equal) → total_cmp()
This commit is contained in:
parent
64d2b441f0
commit
fa7fe8c14b
7 changed files with 187 additions and 264 deletions
29
src/graph.rs
29
src/graph.rs
|
|
@ -73,6 +73,19 @@ impl Graph {
|
|||
&self.communities
|
||||
}
|
||||
|
||||
/// Hub degree threshold: top 5% by degree
|
||||
pub fn hub_threshold(&self) -> usize {
|
||||
let mut degrees: Vec<usize> = self.keys.iter()
|
||||
.map(|k| self.degree(k))
|
||||
.collect();
|
||||
degrees.sort_unstable();
|
||||
if degrees.len() >= 20 {
|
||||
degrees[degrees.len() * 95 / 100]
|
||||
} else {
|
||||
usize::MAX
|
||||
}
|
||||
}
|
||||
|
||||
/// Local clustering coefficient: fraction of a node's neighbors
|
||||
/// that are also neighbors of each other.
|
||||
/// cc(v) = 2E / (deg * (deg - 1))
|
||||
|
|
@ -187,7 +200,7 @@ impl Graph {
|
|||
let n = degrees.len();
|
||||
if n < 2 { return 0.0; }
|
||||
|
||||
degrees.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
|
||||
degrees.sort_by(|a, b| a.total_cmp(b));
|
||||
let mean = degrees.iter().sum::<f64>() / n as f64;
|
||||
if mean < 1e-10 { return 0.0; }
|
||||
|
||||
|
|
@ -255,17 +268,7 @@ impl Graph {
|
|||
pub fn link_impact(&self, source: &str, target: &str) -> LinkImpact {
|
||||
let source_deg = self.degree(source);
|
||||
let target_deg = self.degree(target);
|
||||
|
||||
// Hub threshold: top 5% by degree
|
||||
let mut all_degrees: Vec<usize> = self.keys.iter()
|
||||
.map(|k| self.degree(k))
|
||||
.collect();
|
||||
all_degrees.sort_unstable();
|
||||
let hub_threshold = if all_degrees.len() >= 20 {
|
||||
all_degrees[all_degrees.len() * 95 / 100]
|
||||
} else {
|
||||
usize::MAX // can't define hubs with <20 nodes
|
||||
};
|
||||
let hub_threshold = self.hub_threshold();
|
||||
let is_hub_link = source_deg >= hub_threshold || target_deg >= hub_threshold;
|
||||
|
||||
// Community check
|
||||
|
|
@ -469,7 +472,7 @@ fn label_propagation(
|
|||
|
||||
// Adopt the label with most votes
|
||||
if let Some((&best_label, _)) = votes.iter()
|
||||
.max_by(|a, b| a.1.partial_cmp(b.1).unwrap_or(std::cmp::Ordering::Equal))
|
||||
.max_by(|a, b| a.1.total_cmp(b.1))
|
||||
{
|
||||
let current = labels[key];
|
||||
if best_label != current {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue