Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Tuning & Tips

The engine is built once and cheap to query repeatedly. A few habits keep searches fast and results clean.

Filter early

  • Raise the threshold. A higher similarity threshold prunes weak partial matches before they expand — it improves both quality and speed. It is the single most effective knob.
  • Tighten edit limits. FuzzyLimits per pattern, when you know the expected error characteristics, cuts the explored state space directly.

Shape the cost model to your domain

  • Use the similarity table for look-alike single characters (OCR glyphs, homoglyphs) so those substitutions are cheap and everything else stays expensive.
  • Use FuzzyPenalties to make whole edit types cheaper or pricier.
  • Use the weakest-link floor when a single bad character should disqualify a match regardless of length.

Pick the right entry point

  • Prefer a .non_overlapping() / .non_overlapping_unique() SearchOptions over resolving overlaps yourself.
  • Use SearchOptions::default() (unordered, overlaps kept) as the fastest primitive when you want to build a custom ranking/selection pipeline.

Guard against pathological input

Combining a high edit budget with a low threshold is the classic slow case. Add auto_beam (keeps common cases exact) or an explicit beam_width when limits are high and thresholds low, especially for untrusted input.

Reach for the specialized paths when they fit

  • Streaming for large or incremental inputs (constant memory), and its parallel forms to use all cores on CPU-bound scans.
  • The pre-filter for large, sparse inputs where most of the text can’t match — a big speedup with identical results, and a safe fallback when it doesn’t apply.

Memory footprint

The compiled automaton is immutable and shared by reference (&FuzzyAhoCorasick) — build it once and query it from as many threads as you like without copying it. Each search allocates only bounded, transient per-call state (the BFS frontier, a visited-set for state dedup, and a best-match-per-span map). That state scales with the haystack length and match density, not with the automaton’s pattern count, so per-query memory stays flat even for automata with millions of patterns. This makes the engine cheap to fan out across many concurrent queries: the resident footprint is the one shared automaton plus a small, bounded slice per in-flight search.

Size expectations

A single search call keeps grapheme positions as u32, so one haystack must contain at most u32::MAX grapheme clusters (roughly a 4 GiB ASCII input). A larger haystack returns Err(SearchError::HaystackTooLarge) rather than silently truncating positions to wrong offsets — for inputs that big (or unbounded streams), use the streaming API, which windows the input and reports absolute u64 offsets.

Measuring

Benchmark with your real patterns and representative text — throughput depends heavily on pattern count/length, edit budget, threshold, and match density. The repository ships Criterion benchmarks (cargo bench) and the bitap_prototype / replace_bench examples as starting points.