diff --git a/server/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java b/server/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java index f2f87f3d687a5..20ce1edfb4bcd 100644 --- a/server/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java +++ b/server/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java @@ -933,7 +933,8 @@ private void executeSearch( localIndices, searchRequest.getLocalClusterAlias(), searchContext, - searchRequest.pointInTimeBuilder().getKeepAlive() + searchRequest.pointInTimeBuilder().getKeepAlive(), + searchRequest.allowPartialSearchResults() ); } else { final Index[] indices = resolveLocalIndices(localIndices, clusterState, timeProvider); @@ -1415,7 +1416,8 @@ static List getLocalLocalShardsIteratorFromPointInTime( OriginalIndices originalIndices, String localClusterAlias, SearchContextId searchContext, - TimeValue keepAlive + TimeValue keepAlive, + boolean allowPartialSearchResults ) { final List iterators = new ArrayList<>(searchContext.shards().size()); for (Map.Entry entry : searchContext.shards().entrySet()) { @@ -1427,17 +1429,21 @@ static List getLocalLocalShardsIteratorFromPointInTime( if (clusterState.nodes().nodeExists(perNode.getNode())) { targetNodes.add(perNode.getNode()); } - if (perNode.getSearchContextId().getSearcherId() != null) { - try { - final ShardIterator shards = OperationRouting.getShards(clusterState, shardId); + try { + final ShardIterator shards = OperationRouting.getShards(clusterState, shardId); + if (perNode.getSearchContextId().getSearcherId() != null) { for (ShardRouting shard : shards) { if (shard.currentNodeId().equals(perNode.getNode()) == false) { targetNodes.add(shard.currentNodeId()); } } - } catch (IndexNotFoundException | ShardNotFoundException ignored) { - // We can hit these exceptions if the index was deleted after creating PIT or the cluster state on - // this coordinating node is outdated. It's fine to ignore these extra "retry-able" target shards. + } + } catch (IndexNotFoundException | ShardNotFoundException e) { + // We can hit these exceptions if the index was deleted after creating PIT or the cluster state on + // this coordinating node is outdated. It's fine to ignore these extra "retry-able" target shards + // when allowPartialSearchResults is false + if (allowPartialSearchResults == false) { + throw e; } } OriginalIndices finalIndices = new OriginalIndices( diff --git a/server/src/test/java/org/elasticsearch/action/search/TransportSearchActionTests.java b/server/src/test/java/org/elasticsearch/action/search/TransportSearchActionTests.java index 498f9d7d19264..68f9162d615c6 100644 --- a/server/src/test/java/org/elasticsearch/action/search/TransportSearchActionTests.java +++ b/server/src/test/java/org/elasticsearch/action/search/TransportSearchActionTests.java @@ -37,6 +37,7 @@ import org.elasticsearch.core.TimeValue; import org.elasticsearch.core.Tuple; import org.elasticsearch.index.Index; +import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.index.query.InnerHitBuilder; import org.elasticsearch.index.query.MatchAllQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; @@ -81,6 +82,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; @@ -1292,7 +1294,8 @@ public void testLocalShardIteratorFromPointInTime() { OriginalIndices.NONE, null, new SearchContextId(contexts, aliasFilterMap), - keepAlive + keepAlive, + randomBoolean() ); shardIterators.sort(Comparator.comparing(SearchShardIterator::shardId)); assertThat(shardIterators, hasSize(numberOfShards)); @@ -1319,5 +1322,38 @@ public void testLocalShardIteratorFromPointInTime() { assertThat(shardIterator.getSearchContextId(), equalTo(context.getSearchContextId())); assertThat(shardIterator.getSearchContextKeepAlive(), equalTo(keepAlive)); } + + // Fails when some indices don't exist and `allowPartialSearchResults` is false. + ShardId anotherShardId = new ShardId(new Index("another-index", IndexMetadata.INDEX_UUID_NA_VALUE), randomIntBetween(0, 10)); + contexts.put( + anotherShardId, + new SearchContextIdForNode( + null, + randomFrom(clusterState.nodes().getAllNodes()).getId(), + new ShardSearchContextId(UUIDs.randomBase64UUID(), randomNonNegativeLong(), null) + ) + ); + IndexNotFoundException error = expectThrows(IndexNotFoundException.class, () -> { + TransportSearchAction.getLocalLocalShardsIteratorFromPointInTime( + clusterState, + OriginalIndices.NONE, + null, + new SearchContextId(contexts, aliasFilterMap), + keepAlive, + false + ); + }); + assertThat(error.getIndex().getName(), equalTo("another-index")); + // Ok when some indices don't exist and `allowPartialSearchResults` is true. + Optional anotherShardIterator = TransportSearchAction.getLocalLocalShardsIteratorFromPointInTime( + clusterState, + OriginalIndices.NONE, + null, + new SearchContextId(contexts, aliasFilterMap), + keepAlive, + true + ).stream().filter(si -> si.shardId().equals(anotherShardId)).findFirst(); + assertTrue(anotherShardIterator.isPresent()); + assertThat(anotherShardIterator.get().getTargetNodeIds(), hasSize(1)); } }