Skip to content

Conversation

@rishabhmaurya
Copy link
Contributor

@rishabhmaurya rishabhmaurya commented Jan 26, 2026

Description

Problem
Streaming terms aggregators flush results per-segment, sending all buckets to the coordinator. This causes:

  1. Performance degradation: Excessive data transfer and coordinator memory usage when dealing with high-cardinality fields

  2. Memory pressure: Coordinator must process and reduce all buckets from all segments

Solution
Implemented TopN selection at segment level using quickselect algorithm, handling subAggs an supported metric Aggs, to send only the most relevant buckets to the coordinator.

Benefits:

Better Performance:
Reduces data transfer and coordinator memory/CPU usage by sending only TOP N buckets per segment

Controlled Accuracy:
TopN selection introduces potential accuracy trade-offs, which can be controlled using:

size parameter: Number of final buckets to return

shard_size parameter: Number of buckets to collect per segment (not per shard in streaming aggregations)

New index.aggregation.streaming.min_shard_size setting (default: 1000): Minimum buckets per segment to ensure accuracy. Ideally, we want to set its default as a function of shard_size and number of segments, @bowenlan-amzn is currently analyzing this part.

Testing
A. SubAggregationIT:

  1. Validates TopN selection with max/cardinality sub-aggregation ordering (ASC/DESC)
  2. Verifies correct bucket selection and otherDocCount calculation.

B. Unit Tests:
StreamStringTermsAggregatorTests: tests for TopN selection with various sub-aggregation orderings + minDocCount filtering

StreamNumericTermsAggregatorTests: 13 tests covering LongTerms, DoubleTerms, UnsignedLongTerms with max/min/avg/sum/cardinality ordering + minDocCount. Verifies correct bucket selection and otherDocCount calculation.

I will be opening a public doc issue for entire streaming aggregations.

Note: these changes are built on top of open PR #20359, so contains extra changes.

Related Issues

Resolves #[Issue number to be closed when this PR is merged]

Check List

  • Functionality includes testing.
    - [ ] API changes companion pull request created, if applicable.
    - [ ] Public documentation issue/PR created, if applicable.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 26, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • 🔍 Trigger a full review
📝 Walkthrough

Walkthrough

This pull request introduces segment-level top-N bucket filtering for streaming aggregations and refactors the Arrow Flight transport layer to support asynchronous prefetch-based response processing. Key updates include new streaming aggregation settings, changes to stream response handling mechanisms, and comprehensive test coverage for sub-aggregation ordering scenarios.

Changes

Cohort / File(s) Summary
CHANGELOG
CHANGELOG.md
New entry documenting fixes and refactoring to stream transport for improved robustness.
Flight Transport & Response Handling
plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightClientChannel.java, FlightOutboundHandler.java, FlightServerChannel.java, FlightTransportResponse.java, ServerHeaderMiddleware.java, VectorStreamOutput.java
Refactored streaming response pipeline: replaced synchronous header initialization with asynchronous openAndPrefetchAsync model. FlightServerChannel refactored from Optional to nullable VectorSchemaRoot with header buffer support in completeStream. VectorStreamOutput now supports direct non-Optional root and internal buffering. ServerHeaderMiddleware exposed new getCorrelationId() accessor. CorrelationId and batch tracking added for improved debugging.
Flight Server Configuration
plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/bootstrap/ServerConfig.java, FlightStreamPlugin.java, FlightTransport.java
Expanded settings registry to include FLIGHT_THREAD_POOL_MIN_SIZE. Updated FlightTransport to use MultiThreadIoEventLoopGroup with custom thread factory. Adjusted worker thread count from 2x processors to exactly processors().
Streaming Aggregation Core
server/src/main/java/org/opensearch/search/aggregations/bucket/terms/StreamNumericTermsAggregator.java, StreamStringTermsAggregator.java
Introduced segment-level top-N bucket selection using IntroSelector and IntArray indices. Replaced per-ordinal full bucketing with selective top-buckets approach. New getSegmentSize() helper, SelectionResult container, and ensureOrdinalComparator() method. Updated buildFinalBucket signature from enum-based to explicit (ord, value, docCount, owningBucketOrd). Added resource lifecycle management for reusable indices.
Index Settings
server/src/main/java/org/opensearch/index/IndexSettings.java, IndexScopedSettings.java
New public setting STREAMING_AGGREGATION_MIN_SHARD_SIZE_SETTING (default 1000) with getter getStreamingAggregationMinShardSize() to control minimum shard size for streaming aggregations. Setting registered in built-in index settings.
Integration Tests
plugins/arrow-flight-rpc/src/internalClusterTest/java/org/opensearch/streaming/aggregation/SubAggregationIT.java
Added 8+ streaming aggregation tests covering string and numeric category fields with max/cardinality sub-aggregation ordering (descending/ascending) and no-sort scenarios. Each test creates multi-segment indices, validates streaming behavior, and cleans up resources.
Unit Tests & Framework
plugins/arrow-flight-rpc/src/test/java/org/opensearch/arrow/flight/transport/FlightClientChannelTests.java, FlightTransportTestBase.java, ArrowStreamSerializationTests.java, test/framework/src/main/java/org/opensearch/search/aggregations/AggregatorTestCase.java
Updated error handling in FlightClientChannelTests to record exceptions. Customized TaskManager mocking in FlightTransportTestBase to provide ThreadContext. Adjusted VectorStreamOutput instantiation from Optional.empty() to null. Added IndexShard.indexSettings() mocking in AggregatorTestCase.
Aggregator Unit Tests
server/src/test/java/org/opensearch/search/aggregations/bucket/terms/StreamNumericTermsAggregatorTests.java, StreamStringTermsAggregatorTests.java
Comprehensive new test suites (25+ tests combined) validating streaming terms ordering by sub-aggregations (max, min, avg, sum, cardinality) in both ascending and descending directions. Tests verify bucket keys, aggregation values, otherDocCount, and minDocCount filtering across long, double, and unsigned long numeric types.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Suggested labels

enhancement, Search:Aggregations, Search:Performance

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.75% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'TopN selection for streaming terms aggregations' is a clear, concise summary of the main change—implementing TopN selection logic for streaming aggregations to reduce data transfer and improve performance.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering the problem, solution, benefits, and test coverage. It follows the template with a detailed 'Description' section addressing the motivation and implementation details, and includes a completed checklist confirming that functionality includes testing.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/VectorStreamOutput.java (1)

78-82: close() discards buffered data without flushing.

If close() is called after writeByte() calls but before getRoot(), buffered data in tempBuffer is silently lost. Consider flushing or at least logging a warning if tempBufferPos > 0.

Proposed fix
 `@Override`
 public void close() throws IOException {
+    if (tempBufferPos > 0) {
+        // Log or flush pending data to avoid silent data loss
+        flushTempBuffer();
+    }
     row = 0;
     vector.close();
 }
plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightOutboundHandler.java (1)

1-15: Duplicate SPDX license header.

The license block appears twice (lines 1-7 and 9-15).

Proposed fix

Remove lines 9-15 (the duplicate license block).

🤖 Fix all issues with AI agents
In `@CHANGELOG.md`:
- Line 49: Add a changelog entry documenting the TopN selection feature
introduced in this PR: describe "TopN selection at segment level for streaming
terms aggregations using quickselect", list the new index setting
`index.aggregation.streaming.min_shard_size` (default: 1000), and note benefits
(reduced data transfer and coordinator memory/CPU for high-cardinality
aggregations) plus support for sub-aggregations and metric aggregations with
TopN; also update the PR reference(s) to clearly mention both the base stream
transport fixes (`#20359`) and the TopN feature PR (`#20481`) so readers can follow
both changes.

In
`@plugins/arrow-flight-rpc/src/internalClusterTest/java/org/opensearch/streaming/aggregation/SubAggregationIT.java`:
- Around line 197-220: The bulk indexing loop uses
client().bulk(orderBulkRequest).actionGet() without inspecting the BulkResponse,
risking silent failures; modify the loop to capture the BulkResponse from
client().bulk(...).actionGet(), check response.hasFailures() and/or iterate
response.getItems() for isFailed(), and fail the test or throw an exception (or
log and assert) when any item failed. Apply this pattern to the BulkRequest
usages in this method (the loop creating 3 segments) and the other similar
locations referenced (around the other BulkRequest blocks) so partial indexing
failures cannot silently break downstream assertions.
- Around line 781-783: The comment in
testNumericOrderByMaxSubAggregationAscending incorrectly says it reuses the
prior index; update the comment to accurately state that the test creates a new
index named "numeric_order_test2" (or remove the reuse wording) next to the
index creation code (look for testNumericOrderByMaxSubAggregationAscending and
the numericIndexSettings/index name variables) so the comment matches the actual
behavior.
- Around line 173-220: The test creates an "order_test" index in setUp() but
never deletes it, causing "index already exists" on subsequent runs; update the
tearDown() method to delete the "order_test" index (like the numeric_order_test
cleanup) by calling the cluster client to delete the index (e.g.,
client().admin().indices().delete(...)) or using the same helper used for
numeric_order_test removal, ensuring deletion is conditional/ignored if the
index doesn't exist to avoid flakiness.

In
`@plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightClientChannel.java`:
- Around line 254-291: The task exceptions from openStreamAndInvokeHandler
(e.g., header null or handler.handleStreamResponse throwing) must be propagated
to the response handler instead of being rethrown; update the Runnable so that
any Exception is caught, call cleanupStreamResponse(streamResponse) and then
call handleStreamException(streamResponse, e) (wrapping non-Exception Throwables
as needed, similar to earlier usage) before returning, and ensure the same
behavior occurs whether the task is executed inline (ThreadPool.Names.SAME) or
submitted to threadPool.executor(executor). Use the existing symbols:
openStreamAndInvokeHandler, handleStreamException, cleanupStreamResponse,
handler.handleStreamResponse, StreamException/StreamErrorCode.INTERNAL to locate
and implement the change.

In
`@plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightServerChannel.java`:
- Around line 67-68: FlightServerChannel currently calls
Long.parseLong(middleware.getCorrelationId()) which can throw
NullPointerException or NumberFormatException for null or non-numeric headers;
update the FlightServerChannel constructor to defensively read
middleware.getCorrelationId(), check for null/empty, and wrap
Long.parseLong(...) in a try/catch(NumberFormatException) block (or use
Long.parseLong only if StringUtils.isNumeric), logging a warning via logger.warn
including the raw header and stacktrace, and assign a safe fallback value to the
correlationId field (e.g., -1L or a generated id) so parsing failures do not
crash construction.
- Around line 126-146: The computed putNextTime is already in milliseconds
(putNextTime = (System.nanoTime() - batchStartTime) / 1_000_000) but the logger
calls divide it again by 1_000_000 producing near-zero values; update the two
logger.debug invocations in FlightServerChannel to use putNextTime directly
(remove the extra "/ 1_000_000" in the third format argument), and also fix the
else-branch logger format to remove the stray "bytes," placeholder or supply the
correct size argument so the format string and arguments match (references:
putNextTime, batchStartTime, callTracker,
FlightUtils.calculateVectorSchemaRootSize, and the logger.debug calls).

In
`@plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightTransport.java`:
- Around line 413-416: The createEventLoopGroup method currently builds a custom
ThreadFactory producing non-daemon threads; replace the custom factory with
Netty's DefaultThreadFactory to standardize thread configuration but preserve
non-daemon semantics (use new DefaultThreadFactory(name) rather than
DefaultThreadFactory(name, true)), or if you intentionally want daemon threads,
document that decision in the method javadoc and switch to new
DefaultThreadFactory(name, true); update the ThreadFactory in
createEventLoopGroup accordingly so MultiThreadIoEventLoopGroup(threads,
threadFactory, ...) uses the chosen default factory and behavior is explicit.

In
`@plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/VectorStreamOutput.java`:
- Around line 73-76: The flush() method in VectorStreamOutput currently does
nothing, leaving bytes buffered by writeByte() uncommitted; update
VectorStreamOutput.flush() to flush the temp buffer into the main buffer (commit
any pending single-byte buffer contents to the underlying Byte/Vector buffer)
and reset/clear the temp buffer so subsequent getRoot() sees all written data;
locate the temp buffer/fields used by writeByte() and call the same commit logic
there (or extract it to a private commitTempBuffer() helper) from both
writeByte() and flush() to avoid duplication and ensure flush() guarantees all
buffered bytes are emitted before returning.

In
`@server/src/main/java/org/opensearch/search/aggregations/bucket/terms/StreamStringTermsAggregator.java`:
- Around line 95-116: ensureOrdinalComparator currently leaves ordinalComparator
null when isKeyOrder(order) is true, causing selection to fall back to doc-count
comparisons; update ensureOrdinalComparator so that when key ordering is
requested it sets ordinalComparator to compare bucket ordinals (respecting
ascending/descending key order) instead of leaving it null (or alternatively
mark to bypass quickselect for key order). Concretely, inside
ensureOrdinalComparator add a branch for isKeyOrder(order) that constructs
tempBucket1/tempBucket2 (or reuses existing ones) with compareKey implemented
and set ordinalComparator to compare leftOrd/rightOrd by assigning
bucketOrd/docCount and returning compareKey (or reverse the result for
descending), ensuring the comparator uses bucketOrd (and not bucketDocCount or
partiallyBuiltBucketComparator) when the ordering is key-based.
🧹 Nitpick comments (5)
plugins/arrow-flight-rpc/src/internalClusterTest/java/org/opensearch/streaming/aggregation/SubAggregationIT.java (1)

706-996: Ensure numeric test indices are deleted even on assertion failure.
Deletion happens only at the end of each test. If an assertion fails mid-test, the index remains and can affect later tests. Wrapping each test body in try/finally improves reliability.

🧹 Example pattern (apply to numeric_order_test*, similarly)
-        client().admin().indices().create(numericIndexRequest).actionGet();
-        client().admin()
-            .cluster()
-            .prepareHealth("numeric_order_test")
-            .setWaitForGreenStatus()
-            .setTimeout(TimeValue.timeValueSeconds(30))
-            .get();
-
-        // Create 3 segments
-        for (int seg = 0; seg < 3; seg++) {
-            ...
-        }
-
-        TermsAggregationBuilder agg = terms("categories")...
-        SearchResponse resp = client().prepareStreamSearch("numeric_order_test")...
-        ...
-        client().admin()
-            .indices()
-            .delete(new org.opensearch.action.admin.indices.delete.DeleteIndexRequest("numeric_order_test"))
-            .actionGet();
+        client().admin().indices().create(numericIndexRequest).actionGet();
+        client().admin()
+            .cluster()
+            .prepareHealth("numeric_order_test")
+            .setWaitForGreenStatus()
+            .setTimeout(TimeValue.timeValueSeconds(30))
+            .get();
+
+        try {
+            // Create 3 segments
+            for (int seg = 0; seg < 3; seg++) {
+                ...
+            }
+
+            TermsAggregationBuilder agg = terms("categories")...
+            SearchResponse resp = client().prepareStreamSearch("numeric_order_test")...
+            ...
+        } finally {
+            client().admin()
+                .indices()
+                .delete(new org.opensearch.action.admin.indices.delete.DeleteIndexRequest("numeric_order_test"))
+                .actionGet();
+        }
plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/bootstrap/ServerConfig.java (1)

199-211: Incomplete settings export — FLIGHT_THREAD_POOL_MAX_SIZE and FLIGHT_THREAD_POOL_KEEP_ALIVE are missing.

The getSettings() method now exports FLIGHT_THREAD_POOL_MIN_SIZE but omits FLIGHT_THREAD_POOL_MAX_SIZE and FLIGHT_THREAD_POOL_KEEP_ALIVE. All three are used in init() (lines 143-146). If the min size setting is needed externally, the max size and keep-alive settings likely are too.

Proposed fix
     public static List<Setting<?>> getSettings() {
         return new ArrayList<>(
             Arrays.asList(
                 ARROW_ALLOCATION_MANAGER_TYPE,
                 ARROW_ENABLE_NULL_CHECK_FOR_GET,
                 ARROW_ENABLE_DEBUG_ALLOCATOR,
                 ARROW_ENABLE_UNSAFE_MEMORY_ACCESS,
                 ARROW_SSL_ENABLE,
                 FLIGHT_EVENT_LOOP_THREADS,
-                FLIGHT_THREAD_POOL_MIN_SIZE
+                FLIGHT_THREAD_POOL_MIN_SIZE,
+                FLIGHT_THREAD_POOL_MAX_SIZE,
+                FLIGHT_THREAD_POOL_KEEP_ALIVE
             )
         );
     }
plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightTransportResponse.java (1)

164-170: Silent swallow of IllegalStateException in close().

The empty catch block at line 167 silently ignores IllegalStateException. Consider adding a brief comment explaining when this is expected (e.g., stream already closed), or log at trace level.

Proposed improvement
         if (flightStream != null) {
             try {
                 flightStream.close();
-            } catch (IllegalStateException ignore) {} catch (Exception e) {
+            } catch (IllegalStateException e) {
+                // Expected if stream was already closed or never fully initialized
+                logger.trace("Ignoring IllegalStateException on close", e);
+            } catch (Exception e) {
                 throw new StreamException(StreamErrorCode.INTERNAL, "Error closing flight stream", e);
             }
         }
server/src/main/java/org/opensearch/search/aggregations/bucket/terms/StreamNumericTermsAggregator.java (2)

287-303: O(n·m) lookup when building selected buckets can be improved.

After quickselect, the code iterates through all ordinals and for each checks against all selected ordinals (lines 291-300), resulting in O(n·m) complexity where n = total buckets and m = segmentSize. For high-cardinality fields, this could be a performance bottleneck.

The StreamStringTermsAggregator uses a more efficient approach by marking selected indices in the reusableIndices array and then iterating once through ordinals to check the mark.

♻️ Suggested improvement using marking approach
-            // Collect selected ordinals
-            int[] selectedOrdinals = new int[segmentSize];
-            for (int i = 0; i < segmentSize; i++) {
-                selectedOrdinals[i] = reusableIndices.get(i);
-            }
-
-            // Build result by finding values for selected ordinals
-            ordsEnum = bucketOrds.ordsEnum(owningBucketOrd);
-            List<B> result = new ArrayList<>(segmentSize);
-            long selectedDocCount = 0;
-            while (ordsEnum.next()) {
-                for (int selectedOrd : selectedOrdinals) {
-                    if (ordsEnum.ord() == selectedOrd) {
-                        long docCount = StreamNumericTermsAggregator.this.bucketDocCount(ordsEnum.ord());
-                        result.add(buildFinalBucket(ordsEnum.ord(), ordsEnum.value(), docCount, owningBucketOrd));
-                        selectedDocCount += docCount;
-                        break;
-                    }
-                }
-            }
+            // Mark selected ordinals in reusableIndices
+            int[] selected = new int[segmentSize];
+            for (int i = 0; i < segmentSize; i++) {
+                selected[i] = reusableIndices.get(i);
+            }
+
+            reusableIndices.fill(0, totalBuckets, 0);
+            for (int i = 0; i < segmentSize; i++) {
+                reusableIndices.set(selected[i], 1);
+            }
+
+            // Build result by iterating once and checking marks - O(n)
+            ordsEnum = bucketOrds.ordsEnum(owningBucketOrd);
+            List<B> result = new ArrayList<>(segmentSize);
+            long selectedDocCount = 0;
+            while (ordsEnum.next()) {
+                if (reusableIndices.get((int) ordsEnum.ord()) == 1) {
+                    long docCount = StreamNumericTermsAggregator.this.bucketDocCount(ordsEnum.ord());
+                    result.add(buildFinalBucket(ordsEnum.ord(), ordsEnum.value(), docCount, owningBucketOrd));
+                    selectedDocCount += docCount;
+                }
+            }

422-445: Consider extracting duplicate ensureOrdinalComparator pattern.

The three ensureOrdinalComparator implementations in LongTermsResults, DoubleTermsResults, and UnsignedLongTermsResults follow an identical pattern, differing only in bucket type instantiation. While this duplication is acceptable for type safety, if this pattern grows more complex, consider extracting the common logic to reduce maintenance burden.

Also applies to: 528-551, 640-663

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 672039d and 708675b.

📒 Files selected for processing (21)
  • CHANGELOG.md
  • plugins/arrow-flight-rpc/src/internalClusterTest/java/org/opensearch/streaming/aggregation/SubAggregationIT.java
  • plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/bootstrap/ServerConfig.java
  • plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightClientChannel.java
  • plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightOutboundHandler.java
  • plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightServerChannel.java
  • plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightStreamPlugin.java
  • plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightTransport.java
  • plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightTransportResponse.java
  • plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/ServerHeaderMiddleware.java
  • plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/VectorStreamOutput.java
  • plugins/arrow-flight-rpc/src/test/java/org/opensearch/arrow/flight/transport/ArrowStreamSerializationTests.java
  • plugins/arrow-flight-rpc/src/test/java/org/opensearch/arrow/flight/transport/FlightClientChannelTests.java
  • plugins/arrow-flight-rpc/src/test/java/org/opensearch/arrow/flight/transport/FlightTransportTestBase.java
  • server/src/main/java/org/opensearch/common/settings/IndexScopedSettings.java
  • server/src/main/java/org/opensearch/index/IndexSettings.java
  • server/src/main/java/org/opensearch/search/aggregations/bucket/terms/StreamNumericTermsAggregator.java
  • server/src/main/java/org/opensearch/search/aggregations/bucket/terms/StreamStringTermsAggregator.java
  • server/src/test/java/org/opensearch/search/aggregations/bucket/terms/StreamNumericTermsAggregatorTests.java
  • server/src/test/java/org/opensearch/search/aggregations/bucket/terms/StreamStringTermsAggregatorTests.java
  • test/framework/src/main/java/org/opensearch/search/aggregations/AggregatorTestCase.java
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-12-13T20:16:15.318Z
Learnt from: reta
Repo: opensearch-project/OpenSearch PR: 20017
File: modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4Http3ServerTransport.java:101-123
Timestamp: 2025-12-13T20:16:15.318Z
Learning: In OpenSearch, only one HTTP transport implementation can be active and loaded at a time, so duplicate setting definitions (such as h3.max_stream_local_length, h3.max_stream_remote_length, and h3.max_streams) across different transport implementations like Netty4Http3ServerTransport and ReactorNetty4HttpServerTransport will not cause setting registration conflicts.

Applied to files:

  • plugins/arrow-flight-rpc/src/test/java/org/opensearch/arrow/flight/transport/FlightTransportTestBase.java
📚 Learning: 2026-01-13T17:40:27.167Z
Learnt from: reta
Repo: opensearch-project/OpenSearch PR: 20411
File: server/src/main/java/org/opensearch/index/codec/CodecService.java:112-133
Timestamp: 2026-01-13T17:40:27.167Z
Learning: Avoid capturing or evaluating a supplier (e.g., this::defaultCodec) upfront when passing it to a registry during object construction. If registries may replace defaults during iteration (as in EnginePlugin.getAdditionalCodecs), pass the supplier itself and only resolve it at use time. This ensures dynamic behavior is preserved during initialization and prevents premature binding of defaults in codecs/registry setup. This pattern should apply to similar initialization paths in Java server code where registries may mutate defaults during construction.

Applied to files:

  • server/src/main/java/org/opensearch/index/IndexSettings.java
  • server/src/main/java/org/opensearch/search/aggregations/bucket/terms/StreamNumericTermsAggregator.java
  • server/src/main/java/org/opensearch/common/settings/IndexScopedSettings.java
  • server/src/main/java/org/opensearch/search/aggregations/bucket/terms/StreamStringTermsAggregator.java
📚 Learning: 2025-12-02T22:44:14.799Z
Learnt from: prudhvigodithi
Repo: opensearch-project/OpenSearch PR: 20112
File: server/src/internalClusterTest/java/org/opensearch/search/slice/SearchSliceIT.java:73-81
Timestamp: 2025-12-02T22:44:14.799Z
Learning: In OpenSearch integration tests extending OpenSearchIntegTestCase, using `LuceneTestCase.SuppressCodecs("*")` triggers special handling that selects a random production codec from the CODECS array, while `SuppressCodecs("Asserting")` or other specific codec suppressions still allow Lucene's default codec randomization which may include the asserting codec. Use `SuppressCodecs("*")` when you need to completely avoid asserting codecs (e.g., for cross-thread StoredFieldsReader usage) while maintaining production codec test coverage.

Applied to files:

  • server/src/test/java/org/opensearch/search/aggregations/bucket/terms/StreamNumericTermsAggregatorTests.java
🧬 Code graph analysis (4)
plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightTransportResponse.java (3)
plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/ClientHeaderMiddleware.java (1)
  • ClientHeaderMiddleware (35-127)
plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightErrorMapper.java (1)
  • FlightErrorMapper (31-116)
plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightUtils.java (1)
  • FlightUtils (13-30)
plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightServerChannel.java (1)
plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightUtils.java (1)
  • FlightUtils (13-30)
plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightClientChannel.java (1)
server/src/main/java/org/opensearch/threadpool/ThreadPool.java (1)
  • Names (99-129)
server/src/main/java/org/opensearch/search/aggregations/bucket/terms/StreamNumericTermsAggregator.java (2)
libs/common/src/main/java/org/opensearch/common/Numbers.java (1)
  • Numbers (43-287)
server/src/main/java/org/opensearch/search/aggregations/bucket/terms/StreamStringTermsAggregator.java (2)
  • ResultStrategy (216-412)
  • SelectionResult (271-279)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: gradle-check
🔇 Additional comments (38)
plugins/arrow-flight-rpc/src/test/java/org/opensearch/arrow/flight/transport/ArrowStreamSerializationTests.java (1)

53-53: LGTM!

The change from Optional.empty() to null correctly aligns with the updated VectorStreamOutput constructor signature that now accepts a nullable VectorSchemaRoot directly instead of an Optional<VectorSchemaRoot>.

plugins/arrow-flight-rpc/src/internalClusterTest/java/org/opensearch/streaming/aggregation/SubAggregationIT.java (1)

619-704: Ordering coverage for string categories looks solid.
The max/cardinality/no-sort scenarios are well targeted and read clearly.

plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/ServerHeaderMiddleware.java (1)

40-42: LGTM!

The new accessor aligns with the correlation ID tracking pattern used across the transport layer (e.g., CORRELATION_ID_KEY in ClientHeaderMiddleware).

plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightOutboundHandler.java (1)

217-219: LGTM!

The completeStream call now correctly passes the header buffer, aligning with the updated FlightServerChannel.completeStream(ByteBuffer) signature.

plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightTransportResponse.java (2)

77-108: Async prefetch implementation looks sound.

The double-checked locking with volatile prefetchStarted is correct. Using virtual threads for the blocking getStream() and next() calls is appropriate for this I/O-bound operation.


114-141: LGTM!

The nextResponse() method correctly handles the prefetch state via firstBatchConsumed, includes slow-log monitoring, and properly maps exceptions.

plugins/arrow-flight-rpc/src/test/java/org/opensearch/arrow/flight/transport/FlightClientChannelTests.java (1)

558-561: Good: framework-level errors now unblock the test.

Capturing the exception and counting down the latch avoids hangs and validates the expected failure path.

plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightStreamPlugin.java (1)

363-369: LGTM: publish host/port settings are now exposed.

This makes the new publish-port configuration available through the plugin settings list.

test/framework/src/main/java/org/opensearch/search/aggregations/AggregatorTestCase.java (1)

502-505: Good: IndexShard now returns indexSettings in tests.

This keeps SearchContext mocks aligned with index settings usage in new streaming logic.

server/src/main/java/org/opensearch/common/settings/IndexScopedSettings.java (1)

171-176: LGTM: streaming min shard size setting is registered.

Keeps index-scoped validation consistent with the new setting.

plugins/arrow-flight-rpc/src/test/java/org/opensearch/arrow/flight/transport/FlightTransportTestBase.java (1)

107-111: Good: TaskManager now returns a StoredContext for task start.

This aligns the mock with thread-context handling used by stream transport tests.

plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightTransport.java (1)

136-138: LGTM: worker ELG sizing is now CPU-aligned.

This keeps event-loop sizing predictable and avoids oversubscription.

server/src/main/java/org/opensearch/index/IndexSettings.java (5)

636-647: LGTM: streaming min shard size setting is well-scoped.


1014-1017: LGTM: cached field for streaming min shard size.


1187-1187: LGTM: initialization from scoped settings.


1320-1320: LGTM: dynamic update consumer registered.


2074-2083: LGTM: getter/setter exposure for the new setting.

server/src/main/java/org/opensearch/search/aggregations/bucket/terms/StreamStringTermsAggregator.java (11)

16-19: LGTM: selection-related imports added.


57-59: LGTM: ordinal comparator temp buckets are in place.


85-92: LGTM: reset releases reusable buffers and clears comparator state.


124-128: LGTM: segment size honors shard size minimum.


145-145: LGTM: valueCount captured per-segment.


220-230: LGTM: reusable index buffer is allocated/grown via big arrays.


234-260: LGTM: TopN selection integrated with otherDocCount tracking.


271-279: LGTM: SelectionResult bundles buckets and otherDocCount cleanly.


281-359: LGTM: quickselect path and otherDocCount accounting look solid.


361-364: LGTM: reusableIndices are released on strategy close.


506-509: LGTM: aggregator closes result strategy.

plugins/arrow-flight-rpc/src/main/java/org/opensearch/arrow/flight/transport/FlightClientChannel.java (3)

47-48: LGTM: global channel counter for correlation ID seeding.


115-119: LGTM: correlation IDs seeded with timestamp + channel ID.


237-239: LGTM: sendMessage delegates to async stream-open path.

server/src/test/java/org/opensearch/search/aggregations/bucket/terms/StreamStringTermsAggregatorTests.java (4)

23-50: LGTM: test imports cover new settings and cardinality scenarios.


1158-1161: LGTM: updated expected counts for reduce with sub-aggregations.


1356-1357: LGTM: explicit assertion for multi-segment guard.


1511-2058: Great coverage for TopN ordering, cardinality, and minDocCount cases.

server/src/test/java/org/opensearch/search/aggregations/bucket/terms/StreamNumericTermsAggregatorTests.java (1)

1771-2649: LGTM! Comprehensive test coverage for TopN selection.

The new test methods provide excellent coverage of the segment-level TopN filtering feature:

  • Various sub-aggregation orderings (max, min, avg, sum, cardinality) in both ascending and descending modes
  • Different numeric types (Long, Double, UnsignedLong)
  • minDocCount filtering behavior
  • Correct otherDocCount calculation for excluded buckets

The test data setup and assertions are consistent and verify both the bucket selection logic and the key-based sorting at shard level.

server/src/main/java/org/opensearch/search/aggregations/bucket/terms/StreamNumericTermsAggregator.java (2)

129-137: LGTM!

The getSegmentSize() method correctly enforces the minimum shard size setting while respecting the user-requested shard size, ensuring accuracy trade-offs are configurable.


85-89: LGTM! Proper resource cleanup in doReset.

The doReset method now properly closes both bucketOrds and resultStrategy using Releasables.close(), which handles null values and prevents resource leaks across segment boundaries.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@github-actions
Copy link
Contributor

❌ Gradle check result for 708675b: 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?

@github-actions
Copy link
Contributor

❌ Gradle check result for 7e85515: 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?

@codecov
Copy link

codecov bot commented Jan 27, 2026

Codecov Report

❌ Patch coverage is 90.73171% with 19 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.35%. Comparing base (672039d) to head (c7ea430).
⚠️ Report is 11 commits behind head on main.

Files with missing lines Patch % Lines
...ons/bucket/terms/StreamNumericTermsAggregator.java 91.34% 5 Missing and 4 partials ⚠️
...ions/bucket/terms/StreamStringTermsAggregator.java 91.39% 5 Missing and 3 partials ⚠️
.../main/java/org/opensearch/index/IndexSettings.java 66.66% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main   #20481      +/-   ##
============================================
+ Coverage     73.25%   73.35%   +0.10%     
- Complexity    71979    72092     +113     
============================================
  Files          5796     5796              
  Lines        329287   329539     +252     
  Branches      47419    47465      +46     
============================================
+ Hits         241203   241725     +522     
+ Misses        68759    68502     -257     
+ Partials      19325    19312      -13     

☔ 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.

@github-actions
Copy link
Contributor

❌ Gradle check result for 46cf3f6: 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?

@github-actions
Copy link
Contributor

✅ Gradle check result for 7277447: SUCCESS

@github-actions
Copy link
Contributor

❌ Gradle check result for b27f4a9: 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: Rishabh Maurya <rishabhmaurya05@gmail.com>
…for topN logic when no sort_order

Signed-off-by: Rishabh Maurya <rishabhmaurya05@gmail.com>
Signed-off-by: Rishabh Maurya <rishabhmaurya05@gmail.com>
Signed-off-by: Rishabh Maurya <rishabhmaurya05@gmail.com>
Signed-off-by: Rishabh Maurya <rishabhmaurya05@gmail.com>
Signed-off-by: Rishabh Maurya <rishabhmaurya05@gmail.com>
Signed-off-by: Rishabh Maurya <rishabhmaurya05@gmail.com>
Signed-off-by: Rishabh Maurya <rishabhmaurya05@gmail.com>
@github-project-automation github-project-automation bot moved this from In-Review to In Progress in Performance Roadmap Jan 28, 2026
@github-actions
Copy link
Contributor

❕ Gradle check result for c7ea430: UNSTABLE

Please review all flaky tests that succeeded after retry and create an issue if one does not already exist to track the flaky failure.

@rishabhmaurya rishabhmaurya merged commit fc33a53 into opensearch-project:main Jan 28, 2026
34 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in Performance Roadmap Jan 28, 2026
rakshit98 pushed a commit to rakshit98/OpenSearch that referenced this pull request Jan 28, 2026
…0481)

* topN logic for StreamStringTermsAggregator
* Add index setting for min threshold on shard_size for streaming; fix for topN logic when no sort_order
* fix other doc count
* fix minDocCount issue
* topN for StreamNumericTermsAggregator and tests
* Fix key order issue in streaming aggs with topN
---------

Signed-off-by: Rishabh Maurya <rishabhmaurya05@gmail.com>
Signed-off-by: Rakshit Goyal <irakshg@amazon.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v3.5.0 Issues and PRs related to version 3.4.0

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants