Skip to content

fix: improve large dictionary matching performance - #78

Merged
jan-kubica merged 3 commits into
mainfrom
fix/anonymization-performance
Jun 4, 2026
Merged

fix: improve large dictionary matching performance#78
jan-kubica merged 3 commits into
mainfrom
fix/anonymization-performance

Conversation

@jan-kubica

@jan-kubica jan-kubica commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

This improves matching performance for large literal dictionaries and whole-word searches. It avoids building a fallback automaton on the first scan when the standard overlapping search can provide the needed candidates. Large case-insensitive dictionaries use a folded-text path instead of forcing the builder's ASCII case-insensitive mode, keeping offsets and match semantics unchanged while reducing setup and search overhead.

@jan-kubica jan-kubica changed the title fix: improve anonymization performance fix: improve performance Jun 4, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the stella-aho-corasick library to version 1.0.2, optimizing the wholeWords option by utilizing a Standard automaton and selecting leftmost-longest matches after boundary filtering. It also optimizes case-insensitive building for ASCII patterns and removes several unused search methods. The review feedback suggests two key improvements: simplifying the candidate selection loop in src/lib.rs since the candidates are already sorted in the desired order, and avoiding an unnecessary clone of effective_patterns in src/case_folding.rs by moving the vector directly.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/lib.rs
Comment on lines +270 to +283
let mut best = candidates[i];
i += 1;
while i < candidates.len()
&& candidates[i].start == start
{
let candidate = candidates[i];
if candidate.end > best.end
|| (candidate.end == best.end
&& candidate.pattern < best.pattern)
{
best = candidate;
}
i += 1;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since candidates is already sorted by start (ascending), then end (descending), and then pattern (ascending), the first candidate for any given start is guaranteed to be the leftmost-longest match with the lowest pattern index.\n\nThe subsequent loop that compares candidate.end and candidate.pattern is redundant because no subsequent candidate with the same start can have a larger end, or the same end with a smaller pattern index. We can simplify this loop to just skip the remaining candidates with the same start without performing any comparisons.

    let best = candidates[i];\n    i += 1;\n    while i < candidates.len()\n      && candidates[i].start == start\n    {\n      i += 1;\n    }

Comment thread src/case_folding.rs
Comment on lines +255 to +259
fallback_patterns: if raw_supports_overlapping {
None
} else {
Some(effective_patterns.clone())
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The effective_patterns vector is passed by value to CaseFoldingAC::build and is not used after the fallback_patterns assignment. We can avoid cloning it by moving effective_patterns directly into Some(effective_patterns).

      fallback_patterns: if raw_supports_overlapping {\n        None\n      } else {\n        Some(effective_patterns)\n      },

@jan-kubica jan-kubica changed the title fix: improve performance fix: improve large dictionary matching performance Jun 4, 2026
@jan-kubica
jan-kubica marked this pull request as ready for review June 4, 2026 00:22

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ac249f6fa6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/lib.rs
Comment on lines 357 to +358
let effective_kind = if whole_words {
RawMatchKind::LeftmostLongest
RawMatchKind::Standard

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve matchKind when wholeWords is set

When wholeWords is true this discards the requested/default matchKind, and the new whole-word path later selects the longest candidate at each start. That changes documented leftmost-first behavior for inputs where multiple boundary-valid patterns start together, e.g. new AhoCorasick(["a", "a-"], { wholeWords: true, matchKind: "leftmost-first" }).findIter("a-") now returns/replaces "a-" instead of pattern 0 "a".

Useful? React with 👍 / 👎.

@jan-kubica
jan-kubica merged commit 5ca6d2a into main Jun 4, 2026
21 checks passed
@jan-kubica
jan-kubica deleted the fix/anonymization-performance branch June 4, 2026 00:46
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 4, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant