Skip to content

Preserve constant_score through filtered aliases - #227

Open
DarshitChanpura wants to merge 7 commits into
mainfrom
feat/constant-score-filtered-query
Open

DarshitChanpura wants to merge 7 commits into
mainfrom
feat/constant-score-filtered-query

Conversation

@DarshitChanpura

Copy link
Copy Markdown
Owner

What

When a search targets a filtered alias, DefaultSearchContext.buildFilteredQuery
adds the alias filter by wrapping the user's query in a scoring BooleanQuery
(bool[query MUST, aliasFilter FILTER]). If the user's query was a
ConstantScoreQuery, nesting it inside that scoring boolean:

  1. re-introduces scoring of the inner query (breaking the caller's explicit
    "no scoring" request — hits no longer score a constant), and
  2. defeats Lucene's COMPLETE_NO_SCORES fast path, so the inner query's scorer
    is set up over the whole postings list.

The second point is a real latency cliff: a constant_score(match: <frequent term>)
that runs in ~0 ms against a concrete index takes ~15 ms through a filtered alias
at scale, purely because the alias filter re-wraps it in a scoring boolean.

Fix

Re-wrap the filtered result in a ConstantScoreQuery when the main query was
already constant-scored, so the outermost query stays non-scoring. This preserves
both the no-scoring contract and the fast path end-to-end.

Only the constant-score path is affected; normal scored queries on aliases are
unchanged.

Testing

  • ConstantScoreFilteredAliasIT — a constant_score query scores every hit
    exactly 1.0 through a filtered alias, identical to the backing index (before
    the fix the alias path produced varying BM25 scores).
  • IndexAliasesIT (29/29) — no regression for normal scored alias queries.

@DarshitChanpura
DarshitChanpura force-pushed the feat/constant-score-filtered-query branch from 96e9faf to 0073302 Compare August 19, 2026 16:42
When a search targets a filtered alias, DefaultSearchContext.buildFilteredQuery
adds the alias filter by wrapping the user's query in a scoring BooleanQuery
(bool[query MUST, aliasFilter FILTER]). If the user's query was a
ConstantScoreQuery, nesting it inside that scoring boolean re-introduces scoring
of the inner query and defeats Lucene's COMPLETE_NO_SCORES fast path, so the
inner query's scorer is set up over the whole postings list.

Re-wrap the filtered result in a ConstantScoreQuery when the main query was
already constant-scored, keeping the outermost query non-scoring. This preserves
both the no-scoring contract and the fast path end-to-end. Matters for
access-control filters (e.g. document-level security composed with a filtered
alias), where the combined query would otherwise be scored despite the caller
having requested constant scoring.

Verified by ConstantScoreFilteredAliasIT (hits score 1.0 through the alias,
matching the backing index); IndexAliasesIT (29/29) confirms no regression for
normal scored alias queries.

Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
@DarshitChanpura
DarshitChanpura force-pushed the feat/constant-score-filtered-query branch from 0073302 to 6c9c337 Compare August 19, 2026 20:00
chishui and others added 6 commits August 19, 2026 18:52
…ect#22765)

Signed-off-by: Liyun Xiu <xiliyun@amazon.com>
Co-authored-by: Andriy Redko <drreta@gmail.com>
…earch-project#22493)

collectDocs now returns packed i64: upper 32 bits = next matching docId
beyond maxDoc, lower 32 bits = wordsWritten. No new FFM calls needed.

Rust consumers use nextDoc for three levels of optimization:
1. Full RG skip: nextDoc >= rgMax → no collectDocs call
2. Tightened range: nextDoc > rgMin → start from nextDoc, smaller bitset
3. No benefit: nextDoc <= rgMin → call as before

Implemented in both SingleCollectorEvaluator (AtomicI32 across RGs) and
CollectorLeafBitmaps/BitmapTree (per-leaf HashMap keyed by Arc identity).

Signed-off-by: Somesh Gupta <someshgupta987@gmail.com>
…ect#22704)

* Remove Jackson 2.x dependencies from OpenSearch core

Signed-off-by: Andriy Redko <drreta@gmail.com>

* Address review comments

Signed-off-by: Andriy Redko <drreta@gmail.com>

---------

Signed-off-by: Andriy Redko <drreta@gmail.com>
Covers both branches of the ConstantScoreQuery re-wrap in
DefaultSearchContext.buildFilteredQuery: a ConstantScoreQuery input with a
filter present stays non-scoring (returns a ConstantScoreQuery), and a normal
query is combined into a scoring BooleanQuery. Complements the existing
ConstantScoreFilteredAliasIT with method-level coverage.

Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants