Skip to content

Commit 85dad44

Browse files
committed
Always build SourceProvider from the mapping lookup
1 parent a016f78 commit 85dad44

25 files changed

+148
-175
lines changed

benchmarks/src/main/java/org/elasticsearch/benchmark/script/ScriptScoreBenchmark.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@
3030
import org.elasticsearch.index.fielddata.IndexFieldDataCache;
3131
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
3232
import org.elasticsearch.index.mapper.MappedFieldType;
33+
import org.elasticsearch.index.mapper.MappingLookup;
3334
import org.elasticsearch.index.mapper.NumberFieldMapper.NumberFieldType;
3435
import org.elasticsearch.index.mapper.NumberFieldMapper.NumberType;
36+
import org.elasticsearch.index.mapper.SourceFieldMetrics;
3537
import org.elasticsearch.indices.breaker.CircuitBreakerService;
3638
import org.elasticsearch.indices.breaker.NoneCircuitBreakerService;
3739
import org.elasticsearch.plugins.PluginsService;
@@ -89,7 +91,7 @@ public class ScriptScoreBenchmark {
8991
private final SearchLookup lookup = new SearchLookup(
9092
fieldTypes::get,
9193
(mft, lookup, fdo) -> mft.fielddataBuilder(FieldDataContext.noRuntimeFields("benchmark")).build(fieldDataCache, breakerService),
92-
SourceProvider.fromStoredFields()
94+
SourceProvider.fromLookup(MappingLookup.EMPTY, SourceFieldMetrics.NOOP)
9395
);
9496

9597
@Param({ "expression", "metal", "painless_cast", "painless_def" })

plugins/mapper-murmur3/src/test/java/org/elasticsearch/index/mapper/murmur3/Murmur3FieldMapperTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ protected void assertFetch(MapperService mapperService, String field, Object val
107107
ValueFetcher nativeFetcher = ft.valueFetcher(searchExecutionContext, format);
108108
ParsedDocument doc = mapperService.documentMapper().parse(source);
109109
withLuceneIndex(mapperService, iw -> iw.addDocuments(doc.docs()), ir -> {
110-
Source s = SourceProvider.fromStoredFields().getSource(ir.leaves().get(0), 0);
110+
Source s = SourceProvider.fromLookup(mapperService.mappingLookup(), mapperService.getMapperMetrics().sourceFieldMetrics())
111+
.getSource(ir.leaves().get(0), 0);
111112
docValueFetcher.setNextReader(ir.leaves().get(0));
112113
nativeFetcher.setNextReader(ir.leaves().get(0));
113114
List<Object> fromDocValues = docValueFetcher.fetchValues(s, 0, new ArrayList<>());

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -493,9 +493,7 @@ public boolean containsBrokenAnalysis(String field) {
493493
*/
494494
public SearchLookup lookup() {
495495
if (this.lookup == null) {
496-
SourceProvider sourceProvider = isSourceSynthetic()
497-
? SourceProvider.fromSyntheticSource(mappingLookup.getMapping(), mapperMetrics.sourceFieldMetrics())
498-
: SourceProvider.fromStoredFields();
496+
SourceProvider sourceProvider = SourceProvider.fromLookup(mappingLookup, mapperMetrics.sourceFieldMetrics());
499497
setLookupProviders(sourceProvider, LeafFieldLookupProvider.fromStoredFields());
500498
}
501499
return this.lookup;
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.search.lookup;
10+
11+
import org.apache.lucene.index.LeafReaderContext;
12+
import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
13+
import org.elasticsearch.index.fieldvisitor.LeafStoredFieldLoader;
14+
import org.elasticsearch.index.fieldvisitor.StoredFieldLoader;
15+
import org.elasticsearch.index.mapper.SourceFieldMapper;
16+
import org.elasticsearch.index.mapper.SourceLoader;
17+
18+
import java.io.IOException;
19+
import java.util.Map;
20+
21+
/**
22+
* A {@link SourceProvider} that loads _source from a concurrent search.
23+
*
24+
* @warning: This is written under the assumption that individual segments are accessed by a single
25+
* thread, even if separate segments may be searched concurrently. If we ever implement
26+
* within-segment concurrency this will have to work entirely differently.
27+
* **/
28+
class ConcurrentSegmentSourceProvider implements SourceProvider {
29+
private final SourceLoader sourceLoader;
30+
private final StoredFieldLoader storedFieldLoader;
31+
private final Map<Object, Leaf> leaves = ConcurrentCollections.newConcurrentMap();
32+
33+
ConcurrentSegmentSourceProvider(SourceLoader loader) {
34+
this.sourceLoader = loader;
35+
var fields = sourceLoader.requiredStoredFields();
36+
boolean loadSource = fields.contains(SourceFieldMapper.NAME);
37+
this.storedFieldLoader = fields.isEmpty() ? StoredFieldLoader.empty() : StoredFieldLoader.create(loadSource, fields);
38+
}
39+
40+
@Override
41+
public Source getSource(LeafReaderContext ctx, int doc) throws IOException {
42+
final Object id = ctx.id();
43+
var leaf = leaves.get(id);
44+
if (leaf == null) {
45+
leaf = new Leaf(sourceLoader.leaf(ctx.reader(), null), storedFieldLoader.getLoader(ctx, null));
46+
var existing = leaves.put(id, leaf);
47+
assert existing == null : "unexpected source provider [" + existing + "]";
48+
}
49+
return leaf.getSource(ctx, doc);
50+
}
51+
52+
private static class Leaf implements SourceProvider {
53+
private final SourceLoader.Leaf sourceLoader;
54+
private final LeafStoredFieldLoader storedFieldLoader;
55+
int doc = -1;
56+
Source source = null;
57+
58+
private Leaf(SourceLoader.Leaf sourceLoader, LeafStoredFieldLoader storedFieldLoader) {
59+
this.sourceLoader = sourceLoader;
60+
this.storedFieldLoader = storedFieldLoader;
61+
}
62+
63+
@Override
64+
public Source getSource(LeafReaderContext ctx, int doc) throws IOException {
65+
if (this.doc == doc) {
66+
return source;
67+
}
68+
this.doc = doc;
69+
storedFieldLoader.advanceTo(doc);
70+
return source = sourceLoader.source(storedFieldLoader, doc);
71+
}
72+
}
73+
}

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

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@
1010
package org.elasticsearch.search.lookup;
1111

1212
import org.apache.lucene.index.LeafReaderContext;
13-
import org.elasticsearch.index.fieldvisitor.StoredFieldLoader;
14-
import org.elasticsearch.index.mapper.Mapping;
13+
import org.elasticsearch.index.mapper.MappingLookup;
1514
import org.elasticsearch.index.mapper.SourceFieldMetrics;
16-
import org.elasticsearch.index.mapper.SourceLoader;
1715

1816
import java.io.IOException;
1917

@@ -28,27 +26,14 @@ public interface SourceProvider {
2826
Source getSource(LeafReaderContext ctx, int doc) throws IOException;
2927

3028
/**
31-
* A SourceProvider that loads source from stored fields
29+
* A SourceProvider that delegate loading source to the provided {@link MappingLookup}.
3230
*
3331
* The returned SourceProvider is thread-safe across segments, in that it may be
3432
* safely used by a searcher that searches different segments on different threads,
3533
* but it is not safe to use this to access documents from the same segment across
3634
* multiple threads.
3735
*/
38-
static SourceProvider fromStoredFields() {
39-
StoredFieldLoader storedFieldLoader = StoredFieldLoader.sequentialSource();
40-
return new StoredFieldSourceProvider(storedFieldLoader);
41-
}
42-
43-
/**
44-
* A SourceProvider that loads source from synthetic source
45-
*
46-
* The returned SourceProvider is thread-safe across segments, in that it may be
47-
* safely used by a searcher that searches different segments on different threads,
48-
* but it is not safe to use this to access documents from the same segment across
49-
* multiple threads.
50-
*/
51-
static SourceProvider fromSyntheticSource(Mapping mapping, SourceFieldMetrics metrics) {
52-
return new SyntheticSourceProvider(new SourceLoader.Synthetic(mapping::syntheticFieldLoader, metrics));
36+
static SourceProvider fromLookup(MappingLookup lookup, SourceFieldMetrics metrics) {
37+
return new ConcurrentSegmentSourceProvider(lookup.newSourceLoader(metrics));
5338
}
5439
}

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

Lines changed: 0 additions & 63 deletions
This file was deleted.

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

Lines changed: 0 additions & 61 deletions
This file was deleted.

server/src/test/java/org/elasticsearch/index/mapper/CompositeRuntimeFieldTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ public void testParseDocumentSubFieldAccess() throws IOException {
346346
(mft, lookupSupplier, fdo) -> mft.fielddataBuilder(
347347
new FieldDataContext("test", null, lookupSupplier, mapperService.mappingLookup()::sourcePaths, fdo)
348348
).build(null, null),
349-
SourceProvider.fromStoredFields()
349+
SourceProvider.fromLookup(mapperService.mappingLookup(), mapperService.getMapperMetrics().sourceFieldMetrics())
350350
);
351351

352352
LeafSearchLookup leafSearchLookup = searchLookup.getLeafSearchLookup(reader.leaves().get(0));

server/src/test/java/org/elasticsearch/index/mapper/DateFieldScriptTests.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,11 @@ public final void testFromSourceDoesNotEnforceValuesLimit() throws IOException {
106106
DateFieldScript.LeafFactory leafFactory = fromSource().newFactory(
107107
"field",
108108
Collections.emptyMap(),
109-
new SearchLookup(field -> null, (ft, lookup, fdt) -> null, SourceProvider.fromStoredFields()),
109+
new SearchLookup(
110+
field -> null,
111+
(ft, lookup, fdt) -> null,
112+
SourceProvider.fromLookup(MappingLookup.EMPTY, SourceFieldMetrics.NOOP)
113+
),
110114
DateFormatter.forPattern("epoch_millis"),
111115
OnScriptError.FAIL
112116
);

server/src/test/java/org/elasticsearch/index/mapper/DoubleFieldScriptTests.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,11 @@ public final void testFromSourceDoesNotEnforceValuesLimit() throws IOException {
103103
DoubleFieldScript.LeafFactory leafFactory = fromSource().newFactory(
104104
"field",
105105
Collections.emptyMap(),
106-
new SearchLookup(field -> null, (ft, lookup, fdt) -> null, SourceProvider.fromStoredFields()),
106+
new SearchLookup(
107+
field -> null,
108+
(ft, lookup, fdt) -> null,
109+
SourceProvider.fromLookup(MappingLookup.EMPTY, SourceFieldMetrics.NOOP)
110+
),
107111
OnScriptError.FAIL
108112
);
109113
DoubleFieldScript doubleFieldScript = leafFactory.newInstance(reader.leaves().get(0));

0 commit comments

Comments
 (0)