Skip to content

RapidFuzz

Fuzzy string matching and edit-distance for DuckDB, powered by the RapidFuzz C++ library.

1,203,531
extension loads Β· last 90 days
On this page

Technical Overview

Joining data that shares no clean key

What this extension is for

  • β€’ Record linkage / fuzzy join: Two datasets that should match on name or address but don't share clean keys: score every candidate pair with rapidfuzz_jaro_winkler_normalized_similarity or rapidfuzz_ratio, filter by threshold, keep the best per row with QUALIFY ROW_NUMBER().
  • β€’ Dedup messy free-text: Cluster near-duplicate rows in a customer or product table β€” pick a ratio variant that matches your data semantics (token-set for reordered or stuttering text, partial-ratio for fragments) and emit pairs above a threshold.
  • β€’ Spell-check / typo tolerance: Score an input against a known-good dictionary with rapidfuzz_osa_distance or rapidfuzz_jaro_winkler_normalized_similarity and pick the closest match. Handles single-character typos and adjacent-key swaps directly.
  • β€’ Similarity ranking: Score a query string against every row in a small table and ORDER BY the score β€” the simplest "which of these is closest?" pattern, no separate search index.

How it works

  • β€’ Two function families: Ratio scores (rapidfuzz_ratio, rapidfuzz_partial_ratio, rapidfuzz_token_sort_ratio, rapidfuzz_token_set_ratio, rapidfuzz_partial_token_set_ratio) return 0–100 similarity, matching Python rapidfuzz.fuzz. Distance algorithms (Jaro, Jaro-Winkler, Hamming, Indel, Levenshtein/OSA, LCS, prefix, postfix) each ship four variants β€” _distance, _similarity, _normalized_distance, _normalized_similarity.
  • β€’ Pick distance vs. normalized: Raw _distance / _similarity return integer edit counts β€” useful when the strings are the same length or you want a numeric threshold (e.g. "differ by ≀ 2 characters"). The _normalized_* variants scale to [0, 1] and divide by the longer string's length, so they don't penalize length mismatches; reach for these for cross-pair comparisons.
  • β€’ Vectorized over columns: Every function is scalar with (VARCHAR, VARCHAR) -> DOUBLE. Use it in SELECT, WHERE, JOIN ... ON, ORDER BY, QUALIFY β€” anywhere a scalar fits. DuckDB pipelines and multi-threads the call.
  • β€’ Behavior parity with upstream: Outputs match the upstream Python library, so the RapidFuzz docs are an authoritative reference for algorithm semantics. The naming scheme is rapidfuzz_<algo>[_normalized]_<distance|similarity> β€” predictable across all eight algorithm groups.

Cost and scaling

  • β€’ Self-joins are O(nΒ²): 100k rows Γ— 100k rows is 10 billion pairs β€” still tractable on a fast machine for the simpler ratios, but will dominate query time. 1M Γ— 1M is not. Filter the pair space before scoring.
  • β€’ Use blocking to prune candidates: Blocking (a.k.a. indexing) is the standard record-linkage technique: only compare rows that share a cheap key. First letter, length bucket, normalized prefix, or a phonetic code (e.g. soundex via the fuzzy extension) β€” join on the block, score on the strings. Reduces O(nΒ²) to O(nΒ·k) where k is the average block size.
  • β€’ Pre-normalize once: Lowercase, strip punctuation, collapse whitespace before scoring β€” every per-row transformation you can hoist out of the join saves it from running on every pair. Pair with the inflector extension when you need consistent casing across both sides.
  • β€’ Threshold inside the join: Push the similarity threshold into the WHERE/ON clause so DuckDB can short-circuit. For top-1 per left row, layer QUALIFY ROW_NUMBER() OVER (PARTITION BY left_id ORDER BY score DESC) = 1.

Common Use Cases

Deep Dive

Technical Details

Install

INSTALL rapidfuzz FROM community;
LOAD rapidfuzz;

Quick Start

Headline ratio (0–100, like Python rapidfuzz.fuzz.ratio)

SELECT rapidfuzz_ratio('hello world', 'helo wrld');  -- 90.0

Match with reordered words

SELECT rapidfuzz_token_sort_ratio('world hello', 'hello world');  -- 100.0

Pick best match per row

SELECT a.id, b.id,
       rapidfuzz_ratio(a.name, b.name) AS score
FROM left_records a, right_records b
WHERE rapidfuzz_ratio(a.name, b.name) > 85
ORDER BY a.id, score DESC;

Reference

Extension Contents

Quick reference to all available functions and settings organized by category.

Name Description
Hamming
rapidfuzz_hamming_distance() Number of differing positions between two equal-length strings.
rapidfuzz_hamming_normalized_distance() Number of differing positions between two equal-length strings.
rapidfuzz_hamming_normalized_similarity() Number of differing positions between two equal-length strings.
rapidfuzz_hamming_similarity() Number of differing positions between two equal-length strings.
Indel
rapidfuzz_indel_distance() Insertions+deletions to transform one string into another (no substitutions).
rapidfuzz_indel_normalized_distance() Insertions+deletions to transform one string into another (no substitutions).
rapidfuzz_indel_normalized_similarity() Insertions+deletions to transform one string into another (no substitutions).
rapidfuzz_indel_similarity() Insertions+deletions to transform one string into another (no substitutions).
Jaro
rapidfuzz_jaro_distance() Jaro similarity β€” character matches and transpositions.
rapidfuzz_jaro_normalized_distance() Jaro similarity β€” character matches and transpositions.
rapidfuzz_jaro_normalized_similarity() Jaro similarity β€” character matches and transpositions.
rapidfuzz_jaro_similarity() Jaro similarity β€” character matches and transpositions.
Jaro Winkler
rapidfuzz_jaro_winkler_distance() Jaro-Winkler β€” Jaro with extra weight on common prefixes.
rapidfuzz_jaro_winkler_normalized_distance() Jaro-Winkler β€” Jaro with extra weight on common prefixes.
rapidfuzz_jaro_winkler_normalized_similarity() Jaro-Winkler β€” Jaro with extra weight on common prefixes.
rapidfuzz_jaro_winkler_similarity() Jaro-Winkler β€” Jaro with extra weight on common prefixes.
Lcs Seq
rapidfuzz_lcs_seq_distance() Longest common subsequence β€” preserves character order but not adjacency.
rapidfuzz_lcs_seq_normalized_distance() Longest common subsequence β€” preserves character order but not adjacency.
rapidfuzz_lcs_seq_normalized_similarity() Longest common subsequence β€” preserves character order but not adjacency.
rapidfuzz_lcs_seq_similarity() Longest common subsequence β€” preserves character order but not adjacency.
Osa
rapidfuzz_osa_distance() Optimal string alignment β€” Levenshtein with adjacent transpositions counted as one edit.
rapidfuzz_osa_normalized_distance() Optimal string alignment β€” Levenshtein with adjacent transpositions counted as one edit.
rapidfuzz_osa_normalized_similarity() Optimal string alignment β€” Levenshtein with adjacent transpositions counted as one edit.
rapidfuzz_osa_similarity() Optimal string alignment β€” Levenshtein with adjacent transpositions counted as one edit.
Postfix
rapidfuzz_postfix_distance() Edit distance considering only matching suffixes.
rapidfuzz_postfix_normalized_distance() Edit distance considering only matching suffixes.
rapidfuzz_postfix_normalized_similarity() Edit distance considering only matching suffixes.
rapidfuzz_postfix_similarity() Edit distance considering only matching suffixes.
Prefix
rapidfuzz_prefix_distance() Edit distance considering only matching prefixes.
rapidfuzz_prefix_normalized_distance() Edit distance considering only matching prefixes.
rapidfuzz_prefix_normalized_similarity() Edit distance considering only matching prefixes.
rapidfuzz_prefix_similarity() Edit distance considering only matching prefixes.
Ratio Scores
rapidfuzz_partial_ratio() Best similarity score for any substring of the longer input against the shorter β€” useful when one string is a fragment of the other.
rapidfuzz_partial_token_set_ratio() Token-set comparison with a partial-ratio fallback β€” best when one string is a subset/partial match of the other.
rapidfuzz_ratio() Levenshtein-based similarity (0–100).
rapidfuzz_token_set_ratio() Compare token sets (deduped, unordered).
rapidfuzz_token_sort_ratio() Compare after sorting tokens (words).

API Reference

Function Documentation

Practical Examples

Cookbook

Real-world recipes and patterns for common use cases.

Platform Support

Compatibility

Extension availability may vary by platform and DuckDB version. Check below to ensure this extension supports your environment before installation.

Quick Facts

Release status Stable
Software License MIT
Pricing Free
Written In C++
Source Available Yes
View on GitHub
Usage
1,203,531
loads Β· last 90 days

Platforms

  • Linux x86_64 aarch64
  • Linux (musl) Not available
  • macOS Intel Apple Silicon
  • Windows x86_64
  • WASM eh mvp threads
Compiled binary sizes
Platform Architecture Size
Linux x86_64 3.29 MB
Linux aarch64 2.92 MB
macOS Intel 1.51 MB
macOS Apple Silicon 1.37 MB
Windows x86_64 7.44 MB
WASM eh 66.9 KB
WASM mvp 68.9 KB
WASM threads 67.0 KB

Compressed download size from the Haybarn extension repository.

DuckDB & Haybarn

Release calendar