Skip to content

#17593 Add Extension Points For Pre and Post Collection of Scores in QueryPhase #18814

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

atris
Copy link
Contributor

@atris atris commented Jul 22, 2025

Resolves #17593

Problem

Plugins implementing hybrid queries and neural search currently rely on AggregationProcessor workarounds to inject custom CollectorManager implementations. This approach is fragile and breaks when the aggregation system changes.

Solution

Add extension points directly in QueryPhase around the actual score collection operation:

  • QueryPhaseExtension interface with beforeScoreCollection() and afterScoreCollection() methods
  • Extension registration via QueryPhaseSearcher.queryPhaseExtensions()
  • Execution in DefaultQueryPhaseSearcher with proper error isolation

Implementation

New interface:

@PublicApi(since = "3.0.0")
public interface QueryPhaseExtension {
    void beforeScoreCollection(SearchContext searchContext);
    void afterScoreCollection(SearchContext searchContext);
}

Extension points placed around:
searcher.search(query, collector) // <- actual score collection

Features:
- Extensions execute before and after score collection in try/finally blocks
- Individual extension failures are logged but don't break search
- Default implementations return empty extension lists (backward compatible)
- Zero overhead when no extensions are registered

Usage

public class HybridQueryPhaseSearcher extends DefaultQueryPhaseSearcher {
    @Override
    public List<QueryPhaseExtension> queryPhaseExtensions() {
        return List.of(new HybridQueryExtension(), new NeuralSearchExtension());
    }
}

Testing

Unit tests verify:

  • Interface functionality
  • Extension registration
  • Integration with search execution
  • Error handling and isolation

No existing functionality affected.

@github-actions github-actions bot added enhancement Enhancement or improvement to existing feature or request Search Search query, autocomplete ...etc labels Jul 22, 2025
@atris
Copy link
Contributor Author

atris commented Jul 22, 2025

@getsaurabh02

Copy link
Contributor

❌ Gradle check result for da66380: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@owaiskazi19
Copy link
Member

@atris now that we have a way to inject QueryCollectorContext in core, would that solve your need? #18278

try {
searcher.searchWith(searchContext, indexSearcher, query, collectors, false, false);
} catch (Exception ignored) {
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should fail the test in case of exception

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

*
* @opensearch.api
*/
@PublicApi(since = "3.0.0")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be 3.2.0 or whatever next version you're aiming for. 3.0.0 has been released some time ago

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

try {
extension.beforeScoreCollection(searchContext);
} catch (Exception e) {
LOGGER.warn(new ParameterizedMessage("Failed to execute beforeScoreCollection extension [{}]", extension.getClass().getName()), e);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we make this behavior configurable, and fail execution by default, similar to behavior of ignore_failure flag? This can be part of extension interface

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

/**
* Unit tests for QueryPhaseExtension interface.
*/
public class QueryPhaseExtensionTests extends OpenSearchTestCase {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're missing the test case for scenario when extension is throwing exception, if so please add test for such scenario

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

Copy link
Contributor

❌ Gradle check result for 0a0f121: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@atris atris force-pushed the add_querytime_extensions branch from 67ddc71 to ae4b60c Compare July 28, 2025 16:37
Copy link
Contributor

❌ Gradle check result for ae4b60c: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

Signed-off-by: Atri Sharma <[email protected]>

Signed-off-by: Atri Sharma <[email protected]>
@atris atris force-pushed the add_querytime_extensions branch from ae4b60c to 51d8de7 Compare July 28, 2025 17:53
Copy link
Contributor

❌ Gradle check result for 51d8de7: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

Copy link
Contributor

❌ Gradle check result for ddf59ab: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@atris atris closed this Jul 29, 2025
@atris atris reopened this Jul 29, 2025
Copy link
Contributor

❌ Gradle check result for ddf59ab: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@atris
Copy link
Contributor Author

atris commented Jul 29, 2025

Flaky tests #15813

@atris atris closed this Jul 29, 2025
@atris atris reopened this Jul 29, 2025
Copy link
Contributor

✅ Gradle check result for ddf59ab: SUCCESS

Copy link

codecov bot commented Jul 29, 2025

Codecov Report

❌ Patch coverage is 72.50000% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.88%. Comparing base (42a1dd2) to head (ddf59ab).
⚠️ Report is 23 commits behind head on main.

Files with missing lines Patch % Lines
...rch/search/query/ConcurrentQueryPhaseSearcher.java 55.00% 8 Missing and 1 partial ⚠️
...n/java/org/opensearch/search/query/QueryPhase.java 89.47% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main   #18814      +/-   ##
============================================
+ Coverage     72.80%   72.88%   +0.07%     
- Complexity    68564    68570       +6     
============================================
  Files          5567     5567              
  Lines        314844   314949     +105     
  Branches      45675    45690      +15     
============================================
+ Hits         229227   229545     +318     
+ Misses        67028    66770     -258     
- Partials      18589    18634      +45     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@atris
Copy link
Contributor Author

atris commented Jul 29, 2025

@owaiskazi19 @martin-gaievski Updated the PR and CI passes. Plsse review

Copy link
Member

@martin-gaievski martin-gaievski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, thank you. Please look into failing check for low test coverage, maybe you can came up with more test scenario, the gap between actual and expected procentage is tiny

beforeContext.set(searchContext);
// At this point, query should be available but not results
assertNotNull("SearchContext should not be null in beforeScoreCollection", searchContext);
assertNotNull("Query should be available in beforeScoreCollection", searchContext.query());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also check

            assertNull("Query result should be null", searchContext.queryResult());

@owaiskazi19
Copy link
Member

@msfroh can you take another look? Overall LGTM

Copy link
Contributor

❌ Gradle check result for 89f4afe: null

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Enhancement or improvement to existing feature or request Search Search query, autocomplete ...etc
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feature Request] Add extension points for pre/post collecting scores in QueryPhase
3 participants