Skip to content

Commit 476a8fb

Browse files
wash2mmstick
authored andcommitted
fix: total ordering for Priority
1 parent 8cc0d28 commit 476a8fb

File tree

3 files changed

+42
-39
lines changed

3 files changed

+42
-39
lines changed

service/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -572,8 +572,8 @@ impl<O: futures::Sink<Response> + Unpin> Service<O> {
572572
Priority {
573573
plugin_priority: plg.config.query.priority,
574574
match_score: calculate_weight(sr, query),
575-
recent_use_index: ex.as_ref().map(|s| recent.get_recent(s)).unwrap_or(0),
576-
use_freq: ex.as_ref().map(|s| recent.get_freq(s)).unwrap_or(0),
575+
recent_score: ex.as_ref().map(|s| recent.get_recent(s)).unwrap_or(0.),
576+
freq_score: ex.as_ref().map(|s| recent.get_freq(s)).unwrap_or(0.),
577577
execlen: sr.name.len(),
578578
}
579579
};

service/src/priority.rs

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,62 +6,50 @@ use crate::PluginPriority;
66
pub struct Priority {
77
pub plugin_priority: PluginPriority,
88
pub match_score: f64,
9-
pub recent_use_index: usize,
10-
pub use_freq: usize,
9+
pub recent_score: f64,
10+
pub freq_score: f64,
1111
pub execlen: usize,
1212
}
1313

14-
fn signum(val: i32) -> f64 {
15-
if val > 0 {
16-
return 1.0;
17-
}
18-
if val < 0 {
19-
return -1.0;
20-
}
21-
0.0
14+
fn falloff(x: f64) -> f64 {
15+
x.clamp(0., 1.).powi(3)
2216
}
2317

2418
impl Priority {
25-
fn compute_value(&self, other: &Self) -> f64 {
26-
// increases compared jw-score if this search result
27-
// was activated more frequent or recent by constant values
28-
let score = self.match_score
29-
+ 0.06 * signum(self.recent_use_index as i32 - other.recent_use_index as i32)
30-
+ 0.03 * signum(self.use_freq as i32 - other.use_freq as i32);
31-
// score cannot surpass exact matches
32-
if self.match_score < 1.0 {
33-
return score.min(0.99);
34-
}
35-
36-
score
19+
fn compute_value(&self) -> f64 {
20+
let score = if self.match_score > 1. {
21+
self.match_score + 0.1
22+
} else {
23+
self.match_score
24+
};
25+
score + 0.06 * falloff(self.recent_score) + 0.03 * falloff(self.freq_score)
3726
}
3827
}
3928

4029
impl PartialEq for Priority {
4130
fn eq(&self, other: &Self) -> bool {
4231
self.plugin_priority == other.plugin_priority
43-
&& self.compute_value(other) == other.match_score
32+
&& self.compute_value() == other.compute_value()
4433
&& self.execlen == other.execlen
4534
}
4635
}
4736

4837
impl Eq for Priority {}
4938

5039
impl PartialOrd for Priority {
51-
#[allow(clippy::non_canonical_partial_ord_impl)]
5240
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
53-
// todo: what is going on here ?
54-
(
55-
other.plugin_priority,
56-
self.compute_value(other),
57-
self.execlen,
58-
)
59-
.partial_cmp(&(self.plugin_priority, other.match_score, other.execlen))
41+
Some(self.cmp(other))
6042
}
6143
}
6244

6345
impl Ord for Priority {
6446
fn cmp(&self, other: &Self) -> Ordering {
65-
self.partial_cmp(other).unwrap()
47+
match other.plugin_priority.cmp(&self.plugin_priority) {
48+
Ordering::Equal => match self.compute_value().total_cmp(&other.compute_value()) {
49+
Ordering::Equal => self.execlen.cmp(&other.execlen),
50+
p => p,
51+
},
52+
p => p,
53+
}
6654
}
6755
}

service/src/recent.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ const LONGTERM_CAP: usize = 100;
1515
pub struct RecentUseStorage {
1616
long_term: HashMap<u64, usize>,
1717
short_term: HashMap<u64, usize>,
18+
/// used for normalizing individual scores
19+
max_long_term: usize,
20+
/// used for normalizing individual scores
21+
max_short_term: usize,
1822
}
1923

2024
fn hash_key<K: Hash>(key: K) -> u64 {
@@ -26,8 +30,11 @@ fn hash_key<K: Hash>(key: K) -> u64 {
2630
impl RecentUseStorage {
2731
pub fn add<K: Hash>(&mut self, exec: &K) {
2832
let key = hash_key(exec);
29-
*self.long_term.entry(key).or_insert(0) += 1;
33+
let entry = self.long_term.entry(key).or_insert(0);
34+
*entry += 1;
35+
self.max_long_term = self.max_long_term.max(*entry);
3036
let short_term_idx = self.short_term.values().max().unwrap_or(&0) + 1;
37+
self.max_short_term = self.max_short_term.max(short_term_idx);
3138
self.short_term.insert(key, short_term_idx);
3239
self.trim();
3340
}
@@ -39,6 +46,8 @@ impl RecentUseStorage {
3946
}
4047

4148
while self.long_term.values().sum::<usize>() > LONGTERM_CAP {
49+
self.max_long_term /= 2;
50+
4251
let mut delete_keys = Vec::new();
4352
for (k, v) in &mut self.long_term {
4453
*v /= 2;
@@ -52,12 +61,14 @@ impl RecentUseStorage {
5261
}
5362
}
5463

55-
pub fn get_recent<K: Hash>(&self, exec: &K) -> usize {
56-
self.short_term.get(&hash_key(exec)).copied().unwrap_or(0)
64+
pub fn get_recent<K: Hash>(&self, exec: &K) -> f64 {
65+
self.short_term.get(&hash_key(exec)).copied().unwrap_or(0) as f64
66+
/ (self.max_short_term.max(1) as f64)
5767
}
5868

59-
pub fn get_freq<K: Hash>(&self, exec: &K) -> usize {
60-
self.long_term.get(&hash_key(exec)).copied().unwrap_or(0)
69+
pub fn get_freq<K: Hash>(&self, exec: &K) -> f64 {
70+
self.long_term.get(&hash_key(exec)).copied().unwrap_or(0) as f64
71+
/ (self.max_long_term.max(1) as f64)
6172
}
6273
}
6374

@@ -80,9 +91,13 @@ impl<'de> Deserialize<'de> for RecentUseStorage {
8091
type SerType = (HashMap<u64, usize>, Vec<u64>);
8192
let (long_term, stv) = SerType::deserialize(deserializer)?;
8293
let short_term: HashMap<_, _> = stv.into_iter().enumerate().map(|(v, k)| (k, v)).collect();
94+
let max_long_term = long_term.values().max().copied().unwrap_or(1);
95+
let max_short_term = short_term.values().max().copied().unwrap_or(1);
8396
Ok(RecentUseStorage {
8497
long_term,
8598
short_term,
99+
max_long_term,
100+
max_short_term,
86101
})
87102
}
88103
}

0 commit comments

Comments
 (0)