Skip to content

Commit 462e25f

Browse files
authored
Pass SearchLookup supplier through to fielddataBuilder (#61430)
Runtime fields need to have a SearchLookup available, when building their fielddata implementations, so that they can look up other fields, runtime or not. To achieve that, we add a Supplier<SearchLookup> argument to the existing MappedFieldType#fielddataBuilder method. As we introduce the ability to look up other fields while building fielddata for mapped fields, we implicitly add the ability for a field to require other fields. This requires some protection mechanism that detects dependency cycles to prevent stack overflow errors. With this commit we also introduce detection for cycles, as well as a limit on the depth of the references for a runtime field. Note that we also plan on introducing cycles detection at compile time, so the runtime cycles detection is a last resort to prevent stack overflow errors but we hope that we can reject runtime fields from being registered in the mappings when they create a cycle in their definition. Note that this commit does not introduce any production implementation of runtime fields, but is rather a pre-requisite to merge the runtime fields feature branch. This is a breaking change for MapperPlugins that plug in a mapper, as the signature of MappedFieldType#fielddataBuilder changes from taking a single argument (the index name), to also accept a Supplier<SearchLookup>. Co-authored-by: Nik Everett <[email protected]> Relates to #59332
1 parent 49350dd commit 462e25f

File tree

54 files changed

+562
-144
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+562
-144
lines changed

modules/lang-expression/src/test/java/org/elasticsearch/script/expression/ExpressionFieldScriptTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919

2020
package org.elasticsearch.script.expression;
2121

22-
import org.elasticsearch.index.fielddata.LeafNumericFieldData;
2322
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
23+
import org.elasticsearch.index.fielddata.LeafNumericFieldData;
2424
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
2525
import org.elasticsearch.index.mapper.MapperService;
2626
import org.elasticsearch.index.mapper.NumberFieldMapper;
@@ -64,7 +64,7 @@ public void setUp() throws Exception {
6464
when(fieldData.load(anyObject())).thenReturn(atomicFieldData);
6565

6666
service = new ExpressionScriptEngine();
67-
lookup = new SearchLookup(mapperService, ignored -> fieldData);
67+
lookup = new SearchLookup(mapperService, (ignored, lookup) -> fieldData);
6868
}
6969

7070
private FieldScript.LeafFactory compile(String expression) {

modules/lang-expression/src/test/java/org/elasticsearch/script/expression/ExpressionNumberSortScriptTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919

2020
package org.elasticsearch.script.expression;
2121

22-
import org.elasticsearch.index.fielddata.LeafNumericFieldData;
2322
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
23+
import org.elasticsearch.index.fielddata.LeafNumericFieldData;
2424
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
2525
import org.elasticsearch.index.mapper.MapperService;
2626
import org.elasticsearch.index.mapper.NumberFieldMapper.NumberFieldType;
@@ -64,7 +64,7 @@ public void setUp() throws Exception {
6464
when(fieldData.load(anyObject())).thenReturn(atomicFieldData);
6565

6666
service = new ExpressionScriptEngine();
67-
lookup = new SearchLookup(mapperService, ignored -> fieldData);
67+
lookup = new SearchLookup(mapperService, (ignored, lookup) -> fieldData);
6868
}
6969

7070
private NumberSortScript.LeafFactory compile(String expression) {

modules/lang-expression/src/test/java/org/elasticsearch/script/expression/ExpressionTermsSetQueryTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919

2020
package org.elasticsearch.script.expression;
2121

22-
import org.elasticsearch.index.fielddata.LeafNumericFieldData;
2322
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
23+
import org.elasticsearch.index.fielddata.LeafNumericFieldData;
2424
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
2525
import org.elasticsearch.index.mapper.MapperService;
2626
import org.elasticsearch.index.mapper.NumberFieldMapper.NumberFieldType;
@@ -64,7 +64,7 @@ public void setUp() throws Exception {
6464
when(fieldData.load(anyObject())).thenReturn(atomicFieldData);
6565

6666
service = new ExpressionScriptEngine();
67-
lookup = new SearchLookup(mapperService, ignored -> fieldData);
67+
lookup = new SearchLookup(mapperService, (ignored, lookup) -> fieldData);
6868
}
6969

7070
private TermsSetQueryScript.LeafFactory compile(String expression) {

modules/lang-painless/src/test/java/org/elasticsearch/painless/NeedsScoreTests.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import org.elasticsearch.painless.spi.Whitelist;
2626
import org.elasticsearch.script.NumberSortScript;
2727
import org.elasticsearch.script.ScriptContext;
28-
import org.elasticsearch.search.lookup.SearchLookup;
2928
import org.elasticsearch.test.ESSingleNodeTestCase;
3029

3130
import java.util.Collections;
@@ -47,23 +46,21 @@ public void testNeedsScores() {
4746
PainlessScriptEngine service = new PainlessScriptEngine(Settings.EMPTY, contexts);
4847

4948
QueryShardContext shardContext = index.newQueryShardContext(0, null, () -> 0, null);
50-
SearchLookup lookup = new SearchLookup(index.mapperService(), shardContext::getForField);
5149

5250
NumberSortScript.Factory factory = service.compile(null, "1.2", NumberSortScript.CONTEXT, Collections.emptyMap());
53-
NumberSortScript.LeafFactory ss = factory.newFactory(Collections.emptyMap(), lookup);
51+
NumberSortScript.LeafFactory ss = factory.newFactory(Collections.emptyMap(), shardContext.lookup());
5452
assertFalse(ss.needs_score());
5553

5654
factory = service.compile(null, "doc['d'].value", NumberSortScript.CONTEXT, Collections.emptyMap());
57-
ss = factory.newFactory(Collections.emptyMap(), lookup);
55+
ss = factory.newFactory(Collections.emptyMap(), shardContext.lookup());
5856
assertFalse(ss.needs_score());
5957

6058
factory = service.compile(null, "1/_score", NumberSortScript.CONTEXT, Collections.emptyMap());
61-
ss = factory.newFactory(Collections.emptyMap(), lookup);
59+
ss = factory.newFactory(Collections.emptyMap(), shardContext.lookup());
6260
assertTrue(ss.needs_score());
6361

6462
factory = service.compile(null, "doc['d'].value * _score", NumberSortScript.CONTEXT, Collections.emptyMap());
65-
ss = factory.newFactory(Collections.emptyMap(), lookup);
63+
ss = factory.newFactory(Collections.emptyMap(), shardContext.lookup());
6664
assertTrue(ss.needs_score());
6765
}
68-
6966
}

modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/RankFeatureFieldMapper.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,13 @@
3131
import org.elasticsearch.common.xcontent.support.XContentMapValues;
3232
import org.elasticsearch.index.fielddata.IndexFieldData;
3333
import org.elasticsearch.index.query.QueryShardContext;
34+
import org.elasticsearch.search.lookup.SearchLookup;
3435

3536
import java.io.IOException;
3637
import java.util.Iterator;
3738
import java.util.List;
3839
import java.util.Map;
40+
import java.util.function.Supplier;
3941

4042
/**
4143
* A {@link FieldMapper} that exposes Lucene's {@link FeatureField}.
@@ -118,7 +120,7 @@ public Query existsQuery(QueryShardContext context) {
118120
}
119121

120122
@Override
121-
public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName) {
123+
public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName, Supplier<SearchLookup> searchLookup) {
122124
throw new IllegalArgumentException("[rank_feature] fields do not support sorting, scripting or aggregating");
123125
}
124126

modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/RankFeaturesFieldMapper.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@
2727
import org.elasticsearch.common.xcontent.XContentParser.Token;
2828
import org.elasticsearch.index.fielddata.IndexFieldData;
2929
import org.elasticsearch.index.query.QueryShardContext;
30+
import org.elasticsearch.search.lookup.SearchLookup;
3031

3132
import java.io.IOException;
3233
import java.util.List;
3334
import java.util.Map;
35+
import java.util.function.Supplier;
3436

3537
/**
3638
* A {@link FieldMapper} that exposes Lucene's {@link FeatureField} as a sparse
@@ -91,7 +93,7 @@ public Query existsQuery(QueryShardContext context) {
9193
}
9294

9395
@Override
94-
public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName) {
96+
public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName, Supplier<SearchLookup> searchLookup) {
9597
throw new IllegalArgumentException("[rank_features] fields do not support sorting, scripting or aggregating");
9698
}
9799

modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/ScaledFloatFieldMapper.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import org.elasticsearch.index.query.QueryShardContext;
4949
import org.elasticsearch.search.DocValueFormat;
5050
import org.elasticsearch.search.aggregations.support.ValuesSourceType;
51+
import org.elasticsearch.search.lookup.SearchLookup;
5152

5253
import java.io.IOException;
5354
import java.math.BigDecimal;
@@ -56,6 +57,7 @@
5657
import java.util.Collections;
5758
import java.util.List;
5859
import java.util.Map;
60+
import java.util.function.Supplier;
5961

6062
/** A {@link FieldMapper} for scaled floats. Values are internally multiplied
6163
* by a scaling factor and rounded to the closest long. */
@@ -215,7 +217,7 @@ public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower
215217
}
216218

217219
@Override
218-
public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName) {
220+
public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName, Supplier<SearchLookup> searchLookup) {
219221
failIfNoDocValues();
220222
return (cache, breakerService, mapperService) -> {
221223
final IndexNumericFieldData scaledValues = new SortedNumericIndexFieldData.Builder(

modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/ScaledFloatFieldTypeTests.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,9 @@ public void testFieldData() throws IOException {
150150
// single-valued
151151
ScaledFloatFieldMapper.ScaledFloatFieldType f1
152152
= new ScaledFloatFieldMapper.ScaledFloatFieldType("scaled_float1", scalingFactor);
153-
IndexNumericFieldData fielddata = (IndexNumericFieldData) f1.fielddataBuilder("index").build(null, null, null);
153+
IndexNumericFieldData fielddata = (IndexNumericFieldData) f1.fielddataBuilder("index", () -> {
154+
throw new UnsupportedOperationException();
155+
}).build(null, null, null);
154156
assertEquals(fielddata.getNumericType(), IndexNumericFieldData.NumericType.DOUBLE);
155157
LeafNumericFieldData leafFieldData = fielddata.load(reader.leaves().get(0));
156158
SortedNumericDoubleValues values = leafFieldData.getDoubleValues();
@@ -161,7 +163,9 @@ public void testFieldData() throws IOException {
161163
// multi-valued
162164
ScaledFloatFieldMapper.ScaledFloatFieldType f2
163165
= new ScaledFloatFieldMapper.ScaledFloatFieldType("scaled_float2", scalingFactor);
164-
fielddata = (IndexNumericFieldData) f2.fielddataBuilder("index").build(null, null, null);
166+
fielddata = (IndexNumericFieldData) f2.fielddataBuilder("index", () -> {
167+
throw new UnsupportedOperationException();
168+
}).build(null, null, null);
165169
leafFieldData = fielddata.load(reader.leaves().get(0));
166170
values = leafFieldData.getDoubleValues();
167171
assertTrue(values.advanceExact(0));

modules/parent-join/src/main/java/org/elasticsearch/join/mapper/MetaJoinFieldMapper.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@
3333
import org.elasticsearch.index.mapper.ValueFetcher;
3434
import org.elasticsearch.index.query.QueryShardContext;
3535
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
36+
import org.elasticsearch.search.lookup.SearchLookup;
3637

3738
import java.io.IOException;
3839
import java.util.Collections;
3940
import java.util.List;
41+
import java.util.function.Supplier;
4042

4143
/**
4244
* Simple field mapper hack to ensure that there is a one and only {@link ParentJoinFieldMapper} per mapping.
@@ -90,7 +92,7 @@ public String typeName() {
9092
}
9193

9294
@Override
93-
public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName) {
95+
public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName, Supplier<SearchLookup> searchLookup) {
9496
failIfNoDocValues();
9597
return new SortedSetOrdinalsIndexFieldData.Builder(name(), CoreValuesSourceType.BYTES);
9698
}

modules/parent-join/src/main/java/org/elasticsearch/join/mapper/ParentIdFieldMapper.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,14 @@
4343
import org.elasticsearch.index.mapper.ValueFetcher;
4444
import org.elasticsearch.index.query.QueryShardContext;
4545
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
46+
import org.elasticsearch.search.lookup.SearchLookup;
4647

4748
import java.io.IOException;
4849
import java.util.Collection;
4950
import java.util.List;
5051
import java.util.Map;
5152
import java.util.Set;
53+
import java.util.function.Supplier;
5254

5355
/**
5456
* A field mapper used internally by the {@link ParentJoinFieldMapper} to index
@@ -108,7 +110,7 @@ public String typeName() {
108110
}
109111

110112
@Override
111-
public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName) {
113+
public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName, Supplier<SearchLookup> searchLookup) {
112114
failIfNoDocValues();
113115
return new SortedSetOrdinalsIndexFieldData.Builder(name(), CoreValuesSourceType.BYTES);
114116
}

0 commit comments

Comments
 (0)