Skip to content

Commit

Permalink
feat: strsim fuzzy matching feature is now enabled on by default
Browse files Browse the repository at this point in the history
  • Loading branch information
leontoeides committed Oct 19, 2024
1 parent f640496 commit 58553d7
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 37 deletions.
4 changes: 1 addition & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@

# 0.6.3

* 2024-10-19: Removed unnecessary `collect` on some iterators. Thank you for
pointing this out, `clippy`. This should provide a small performance
improvement.
* 2024-10-19: `strsim` fuzzy matching feature is now enabled on by default.

# 0.6.2

Expand Down
13 changes: 8 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,17 @@ repository = "https://github.com/leontoeides/indicium"
rust-version = "1.73.0"

[features]
default = [ "simple", "dep:strsim", "dep:ahash" ]
simple = []
default = [ "simple" ]

simple = [ "strsim", "ahash" ]
select2 = [ "simple", "dep:serde" ]
fuzzy = [ "dep:strsim" ] # Deprecated feature. Redirects to `strsim` feature.
ahash = [ "dep:ahash" ]

fuzzy = [ "dep:strsim" ]
strsim = [ "dep:strsim" ]
eddie = [ "dep:eddie" ]

ahash = [ "dep:ahash" ]
gxhash = [ "dep:gxhash" ]
strsim = [ "dep:strsim" ]

[dependencies]
ahash = { version = "0.8", optional = true }
Expand Down
29 changes: 18 additions & 11 deletions src/simple/autocomplete/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ impl<K: Hash + Ord> SearchIndex<K> {
// Intersect the autocompletions for the last keyword with the
// search results for the preceding keywords. This way, only
// relevant autocompletions are returned:
let mut autocompletions = self
let mut autocompletions: Vec<&KString> = self
.b_tree_map
// Get matching keywords starting with (partial) keyword string:
.range(KString::from_ref(&last_keyword)..)
Expand Down Expand Up @@ -143,12 +143,14 @@ impl<K: Hash + Ord> SearchIndex<K> {
.take(*maximum_autocomplete_options)
// `range` returns a key-value pair. We're autocompleting the
// key (keyword), so discard the value (record key):
.map(|(key, _value)| key);
.map(|(key, _value)| key)
// Collect all keyword autocompletions into a `Vec`:
.collect();

// If `eddie` fuzzy matching enabled, examine the resulting
// auto-complete options before using them:
#[cfg(feature = "eddie")]
if autocompletions.peek().is_none() {
if autocompletions.is_empty() {
// No autocomplete options were found for the user's last
// (partial) keyword. Attempt to use fuzzy string search to find
// other autocomplete options:
Expand All @@ -164,13 +166,15 @@ impl<K: Hash + Ord> SearchIndex<K> {
// `eddie_autocomplete` returns both the keyword and keys.
// We're autocompleting the last (partial) keyword, so
// discard the keys:
.map(|(keyword, _keys)| keyword);
.map(|(keyword, _keys)| keyword)
// Collect all keyword autocompletions into a `Vec`:
.collect();
} // if

// If `strsim` fuzzy matching enabled, examine the resulting
// auto-complete options before using them:
#[cfg(all(feature = "strsim", not(feature = "eddie")))]
if autocompletions.peek().is_none() {
if autocompletions.is_empty() {
// No autocomplete options were found for the user's last
// (partial) keyword. Attempt to use fuzzy string search to find
// other autocomplete options:
Expand All @@ -186,28 +190,31 @@ impl<K: Hash + Ord> SearchIndex<K> {
// `strsim_autocomplete` returns both the keyword and keys.
// We're autocompleting the last (partial) keyword, so
// discard the keys:
.map(|(keyword, _keys)| keyword);
.map(|(keyword, _keys)| keyword)
// Collect all keyword autocompletions into a `Vec`:
.collect();
} // if

// Push a blank placeholder onto the end of the keyword list. We
// will be putting our autocompletions for the last keyword into
// this spot:
let mut autocompleted_string = keywords.clone();
autocompleted_string.push("".into());
keywords.push("".into());

// Build autocompleted search strings from the autocompletions
// derived from the last keyword:
autocompletions
// Iterate over each autocompleted last keyword:
.into_iter()
// Use the prepended `keywords` and autocompleted last keyword
// to build an autocompleted search string:
.map(|last_keyword| {
// Remove previous autocompleted last keyword from list:
autocompleted_string.pop();
keywords.pop();
// Add current autocompleted last keyword to end of list:
autocompleted_string.push(last_keyword.clone());
keywords.push(last_keyword.clone());
// Join all keywords together into a single `String` using a
// space delimiter:
autocompleted_string.join(" ").trim_end().to_string()
keywords.join(" ").trim_end().to_string()
})
// Collect all string autocompletions into a `Vec`:
.collect()
Expand Down
25 changes: 16 additions & 9 deletions src/simple/autocomplete/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ impl<K: Hash + Ord> SearchIndex<K> {
// autocompleting:
keywords.pop().map_or_else(Vec::new, |last_keyword| {
// Autocomplete the last keyword:
let mut autocompletions = self
let mut autocompletions: Vec<&KString> = self
.b_tree_map
// Get matching keywords starting with (partial) keyword string:
.range(KString::from_ref(&last_keyword)..)
Expand Down Expand Up @@ -141,7 +141,9 @@ impl<K: Hash + Ord> SearchIndex<K> {
// .filter(|autocompletion| *autocompletion != &keyword)
// Only return `maximum_autocomplete_options` number of
// keywords:
.take(*maximum_autocomplete_options);
.take(*maximum_autocomplete_options)
// Collect all keyword autocompletions into a `Vec`:
.collect();

// If `eddie` fuzzy matching enabled, examine the resulting
// auto-complete options before using them:
Expand All @@ -162,7 +164,9 @@ impl<K: Hash + Ord> SearchIndex<K> {
// `eddie_autocomplete` returns both the keyword and keys.
// We're autocompleting the last (partial) keyword, so
// discard the keys:
.map(|(keyword, _keys)| keyword);
.map(|(keyword, _keys)| keyword)
// Collect all keyword autocompletions into a `Vec`:
.collect();
} // if

// If `strsim` fuzzy matching enabled, examine the resulting
Expand All @@ -184,28 +188,31 @@ impl<K: Hash + Ord> SearchIndex<K> {
// `strsim_autocomplete` returns both the keyword and keys.
// We're autocompleting the last (partial) keyword, so
// discard the keys:
.map(|(keyword, _keys)| keyword);
.map(|(keyword, _keys)| keyword)
// Collect all keyword autocompletions into a `Vec`:
.collect();
} // if

// Push a blank placeholder onto the end of the keyword list. We
// will be putting our autocompletions for the last keyword into
// this spot:
let mut autocompleted_string = keywords.clone();
autocompleted_string.push("".into());
keywords.push("".into());

// Build autocompleted search strings from the autocompletions
// derived from the last keyword:
autocompletions
// Iterate over each autocompleted last keyword:
.into_iter()
// Use the prepended `keywords` and autocompleted last keyword
// to build an autocompleted search string:
.map(|autocompletion| {
// Remove previous autocompleted last keyword from list:
autocompleted_string.pop();
keywords.pop();
// Add current autocompleted last keyword to end of list:
autocompleted_string.push(autocompletion.clone());
keywords.push(autocompletion.clone());
// Join all keywords together into a single `String` using a
// space delimiter:
autocompleted_string.join(" ").trim_end().to_string()
keywords.join(" ").trim_end().to_string()
})
// Collect all string autocompletions into a `Vec`:
.collect()
Expand Down
21 changes: 14 additions & 7 deletions src/simple/autocomplete/keyword.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ impl<K: Hash + Ord> SearchIndex<K> {
tracing::debug!("autocompleting: {:?}", keyword);

// Attempt to get matching keywords from `BTreeMap`:
let autocomplete_options = self
let autocomplete_options: Vec<&KString> = self
.b_tree_map
// Get matching keywords starting with (partial) keyword string:
.range(KString::from_ref(&keyword)..)
Expand All @@ -121,12 +121,14 @@ impl<K: Hash + Ord> SearchIndex<K> {
// in New York), do not return "new" as an auto-completed keyword:
// .filter(|autocompletion| *autocompletion != &keyword)
// Only return `maximum_autocomplete_options` number of keywords:
.take(*maximum_autocomplete_options);
.take(*maximum_autocomplete_options)
// Collect all keyword autocompletions into a `Vec`:
.collect();

// If `eddie` fuzzy matching enabled, examine the resulting
// auto-complete options before returning them:
#[cfg(feature = "eddie")]
if autocomplete_options.peek().is_none() {
if autocomplete_options.is_empty() {
// No autocomplete options were found for the user's last
// (partial) keyword. Attempt to use fuzzy string search to find
// other autocomplete options:
Expand All @@ -138,7 +140,9 @@ impl<K: Hash + Ord> SearchIndex<K> {
// `eddie_autocomplete` returns both the keyword and keys.
// We're autocompleting the last (partial) keyword, so discard
// the keys:
.map(|(keyword, _keys)| keyword.as_str());
.map(|(keyword, _keys)| keyword.as_str())
// Collect all keyword autocompletions into a `Vec`:
.collect()
} else {
// There were some matches. Return the results without processing:
autocomplete_options
Expand All @@ -150,7 +154,7 @@ impl<K: Hash + Ord> SearchIndex<K> {
// If `strsim` fuzzy matching enabled, examine the resulting
// auto-complete options before returning them:
#[cfg(all(feature = "strsim", not(feature = "eddie")))]
if autocomplete_options.peek().is_none() {
if autocomplete_options.is_empty() {
// No autocomplete options were found for the user's last
// (partial) keyword. Attempt to use fuzzy string search to find
// other autocomplete options:
Expand All @@ -162,20 +166,23 @@ impl<K: Hash + Ord> SearchIndex<K> {
// `strsim_autocomplete` returns both the keyword and keys.
// We're autocompleting the last (partial) keyword, so discard
// the keys:
.map(|(keyword, _keys)| keyword.as_str());
.map(|(keyword, _keys)| keyword.as_str())
// Collect all keyword autocompletions into a `Vec`:
.collect()
} else {
// There were some matches. Return the results without processing:
autocomplete_options
.into_iter()
.map(kstring::KStringBase::as_str)
.collect()
} // if

// If fuzzy string searching disabled, return the resulting
// auto-complete options without further processing:
#[cfg(not(any(feature = "strsim", feature = "eddie")))]
autocomplete_options
.into_iter()
.map(KString::as_str)
.map(|kstring| kstring.as_str())
.collect()
} // fn
} // impl
7 changes: 5 additions & 2 deletions src/simple/internal/eddie/eddie_global_keyword.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ impl<K: Hash + Ord> SearchIndex<K> {
/// matches, these `eddie_keyword_*` methods can be used to find the best
/// match for substitution.
pub(crate) fn eddie_global_keyword(&self, user_keyword: &str) -> Option<&KString> {
pub(crate) fn eddie_global_keyword(
&self,
user_keyword: &str
) -> Option<&KString> {
// Build an index keyword range to fuzzy match against.
//
// | Example | User Keyword | Length | Index Keyword Must Start With... |
Expand Down Expand Up @@ -52,7 +55,7 @@ impl<K: Hash + Ord> SearchIndex<K> {
// fuzzy match against:
match byte_index {
Some(byte_index) => &user_keyword[0..byte_index],
None => return vec![],
None => return None,
} // match
} else {
// The user's keyword is too short. Do not perform any fuzzy
Expand Down

0 comments on commit 58553d7

Please sign in to comment.