diff --git a/docs/changelog/103690.yaml b/docs/changelog/103690.yaml new file mode 100644 index 0000000000000..fa9076789c1cd --- /dev/null +++ b/docs/changelog/103690.yaml @@ -0,0 +1,5 @@ +pr: 103690 +summary: Restore inter-segment search concurrency with synthetic source is enabled +area: Search +type: bug +issues: [] diff --git a/server/src/main/java/org/elasticsearch/index/mapper/SourceLoader.java b/server/src/main/java/org/elasticsearch/index/mapper/SourceLoader.java index 607ba2b261f5d..c07821f3c9ae7 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/SourceLoader.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/SourceLoader.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -79,12 +80,15 @@ public Set requiredStoredFields() { * Load {@code _source} from doc values. */ class Synthetic implements SourceLoader { - private final SyntheticFieldLoader loader; - private final Map storedFieldLoaders; + private final Supplier syntheticFieldLoaderLeafSupplier; + private final Set requiredStoredFields; public Synthetic(Mapping mapping) { - loader = mapping.syntheticFieldLoader(); - storedFieldLoaders = Map.copyOf(loader.storedFieldLoaders().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))); + this.syntheticFieldLoaderLeafSupplier = mapping::syntheticFieldLoader; + this.requiredStoredFields = syntheticFieldLoaderLeafSupplier.get() + .storedFieldLoaders() + .map(Map.Entry::getKey) + .collect(Collectors.toSet()); } @Override @@ -94,19 +98,26 @@ public boolean reordersFieldValues() { @Override public Set requiredStoredFields() { - return storedFieldLoaders.keySet(); + return requiredStoredFields; } @Override public Leaf leaf(LeafReader reader, int[] docIdsInLeaf) throws IOException { - return new SyntheticLeaf(loader.docValuesLoader(reader, docIdsInLeaf)); + SyntheticFieldLoader loader = syntheticFieldLoaderLeafSupplier.get(); + return new SyntheticLeaf(loader, loader.docValuesLoader(reader, docIdsInLeaf)); } - private class SyntheticLeaf implements Leaf { + private static class SyntheticLeaf implements Leaf { + private final SyntheticFieldLoader loader; private final SyntheticFieldLoader.DocValuesLoader docValuesLoader; + private final Map storedFieldLoaders; - private SyntheticLeaf(SyntheticFieldLoader.DocValuesLoader docValuesLoader) { + private SyntheticLeaf(SyntheticFieldLoader loader, SyntheticFieldLoader.DocValuesLoader docValuesLoader) { + this.loader = loader; this.docValuesLoader = docValuesLoader; + this.storedFieldLoaders = Map.copyOf( + loader.storedFieldLoaders().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)) + ); } @Override diff --git a/server/src/main/java/org/elasticsearch/search/DefaultSearchContext.java b/server/src/main/java/org/elasticsearch/search/DefaultSearchContext.java index a8721503c7454..773934615e051 100644 --- a/server/src/main/java/org/elasticsearch/search/DefaultSearchContext.java +++ b/server/src/main/java/org/elasticsearch/search/DefaultSearchContext.java @@ -32,7 +32,6 @@ import org.elasticsearch.index.fielddata.FieldDataContext; import org.elasticsearch.index.fielddata.IndexFieldData; import org.elasticsearch.index.fielddata.IndexOrdinalsFieldData; -import org.elasticsearch.index.mapper.DocumentMapper; import org.elasticsearch.index.mapper.IdLoader; import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.NestedLookup; @@ -167,20 +166,13 @@ final class DefaultSearchContext extends SearchContext { this.indexShard = readerContext.indexShard(); Engine.Searcher engineSearcher = readerContext.acquireSearcher("search"); - int maximumNumberOfSlices; - if (hasSyntheticSource(indexService)) { - // accessing synthetic source is not thread safe - maximumNumberOfSlices = 1; - } else { - maximumNumberOfSlices = determineMaximumNumberOfSlices( - executor, - request, - resultsType, - enableQueryPhaseParallelCollection, - field -> getFieldCardinality(field, readerContext.indexService(), engineSearcher.getDirectoryReader()) - ); - - } + int maximumNumberOfSlices = determineMaximumNumberOfSlices( + executor, + request, + resultsType, + enableQueryPhaseParallelCollection, + field -> getFieldCardinality(field, readerContext.indexService(), engineSearcher.getDirectoryReader()) + ); if (executor == null) { this.searcher = new ContextIndexSearcher( engineSearcher.getIndexReader(), @@ -222,14 +214,6 @@ final class DefaultSearchContext extends SearchContext { } } - private static boolean hasSyntheticSource(IndexService indexService) { - DocumentMapper documentMapper = indexService.mapperService().documentMapper(); - if (documentMapper != null) { - return documentMapper.sourceMapper().isSynthetic(); - } - return false; - } - static long getFieldCardinality(String field, IndexService indexService, DirectoryReader directoryReader) { MappedFieldType mappedFieldType = indexService.mapperService().fieldType(field); if (mappedFieldType == null) { diff --git a/server/src/test/java/org/elasticsearch/search/DefaultSearchContextTests.java b/server/src/test/java/org/elasticsearch/search/DefaultSearchContextTests.java index a531a74d956ee..9aa358123d282 100644 --- a/server/src/test/java/org/elasticsearch/search/DefaultSearchContextTests.java +++ b/server/src/test/java/org/elasticsearch/search/DefaultSearchContextTests.java @@ -395,8 +395,6 @@ public void testClearQueryCancellationsOnClose() throws IOException { when(indexShard.getThreadPool()).thenReturn(threadPool); IndexService indexService = mock(IndexService.class); - MapperService mapperService = mock(MapperService.class); - when(indexService.mapperService()).thenReturn(mapperService); try (Directory dir = newDirectory(); RandomIndexWriter w = new RandomIndexWriter(random(), dir)) {