feat: fuzzy match (#168)

This commit is contained in:
stefan-gorules
2024-05-23 12:00:58 +02:00
committed by GitHub
parent bfc8f94eaa
commit 7ce6ceb9e4
7 changed files with 58 additions and 1 deletions
+1
View File
@@ -25,6 +25,7 @@ nohash-hasher = "0.2.0"
thiserror = { workspace = true }
rust_decimal = { workspace = true, features = ["maths-nopanic"] }
rust_decimal_macros = { workspace = true }
strsim = "0.11.1"
[dev-dependencies]
anyhow = { workspace = true }
+5
View File
@@ -329,6 +329,11 @@ impl<'arena, 'bytecode_ref> CompilerInner<'arena, 'bytecode_ref> {
self.compile_argument(kind, arguments, 1)?;
Ok(self.emit(Opcode::Matches))
}
BuiltInFunction::FuzzyMatch => {
self.compile_argument(kind, arguments, 0)?;
self.compile_argument(kind, arguments, 1)?;
Ok(self.emit(Opcode::FuzzyMatch))
}
BuiltInFunction::Extract => {
self.compile_argument(kind, arguments, 0)?;
self.compile_argument(kind, arguments, 1)?;
+1
View File
@@ -53,6 +53,7 @@ pub enum Opcode<'a> {
StartsWith,
EndsWith,
Matches,
FuzzyMatch,
Extract,
Slice,
Array,
+2
View File
@@ -22,6 +22,7 @@ pub enum BuiltInFunction {
EndsWith,
Matches,
Extract,
FuzzyMatch,
// Math
Abs,
@@ -88,6 +89,7 @@ impl BuiltInFunction {
BuiltInFunction::EndsWith => Arity::Dual,
BuiltInFunction::Matches => Arity::Dual,
BuiltInFunction::Extract => Arity::Dual,
BuiltInFunction::FuzzyMatch => Arity::Dual,
// Math
BuiltInFunction::Abs => Arity::Single,
+1
View File
@@ -303,6 +303,7 @@ impl From<&Node<'_>> for UnaryNodeBehaviour {
BuiltInFunction::StartsWith => AsBoolean,
BuiltInFunction::EndsWith => AsBoolean,
BuiltInFunction::Matches => AsBoolean,
BuiltInFunction::FuzzyMatch => CompareWithReference(Equal),
BuiltInFunction::IsNumeric => AsBoolean,
BuiltInFunction::Keys => CompareWithReference(In),
BuiltInFunction::All => AsBoolean,
+44 -1
View File
@@ -10,7 +10,7 @@ use chrono::{Datelike, Timelike};
use regex::Regex;
#[cfg(feature = "regex-lite")]
use regex_lite::Regex;
use rust_decimal::prelude::ToPrimitive;
use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
use rust_decimal::{Decimal, MathematicalOps};
use rust_decimal_macros::dec;
@@ -989,6 +989,49 @@ impl<'arena, 'parent_ref, 'bytecode_ref> VMInner<'arena, 'parent_ref, 'bytecode_
self.push(Bool(regex.is_match(a)));
}
Opcode::FuzzyMatch => {
let b = self.pop()?;
let a = self.pop()?;
let String(b) = b else {
return Err(OpcodeErr {
opcode: "FuzzyMatch".into(),
message: "Unsupported type".into(),
});
};
match a {
String(a) => {
let sim = strsim::normalized_damerau_levenshtein(a, b);
// This is okay, as NDL will return [0, 1]
self.push(Number(Decimal::from_f64(sim).unwrap_or(dec!(0))));
}
Array(a) => {
let mut sims = BumpVec::with_capacity_in(a.len(), &self.bump);
for v in a.iter() {
let String(s) = v else {
return Err(OpcodeErr {
opcode: "FuzzyMatch".into(),
message: "Unsupported type".into(),
});
};
let sim =
Decimal::from_f64(strsim::normalized_damerau_levenshtein(s, b))
.unwrap_or(dec!(0));
sims.push(&*self.bump.alloc(Number(sim)));
}
self.push(Array(sims.into_bump_slice()))
}
_ => {
return Err(OpcodeErr {
opcode: "FuzzyMatch".into(),
message: "Unsupported type".into(),
})
}
}
}
Opcode::Extract => {
let b = self.pop()?;
let a = self.pop()?;
+4
View File
@@ -120,6 +120,10 @@ contains("Hello, World!", "foo");; false
matches("Hello, World!", "H[a-z]+, W[a-z]+!");; true
matches("Hello, World!", "[0-9]+");; false
extract("2022-09-18", "(\d{4})-(\d{2})-(\d{2})");; ["2022-09-18", "2022", "09", "18"]
fuzzyMatch("hello", "hello");; 1
fuzzyMatch("world", "hello");; 0.2
fuzzyMatch(["hello", "world"], "hello");;[1, 0.2]
# String Slice
string[0:5];{string: 'sample_string'};'sample'
Can't render this file because it contains an unexpected character in line 14 and column 13.