multimatcher/
multimatcher.rs1use matchete::{Matcher, MultiMatcher, Custom, Similarity};
2
3struct LevenshteinMetric;
5struct JaccardMetric;
6
7impl Similarity<String, String> for LevenshteinMetric {
8 fn score(&self, query: &String, candidate: &String) -> f64 {
9 let distance = levenshtein_distance(query, candidate);
10 let max_len = query.len().max(candidate.len());
11 if max_len == 0 { 1.0 } else { 1.0 - (distance as f64 / max_len as f64) }
12 }
13
14 fn exact(&self, query: &String, candidate: &String) -> bool {
15 query == candidate
16 }
17}
18
19impl Similarity<String, String> for JaccardMetric {
20 fn score(&self, query: &String, candidate: &String) -> f64 {
21 let query_chars: std::collections::HashSet<char> = query.chars().collect();
22 let candidate_chars: std::collections::HashSet<char> = candidate.chars().collect();
23
24 let intersection = query_chars.intersection(&candidate_chars).count();
25 let union = query_chars.union(&candidate_chars).count();
26
27 if union == 0 { 1.0 } else { intersection as f64 / union as f64 }
28 }
29}
30
31fn levenshtein_distance(a: &str, b: &str) -> usize {
32 let len_a = a.len();
34 let len_b = b.len();
35
36 if len_a == 0 { return len_b; }
37 if len_b == 0 { return len_a; }
38
39 let mut matrix = vec![vec![0; len_b + 1]; len_a + 1];
40
41 for i in 0..=len_a { matrix[i][0] = i; }
42 for j in 0..=len_b { matrix[0][j] = j; }
43
44 for i in 1..=len_a {
45 for j in 1..=len_b {
46 let cost = if a.chars().nth(i - 1) == b.chars().nth(j - 1) { 0 } else { 1 };
47 matrix[i][j] = (matrix[i - 1][j] + 1)
48 .min(matrix[i][j - 1] + 1)
49 .min(matrix[i - 1][j - 1] + cost);
50 }
51 }
52
53 matrix[len_a][len_b]
54}
55
56fn main() {
57 let matcher1 = Matcher::<String, String>::new()
59 .add(LevenshteinMetric, 1.0)
60 .threshold(0.6);
61
62 let matcher2 = Matcher::<String, String>::new()
63 .add(JaccardMetric, 1.0)
64 .threshold(0.4);
65
66 let multi_matcher = MultiMatcher::<String, String>::new()
68 .add(matcher1)
69 .add(matcher2)
70 .threshold(0.5);
71
72 let query = String::from("example");
74 let candidates = vec![
75 String::from("example"),
76 String::from("examp"),
77 String::from("test"),
78 ];
79
80 println!("MultiMatcher Example");
82 println!("===================");
83 let matches = multi_matcher.find_limit(&query, &candidates, 2);
84 println!("Matches found: {}", matches.len());
85 for (i, m) in matches.iter().enumerate() {
86 println!(
87 "Match {}:\n Score: {:.2}\n Candidate: {}\n Exact: {}",
88 i + 1, m.score, m.candidate, m.exact
89 );
90 }
91}