Skip to content

Commit f50fb3c

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 ac4ecc4 commit f50fb3c

File tree

58 files changed

+749
-80
lines changed

Some content is hidden

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

58 files changed

+749
-80
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
@@ -152,11 +152,7 @@ protected void parseCreateField(ParseContext context) throws IOException {
152152
float value;
153153
if (context.externalValueSet()) {
154154
Object v = context.externalValue();
155-
if (v instanceof Number) {
156-
value = ((Number) v).floatValue();
157-
} else {
158-
value = Float.parseFloat(v.toString());
159-
}
155+
value = objectToFloat(v);
160156
} else if (context.parser().currentToken() == Token.VALUE_NULL) {
161157
// skip
162158
return;
@@ -176,6 +172,19 @@ protected void parseCreateField(ParseContext context) throws IOException {
176172
context.doc().addWithKey(name(), new FeatureField("_feature", name(), value));
177173
}
178174

175+
private Float objectToFloat(Object value) {
176+
if (value instanceof Number) {
177+
return ((Number) value).floatValue();
178+
} else {
179+
return Float.parseFloat(value.toString());
180+
}
181+
}
182+
183+
@Override
184+
protected Float parseSourceValue(Object value) {
185+
return objectToFloat(value);
186+
}
187+
179188
@Override
180189
protected String contentType() {
181190
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
@@ -159,6 +159,11 @@ protected void parseCreateField(ParseContext context) throws IOException {
159159
throw new AssertionError("parse is implemented directly");
160160
}
161161

162+
@Override
163+
protected Object parseSourceValue(Object value) {
164+
return value;
165+
}
166+
162167
@Override
163168
protected boolean indexedByDefault() {
164169
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
@@ -473,6 +473,13 @@ private static double objectToDouble(Object value) {
473473
return doubleValue;
474474
}
475475

476+
@Override
477+
protected Double parseSourceValue(Object value) {
478+
double doubleValue = objectToDouble(value);
479+
double scalingFactor = fieldType().getScalingFactor();
480+
return Math.round(doubleValue * scalingFactor) / scalingFactor;
481+
}
482+
476483
private static class ScaledFloatIndexFieldData extends IndexNumericFieldData {
477484

478485
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
@@ -418,6 +418,11 @@ protected void parseCreateField(ParseContext context) {
418418
throw new UnsupportedOperationException();
419419
}
420420

421+
@Override
422+
protected Object parseSourceValue(Object value) {
423+
throw new UnsupportedOperationException();
424+
}
425+
421426
@Override
422427
protected void mergeOptions(FieldMapper other, List<String> conflicts) {
423428

@@ -459,6 +464,11 @@ protected void mergeOptions(FieldMapper other, List<String> conflicts) {
459464

460465
}
461466

467+
@Override
468+
protected Object parseSourceValue(Object value) {
469+
throw new UnsupportedOperationException();
470+
}
471+
462472
@Override
463473
protected String contentType() {
464474
return "shingle";
@@ -577,6 +587,11 @@ protected void parseCreateField(ParseContext context) throws IOException {
577587
}
578588
}
579589

590+
@Override
591+
protected String parseSourceValue(Object value) {
592+
return value.toString();
593+
}
594+
580595
@Override
581596
protected String contentType() {
582597
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
@@ -135,6 +135,11 @@ protected void parseCreateField(ParseContext context) throws IOException {
135135
throw new IllegalStateException("Should never be called");
136136
}
137137

138+
@Override
139+
protected Object parseSourceValue(Object value) {
140+
throw new UnsupportedOperationException("The " + typeName() + " field is not stored in _source.");
141+
}
142+
138143
@Override
139144
protected String contentType() {
140145
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
@@ -185,6 +185,11 @@ protected void parseCreateField(ParseContext context) throws IOException {
185185
context.doc().add(new SortedDocValuesField(fieldType().name(), binaryValue));
186186
}
187187

188+
@Override
189+
protected Object parseSourceValue(Object value) {
190+
throw new UnsupportedOperationException("The " + typeName() + " field is not stored in _source.");
191+
}
192+
188193
@Override
189194
protected void mergeOptions(FieldMapper other, List<String> conflicts) {
190195
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
@@ -347,6 +347,11 @@ protected void parseCreateField(ParseContext context) throws IOException {
347347
throw new UnsupportedOperationException("parsing is implemented in parse(), this method should NEVER be called");
348348
}
349349

350+
@Override
351+
protected Object parseSourceValue(Object value) {
352+
return value;
353+
}
354+
350355
@Override
351356
public void parse(ParseContext context) throws IOException {
352357
context.path().add(simpleName());

0 commit comments

Comments
 (0)