Skip to content

Commit cc09b6b

Browse files
authored
Make array value parsing flag more robust. (#63354)
When constructing a value fetcher, the 'parsesArrayValue' flag must match `FieldMapper#parsesArrayValue`. However there is nothing in code or tests to help enforce this. This PR reworks the value fetcher constructors so that `parsesArrayValue` is 'false' by default. Just as for `FieldMapper#parsesArrayValue`, field types must explicitly set it to true and ensure the behavior is covered by tests. Follow-up to #62974.
1 parent 27089e7 commit cc09b6b

File tree

28 files changed

+140
-54
lines changed

28 files changed

+140
-54
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searc
118118
if (format != null) {
119119
throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] doesn't support formats.");
120120
}
121-
return new SourceValueFetcher(name(), mapperService, false) {
121+
return new SourceValueFetcher(name(), mapperService) {
122122
@Override
123123
protected Float parseSourceValue(Object value) {
124124
return objectToFloat(value);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searc
9393
if (format != null) {
9494
throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] doesn't support formats.");
9595
}
96-
return new SourceValueFetcher(name(), mapperService, false) {
96+
return new SourceValueFetcher(name(), mapperService) {
9797
@Override
9898
protected Object parseSourceValue(Object value) {
9999
return value;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searc
211211
if (format != null) {
212212
throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] doesn't support formats.");
213213
}
214-
return new SourceValueFetcher(name(), mapperService, false) {
214+
return new SourceValueFetcher(name(), mapperService) {
215215
@Override
216216
protected Double parseSourceValue(Object value) {
217217
double doubleValue;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searc
227227
if (format != null) {
228228
throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] doesn't support formats.");
229229
}
230-
return new SourceValueFetcher(name(), mapperService, false) {
230+
return new SourceValueFetcher(name(), mapperService) {
231231
@Override
232232
protected Object parseSourceValue(Object value) {
233233
return value;

modules/percolator/src/main/java/org/elasticsearch/percolator/PercolatorFieldMapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searc
222222
if (format != null) {
223223
throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] doesn't support formats.");
224224
}
225-
return new SourceValueFetcher(name(), mapperService, false) {
225+
return new SourceValueFetcher(name(), mapperService) {
226226
@Override
227227
protected Object parseSourceValue(Object value) {
228228
return value;

plugins/analysis-icu/src/main/java/org/elasticsearch/index/mapper/ICUCollationKeywordFieldMapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searc
104104
throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] doesn't support formats.");
105105
}
106106

107-
return new SourceValueFetcher(name(), mapperService, false, nullValue) {
107+
return new SourceValueFetcher(name(), mapperService, nullValue) {
108108
@Override
109109
protected String parseSourceValue(Object value) {
110110
String keywordValue = value.toString();

plugins/mapper-murmur3/src/main/java/org/elasticsearch/index/mapper/murmur3/Murmur3FieldMapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searc
110110
if (format != null) {
111111
throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] doesn't support formats.");
112112
}
113-
return new SourceValueFetcher(name(), mapperService, false) {
113+
return new SourceValueFetcher(name(), mapperService) {
114114
@Override
115115
protected String parseSourceValue(Object value) {
116116
return value.toString();

server/src/main/java/org/elasticsearch/index/mapper/AbstractGeometryFieldMapper.java

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -256,13 +256,21 @@ public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searc
256256
String geoFormat = format != null ? format : GeoJsonGeometryFormat.NAME;
257257

258258
Function<Object, Object> valueParser = value -> geometryParser.parseAndFormatObject(value, geoFormat);
259-
260-
return new SourceValueFetcher(name(), mapperService, parsesArrayValue) {
261-
@Override
262-
protected Object parseSourceValue(Object value) {
263-
return valueParser.apply(value);
264-
}
265-
};
259+
if (parsesArrayValue) {
260+
return new ArraySourceValueFetcher(name(), mapperService) {
261+
@Override
262+
protected Object parseSourceValue(Object value) {
263+
return valueParser.apply(value);
264+
}
265+
};
266+
} else {
267+
return new SourceValueFetcher(name(), mapperService) {
268+
@Override
269+
protected Object parseSourceValue(Object value) {
270+
return valueParser.apply(value);
271+
}
272+
};
273+
}
266274
}
267275
}
268276

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.index.mapper;
21+
22+
import org.elasticsearch.common.Nullable;
23+
import org.elasticsearch.search.lookup.SourceLookup;
24+
25+
import java.util.ArrayList;
26+
import java.util.List;
27+
import java.util.Set;
28+
29+
/**
30+
* An implementation of {@link ValueFetcher} that knows how to extract values
31+
* from the document source.
32+
*
33+
* This class differs from {@link SourceValueFetcher} in that it directly handles
34+
* array values in parsing. Field types should use this class if their corresponding
35+
* mapper returns true for {@link FieldMapper#parsesArrayValue()}.
36+
*/
37+
public abstract class ArraySourceValueFetcher implements ValueFetcher {
38+
private final Set<String> sourcePaths;
39+
private final @Nullable Object nullValue;
40+
41+
public ArraySourceValueFetcher(String fieldName, MapperService mapperService) {
42+
this(fieldName, mapperService, null);
43+
}
44+
45+
/**
46+
* @param fieldName The name of the field.
47+
* @param mapperService A mapper service.
48+
* @param nullValue A optional substitute value if the _source value is 'null'.
49+
*/
50+
public ArraySourceValueFetcher(String fieldName, MapperService mapperService, Object nullValue) {
51+
this.sourcePaths = mapperService.sourcePath(fieldName);
52+
this.nullValue = nullValue;
53+
}
54+
55+
@Override
56+
public List<Object> fetchValues(SourceLookup lookup) {
57+
List<Object> values = new ArrayList<>();
58+
for (String path : sourcePaths) {
59+
Object sourceValue = lookup.extractValue(path, nullValue);
60+
if (sourceValue == null) {
61+
return List.of();
62+
}
63+
values.addAll((List<?>) parseSourceValue(sourceValue));
64+
}
65+
return values;
66+
}
67+
68+
/**
69+
* Given a value that has been extracted from a document's source, parse it into a standard
70+
* format. This parsing logic should closely mirror the value parsing in
71+
* {@link FieldMapper#parseCreateField} or {@link FieldMapper#parse}.
72+
*/
73+
protected abstract Object parseSourceValue(Object value);
74+
}

server/src/main/java/org/elasticsearch/index/mapper/BinaryFieldMapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public ValueFetcher valueFetcher(MapperService mapperService, SearchLookup searc
102102
if (format != null) {
103103
throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] doesn't support formats.");
104104
}
105-
return new SourceValueFetcher(name(), mapperService, false) {
105+
return new SourceValueFetcher(name(), mapperService) {
106106
@Override
107107
protected Object parseSourceValue(Object value) {
108108
return value;

0 commit comments

Comments
 (0)