@@ -81,7 +81,7 @@ public class OpenSearchQueryRequest implements OpenSearchRequest {
8181
8282 @ ToString .Exclude private Map <String , Object > afterKey ;
8383
84- @ EqualsAndHashCode . Exclude @ ToString .Exclude private boolean afterKeyToReset = false ;
84+ @ ToString .Exclude private boolean calciteEnabled ;
8585
8686 @ TestOnly
8787 static OpenSearchQueryRequest of (
@@ -108,7 +108,8 @@ public static OpenSearchQueryRequest of(
108108 SearchSourceBuilder sourceBuilder ,
109109 OpenSearchExprValueFactory factory ,
110110 List <String > includes ) {
111- return new OpenSearchQueryRequest (indexName , sourceBuilder , factory , includes , null , null );
111+ return new OpenSearchQueryRequest (
112+ indexName , sourceBuilder , factory , includes , null , null , false );
112113 }
113114
114115 /** Build an OpenSearchQueryRequest with PIT support. */
@@ -118,9 +119,10 @@ public static OpenSearchQueryRequest pitOf(
118119 OpenSearchExprValueFactory factory ,
119120 List <String > includes ,
120121 TimeValue cursorKeepAlive ,
121- String pitId ) {
122+ String pitId ,
123+ boolean calciteEnabled ) {
122124 return new OpenSearchQueryRequest (
123- indexName , sourceBuilder , factory , includes , cursorKeepAlive , pitId );
125+ indexName , sourceBuilder , factory , includes , cursorKeepAlive , pitId , calciteEnabled );
124126 }
125127
126128 /** Do not new it directly, use of() and pitOf() instead. */
@@ -130,13 +132,15 @@ public static OpenSearchQueryRequest pitOf(
130132 OpenSearchExprValueFactory factory ,
131133 List <String > includes ,
132134 TimeValue cursorKeepAlive ,
133- String pitId ) {
135+ String pitId ,
136+ boolean calciteEnabled ) {
134137 this .indexName = indexName ;
135138 this .sourceBuilder = sourceBuilder ;
136139 this .exprValueFactory = factory ;
137140 this .includes = includes ;
138141 this .cursorKeepAlive = cursorKeepAlive ;
139142 this .pitId = pitId ;
143+ this .calciteEnabled = calciteEnabled ;
140144 }
141145
142146 /**
@@ -181,7 +185,7 @@ public OpenSearchResponse search(
181185 Function <SearchRequest , SearchResponse > searchAction ,
182186 Function <SearchScrollRequest , SearchResponse > scrollAction ) {
183187 if (this .pitId == null ) {
184- return search (searchAction );
188+ return calciteEnabled ? search ( searchAction ) : searchForV2 (searchAction );
185189 } else {
186190 // Search with PIT instead of scroll API
187191 return searchWithPIT (searchAction );
@@ -196,29 +200,41 @@ public boolean isCountAggRequest() {
196200 && sourceBuilder .trackTotalHitsUpTo () == Integer .MAX_VALUE ;
197201 }
198202
203+ /** Call the old search logic for v2, since we don't support paginating aggregate in v2. */
204+ @ Deprecated
205+ private OpenSearchResponse searchForV2 (Function <SearchRequest , SearchResponse > searchAction ) {
206+ // When SearchRequest doesn't contain PitId, fetch single page request
207+ if (needClean ) {
208+ return new OpenSearchResponse (
209+ SearchHits .empty (), exprValueFactory , includes , isCountAggRequest ());
210+ } else {
211+ // get the value before set needClean = true
212+ boolean isCountAggRequest = isCountAggRequest ();
213+ needClean = true ;
214+ return new OpenSearchResponse (
215+ searchAction .apply (
216+ new SearchRequest ().indices (indexName .getIndexNames ()).source (sourceBuilder )),
217+ exprValueFactory ,
218+ includes ,
219+ isCountAggRequest );
220+ }
221+ }
222+
199223 private OpenSearchResponse search (Function <SearchRequest , SearchResponse > searchAction ) {
200224 OpenSearchResponse openSearchResponse ;
201225 if (needClean ) {
202226 openSearchResponse =
203227 new OpenSearchResponse (
204228 SearchHits .empty (), exprValueFactory , includes , isCountAggRequest ());
205229 } else {
206- // On first call: reset builder to clear any afterKey from other requests
230+ // Set afterKey to request
207231 if (this .sourceBuilder .aggregations () != null ) {
208232 this .sourceBuilder .aggregations ().getAggregatorFactories ().stream ()
209233 .filter (b -> b instanceof CompositeAggregationBuilder )
210- .forEach (
211- c -> {
212- if (!afterKeyToReset ) {
213- // First call: reset to clear any previous afterKey from shared builder
214- // Use null instead of empty map to avoid "[after] has 0 value(s)" error
215- ((CompositeAggregationBuilder ) c ).aggregateAfter (null );
216- afterKeyToReset = true ;
217- }
218- if (afterKey != null && !afterKey .isEmpty ()) {
219- ((CompositeAggregationBuilder ) c ).aggregateAfter (afterKey );
220- }
221- });
234+ .forEach (c -> ((CompositeAggregationBuilder ) c ).aggregateAfter (afterKey ));
235+ if (LOG .isDebugEnabled ()) {
236+ LOG .debug (sourceBuilder );
237+ }
222238 }
223239
224240 SearchRequest searchRequest =
@@ -230,11 +246,11 @@ private OpenSearchResponse search(Function<SearchRequest, SearchResponse> search
230246 this .searchResponse , exprValueFactory , includes , isCountAggRequest ());
231247
232248 needClean = openSearchResponse .isEmpty ();
233- if ( openSearchResponse . isCompositeAggregationResponse ()) {
234- InternalComposite compositeAgg =
235- ( InternalComposite ) this . searchResponse . getAggregations ().asList ().get ( 0 );
236- // Update afterKey from response
237- afterKey = compositeAgg .afterKey ();
249+ // Get afterKey from response
250+ if ( openSearchResponse . isAggregationResponse ()) {
251+ openSearchResponse . getAggregations ().asList ().stream ()
252+ . filter ( b -> b instanceof InternalComposite )
253+ . forEach ( c -> afterKey = (( InternalComposite ) c ) .afterKey () );
238254 }
239255 }
240256 return openSearchResponse ;
0 commit comments