Skip to content

Commit e8bb1ac

Browse files
committed
Return an empty suggestion when suggest phase times out
We recently fixed timeout handling in the suggest phase. A test failure on SearchTimeoutIT surfaced an issue with the current approach. In case partial results are allowed, it may happen that some shards time out while executing the suggest phase and some don't. SearchPhaseController assumes that if one shard has suggest results, all of the other shards will have suggest results too. We could address that assertion and check is the search timed out, instead this commit changes timeout handling in the suggest phase to return an empty suggestion instead of null. This seems appropriate in terms of providing some results and makes the assertion about non null suggestions in SearchPhaseController happy. Relates to elastic#122357
1 parent d00440e commit e8bb1ac

File tree

4 files changed

+33
-29
lines changed

4 files changed

+33
-29
lines changed

server/src/internalClusterTest/java/org/elasticsearch/search/SearchTimeoutIT.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -484,8 +484,7 @@ protected TermSuggestion innerExecute(
484484
CharsRefBuilder spare
485485
) {
486486
contextIndexSearcher.throwTimeExceededException();
487-
assert false;
488-
return new TermSuggestion(name, suggestion.getSize(), SortBy.SCORE);
487+
throw new AssertionError("should have thrown TimeExceededException");
489488
}
490489

491490
@Override

server/src/main/java/org/elasticsearch/search/query/QueryPhase.java

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -126,15 +126,7 @@ static void executeRank(SearchContext searchContext) throws QueryPhaseExecutionE
126126

127127
static void executeQuery(SearchContext searchContext) throws QueryPhaseExecutionException {
128128
if (searchContext.hasOnlySuggest()) {
129-
try {
130-
SuggestPhase.execute(searchContext);
131-
} catch (ContextIndexSearcher.TimeExceededException timeExceededException) {
132-
SearchTimeoutException.handleTimeout(
133-
searchContext.request().allowPartialSearchResults(),
134-
searchContext.shardTarget(),
135-
searchContext.queryResult()
136-
);
137-
}
129+
SuggestPhase.execute(searchContext);
138130
searchContext.queryResult().topDocs(new TopDocsAndMaxScore(Lucene.EMPTY_TOP_DOCS, Float.NaN), new DocValueFormat[0]);
139131
return;
140132
}
@@ -150,18 +142,10 @@ static void executeQuery(SearchContext searchContext) throws QueryPhaseExecution
150142

151143
addCollectorsAndSearch(searchContext);
152144

153-
try {
154-
RescorePhase.execute(searchContext);
155-
SuggestPhase.execute(searchContext);
156-
if (searchContext.getProfilers() != null) {
157-
searchContext.queryResult().profileResults(searchContext.getProfilers().buildQueryPhaseResults());
158-
}
159-
} catch (ContextIndexSearcher.TimeExceededException timeExceededException) {
160-
SearchTimeoutException.handleTimeout(
161-
searchContext.request().allowPartialSearchResults(),
162-
searchContext.shardTarget(),
163-
searchContext.queryResult()
164-
);
145+
RescorePhase.execute(searchContext);
146+
SuggestPhase.execute(searchContext);
147+
if (searchContext.getProfilers() != null) {
148+
searchContext.queryResult().profileResults(searchContext.getProfilers().buildQueryPhaseResults());
165149
}
166150
}
167151

server/src/main/java/org/elasticsearch/search/rescore/RescorePhase.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
import org.elasticsearch.common.lucene.search.TopDocsAndMaxScore;
1919
import org.elasticsearch.common.util.Maps;
2020
import org.elasticsearch.lucene.grouping.TopFieldGroups;
21+
import org.elasticsearch.search.internal.ContextIndexSearcher;
2122
import org.elasticsearch.search.internal.SearchContext;
23+
import org.elasticsearch.search.query.SearchTimeoutException;
2224
import org.elasticsearch.search.sort.ShardDocSortField;
2325
import org.elasticsearch.search.sort.SortAndFormats;
2426

@@ -84,6 +86,13 @@ public static void execute(SearchContext context) {
8486
.topDocs(new TopDocsAndMaxScore(topDocs, topDocs.scoreDocs[0].score), context.queryResult().sortValueFormats());
8587
} catch (IOException e) {
8688
throw new ElasticsearchException("Rescore Phase Failed", e);
89+
} catch (ContextIndexSearcher.TimeExceededException timeExceededException) {
90+
SearchTimeoutException.handleTimeout(
91+
context.request().allowPartialSearchResults(),
92+
context.shardTarget(),
93+
context.queryResult()
94+
);
95+
//if the rescore phase times out and partial results are allowed, the returned top docs from this shard won't be rescored
8796
}
8897
}
8998

server/src/main/java/org/elasticsearch/search/suggest/SuggestPhase.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010

1111
import org.apache.lucene.util.CharsRefBuilder;
1212
import org.elasticsearch.ElasticsearchException;
13+
import org.elasticsearch.search.internal.ContextIndexSearcher;
1314
import org.elasticsearch.search.internal.SearchContext;
15+
import org.elasticsearch.search.query.SearchTimeoutException;
1416
import org.elasticsearch.search.suggest.Suggest.Suggestion;
1517
import org.elasticsearch.search.suggest.Suggest.Suggestion.Entry;
1618
import org.elasticsearch.search.suggest.Suggest.Suggestion.Entry.Option;
@@ -40,12 +42,22 @@ public static void execute(SearchContext context) {
4042
for (Map.Entry<String, SuggestionSearchContext.SuggestionContext> entry : suggest.suggestions().entrySet()) {
4143
SuggestionSearchContext.SuggestionContext suggestion = entry.getValue();
4244
Suggester<SuggestionContext> suggester = suggestion.getSuggester();
43-
Suggestion<? extends Entry<? extends Option>> result = suggester.execute(
44-
entry.getKey(),
45-
suggestion,
46-
context.searcher(),
47-
spare
48-
);
45+
Suggestion<? extends Entry<? extends Option>> result;
46+
try {
47+
result = suggester.execute(
48+
entry.getKey(),
49+
suggestion,
50+
context.searcher(),
51+
spare
52+
);
53+
} catch(ContextIndexSearcher.TimeExceededException timeExceededException) {
54+
SearchTimeoutException.handleTimeout(
55+
context.request().allowPartialSearchResults(),
56+
context.shardTarget(),
57+
context.queryResult()
58+
);
59+
result = suggester.emptySuggestion(entry.getKey(), suggestion, spare);
60+
}
4961
if (result != null) {
5062
assert entry.getKey().equals(result.name);
5163
suggestions.add(result);

0 commit comments

Comments
 (0)