From 748330933b12691b7c904f8ffa00f32a9e97cfa1 Mon Sep 17 00:00:00 2001 From: akamick86 <12109250+akamick86@users.noreply.github.com> Date: Fri, 5 Jun 2026 03:52:41 -0700 Subject: [PATCH] Build name-tagger automaton as a noncontiguous NFA Needles::build let AhoCorasickBuilder choose the automaton kind (Auto). Force NoncontiguousNFA: it is cheaper to build, which matters for the large needle sets the name tagger seeds (~470k aliases), whose one-time build dominates first-use latency. kind only changes the internal representation, not which matches are returned, and the prefilter stays enabled so search is unaffected for the short haystacks the tagger sees. Release build, person tagger (470,083 needles): Auto 1624 ms, ContiguousNFA 1516 ms, NoncontiguousNFA 1443 ms. About 11% off the automaton build; overlapping-search results are byte-identical across kinds. Existing test suite passes (192). --- rust/src/names/matcher.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/rust/src/names/matcher.rs b/rust/src/names/matcher.rs index 5fbc91a1..16a138e3 100644 --- a/rust/src/names/matcher.rs +++ b/rust/src/names/matcher.rs @@ -35,7 +35,7 @@ // the valid one. Cost is negligible at our data sizes (~1k needles, // ~30-char haystacks, a handful of candidates per call). -use aho_corasick::{AhoCorasick, AhoCorasickBuilder, MatchKind}; +use aho_corasick::{AhoCorasick, AhoCorasickBuilder, AhoCorasickKind, MatchKind}; use std::collections::HashMap; /// A multi-needle string search automaton with per-needle payload. @@ -86,6 +86,15 @@ impl Needles { // We implement leftmost-longest ourselves via greedy // selection on the overlapping match set. .match_kind(MatchKind::Standard) + // Force the noncontiguous NFA. The builder default (Auto) does + // extra work selecting and constructing a contiguous NFA; for the + // large needle sets rigour builds (the name tagger seeds ~470k + // aliases) that is ~11% of a one-time build that dominates first- + // use latency. `kind` changes the internal representation only, + // never which matches are returned; the prefilter stays enabled + // and our haystacks are short (~30 chars), so search speed is + // unchanged in practice. + .kind(Some(AhoCorasickKind::NoncontiguousNFA)) .build(&keys) .expect("needle automaton builds"); Self { ac, payloads }