Skip to content

Commit 01950bc

Browse files
authored
Move FieldMapper#valueFetcher to MappedFieldType (#62974) (#63220)
For runtime fields, we will want to do all search-time interaction with a field definition via a MappedFieldType, rather than a FieldMapper, to avoid interfering with the logic of document parsing. Currently, fetching values for runtime scripts and for building top hits responses need to call a method on FieldMapper. This commit moves this method to MappedFieldType, incidentally simplifying the current call sites and freeing us up to implement runtime fields as pure MappedFieldType objects.
1 parent 1c136bb commit 01950bc

File tree

119 files changed

+1761
-1408
lines changed

Some content is hidden

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

119 files changed

+1761
-1408
lines changed

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

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,19 @@ public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName, S
113113
throw new IllegalArgumentException("[rank_feature] fields do not support sorting, scripting or aggregating");
114114
}
115115

116+
@Override
117+
public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searchLookup, String format) {
118+
if (format != null) {
119+
throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] doesn't support formats.");
120+
}
121+
return new SourceValueFetcher(name(), mapperService, false) {
122+
@Override
123+
protected Float parseSourceValue(Object value) {
124+
return objectToFloat(value);
125+
}
126+
};
127+
}
128+
116129
@Override
117130
public Query termQuery(Object value, QueryShardContext context) {
118131
throw new IllegalArgumentException("Queries on [rank_feature] fields are not supported");
@@ -162,27 +175,14 @@ protected void parseCreateField(ParseContext context) throws IOException {
162175
context.doc().addWithKey(name(), new FeatureField("_feature", name(), value));
163176
}
164177

165-
private Float objectToFloat(Object value) {
178+
private static Float objectToFloat(Object value) {
166179
if (value instanceof Number) {
167180
return ((Number) value).floatValue();
168181
} else {
169182
return Float.parseFloat(value.toString());
170183
}
171184
}
172185

173-
@Override
174-
public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searchLookup, String format) {
175-
if (format != null) {
176-
throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] doesn't support formats.");
177-
}
178-
return new SourceValueFetcher(name(), mapperService, parsesArrayValue()) {
179-
@Override
180-
protected Float parseSourceValue(Object value) {
181-
return objectToFloat(value);
182-
}
183-
};
184-
}
185-
186186
@Override
187187
protected String contentType() {
188188
return CONTENT_TYPE;

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import org.apache.lucene.search.Query;
2323
import org.elasticsearch.index.query.QueryShardContext;
24+
import org.elasticsearch.search.lookup.SearchLookup;
2425

2526
import java.util.Collections;
2627

@@ -50,6 +51,11 @@ public String typeName() {
5051
return CONTENT_TYPE;
5152
}
5253

54+
@Override
55+
public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searchLookup, String format) {
56+
throw new UnsupportedOperationException("Cannot fetch values for internal field [" + typeName() + "].");
57+
}
58+
5359
@Override
5460
public Query existsQuery(QueryShardContext context) {
5561
throw new UnsupportedOperationException("Cannot run exists query on [_feature]");

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

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,19 @@ public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName, S
8888
throw new IllegalArgumentException("[rank_features] fields do not support sorting, scripting or aggregating");
8989
}
9090

91+
@Override
92+
public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searchLookup, String format) {
93+
if (format != null) {
94+
throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] doesn't support formats.");
95+
}
96+
return new SourceValueFetcher(name(), mapperService, false) {
97+
@Override
98+
protected Object parseSourceValue(Object value) {
99+
return value;
100+
}
101+
};
102+
}
103+
91104
@Override
92105
public Query termQuery(Object value, QueryShardContext context) {
93106
throw new IllegalArgumentException("Queries on [rank_features] fields are not supported");
@@ -152,19 +165,6 @@ protected void parseCreateField(ParseContext context) {
152165
throw new AssertionError("parse is implemented directly");
153166
}
154167

155-
@Override
156-
public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searchLookup, String format) {
157-
if (format != null) {
158-
throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] doesn't support formats.");
159-
}
160-
return new SourceValueFetcher(name(), mapperService, parsesArrayValue()) {
161-
@Override
162-
protected Object parseSourceValue(Object value) {
163-
return value;
164-
}
165-
};
166-
}
167-
168168
@Override
169169
protected String contentType() {
170170
return CONTENT_TYPE;

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

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ protected List<Parameter<?>> getParameters() {
124124
@Override
125125
public ScaledFloatFieldMapper build(BuilderContext context) {
126126
ScaledFloatFieldType type = new ScaledFloatFieldType(buildFullName(context), indexed.getValue(), stored.getValue(),
127-
hasDocValues.getValue(), meta.getValue(), scalingFactor.getValue());
127+
hasDocValues.getValue(), meta.getValue(), scalingFactor.getValue(), nullValue.getValue());
128128
return new ScaledFloatFieldMapper(name, type, multiFieldsBuilder.build(this, context), copyTo.build(), this);
129129
}
130130
}
@@ -134,15 +134,17 @@ public ScaledFloatFieldMapper build(BuilderContext context) {
134134
public static final class ScaledFloatFieldType extends SimpleMappedFieldType {
135135

136136
private final double scalingFactor;
137+
private final Double nullValue;
137138

138139
public ScaledFloatFieldType(String name, boolean indexed, boolean stored, boolean hasDocValues,
139-
Map<String, String> meta, double scalingFactor) {
140+
Map<String, String> meta, double scalingFactor, Double nullValue) {
140141
super(name, indexed, stored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
141142
this.scalingFactor = scalingFactor;
143+
this.nullValue = nullValue;
142144
}
143145

144146
public ScaledFloatFieldType(String name, double scalingFactor) {
145-
this(name, true, false, true, Collections.emptyMap(), scalingFactor);
147+
this(name, true, false, true, Collections.emptyMap(), scalingFactor, null);
146148
}
147149

148150
public double getScalingFactor() {
@@ -218,6 +220,30 @@ public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName, S
218220
};
219221
}
220222

223+
@Override
224+
public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searchLookup, String format) {
225+
if (format != null) {
226+
throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] doesn't support formats.");
227+
}
228+
return new SourceValueFetcher(name(), mapperService, false) {
229+
@Override
230+
protected Double parseSourceValue(Object value) {
231+
double doubleValue;
232+
if (value.equals("")) {
233+
if (nullValue == null) {
234+
return null;
235+
}
236+
doubleValue = nullValue;
237+
} else {
238+
doubleValue = objectToDouble(value);
239+
}
240+
241+
double scalingFactor = getScalingFactor();
242+
return Math.round(doubleValue * scalingFactor) / scalingFactor;
243+
}
244+
};
245+
}
246+
221247
@Override
222248
public Object valueForDisplay(Object value) {
223249
if (value == null) {
@@ -394,31 +420,6 @@ private static double objectToDouble(Object value) {
394420
return doubleValue;
395421
}
396422

397-
@Override
398-
public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searchLookup, String format) {
399-
if (format != null) {
400-
throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] doesn't support formats.");
401-
}
402-
return new SourceValueFetcher(name(), mapperService, parsesArrayValue()) {
403-
@Override
404-
protected Double parseSourceValue(Object value) {
405-
double doubleValue;
406-
if (value.equals("")) {
407-
if (nullValue == null) {
408-
return null;
409-
}
410-
doubleValue = nullValue;
411-
} else {
412-
doubleValue = objectToDouble(value);
413-
}
414-
415-
double scalingFactor = fieldType().getScalingFactor();
416-
return Math.round(doubleValue * scalingFactor) / scalingFactor;
417-
}
418-
};
419-
}
420-
421-
422423
private static class ScaledFloatIndexFieldData extends IndexNumericFieldData {
423424

424425
private final IndexNumericFieldData scaledFieldData;

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

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,11 @@ private ShingleFieldType shingleFieldForPositions(int positions) {
263263
return shingleFields[Math.min(indexFromShingleSize, shingleFields.length - 1)];
264264
}
265265

266+
@Override
267+
public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searchLookup, String format) {
268+
throw new UnsupportedOperationException();
269+
}
270+
266271
@Override
267272
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, boolean caseInsensitive, QueryShardContext context) {
268273
if (prefixField == null || prefixField.termLengthWithinBounds(value.length()) == false) {
@@ -369,6 +374,11 @@ public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, bool
369374
.build();
370375
}
371376

377+
@Override
378+
public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searchLookup, String format) {
379+
throw new UnsupportedOperationException();
380+
}
381+
372382
@Override
373383
public String typeName() {
374384
return "prefix";
@@ -405,11 +415,6 @@ protected void parseCreateField(ParseContext context) {
405415
throw new UnsupportedOperationException();
406416
}
407417

408-
@Override
409-
public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searchLookup, String format) {
410-
throw new UnsupportedOperationException();
411-
}
412-
413418
@Override
414419
protected void mergeOptions(FieldMapper other, List<String> conflicts) {
415420

@@ -451,11 +456,6 @@ protected void mergeOptions(FieldMapper other, List<String> conflicts) {
451456

452457
}
453458

454-
@Override
455-
public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searchLookup, String format) {
456-
throw new UnsupportedOperationException();
457-
}
458-
459459
@Override
460460
protected String contentType() {
461461
return "shingle";
@@ -478,6 +478,11 @@ void setPrefixFieldType(PrefixFieldType prefixFieldType) {
478478
this.prefixFieldType = prefixFieldType;
479479
}
480480

481+
@Override
482+
public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searchLookup, String format) {
483+
throw new UnsupportedOperationException();
484+
}
485+
481486
@Override
482487
public String typeName() {
483488
return CONTENT_TYPE;
@@ -573,11 +578,6 @@ protected void parseCreateField(ParseContext context) throws IOException {
573578
}
574579
}
575580

576-
@Override
577-
public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searchLookup, String format) {
578-
throw new UnsupportedOperationException();
579-
}
580-
581581
@Override
582582
protected String contentType() {
583583
return CONTENT_TYPE;

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

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import org.apache.lucene.analysis.TokenStream;
2424
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
2525
import org.elasticsearch.index.analysis.NamedAnalyzer;
26-
import org.elasticsearch.search.lookup.SearchLookup;
2726

2827
import java.io.IOException;
2928
import java.util.Arrays;
@@ -79,6 +78,8 @@ public TokenCountFieldMapper build(BuilderContext context) {
7978
index.getValue(),
8079
store.getValue(),
8180
hasDocValues.getValue(),
81+
false,
82+
nullValue.getValue(),
8283
meta.getValue());
8384
return new TokenCountFieldMapper(name, ft, multiFieldsBuilder.build(this, context), copyTo.build(), this);
8485
}
@@ -129,20 +130,6 @@ protected void parseCreateField(ParseContext context) throws IOException {
129130
);
130131
}
131132

132-
@Override
133-
public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searchLookup, String format) {
134-
if (format != null) {
135-
throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] doesn't support formats.");
136-
}
137-
138-
return new SourceValueFetcher(name(), mapperService, parsesArrayValue(), nullValue) {
139-
@Override
140-
protected String parseSourceValue(Object value) {
141-
return value.toString();
142-
}
143-
};
144-
}
145-
146133
/**
147134
* Count position increments in a token stream. Package private for testing.
148135
* @param analyzer analyzer to create token stream

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

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,8 @@
2525
import org.apache.lucene.index.IndexableField;
2626
import org.apache.lucene.search.Query;
2727
import org.apache.lucene.search.TermQuery;
28-
import org.elasticsearch.Version;
29-
import org.elasticsearch.cluster.metadata.IndexMetadata;
3028
import org.elasticsearch.common.Strings;
3129
import org.elasticsearch.common.collect.List;
32-
import org.elasticsearch.common.settings.Settings;
3330
import org.elasticsearch.common.xcontent.XContentBuilder;
3431
import org.elasticsearch.plugins.Plugin;
3532

@@ -144,13 +141,4 @@ public void testRejectMultiValuedFields() throws MapperParsingException, IOExcep
144141
assertEquals("[rank_feature] fields do not support indexing multiple values for the same field [foo.field] in the same document",
145142
e.getCause().getMessage());
146143
}
147-
148-
public void testFetchSourceValue() throws IOException {
149-
Settings settings = Settings.builder().put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT.id).build();
150-
Mapper.BuilderContext context = new Mapper.BuilderContext(settings, new ContentPath());
151-
RankFeatureFieldMapper mapper = new RankFeatureFieldMapper.Builder("field").build(context);
152-
153-
assertEquals(List.of(3.14f), fetchSourceValue(mapper, 3.14));
154-
assertEquals(List.of(42.9f), fetchSourceValue(mapper, "42.9"));
155-
}
156144
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919

2020
package org.elasticsearch.index.mapper;
2121

22+
import org.elasticsearch.Version;
23+
import org.elasticsearch.cluster.metadata.IndexMetadata;
24+
import org.elasticsearch.common.settings.Settings;
25+
26+
import java.io.IOException;
2227
import java.util.Collections;
2328

2429
public class RankFeatureFieldTypeTests extends FieldTypeTestCase {
@@ -27,4 +32,13 @@ public void testIsNotAggregatable() {
2732
MappedFieldType fieldType = new RankFeatureFieldMapper.RankFeatureFieldType("field", Collections.emptyMap(), true);
2833
assertFalse(fieldType.isAggregatable());
2934
}
35+
36+
public void testFetchSourceValue() throws IOException {
37+
Settings settings = Settings.builder().put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT.id).build();
38+
Mapper.BuilderContext context = new Mapper.BuilderContext(settings, new ContentPath());
39+
MappedFieldType mapper = new RankFeatureFieldMapper.Builder("field").build(context).fieldType();
40+
41+
assertEquals(Collections.singletonList(3.14f), fetchSourceValue(mapper, 3.14));
42+
assertEquals(Collections.singletonList(42.9f), fetchSourceValue(mapper, "42.9"));
43+
}
3044
}

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

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,8 @@
2121

2222
import org.apache.lucene.index.DocValuesType;
2323
import org.apache.lucene.index.IndexableField;
24-
import org.elasticsearch.Version;
25-
import org.elasticsearch.cluster.metadata.IndexMetadata;
2624
import org.elasticsearch.common.Strings;
2725
import org.elasticsearch.common.bytes.BytesReference;
28-
import org.elasticsearch.common.settings.Settings;
2926
import org.elasticsearch.common.xcontent.XContentBuilder;
3027
import org.elasticsearch.common.xcontent.XContentFactory;
3128
import org.elasticsearch.common.xcontent.XContentType;
@@ -285,22 +282,4 @@ public void testRejectIndexOptions() {
285282
containsString("Failed to parse mapping [_doc]: Field [scaling_factor] is required"));
286283
assertWarnings("Parameter [index_options] has no effect on type [scaled_float] and will be removed in future");
287284
}
288-
289-
public void testFetchSourceValue() throws IOException {
290-
Settings settings = Settings.builder().put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT.id).build();
291-
Mapper.BuilderContext context = new Mapper.BuilderContext(settings, new ContentPath());
292-
293-
ScaledFloatFieldMapper mapper = new ScaledFloatFieldMapper.Builder("field", false, false)
294-
.scalingFactor(100)
295-
.build(context);
296-
assertEquals(org.elasticsearch.common.collect.List.of(3.14), fetchSourceValue(mapper, 3.1415926));
297-
assertEquals(org.elasticsearch.common.collect.List.of(3.14), fetchSourceValue(mapper, "3.1415"));
298-
assertEquals(org.elasticsearch.common.collect.List.of(), fetchSourceValue(mapper, ""));
299-
300-
ScaledFloatFieldMapper nullValueMapper = new ScaledFloatFieldMapper.Builder("field", false, false)
301-
.scalingFactor(100)
302-
.nullValue(2.71)
303-
.build(context);
304-
assertEquals(org.elasticsearch.common.collect.List.of(2.71), fetchSourceValue(nullValueMapper, ""));
305-
}
306285
}

0 commit comments

Comments
 (0)