Fuzzy matching names and addresses
Fuzzy matching finds the record that matches a name or address well enough, even when spelling, spacing or word order differ.
- 8 min read
- 3 reading levels
- Published
Read these first
On this page 5
One lesson, three depths. Pick the one that fits you today — you can switch any time.
Beginner — No maths. Plain English.
Fuzzy matching finds the record that is close enough to what someone typed. It does not need an exact match.
Think about a receptionist checking you into a hotel. You say your name once, quickly. She types what she heard into the booking system. It rarely matches the booking letter for letter. A middle initial gets dropped, a word gets reordered. She still finds your reservation, because she matches on "close enough," not "identical."
Fuzzy matching gives software that same "close enough" judgment. It scores how similar two strings are, instead of demanding an exact match.
Why it exists
Real-world names and addresses are typed by different people, at different times, through different systems. "MG Road" and "M.G. Road" and "M G Road" are the same place, typed three different ways.
Exact-match lookups — the kind a database index normally does — treat all three as unrelated strings. Fuzzy matching scores how similar two strings are. It accepts a match above some threshold, closing the gap between "technically different" and "close enough."
How it works
typed: "45 M G road bengaluru 560001"
|
v
compare against every stored address, score similarity
|
v
"45 MG Road, Bengaluru, 560001" <- highest score, chosen as the matchSimilarity is usually scored from 0 to 100 — 100 meaning identical, lower scores meaning increasingly different. A threshold decides how low a score is still an acceptable match.
Where you have already seen it
- Food delivery apps, matching a messily typed address to a saved delivery location.
- Customer support tools, finding your account by name even when you spell it slightly differently than before.
- Deduplication in spreadsheets, catching that "Ravi Kumar" and "ravi kumaar" are almost certainly the same person.
Remember this
- Fuzzy matching scores similarity between strings, and accepts a match above a chosen threshold.
- It handles spelling differences, spacing differences and some word-order differences, in one step.
- The threshold is a real design decision. Too low, and wrong matches slip through. Too high, and real matches get missed.
What to learn next
- Building a spell checker — the single-word version of the same "closest match" idea.
- Fixing OCR errors — using this same technique against a scanner's mistakes instead of a typist's.
- Named entity recognition — finding the name or address inside a longer piece of text, before matching it against anything.
Developer — Code and libraries.
Setup
pip install rapidfuzzMatching a misspelled name, then a messy address
from rapidfuzz import fuzz, process
# Matching a name against a small list of known names
names = ["Pranay Mahendrakar", "Praney Mahendrkar", "P. Mahendrakar", "Rahul Sharma"]
query = "Pranay Mahendrkar"
for n in names:
print(f"{n:22} score={fuzz.ratio(query, n):5.1f}")
# Matching a full address, word order and spacing included
addresses = [
"221B Baker Street, Bengaluru, 560001",
"45 MG Road, Bengaluru, 560001",
"12 Church Street, Bengaluru, 560001",
]
typed_address = "45 M G road bengaluru 560001"
best_match, score, idx = process.extractOne(typed_address, addresses, scorer=fuzz.token_sort_ratio)
print()
print("Typed: ", typed_address)
print("Matched:", best_match)
print("Score: ", round(score, 1))Pranay Mahendrakar score= 97.1 Praney Mahendrkar score= 94.1 P. Mahendrakar score= 77.4 Rahul Sharma score= 34.5 Typed: 45 M G road bengaluru 560001 Matched: 45 MG Road, Bengaluru, 560001 Score: 77.2
Line by line
fuzz.ratio scores overall character similarity between two strings, roughly related to edit distance, scaled to a 0-100 range. The correctly-spelled full name scores 97.1 against a one-letter-off typo of itself — high, but not 100, because it genuinely is not identical.
fuzz.token_sort_ratio splits both strings into words, sorts them, and then compares. This is why "45 M G road bengaluru 560001" still matches "45 MG Road, Bengaluru, 560001" at a decent score, despite the casing, punctuation and the split "M G" versus joined "MG" — word-order and case differences stop mattering once both strings are broken into sorted word tokens.
process.extractOne compares the query against every candidate and returns the single best match, along with its score and position in the list — the pattern you would use to look up one real record from a fuzzy-typed query.
Common mistakes
Using fuzz.ratio on multi-word text with reordered words. Plain character-ratio scoring penalises word reordering heavily, even when every word matches. token_sort_ratio or token_set_ratio handle this far better for names and addresses.
Setting no minimum score threshold at all. extractOne always returns the best available match, even when every candidate is a poor fit. Without a minimum score check, an address with no real match in the system will still confidently "match" the least-bad wrong one.
Fuzzy-matching against a huge candidate list with no pre-filtering. Comparing one query against millions of records, one at a time, does not scale. Production systems narrow the candidate list first — by postal code, by first letter, by a cheap index — before running fuzzy comparison on what remains.
Try it yourself
Add a name that is genuinely a different person, but happens to share several letters with one of the sample names — a real near-collision. Check its score against the correct match's score, and decide where you would set the threshold to accept one but reject the other.
What to learn next
- Building a spell checker — the underlying edit-distance idea, applied to single words.
- Finding and masking personal data in text — matching names for a very different purpose, detection instead of lookup.
- Named entity recognition — pulling names and addresses out of free text before fuzzy matching them against records.
Researcher — Mathematics and papers.
Similarity metrics compared
fuzz.ratio implements normalised Indel distance — a restricted edit distance permitting only insertions and deletions, not substitutions — expressed as a similarity ratio:
ratio(s, t) = 100 * ( 1 - indel_distance(s, t) / (|s| + |t|) )indel_distance(s, t)is the minimum insertions plus deletions to transformsintot.- The denominator
|s| + |t|normalises the score to a fixed 0-100 range regardless of string length.
token_sort_ratio tokenises both strings on whitespace, sorts each token list alphabetically, rejoins into a normalised string, and applies ratio to the result — making the score invariant to word order at the cost of losing any signal from original ordering.
token_set_ratio goes further, computing the token sets' intersection and each side's remainder, then scoring the best of several ratio comparisons between these pieces — robust to one string being a subset of the other's words, at the cost of being more permissive, and therefore more prone to over-matching on short strings.
Why RapidFuzz outperforms naive edit-distance search
RapidFuzz (Bachmann, 2021, successor to the earlier FuzzyWuzzy) implements the same core algorithms in C++ with SIMD-vectorised distance computation, and applies a length-based lower-bound filter before running the full distance calculation: if |s| and |t| differ enough that no achievable edit distance could beat the current best score, the comparison is skipped entirely without computing the full dynamic-programming table.
For process.extractOne scanning n candidates, this early-exit filtering typically cuts real-world runtime by an order of magnitude compared to computing full edit distance against every candidate unconditionally, though worst-case complexity remains O(n * |s| * |t|).
Scaling beyond exhaustive comparison
Exhaustive comparison against every candidate is O(n) string comparisons per query, each themselves O(|s| * |t|) — infeasible for millions of records. Production entity-resolution systems instead use blocking: a cheap key (postal code, phonetic code, first three characters) partitions records into buckets, and fuzzy matching runs only within the bucket a query falls into.
Locality-sensitive hashing (LSH) over character n-gram shingles is a common blocking technique for text specifically, since near-duplicate strings tend to share n-gram shingles even after moderate edits, allowing approximate matches to be located in sublinear time.
Key references
- Levenshtein, V. (1966). Binary Codes Capable of Correcting Deletions, Insertions, and Reversals. Soviet Physics Doklady.
- Bachmann, M. (2021). RapidFuzz. github.com/rapidfuzz/RapidFuzz
- Cohen, W., Ravikumar, P. & Fienberg, S. (2003). A Comparison of String Distance Metrics for Name-Matching Tasks. IIWeb Workshop, IJCAI. — an empirical comparison across edit-distance, token-based and phonetic metrics specifically for name matching.
- Christen, P. (2012). Data Matching: Concepts and Techniques for Record Linkage, Entity Resolution, and Duplicate Detection. Springer. — the standard reference on blocking and large-scale entity resolution.
Current state and open problems
Embedding-based matching — encoding names and addresses with a small transformer and comparing by cosine similarity, the same mechanism covered in multilingual sentence embeddings — increasingly supplements or replaces pure edit-distance methods for cross-lingual or heavily-abbreviated name matching, where character-level distance alone misses genuine equivalences (a name transliterated two different ways from the same source script, for instance).
Fully solving entity resolution — deciding with certainty whether two messy records refer to the same real-world entity — remains an open, actively-researched problem precisely because "close enough" is a judgment call, not a fixed mathematical threshold, and the right threshold genuinely differs by domain, language and the cost of a wrong match in either direction.
What to learn next
- Building a spell checker — the same distance-based matching, formalised for single words.
- Multilingual sentence embeddings — an embedding-based alternative to edit-distance matching.
- Finding and masking personal data in text — a related task, spotting rather than matching names and addresses.