Repository navigation
[Cosmos] Use deterministic ordinal ranks for hybrid-search RRF - #50940
Maya Painter (Maya-Painter) wants to merge 6 commits into
Conversation
Port ordinal and opt-in competition ranking with cached numeric document RID tie-breaking and offline regression coverage. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 29c3522f-9887-43c5-bebb-f42ee9ba4d51
|
Azure Pipelines: Successfully started running 2 pipeline(s). 34 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
Derive strict fusion expectations from standalone component queries and numeric document RIDs. Allow only zero-score title ties to vary in non-RRF queries, and use cleanup-compliant test database creation. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 29c3522f-9887-43c5-bebb-f42ee9ba4d51
Keep the full-text reference setup and numeric RID tie-break expression on single lines as requested. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 29c3522f-9887-43c5-bebb-f42ee9ba4d51
Restore private ranking helpers and replace implementation-coupled unit tests with public-query integration coverage for ordinal and competition ranks, numeric RID ties, weights, and paging. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 29c3522f-9887-43c5-bebb-f42ee9ba4d51
Move ordinal and competition ranking coverage into HybridSearchQueryTest, reuse its database lifecycle, and remove the obsolete emulator ignore gate. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 29c3522f-9887-43c5-bebb-f42ee9ba4d51
| import static org.assertj.core.api.Assertions.assertThat; | ||
| import static org.assertj.core.api.Assertions.fail; | ||
|
|
||
| @Ignore("TODO: Ignore these test cases until the public emulator is released.") |
There was a problem hiding this comment.
Confirming we can remove this ignore?
There was a problem hiding this comment.
You're good but these tests aren't still running against emulator but against a real account.
Preserve both the ordinal hybrid-search release note and main's effective partition-key sub-range fix. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 29c3522f-9887-43c5-bebb-f42ee9ba4d51
There was a problem hiding this comment.
🟡 Changes recommended
The score-matrix sizing change lacks regression coverage for nonempty results with an empty first component-score array or all-empty arrays.
1 open issue
What changed in this PR
Updates Cosmos hybrid-search reciprocal-rank fusion to use deterministic ordinal ranks by default, with an optional competition-ranking mode.
Changes:
- Uses unsigned numeric document RIDs to resolve component-score and fused-score ties.
- Captures the ranking setting per query and sizes score matrices from the query plan.
- Enables and expands integration tests, updates resource hygiene, and documents the behavior change.
| File | Description |
|---|---|
sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/HybridSearchDocumentQueryExecutionContext.java |
Implements ranking modes, deterministic tie-breaking, and plan-based score dimensions. |
sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/hybridsearch/HybridSearchQueryResult.java |
Caches the decoded numeric document RID. |
sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Configs.java |
Adds the competition-ranking configuration setting. |
sdk/cosmos/azure-cosmos/CHANGELOG.md |
Documents ranking modes and tie-breaking behavior. |
sdk/cosmos/azure-cosmos-tests/src/test/resources/test-resource-hygiene-baseline.properties |
Removes the hybrid-search test’s resource-hygiene exception. |
sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/HybridSearchQueryTest.java |
Enables integration tests and adds ranking, paging, and payload assertions. |
Review effort: Balanced
| #### Breaking Changes | ||
|
|
||
| #### Bugs Fixed | ||
| * Hybrid search now uses deterministic ordinal reciprocal-rank fusion: component scores `10, 5, 5, 5, 0` receive ranks `1, 2, 3, 4, 5`. Set `AZURE_COSMOS_HYBRID_SEARCH_USE_COMPETITION_RANKING=true` to use competition ranks `1, 2, 2, 2, 5` instead. Component ties use numeric document RID in the query-plan sort direction; fused-score ties use numeric document RID descending. |
There was a problem hiding this comment.
Isn't this a breakign change? One with an Opt-out to move back to previous behavior - but still abreaking change? Should this be an opt-in instead in the current major version?
| #### Breaking Changes | ||
|
|
||
| #### Bugs Fixed | ||
| * Hybrid search now uses deterministic ordinal reciprocal-rank fusion: component scores `10, 5, 5, 5, 0` receive ranks `1, 2, 3, 4, 5`. Set `AZURE_COSMOS_HYBRID_SEARCH_USE_COMPETITION_RANKING=true` to use competition ranks `1, 2, 2, 2, 5` instead. Component ties use numeric document RID in the query-plan sort direction; fused-score ties use numeric document RID descending. |
There was a problem hiding this comment.
We usually don't recommend using any VM / env variable options in the changelog. The idea behind adding these VM options / env variables is to allow a backdoor entry / exit in case something goes wrong. I wouldn't advertise it unless there is any issue.
| "COSMOS.HYBRID_SEARCH_USE_COMPETITION_RANKING"; | ||
| private static final String HYBRID_SEARCH_USE_COMPETITION_RANKING_VARIABLE = | ||
| "AZURE_COSMOS_HYBRID_SEARCH_USE_COMPETITION_RANKING"; | ||
|
|
There was a problem hiding this comment.
Would be good to also have a default variable with value of false for consistency sake like others in this file. Allows a bit of better debuggability.
Fabian Meiswinkel (FabianMeiswinkel)
left a comment
There was a problem hiding this comment.
Pleas emake this non-breaking (new option as an opt-in - no opt-out to revert back to current behavior)
| // Competition ties share the first position; the next distinct score skips tied positions. | ||
| if (!useCompetitionRanking || (index > 0 | ||
| && componentScores.get(componentIndex).get(index).getScore().doubleValue() | ||
| != componentScores.get(componentIndex).get(index - 1).getScore().doubleValue())) { |
There was a problem hiding this comment.
Could we use Double.compare(currentScore, previousScore) != 0 here so competition-rank tie detection uses the same score-equality semantics as ComponentWeight's comparator?

Description
Ports the ranking behavior from merged Azure/azure-cosmos-dotnet-v3#6130 to the Java Cosmos hybrid-search pipeline.
Component scores
10, 5, 5, 5, 0now receive ordinal ranks1, 2, 3, 4, 5by default. SettingAZURE_COSMOS_HYBRID_SEARCH_USE_COMPETITION_RANKING=trueselects competition ranks1, 2, 2, 2, 5instead, not dense ranks. The internal setting is captured once per query.Component-score ties use the unsigned numeric document RID in the query-plan sort direction, independent of normalized weights. Final results sort by fused score descending, then numeric document RID descending.
Weights and
weight / (60 + rank)remain unchanged.All SDK Contribution checklist:
General Guidelines and Best Practices
Testing Guidelines