Repository navigation
Skip redundant regex work when scoring search passages - #170
Merged
Merged
Conversation
_term_count rebuilt its pattern string on every call, and _clean_passage ran four uncompiled re.sub passes per field even on plain text. Term patterns are now compiled once and cached, cleanup patterns are precompiled and skipped when their required character is absent, and whitespace collapses with str.split, which uses the same Unicode whitespace set as regex \s. Scores and cleaned text are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
admin-raintree
enabled auto-merge (squash)
October 12, 2026 20:37
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Search scoring now does less regex work per passage, and its scores and cleaned text are unchanged.
Problem
After #168, scoring was the largest cost in broad context queries.
_search_scorecalls_term_count9 times per passage, and_term_countrebuilt its pattern string on every call._clean_passageran four uncompiledre.subpasses over each field, even on plain text.Change
All changes are in
src/docpull/pack_tools.py:_term_countcompiles each term's pattern once and caches it withlru_cache._clean_passageuses precompiled patterns. Each one is skipped when the character it needs is absent:](for links,-,*or+for list markers, and#for headings._clean_passagecollapses whitespace with" ".join(text.split()). On every Unicode code point,str.split()and regex\streat the same characters as whitespace, so the result is identical.Checks
test_search_scoring_matches_pre_fast_path_valuespins cleanup output and scores recorded from the previous implementation. It covers markdown links, list and heading markers,c++,caféand Unicode whitespace._clean_passageoutput in the old and new versions.uv run pytest tests/test_pack_tools.py tests/test_context_query.py tests/test_web_search.py -q: 53 passed.ruff check,ruff formatandmypypass on the changed files.bun run validate:fullwas not run.Benchmark
On a synthetic project of 3,000 documents with 52,000 matching passages, the context query "retry backoff" took a median of 1.35s, versus 1.87s with
main's scoring code. Both versions returned identical payloads, and each timing is the median of 3 runs.The synthetic passages contain no
-or#, so every cleanup pattern was skipped. Real documentation usually contains hyphens, so the speedup there will be smaller.🤖 Generated with Claude Code