matchr-rs 0.1.3

Fast fuzzy string matching — Levenshtein, Jaro-Winkler, and trigram similarity. Usable from Rust and Python.
Documentation

matchr

PyPI

Fast fuzzy string matching — written in Rust, usable from Python.

Install

pip install matchr

Python quick start

from matchr import best_match, rank_matches, batch_best_match

# find the closest match
best_match("oatly oat drink", ["Oatly Oat Drink 1L", "Oat Milk", "Oatly Barista"])
# → ('Oatly Oat Drink 1L', 0.902)

# filter weak matches with a threshold
best_match("xyz gibberish", ["Oatly Oat Drink 1L"], threshold=0.7)
# → None

# match many queries at once
batch_best_match(["oatly oat drink", "felix cat food"], catalog, threshold=0.7)
# → [('Oatly Oat Drink 1L', 0.902), ('Felix Cat Food 400g', 0.843)]

Rust usage

use matchr::{levenshtein, jaro_winkler, trigram_similarity};

fn main() {
    println!("{}", levenshtein("cat", "bat"));           // 1
    println!("{}", jaro_winkler("martha", "marhta"));    // 0.961
    println!("{}", trigram_similarity("hello", "helo")); // 0.4
}

Algorithms

  • Levenshtein — minimum edit distance between two strings. Lower = more similar.
  • Jaro-Winkler — similarity score from 0.0 to 1.0, optimised for names and short strings. Gives a bonus for shared prefixes.
  • Trigram — splits strings into overlapping 3-character chunks, scores overlap using the Dice coefficient. Good for longer strings and typo detection.
  • Token sort / token set — order-invariant scorers built on top of combined_score. Sorts (and optionally deduplicates) whitespace-separated tokens before comparing, so "Oat Drink Oatly 1L" and "Oatly Oat Drink 1L" come out equal.
  • Combined score — weighted blend of Levenshtein, Jaro-Winkler, and trigram. Used internally by best_match, rank_matches, and batch_best_match.

Benchmarks

See benchmarks/ for the criterion suite (cargo bench) and a Python comparison vs rapidfuzz. There's also a demo notebook that walks through deduping a synthetic 10k-product catalog end-to-end.

Notes

  • All functions normalise input (trim + lowercase + strip diacritics) before comparing — "Café" and "cafe" are treated as equal
  • levenshtein returns usize (edit distance), all others return f64 (0.0–1.0)
  • Python functions accept an optional threshold parameter — results below it are filtered out
  • batch_best_match is parallelised via rayon and pre-normalises the candidate list once, so it scales with available cores