diff --git a/service/src/lib.rs b/service/src/lib.rs index 88ceaf5..69a8639 100644 --- a/service/src/lib.rs +++ b/service/src/lib.rs @@ -572,8 +572,8 @@ impl + Unpin> Service { Priority { plugin_priority: plg.config.query.priority, match_score: calculate_weight(sr, query), - recent_use_index: ex.as_ref().map(|s| recent.get_recent(s)).unwrap_or(0), - use_freq: ex.as_ref().map(|s| recent.get_freq(s)).unwrap_or(0), + recent_score: ex.as_ref().map(|s| recent.get_recent(s)).unwrap_or(0.), + freq_score: ex.as_ref().map(|s| recent.get_freq(s)).unwrap_or(0.), execlen: sr.name.len(), } }; diff --git a/service/src/priority.rs b/service/src/priority.rs index 582f2dd..ec3a684 100644 --- a/service/src/priority.rs +++ b/service/src/priority.rs @@ -6,41 +6,30 @@ use crate::PluginPriority; pub struct Priority { pub plugin_priority: PluginPriority, pub match_score: f64, - pub recent_use_index: usize, - pub use_freq: usize, + pub recent_score: f64, + pub freq_score: f64, pub execlen: usize, } -fn signum(val: i32) -> f64 { - if val > 0 { - return 1.0; - } - if val < 0 { - return -1.0; - } - 0.0 +fn falloff(x: f64) -> f64 { + x.clamp(0., 1.).powi(3) } impl Priority { - fn compute_value(&self, other: &Self) -> f64 { - // increases compared jw-score if this search result - // was activated more frequent or recent by constant values - let score = self.match_score - + 0.06 * signum(self.recent_use_index as i32 - other.recent_use_index as i32) - + 0.03 * signum(self.use_freq as i32 - other.use_freq as i32); - // score cannot surpass exact matches - if self.match_score < 1.0 { - return score.min(0.99); - } - - score + fn compute_value(&self) -> f64 { + let score = if self.match_score > 1. { + self.match_score + 0.1 + } else { + self.match_score + }; + score + 0.06 * falloff(self.recent_score) + 0.03 * falloff(self.freq_score) } } impl PartialEq for Priority { fn eq(&self, other: &Self) -> bool { self.plugin_priority == other.plugin_priority - && self.compute_value(other) == other.match_score + && self.compute_value() == other.compute_value() && self.execlen == other.execlen } } @@ -48,20 +37,19 @@ impl PartialEq for Priority { impl Eq for Priority {} impl PartialOrd for Priority { - #[allow(clippy::non_canonical_partial_ord_impl)] fn partial_cmp(&self, other: &Self) -> Option { - // todo: what is going on here ? - ( - other.plugin_priority, - self.compute_value(other), - self.execlen, - ) - .partial_cmp(&(self.plugin_priority, other.match_score, other.execlen)) + Some(self.cmp(other)) } } impl Ord for Priority { fn cmp(&self, other: &Self) -> Ordering { - self.partial_cmp(other).unwrap() + match other.plugin_priority.cmp(&self.plugin_priority) { + Ordering::Equal => match self.compute_value().total_cmp(&other.compute_value()) { + Ordering::Equal => self.execlen.cmp(&other.execlen), + p => p, + }, + p => p, + } } } diff --git a/service/src/recent.rs b/service/src/recent.rs index 2c54ae4..0c0e21b 100644 --- a/service/src/recent.rs +++ b/service/src/recent.rs @@ -15,6 +15,10 @@ const LONGTERM_CAP: usize = 100; pub struct RecentUseStorage { long_term: HashMap, short_term: HashMap, + /// used for normalizing individual scores + max_long_term: usize, + /// used for normalizing individual scores + max_short_term: usize, } fn hash_key(key: K) -> u64 { @@ -26,8 +30,11 @@ fn hash_key(key: K) -> u64 { impl RecentUseStorage { pub fn add(&mut self, exec: &K) { let key = hash_key(exec); - *self.long_term.entry(key).or_insert(0) += 1; + let entry = self.long_term.entry(key).or_insert(0); + *entry += 1; + self.max_long_term = self.max_long_term.max(*entry); let short_term_idx = self.short_term.values().max().unwrap_or(&0) + 1; + self.max_short_term = self.max_short_term.max(short_term_idx); self.short_term.insert(key, short_term_idx); self.trim(); } @@ -39,6 +46,8 @@ impl RecentUseStorage { } while self.long_term.values().sum::() > LONGTERM_CAP { + self.max_long_term /= 2; + let mut delete_keys = Vec::new(); for (k, v) in &mut self.long_term { *v /= 2; @@ -52,12 +61,14 @@ impl RecentUseStorage { } } - pub fn get_recent(&self, exec: &K) -> usize { - self.short_term.get(&hash_key(exec)).copied().unwrap_or(0) + pub fn get_recent(&self, exec: &K) -> f64 { + self.short_term.get(&hash_key(exec)).copied().unwrap_or(0) as f64 + / (self.max_short_term.max(1) as f64) } - pub fn get_freq(&self, exec: &K) -> usize { - self.long_term.get(&hash_key(exec)).copied().unwrap_or(0) + pub fn get_freq(&self, exec: &K) -> f64 { + self.long_term.get(&hash_key(exec)).copied().unwrap_or(0) as f64 + / (self.max_long_term.max(1) as f64) } } @@ -80,9 +91,13 @@ impl<'de> Deserialize<'de> for RecentUseStorage { type SerType = (HashMap, Vec); let (long_term, stv) = SerType::deserialize(deserializer)?; let short_term: HashMap<_, _> = stv.into_iter().enumerate().map(|(v, k)| (k, v)).collect(); + let max_long_term = long_term.values().max().copied().unwrap_or(1); + let max_short_term = short_term.values().max().copied().unwrap_or(1); Ok(RecentUseStorage { long_term, short_term, + max_long_term, + max_short_term, }) } }