Repository navigation
fix(search): rank the word as typed above its stem variants - #237
Conversation
Stemming gave the form typed no credit, so collect, collect() and "collect()" ranked chunks full of collections above chunks holding collect itself. A plain body word or one-word phrase now reads half its weight from the word as typed (F_WORDS) and half from its stem. Its stem query stays required, so match sets, counts and highlights are unchanged; only order moves. - The split happens per word inside the compiler, so a pattern, fuzzy or field leaf beside a plain word keeps its whole weight, ^N scales both halves, and a negated word earns nothing. - Multi-word phrases are scored as before: F_WORDS has no positions, and the phrase's words counted apart would outscore the phrase. - Adding the typed form on top of the stems instead cost NQ deeper-section MRR up to 0.051, so the weight is shared, not added. Measured against main (public benchmarks, paired randomisation p): - NQ page nDCG@10: +0.004 full questions (p 0.02), +0.004 3-word (p 0.02), +0.007 2-word (p < 0.001). - NQ full questions, within-page MRR for deeper answers: -0.006 (p 0.03 to 0.05 across scorings). The one cell below main at p < 0.05. - SciFact, NFCorpus, CoSQA: level (no cell at p < 0.05). - Strong-signal shortcut: NFCorpus 16 to 12 of 323 queries; never fires on NQ, SciFact or CoSQA either way. - Latency within 1 ms; no schema change, no reindex.
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Exact-form query compilation fnd/schema.py, fnd/analysis.py, fnd/query_compile.py |
The compiler accepts an exact-form share. For a single token, it weights the stemmed query by the remaining share and adds the typed word as a Should clause. The body-word share is set to 0.5. |
Body query wiring and validation fnd/query.py, tests/test_exact_form_outranks_stem_variants.py, README.md |
The searcher passes the configured share to body-query compilation. Regression tests cover ranking, field scoping, patterns, boosts, and phrase behaviour. The README states that invoice outweighs invoices. |
Estimated code review effort: 3 (Moderate) | ~20 minutes
Change: Bug fix
Merge Risk: 
Minimal · up to 92f19
-
Exact forms receive additional ranking weight. No actionable merge-blocking risk was identified.
Pre-merge checks: 
4 · 
1
-
Failed checks: 1 warning Passed checks: 4 passed-
Full details: Title check
-
Explanation
The title names the main change: search ranking now credits the word as typed over its stem variants. It matches the code changes in fnd/query_compile.py, fnd/schema.py and fnd/analysis.py. The title uses the fix(search) convention and is specific. It is 59 characters, which is within a normal title length.
Full details: Description check
-
Explanation
The description explains the problem (stemming folds collect and collections together, so the typed form earns no credit). It describes the split-weight change, the EXACT_FORM_SHARE and F_WORDS usage, the per-word rules in _Compiler._exact_form, and the new test file. It also reports benchmark results against main, including one below-main metric. The description is directly related to the changeset.
-
Full details: Docstring Coverage
-
Explanation
Docstring coverage is 58.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 12 functions across 5 files. (1 skipped: 1 unsupported.)
Resolution
Write docstrings for the functions missing them to satisfy the coverage threshold.
-
Finishing Touches
-
Generate docstrings
-
- Commit to this branch
- Create a new PR
Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
I’m a rabbit with a query to run,
Stem and typed word share the fun.
Half the weight goes to the form,
Half keeps stemming as the norm.
Tests check the order, clear and bright,
Then I hop off into the night.
Problem
Searching
collect,collect()or"collect()"ranked chunks full ofcollectionsabove chunks holdingcollectitself. Stemming folds both to one stem, so nothing credited the form typed.Change
EXACT_FORM_SHARE) from the word as typed (F_WORDS) and half from its stem._Compiler._exact_form):^Nscales both halves.F_WORDSstores no positions, so a phrase's words counted apart would outscore the phrase itself.Measured against main
Public benchmarks, paired randomisation p:
The deeper-answer MRR cell is the one result below main at p < 0.05: one of about 40 compared, and it would not survive a multiple-comparison correction. It is in the metric the split was designed to protect, so it is stated here rather than left to the code comment.
Tests
tests/test_exact_form_outranks_stem_variants.py, with negative controls run for every case:collect,collect(),"collect()"andCOLLECT, andcollectionsoutrankscollected. All fail with the share at 0, which is main's behaviour.^N, field scope (title:"foo bar" OR baz), a colon that names no field (TODO:"fix it"), a negated phrase, and phrase ranking. Each fails against the earlier designs, or a mutant, that had the defect.