ContextQuery gives an exact context's boost to any longer indexed context that starts with it (exact 'red' boosts a suggestion indexed under 'redwood') when that longer context is matched through a shorter prefix context or addAllContexts(), so document-suggester hits get wrong scores and a wrong order

Finding LFV-254Area: suggest / document (NRT) suggester (ContextQuery: ContextCompletionWeight.setNextMatch boost lookup over ContextSuggestField contexts)Priority: mediumImpact: silent wrong resultsNovelty: new

Finding page for LFV-254

AI-assisted finding, confirmed by automated checks, not yet triaged by a human Lucene committer. This site files nothing upstream.

What it shows

You index 'table lamp' (weight 5) under context 'redwood' and 'table cloth' (weight 4) under 'red' with ContextSuggestField, and query 'tab' with addAllContexts() (or a prefix context 're') plus the exact context 'red' with boost 10; you expect 'table cloth' to score 4 x 10 = 40 and 'table lamp' its plain weight 5, because an exact context matches only an indexed context equal to it. Instead 'table lamp' scores 50 and ranks first: the boost lookup takes the longest query context whose characters equal the start of the indexed context and never checks that the indexed context ends there, so exact 'red' lends its boost to 'redwood'. Filtering is still right (exact 'red' alone does not return 'table lamp'); only scores and order are wrong.

The test shows that an exact ContextQuery context ('red', boost 10) lends its boost to a suggestion indexed under a longer context that starts with it ('redwood') when that suggestion is matched through addAllContexts().

Expected vs actual

Expected the 'lamp' suggestion (context 'redwood', weight 5) to score its plain weight 5; actual 50 (expected:<5.0> but was:<50.0>), with -ea and -da.

Files

Run it

# Lucene checkout at the tested commit, built with: ./gradlew --no-daemon assemble   (JDK 25)
LUCENE=/path/to/lucene; V=12.0.0-SNAPSHOT
CP=$LUCENE/lucene/core/build/libs/lucene-core-$V.jar
CP=$CP:$LUCENE/lucene/codecs/build/libs/lucene-codecs-$V.jar
CP=$CP:$LUCENE/lucene/test-framework/build/libs/lucene-test-framework-$V.jar
CP=$CP:$LUCENE/lucene/analysis/common/build/libs/lucene-analysis-common-$V.jar
CP=$CP:$LUCENE/lucene/suggest/build/libs/lucene-suggest-$V.jar
CP=$CP:randomizedtesting-runner-2.9.2.jar:junit-4.13.2.jar:hamcrest-3.0.jar   # test-framework dependencies (Maven Central)
CP=$CP:junit-platform-console-standalone-6.1.3.jar   # JUnit Platform console launcher (Maven Central)

javac -d classes -cp "$CP" $(find src -name '*.java')

# run 1: assertions on, seed DEADBEEF
java -ea -esa --add-modules jdk.incubator.vector --enable-native-access=ALL-UNNAMED -Dtests.seed=DEADBEEF \
     -cp "classes:$CP" org.junit.platform.console.ConsoleLauncher \
     execute --select-class org.apache.lucene.search.suggest.document.TestContextQueryExactContextBoost

Gradle alternative: copy the test into the matching module's src/test/ tree of the checkout and run ./gradlew -p lucene/<module> test --tests <class> -Ptests.seed=<seed> (add -Ptests.asserts=false for a run without assertions).

Feedback

Open an issue in lucene-ai-bug-hunt. Please do not open issues or pull requests in apache/lucene about this finding unless a Lucene committer agrees it should be filed.

Snapshot of 2026-11-04. AI-assisted; not yet triaged by a human Lucene committer. Feedback: open an issue in lucene-ai-bug-hunt.