Skip to content

Commit 4b0ae15

Browse files
committed
Disable distributed sort optimization on scroll requests (#53759)
This commit disables the sort optimization added in #51852 for scroll requests. Scroll queries keep a state per shard so we cannot modify the request on the first round (submit). This bug was introduced in non-released versions which is why this pr is marked as a non-issue.
1 parent 4a36894 commit 4b0ae15

File tree

2 files changed

+36
-10
lines changed

2 files changed

+36
-10
lines changed

server/src/main/java/org/elasticsearch/action/search/SearchQueryThenFetchAsyncAction.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,10 @@ protected void onShardGroupFailure(int shardIndex, SearchShardTarget shardTarget
8888
@Override
8989
protected void onShardResult(SearchPhaseResult result, SearchShardIterator shardIt) {
9090
QuerySearchResult queryResult = result.queryResult();
91-
if (queryResult.isNull() == false && queryResult.topDocs().topDocs instanceof TopFieldDocs) {
91+
if (queryResult.isNull() == false
92+
// disable sort optims for scroll requests because they keep track of the last bottom doc locally (per shard)
93+
&& getRequest().scroll() == null
94+
&& queryResult.topDocs().topDocs instanceof TopFieldDocs) {
9295
TopFieldDocs topDocs = (TopFieldDocs) queryResult.topDocs().topDocs;
9396
if (bottomSortCollector == null) {
9497
synchronized (this) {

server/src/test/java/org/elasticsearch/action/search/SearchQueryThenFetchAsyncActionTests.java

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.elasticsearch.cluster.routing.GroupShardsIterator;
3030
import org.elasticsearch.common.Strings;
3131
import org.elasticsearch.common.lucene.search.TopDocsAndMaxScore;
32+
import org.elasticsearch.common.unit.TimeValue;
3233
import org.elasticsearch.common.util.BigArrays;
3334
import org.elasticsearch.common.util.concurrent.EsExecutors;
3435
import org.elasticsearch.index.shard.ShardId;
@@ -59,6 +60,14 @@
5960

6061
public class SearchQueryThenFetchAsyncActionTests extends ESTestCase {
6162
public void testBottomFieldSort() throws InterruptedException {
63+
testCase(false);
64+
}
65+
66+
public void testScrollDisableBottomFieldSort() throws InterruptedException {
67+
testCase(true);
68+
}
69+
70+
private void testCase(boolean withScroll) throws InterruptedException {
6271
final TransportSearchAction.SearchTimeProvider timeProvider =
6372
new TransportSearchAction.SearchTimeProvider(0, System.nanoTime(), System::nanoTime);
6473

@@ -89,10 +98,10 @@ public void sendExecuteQuery(Transport.Connection connection, ShardSearchRequest
8998
new SearchShardTarget("node1", new ShardId("idx", "na", shardId), null, OriginalIndices.NONE));
9099
SortField sortField = new SortField("timestamp", SortField.Type.LONG);
91100
queryResult.topDocs(new TopDocsAndMaxScore(new TopFieldDocs(
92-
new TotalHits(1, TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO),
93-
new FieldDoc[] {
94-
new FieldDoc(randomInt(1000), Float.NaN, new Object[] { request.shardId().id() })
95-
}, new SortField[] { sortField }), Float.NaN),
101+
new TotalHits(1, withScroll ? TotalHits.Relation.EQUAL_TO : TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO),
102+
new FieldDoc[] {
103+
new FieldDoc(randomInt(1000), Float.NaN, new Object[] { request.shardId().id() })
104+
}, new SortField[] { sortField }), Float.NaN),
96105
new DocValueFormat[] { DocValueFormat.RAW });
97106
queryResult.from(0);
98107
queryResult.size(1);
@@ -109,8 +118,12 @@ public void sendExecuteQuery(Transport.Connection connection, ShardSearchRequest
109118
searchRequest.setBatchedReduceSize(2);
110119
searchRequest.source(new SearchSourceBuilder()
111120
.size(1)
112-
.trackTotalHitsUpTo(2)
113121
.sort(SortBuilders.fieldSort("timestamp")));
122+
if (withScroll) {
123+
searchRequest.scroll(TimeValue.timeValueMillis(100));
124+
} else {
125+
searchRequest.source().trackTotalHitsUpTo(2);
126+
}
114127
searchRequest.allowPartialSearchResults(false);
115128
SearchPhaseController controller = new SearchPhaseController((b) -> new InternalAggregation.ReduceContextBuilder() {
116129
@Override
@@ -143,12 +156,22 @@ public void run() {
143156
action.start();
144157
latch.await();
145158
assertThat(successfulOps.get(), equalTo(numShards));
146-
assertTrue(canReturnNullResponse.get());
147-
assertThat(numWithTopDocs.get(), greaterThanOrEqualTo(1));
159+
if (withScroll) {
160+
assertFalse(canReturnNullResponse.get());
161+
assertThat(numWithTopDocs.get(), equalTo(0));
162+
} else {
163+
assertTrue(canReturnNullResponse.get());
164+
assertThat(numWithTopDocs.get(), greaterThanOrEqualTo(1));
165+
}
148166
SearchPhaseController.ReducedQueryPhase phase = action.results.reduce();
149167
assertThat(phase.numReducePhases, greaterThanOrEqualTo(1));
150-
assertThat(phase.totalHits.value, equalTo(2L));
151-
assertThat(phase.totalHits.relation, equalTo(TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO));
168+
if (withScroll) {
169+
assertThat(phase.totalHits.value, equalTo((long) numShards));
170+
assertThat(phase.totalHits.relation, equalTo(TotalHits.Relation.EQUAL_TO));
171+
} else {
172+
assertThat(phase.totalHits.value, equalTo(2L));
173+
assertThat(phase.totalHits.relation, equalTo(TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO));
174+
}
152175
assertThat(phase.sortedTopDocs.scoreDocs.length, equalTo(1));
153176
assertThat(phase.sortedTopDocs.scoreDocs[0], instanceOf(FieldDoc.class));
154177
assertThat(((FieldDoc) phase.sortedTopDocs.scoreDocs[0]).fields.length, equalTo(1));

0 commit comments

Comments
 (0)