diff --git a/CHANGELOG.md b/CHANGELOG.md index ba28875b7119e..78e811901276a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased 3.x] ### Added +- Add getWrappedScorer method to ProfileScorer for plugin access to wrapped scorers ([#20548](https://github.com/opensearch-project/OpenSearch/issues/20548)) - Support expected cluster name with validation in CCS Sniff mode ([#20532](https://github.com/opensearch-project/OpenSearch/pull/20532)) ### Changed diff --git a/server/src/main/java/org/opensearch/search/profile/query/ProfileScorer.java b/server/src/main/java/org/opensearch/search/profile/query/ProfileScorer.java index b78ecf4501ae1..f204c880b8e3b 100644 --- a/server/src/main/java/org/opensearch/search/profile/query/ProfileScorer.java +++ b/server/src/main/java/org/opensearch/search/profile/query/ProfileScorer.java @@ -65,6 +65,26 @@ final class ProfileScorer extends Scorer { setMinCompetitiveScoreTimer = profile.getTimer(QueryTimingType.SET_MIN_COMPETITIVE_SCORE); } + /** + * Returns the wrapped scorer. + *
+ * This is useful for plugin queries that extend the Scorer API with custom methods not part of the standard + * Lucene Scorer interface. For example, neural-search's HybridQuery needs to access its HybridBulkScorer + * to call custom methods when profiling is enabled. + *
+ *+ * Note: Calling mutation methods (like {@link #setMinCompetitiveScore(float)}) directly on the + * wrapped scorer will bypass profiling instrumentation for those calls. For read-only access or accessing + * custom methods not part of the standard Scorer API, this is safe and expected. + *
+ * + * @return the underlying wrapped scorer + * @see ProfileCollector#getDelegate() + */ + public Scorer getWrappedScorer() { + return scorer; + } + @Override public int docID() { return scorer.docID(); diff --git a/server/src/test/java/org/opensearch/search/profile/query/ProfileScorerTests.java b/server/src/test/java/org/opensearch/search/profile/query/ProfileScorerTests.java index 0112fa0839965..c37d7852199a6 100644 --- a/server/src/test/java/org/opensearch/search/profile/query/ProfileScorerTests.java +++ b/server/src/test/java/org/opensearch/search/profile/query/ProfileScorerTests.java @@ -101,4 +101,15 @@ public void testPropagateMaxScore() throws IOException { fakeScorer.maxScore = 42f; assertEquals(42f, profileScorer.getMaxScore(DocIdSetIterator.NO_MORE_DOCS), 0f); } + + public void testGetWrappedScorer() throws IOException { + Query query = new MatchAllDocsQuery(); + Weight weight = query.createWeight(new IndexSearcher(new MultiReader()), ScoreMode.TOP_SCORES, 1f); + FakeScorer fakeScorer = new FakeScorer(weight); + QueryProfileBreakdown profile = new QueryProfileBreakdown(ProfileMetricUtil.getDefaultQueryProfileMetrics()); + ProfileScorer profileScorer = new ProfileScorer(fakeScorer, profile); + + // Verify getWrappedScorer returns the original scorer + assertSame(fakeScorer, profileScorer.getWrappedScorer()); + } }