Skip to content

Commit f774b97

Browse files
committed
docs: add approximate matching section, 32-bit tip, sidebar depth fix
1 parent 40a053a commit f774b97

1 file changed

Lines changed: 25 additions & 2 deletions

File tree

docs/articles/how-fuzzy-search-works.md

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,11 @@ See [Fuzzy Search](/fuzzy-search) for details on configuring threshold, distance
4141

4242
## Under the Hood: Bitap
4343

44-
Fuse.js doesn't use a traditional dynamic programming table to compute edit distance. Instead, it uses the [Bitap algorithm](https://en.wikipedia.org/wiki/Bitap_algorithm), which encodes the pattern as bitmasks and uses bitwise operations to check all character positions in parallel. This makes it fast — especially for short patterns (up to 32 characters).
44+
Fuse.js doesn't use a traditional dynamic programming table to compute edit distance. Instead, it uses the [Bitap algorithm](https://en.wikipedia.org/wiki/Bitap_algorithm), which encodes the pattern as bitmasks and uses bitwise operations to check all character positions in parallel. This makes it fast — especially for short patterns.
45+
46+
::: tip Why 32 characters?
47+
The algorithm encodes the pattern as a bitmask and uses bitwise operators (`<<`, `|`, `&`) to process all positions in a single CPU operation. JavaScript's bitwise operators work on 32-bit integers — that's the limit. Longer patterns are split into 32-character chunks and searched independently.
48+
:::
4549

4650
Here's how it works for **exact matching** (zero errors):
4751

@@ -86,6 +90,25 @@ Step through it yourself:
8690

8791
<BitapDemo />
8892

89-
Fuse.js extends this to **approximate matching** by maintaining multiple state vectors — one per error level. Errors (substitutions, insertions, deletions) allow `1` bits to propagate across error levels, so a match with 1 error is tracked in `R1`, with 2 errors in `R2`, and so on.
93+
## Handling Typos: Approximate Matching
94+
95+
The demo above only shows exact matching. But Fuse.js is a *fuzzy* search library — it needs to handle typos, missing characters, and extra characters. It does this by running the Bitap algorithm multiple times, allowing one more error each pass.
96+
97+
Instead of a single state vector `R`, Fuse maintains multiple: `R0` (zero errors), `R1` (one error), `R2` (two errors), and so on. When a partial match dies in one level because the characters don't match, it can continue in the next level — counting that mismatch as an error:
98+
99+
- **Substitution** — a partial match in `R0` hits a wrong character. Instead of dying, it continues in `R1` with one error charged.
100+
- **Deletion** — a partial match skips a pattern position (a character is missing from the text). It continues in `R1`.
101+
- **Insertion** — a partial match skips a text character (an extra character in the text). It continues in `R1`.
102+
103+
For example, searching for `test` in `"tset"` (a transposition):
104+
105+
```
106+
t e s t
107+
R0 (0 errors): 1 0 0 0 ← 't' matches, but 's' ≠ 'e' — exact match dies
108+
R1 (1 error): 1 1 0 0 ← the mismatch continues here as 1 error
109+
R2 (2 errors): 1 1 1 1 ← another mismatch, 2 errors — still matches!
110+
```
111+
112+
The algorithm stops adding error levels when the score exceeds the `threshold`. This is how `threshold` controls fuzziness — a lower threshold means fewer error levels are tried, requiring closer matches.
90113

91114
<PublishDate date="2026-04-09" />

0 commit comments

Comments
 (0)