Skip to content

Commit d6a860d

Browse files
committed
Allow field mappers to retrieve fields from source. (#56928)
This PR adds new method `FieldMapper#lookupValues(SourceLookup)` that extracts and parses the source values. This lets us return values like numbers and dates in a consistent format, and also handle special data types like `constant_keyword`. The `lookupValues` method calls into `parseSourceValue`, which mappers can override to specify how values should be parsed.
1 parent 45bc752 commit d6a860d

File tree

57 files changed

+742
-81
lines changed

Some content is hidden

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

57 files changed

+742
-81
lines changed

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

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,7 @@ protected void parseCreateField(ParseContext context) throws IOException {
161161
float value;
162162
if (context.externalValueSet()) {
163163
Object v = context.externalValue();
164-
if (v instanceof Number) {
165-
value = ((Number) v).floatValue();
166-
} else {
167-
value = Float.parseFloat(v.toString());
168-
}
164+
value = objectToFloat(v);
169165
} else if (context.parser().currentToken() == Token.VALUE_NULL) {
170166
// skip
171167
return;
@@ -185,6 +181,19 @@ protected void parseCreateField(ParseContext context) throws IOException {
185181
context.doc().addWithKey(name(), new FeatureField("_feature", name(), value));
186182
}
187183

184+
private Float objectToFloat(Object value) {
185+
if (value instanceof Number) {
186+
return ((Number) value).floatValue();
187+
} else {
188+
return Float.parseFloat(value.toString());
189+
}
190+
}
191+
192+
@Override
193+
protected Float parseSourceValue(Object value) {
194+
return objectToFloat(value);
195+
}
196+
188197
@Override
189198
protected String contentType() {
190199
return CONTENT_TYPE;

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,11 @@ protected void parseCreateField(ParseContext context) throws IOException {
167167
throw new AssertionError("parse is implemented directly");
168168
}
169169

170+
@Override
171+
protected Object parseSourceValue(Object value) {
172+
return value;
173+
}
174+
170175
@Override
171176
protected boolean indexedByDefault() {
172177
return false;

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,13 @@ private static double objectToDouble(Object value) {
496496
return doubleValue;
497497
}
498498

499+
@Override
500+
protected Double parseSourceValue(Object value) {
501+
double doubleValue = objectToDouble(value);
502+
double scalingFactor = fieldType().getScalingFactor();
503+
return Math.round(doubleValue * scalingFactor) / scalingFactor;
504+
}
505+
499506
private static class ScaledFloatIndexFieldData extends IndexNumericFieldData {
500507

501508
private final IndexNumericFieldData scaledFieldData;

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,11 @@ protected void parseCreateField(ParseContext context) {
493493
throw new UnsupportedOperationException();
494494
}
495495

496+
@Override
497+
protected Object parseSourceValue(Object value) {
498+
throw new UnsupportedOperationException();
499+
}
500+
496501
@Override
497502
protected void mergeOptions(FieldMapper other, List<String> conflicts) {
498503

@@ -534,6 +539,11 @@ protected void mergeOptions(FieldMapper other, List<String> conflicts) {
534539

535540
}
536541

542+
@Override
543+
protected Object parseSourceValue(Object value) {
544+
throw new UnsupportedOperationException();
545+
}
546+
537547
@Override
538548
protected String contentType() {
539549
return "shingle";
@@ -686,6 +696,11 @@ protected void parseCreateField(ParseContext context) throws IOException {
686696
}
687697
}
688698

699+
@Override
700+
protected String parseSourceValue(Object value) {
701+
return value.toString();
702+
}
703+
689704
@Override
690705
protected String contentType() {
691706
return CONTENT_TYPE;

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,11 @@ protected void parseCreateField(ParseContext context) throws IOException {
158158
context.doc().addAll(NumberFieldMapper.NumberType.INTEGER.createFields(fieldType().name(), tokenCount, indexed, docValued, stored));
159159
}
160160

161+
@Override
162+
protected String parseSourceValue(Object value) {
163+
return value.toString();
164+
}
165+
161166
/**
162167
* Count position increments in a token stream. Package private for testing.
163168
* @param analyzer analyzer to create token stream

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,12 @@
2323
import org.apache.lucene.analysis.tokenattributes.TermFrequencyAttribute;
2424
import org.apache.lucene.document.FeatureField;
2525
import org.apache.lucene.index.IndexableField;
26+
import org.elasticsearch.Version;
27+
import org.elasticsearch.cluster.metadata.IndexMetadata;
2628
import org.elasticsearch.common.Strings;
2729
import org.elasticsearch.common.bytes.BytesReference;
2830
import org.elasticsearch.common.compress.CompressedXContent;
31+
import org.elasticsearch.common.settings.Settings;
2932
import org.elasticsearch.common.xcontent.XContentFactory;
3033
import org.elasticsearch.common.xcontent.XContentType;
3134
import org.elasticsearch.index.IndexService;
@@ -186,4 +189,12 @@ public void testRejectMultiValuedFields() throws MapperParsingException, IOExcep
186189
e.getCause().getMessage());
187190
}
188191

192+
public void testParseSourceValue() {
193+
Settings settings = Settings.builder().put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT.id).build();
194+
Mapper.BuilderContext context = new Mapper.BuilderContext(settings, new ContentPath());
195+
RankFeatureFieldMapper mapper = new RankFeatureFieldMapper.Builder("field").build(context);
196+
197+
assertEquals(3.14f, mapper.parseSourceValue(3.14), 0.0001);
198+
assertEquals(42.9f, mapper.parseSourceValue("42.9"), 0.0001);
199+
}
189200
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,12 @@
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;
2426
import org.elasticsearch.common.Strings;
2527
import org.elasticsearch.common.bytes.BytesReference;
2628
import org.elasticsearch.common.compress.CompressedXContent;
29+
import org.elasticsearch.common.settings.Settings;
2730
import org.elasticsearch.common.xcontent.XContentFactory;
2831
import org.elasticsearch.common.xcontent.XContentType;
2932
import org.elasticsearch.index.IndexService;
@@ -398,4 +401,15 @@ public void testMeta() throws Exception {
398401
new CompressedXContent(mapping3), MergeReason.MAPPING_UPDATE);
399402
assertEquals(mapping3, mapper.mappingSource().toString());
400403
}
404+
405+
public void testParseSourceValue() {
406+
Settings settings = Settings.builder().put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT.id).build();
407+
Mapper.BuilderContext context = new Mapper.BuilderContext(settings, new ContentPath());
408+
ScaledFloatFieldMapper mapper = new ScaledFloatFieldMapper.Builder("field")
409+
.scalingFactor(100)
410+
.build(context);
411+
412+
assertEquals(3.14, mapper.parseSourceValue(3.1415926), 0.00001);
413+
assertEquals(3.14, mapper.parseSourceValue("3.1415"), 0.00001);
414+
}
401415
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,11 @@ protected void parseCreateField(ParseContext context) throws IOException {
144144
throw new IllegalStateException("Should never be called");
145145
}
146146

147+
@Override
148+
protected Object parseSourceValue(Object value) {
149+
throw new UnsupportedOperationException("The " + typeName() + " field is not stored in _source.");
150+
}
151+
147152
@Override
148153
protected String contentType() {
149154
return CONTENT_TYPE;

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,11 @@ protected void parseCreateField(ParseContext context) throws IOException {
193193
context.doc().add(new SortedDocValuesField(fieldType().name(), binaryValue));
194194
}
195195

196+
@Override
197+
protected Object parseSourceValue(Object value) {
198+
throw new UnsupportedOperationException("The " + typeName() + " field is not stored in _source.");
199+
}
200+
196201
@Override
197202
protected void mergeOptions(FieldMapper other, List<String> conflicts) {
198203
ParentIdFieldMapper parentMergeWith = (ParentIdFieldMapper) other;

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,11 @@ protected void parseCreateField(ParseContext context) throws IOException {
355355
throw new UnsupportedOperationException("parsing is implemented in parse(), this method should NEVER be called");
356356
}
357357

358+
@Override
359+
protected Object parseSourceValue(Object value) {
360+
return value;
361+
}
362+
358363
@Override
359364
public void parse(ParseContext context) throws IOException {
360365
context.path().add(simpleName());

0 commit comments

Comments
 (0)