Skip to content

Commit 32bb3a5

Browse files
committed
Pass down runtime field name as source filter when source mode is synthetic
This avoids synthesizing fields that are not requested
1 parent 8e9c63f commit 32bb3a5

File tree

7 files changed

+78
-13
lines changed

7 files changed

+78
-13
lines changed

server/src/main/java/org/elasticsearch/index/mapper/AbstractScriptFieldType.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.elasticsearch.script.ScriptContext;
2828
import org.elasticsearch.search.fetch.StoredFieldsSpec;
2929
import org.elasticsearch.search.lookup.SearchLookup;
30+
import org.elasticsearch.search.lookup.SourceFilter;
3031
import org.elasticsearch.xcontent.XContentBuilder;
3132

3233
import java.time.ZoneId;
@@ -190,7 +191,9 @@ public ValueFetcher valueFetcher(SearchExecutionContext context, String format)
190191
* Create a script leaf factory.
191192
*/
192193
protected final LeafFactory leafFactory(SearchLookup searchLookup) {
193-
return factory.apply(searchLookup);
194+
String include = name();
195+
var copy = searchLookup.maybeCopyWithSourceFilter(new SourceFilter(new String[] { include }, new String[0]));
196+
return factory.apply(copy);
194197
}
195198

196199
/**

server/src/main/java/org/elasticsearch/index/query/SearchExecutionContext.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -503,14 +503,14 @@ public boolean containsBrokenAnalysis(String field) {
503503
*/
504504
public SearchLookup lookup() {
505505
if (this.lookup == null) {
506-
var sourceProvider = createSourceProvider();
506+
var sourceProvider = createSourceProvider(null);
507507
setLookupProviders(sourceProvider, LeafFieldLookupProvider.fromStoredFields());
508508
}
509509
return this.lookup;
510510
}
511511

512-
public SourceProvider createSourceProvider() {
513-
return SourceProvider.fromLookup(mappingLookup, null, mapperMetrics.sourceFieldMetrics());
512+
public SourceProvider createSourceProvider(SourceFilter sourceFilter) {
513+
return SourceProvider.fromLookup(mappingLookup, sourceFilter, mapperMetrics.sourceFieldMetrics());
514514
}
515515

516516
/**
@@ -543,6 +543,12 @@ public void setLookupProviders(
543543
);
544544
}
545545

546+
public SearchLookup copyWithSourceFilter(SourceFilter sourceFilter) {
547+
var searchLookup = lookup();
548+
var sourceProvider = SourceProvider.fromLookup(mappingLookup, sourceFilter, mapperMetrics.sourceFieldMetrics());
549+
return new SearchLookup(searchLookup, sourceProvider);
550+
}
551+
546552
public NestedScope nestedScope() {
547553
return nestedScope;
548554
}

server/src/main/java/org/elasticsearch/search/lookup/ConcurrentSegmentSourceProvider.java

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,13 @@
1313
import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
1414
import org.elasticsearch.index.fieldvisitor.LeafStoredFieldLoader;
1515
import org.elasticsearch.index.fieldvisitor.StoredFieldLoader;
16+
import org.elasticsearch.index.mapper.MappingLookup;
17+
import org.elasticsearch.index.mapper.SourceFieldMetrics;
1618
import org.elasticsearch.index.mapper.SourceLoader;
1719

1820
import java.io.IOException;
1921
import java.util.Map;
22+
import java.util.function.Function;
2023

2124
/**
2225
* A {@link SourceProvider} that loads _source from a concurrent search.
@@ -26,16 +29,31 @@
2629
* within-segment concurrency this will have to work entirely differently.
2730
* **/
2831
class ConcurrentSegmentSourceProvider implements SourceProvider {
32+
private final Function<SourceFilter, SourceLoader> sourceLoaderProvider;
2933
private final SourceLoader sourceLoader;
3034
private final StoredFieldLoader storedFieldLoader;
3135
private final Map<Object, Leaf> leaves = ConcurrentCollections.newConcurrentMap();
3236
private final boolean isStoredSource;
3337

34-
ConcurrentSegmentSourceProvider(SourceLoader loader, boolean isStoredSource) {
35-
this.sourceLoader = loader;
38+
ConcurrentSegmentSourceProvider(MappingLookup lookup, SourceFilter filter, SourceFieldMetrics metrics) {
39+
this.sourceLoaderProvider = sourceFilter -> lookup.newSourceLoader(sourceFilter, metrics);
40+
this.sourceLoader = sourceLoaderProvider.apply(filter);
41+
this.isStoredSource = lookup.isSourceSynthetic() == false;
3642
// we force a sequential reader here since it is used during query execution where documents are scanned sequentially
3743
this.storedFieldLoader = StoredFieldLoader.create(isStoredSource, sourceLoader.requiredStoredFields(), true);
38-
this.isStoredSource = isStoredSource;
44+
}
45+
46+
private ConcurrentSegmentSourceProvider(ConcurrentSegmentSourceProvider source, SourceFilter filter) {
47+
this.sourceLoaderProvider = source.sourceLoaderProvider;
48+
this.isStoredSource = source.isStoredSource;
49+
if (isStoredSource) {
50+
this.sourceLoader = source.sourceLoader;
51+
this.storedFieldLoader = source.storedFieldLoader;
52+
} else {
53+
this.sourceLoader = source.sourceLoaderProvider.apply(filter);
54+
// Also re-initialize stored field loader:
55+
this.storedFieldLoader = StoredFieldLoader.create(isStoredSource, sourceLoader.requiredStoredFields(), true);
56+
}
3957
}
4058

4159
@Override
@@ -58,6 +76,12 @@ public Source getSource(LeafReaderContext ctx, int doc) throws IOException {
5876
return leaf.getSource(ctx, doc);
5977
}
6078

79+
@Override
80+
public SourceProvider maybeCopyWithSourceFilter(SourceFilter sourceFilter) {
81+
assert leaves.isEmpty() : "source provider must be unused when applying filter";
82+
return new ConcurrentSegmentSourceProvider(this, sourceFilter);
83+
}
84+
6185
private static class Leaf implements SourceProvider {
6286
private final SourceLoader.Leaf sourceLoader;
6387
private final LeafStoredFieldLoader storedFieldLoader;

server/src/main/java/org/elasticsearch/search/lookup/SearchLookup.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ private SearchLookup(SearchLookup searchLookup, Set<String> fieldChain) {
102102
this.fieldLookupProvider = searchLookup.fieldLookupProvider;
103103
}
104104

105+
public SearchLookup(SearchLookup searchLookup, SourceProvider sourceProvider) {
106+
this.fieldChain = searchLookup.fieldChain;
107+
this.sourceProvider = sourceProvider;
108+
this.fieldTypeLookup = searchLookup.fieldTypeLookup;
109+
this.fieldDataLookup = searchLookup.fieldDataLookup;
110+
this.fieldLookupProvider = searchLookup.fieldLookupProvider;
111+
}
112+
105113
/**
106114
* Creates a copy of the current {@link SearchLookup} that looks fields up in the same way, but also tracks field references
107115
* in order to detect cycles and prevent resolving fields that depend on more than {@link #MAX_FIELD_CHAIN_DEPTH} other fields.
@@ -145,4 +153,8 @@ public Source getSource(LeafReaderContext ctx, int doc) throws IOException {
145153
return sourceProvider.getSource(ctx, doc);
146154
}
147155

156+
public SearchLookup maybeCopyWithSourceFilter(SourceFilter sourceFilter) {
157+
SourceProvider copy = sourceProvider.maybeCopyWithSourceFilter(sourceFilter);
158+
return new SearchLookup(this, copy);
159+
}
148160
}

server/src/main/java/org/elasticsearch/search/lookup/SourceProvider.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ public interface SourceProvider {
3434
* multiple threads.
3535
*/
3636
static SourceProvider fromLookup(MappingLookup lookup, SourceFilter filter, SourceFieldMetrics metrics) {
37-
return new ConcurrentSegmentSourceProvider(lookup.newSourceLoader(filter, metrics), lookup.isSourceSynthetic() == false);
37+
return new ConcurrentSegmentSourceProvider(lookup, filter, metrics);
38+
}
39+
40+
default SourceProvider maybeCopyWithSourceFilter(SourceFilter sourceFilter) {
41+
assert false : "should not be invoked";
42+
return this;
3843
}
3944
}

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.elasticsearch.logging.Logger;
3636
import org.elasticsearch.search.SearchService;
3737
import org.elasticsearch.search.internal.SearchContext;
38+
import org.elasticsearch.search.lookup.SourceFilter;
3839
import org.elasticsearch.search.lookup.SourceProvider;
3940
import org.elasticsearch.tasks.CancellableTask;
4041
import org.elasticsearch.tasks.Task;
@@ -596,7 +597,7 @@ void runCompute(CancellableTask task, ComputeContext context, PhysicalPlan plan,
596597
var searchExecutionContext = new SearchExecutionContext(searchContext.getSearchExecutionContext()) {
597598

598599
@Override
599-
public SourceProvider createSourceProvider() {
600+
public SourceProvider createSourceProvider(SourceFilter sourceFilter) {
600601
return new ReinitializingSourceProvider(super::createSourceProvider);
601602
}
602603
};

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ReinitializingSourceProvider.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99

1010
import org.apache.lucene.index.LeafReaderContext;
1111
import org.elasticsearch.search.lookup.Source;
12+
import org.elasticsearch.search.lookup.SourceFilter;
1213
import org.elasticsearch.search.lookup.SourceProvider;
1314

1415
import java.io.IOException;
15-
import java.util.function.Supplier;
16+
import java.util.function.Function;
1617

1718
/**
1819
* This class exists as a workaround for using SourceProvider in the compute engine.
@@ -25,10 +26,17 @@
2526
*/
2627
final class ReinitializingSourceProvider implements SourceProvider {
2728

29+
private final SourceFilter sourceFilter;
2830
private PerThreadSourceProvider perThreadProvider;
29-
private final Supplier<SourceProvider> sourceProviderFactory;
31+
private final Function<SourceFilter, SourceProvider> sourceProviderFactory;
3032

31-
ReinitializingSourceProvider(Supplier<SourceProvider> sourceProviderFactory) {
33+
ReinitializingSourceProvider(Function<SourceFilter, SourceProvider> sourceProviderFactory) {
34+
this.sourceFilter = null;
35+
this.sourceProviderFactory = sourceProviderFactory;
36+
}
37+
38+
private ReinitializingSourceProvider(SourceFilter sourceFilter, Function<SourceFilter, SourceProvider> sourceProviderFactory) {
39+
this.sourceFilter = sourceFilter;
3240
this.sourceProviderFactory = sourceProviderFactory;
3341
}
3442

@@ -37,13 +45,19 @@ public Source getSource(LeafReaderContext ctx, int doc) throws IOException {
3745
var currentThread = Thread.currentThread();
3846
PerThreadSourceProvider provider = perThreadProvider;
3947
if (provider == null || provider.creatingThread != currentThread || doc < provider.lastSeenDocId) {
40-
provider = new PerThreadSourceProvider(sourceProviderFactory.get(), currentThread);
48+
provider = new PerThreadSourceProvider(sourceProviderFactory.apply(sourceFilter), currentThread);
4149
this.perThreadProvider = provider;
4250
}
4351
provider.lastSeenDocId = doc;
4452
return provider.source.getSource(ctx, doc);
4553
}
4654

55+
@Override
56+
public SourceProvider maybeCopyWithSourceFilter(SourceFilter sourceFilter) {
57+
assert perThreadProvider == null : "source provider must be unused when applying filter";
58+
return new ReinitializingSourceProvider(sourceFilter, sourceProviderFactory);
59+
}
60+
4761
private static final class PerThreadSourceProvider {
4862
final SourceProvider source;
4963
final Thread creatingThread;

0 commit comments

Comments
 (0)