-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Reintroduce QueryPhaseListener with performance optimizations #18994
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
base: main
Are you sure you want to change the base?
Reintroduce QueryPhaseListener with performance optimizations #18994
Conversation
|
@owaiskazi19 @andrross Please review |
|
❌ Gradle check result for ad942ca: 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? |
ad942ca to
bd4c107
Compare
This commit reintroduces the QueryPhaseListener functionality that was reverted in opensearch-project#18913 due to performance regressions, now with optimizations that eliminate the overhead. Changes: - Add QueryPhaseListener interface for plugins to hook into query phase - Add AbstractQueryPhaseSearcher implementing template pattern for listeners - Modify QueryPhaseSearcher interface to support listener registration - Add comprehensive tests for listener functionality Performance optimizations: - Fast-path in DefaultQueryPhaseSearcher bypasses template pattern when no listeners - Direct hasQueryPhaseListeners() check avoids virtual method calls - Single listener optimization avoids iterator creation - Zero overhead for the common case (no listeners registered) The original implementation caused 10-15% regression in neural-search because it forced all searches through the template pattern even without listeners. This optimized version maintains the extension functionality while eliminating overhead for plugins that extend DefaultQueryPhaseSearcher without using listeners. Fixes opensearch-project#17593 Resolves performance regression from opensearch-project#18913 Signed-off-by: Atri Sharma <atri.jiit@gmail.com>
bd4c107 to
526897c
Compare
|
❌ Gradle check result for 526897c: 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? |
|
Flaky tests #16576 |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #18994 +/- ##
============================================
- Coverage 72.88% 72.83% -0.06%
+ Complexity 69327 69326 -1
============================================
Files 5643 5646 +3
Lines 318720 318819 +99
Branches 46113 46129 +16
============================================
- Hits 232294 232198 -96
- Misses 67595 67828 +233
+ Partials 18831 18793 -38 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
The QueryCollectorContextSpec was introduced earlier to inject QueryCollectorContextSpecs from the plugins PR #18637 . Currently, the DefaultQueryPhaseSearcher is been extended by ConcurrentQueryPhaseSearcher. There is already a PR which is in draft to remove this HybridCollectorManager dependency creation via HybridAggregationProcessor. This will also remove HybridQueryPhaseSearcher need because we can simply reuse defaultQP and ConcurrentQP for our searches. We have seen 13% performance improvement by doing that in POC and in the final draft of the PR we expect more. opensearch-project/neural-search#1424. If we introduce QueryPhaseListeners, then I think we might loose the integrity of the QueryPhase. Because currently opensearch supports two type of searches: Concurrent and nonconcurrent. But the concurrent search relies for topDocsCollector on DefaultQP. If we introduce before and after QP listeners then user can change results by writing a custom logic in after QPlistener. This can break logic in HybridQuery. |
Thank you for raising these concerns. Let me address them:
Would it help if we:
The goal is to provide extension points without compromising the integrity of search execution. |
|
I will evaluate it more. But one Quick QQ: Why do we need this listeners? I mean is there any use case of it currently in implementing any functionality? |
| * This method allows for fast-path optimization to skip listener logic entirely. | ||
| * @return true if there are listeners, false otherwise | ||
| */ | ||
| default boolean hasQueryPhaseListeners() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure why we need this method, we can conclude on presence of listeners based on the size of the list of QueryPhaseListener objects. You can change
if (!hasQueryPhaseListeners()) {
to
if (Objects.notNull(queryPhaseListeners()) == false && queryPhaseListeners().isEmpty() == false)
Are you sure about this being a main factor, is there data the support this? The workload we run while checking for regressions - it has vast majority of hybrid queries. |
Sorry for the delay. The template pattern overhead is real but limited in scope. QueryPhaseBeforeAfterTests.java:35-60 shows measurable overhead in tight loops and fast-path eliminates virtual calls when hasQueryPhaseListeners() returns false. Since Neural-search extends DefaultQueryPhaseSearcher without listeners, hence It would benefits from this However, for hybrid queries specifically, I agree that this could not be the singular source of regression. The objective of this PR is to minimise the reproducible lag and then revisit it once the numbers for neural-search come in with this change. But yes, this alone won't fix all hybrid query performance issues. Would need profiling on actual hybrid workloads to identify other bottlenecks. |
|
This PR is stalled because it has been open for 30 days with no activity. |
|
This PR is stalled because it has been open for 30 days with no activity. |
This commit reintroduces the QueryPhaseListener functionality that was reverted
in #18913 due to performance regressions, now with optimizations that eliminate
the overhead.
Changes:
Performance optimizations:
The original implementation caused 10-15% regression in neural-search because it
forced all searches through the template pattern even without listeners. This
optimized version maintains the extension functionality while eliminating overhead
for plugins that extend DefaultQueryPhaseSearcher without using listeners.
Fixes #17593
Resolves performance regression from #18913