Skip to content

Commit c04a956

Browse files
Do not respect synthetic_source_keep=arrays if type parses arrays (elastic#127796)
Types that parse arrays directly should not need to store values in _ignored_source if synthetic_source_keep=arrays. Since they have custom handling of arrays, it provides no benefit to store in _ignored_source when there are multiple values of the type.
1 parent 8ad2723 commit c04a956

File tree

4 files changed

+17
-68
lines changed

4 files changed

+17
-68
lines changed

docs/changelog/127796.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 127796
2+
summary: Do not respect synthetic_source_keep=arrays if type parses arrays
3+
area: Mapping
4+
type: enhancement
5+
issues:
6+
- 126155

docs/reference/elasticsearch/mapping-reference/geo-point.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,9 @@ of official GA features.
218218

219219

220220
Synthetic source may sort `geo_point` fields (first by latitude and then
221-
longitude) and reduces them to their stored precision. For example:
221+
longitude) and reduces them to their stored precision. Additionally, unlike most
222+
types, arrays of `geo_point` fields will not preserve order if
223+
`synthetic_source_keep` is set to `arrays`. For example:
222224

223225
$$$synthetic-source-geo-point-example$$$
224226

@@ -236,15 +238,18 @@ PUT idx
236238
},
237239
"mappings": {
238240
"properties": {
239-
"point": { "type": "geo_point" }
241+
"point": {
242+
"type": "geo_point",
243+
"synthetic_source_keep": "arrays"
244+
}
240245
}
241246
}
242247
}
243248
PUT idx/_doc/1
244249
{
245250
"point": [
246-
{"lat":-90, "lon":-80},
247-
{"lat":10, "lon":30}
251+
{"lat":10, "lon":30},
252+
{"lat":-90, "lon":-80}
248253
]
249254
}
250255
```

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ static void parseObjectOrField(DocumentParserContext context, Mapper mapper) thr
460460
if (context.canAddIgnoredField()
461461
&& (fieldMapper.syntheticSourceMode() == FieldMapper.SyntheticSourceMode.FALLBACK
462462
|| sourceKeepMode == Mapper.SourceKeepMode.ALL
463-
|| (sourceKeepMode == Mapper.SourceKeepMode.ARRAYS && context.inArrayScope())
463+
|| (sourceKeepMode == Mapper.SourceKeepMode.ARRAYS && context.inArrayScope() && parsesArrayValue(mapper) == false)
464464
|| (context.isWithinCopyTo() == false && context.isCopyToDestinationField(mapper.fullPath())))) {
465465
context = context.addIgnoredFieldFromContext(
466466
IgnoredSourceFieldMapper.NameValue.fromContext(context, fieldMapper.fullPath(), null)

server/src/test/java/org/elasticsearch/index/mapper/blockloader/GeoPointFieldBlockLoaderTests.java

Lines changed: 1 addition & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import org.elasticsearch.index.mapper.MappedFieldType;
1818

1919
import java.nio.ByteOrder;
20-
import java.util.ArrayList;
2120
import java.util.Comparator;
2221
import java.util.List;
2322
import java.util.Map;
@@ -30,10 +29,7 @@ public GeoPointFieldBlockLoaderTests(BlockLoaderTestCase.Params params) {
3029

3130
@Override
3231
@SuppressWarnings("unchecked")
33-
protected Object expected(Map<String, Object> fieldMapping, Object value, TestContext testContext) {
34-
var extractedFieldValues = (ExtractedFieldValues) value;
35-
var values = extractedFieldValues.values();
36-
32+
protected Object expected(Map<String, Object> fieldMapping, Object values, TestContext testContext) {
3733
var nullValue = switch (fieldMapping.get("null_value")) {
3834
case String s -> convert(s, null, false);
3935
case null -> null;
@@ -75,9 +71,6 @@ protected Object expected(Map<String, Object> fieldMapping, Object value, TestCo
7571
if (syntheticSourceKeep.equals("all")) {
7672
return exactValuesFromSource(values, nullValue, false);
7773
}
78-
if (syntheticSourceKeep.equals("arrays") && extractedFieldValues.documentHasObjectArrays()) {
79-
return exactValuesFromSource(values, nullValue, false);
80-
}
8174

8275
// synthetic source and doc_values are present
8376
if (hasDocValues(fieldMapping, true)) {
@@ -112,61 +105,6 @@ private Object exactValuesFromSource(Object value, GeoPoint nullValue, boolean n
112105
return maybeFoldList(resultList);
113106
}
114107

115-
private record ExtractedFieldValues(Object values, boolean documentHasObjectArrays) {}
116-
117-
@Override
118-
protected Object getFieldValue(Map<String, Object> document, String fieldName) {
119-
var extracted = new ArrayList<>();
120-
var documentHasObjectArrays = processLevel(document, fieldName, extracted, false);
121-
122-
if (extracted.size() == 1) {
123-
return new ExtractedFieldValues(extracted.get(0), documentHasObjectArrays);
124-
}
125-
126-
return new ExtractedFieldValues(extracted, documentHasObjectArrays);
127-
}
128-
129-
@SuppressWarnings("unchecked")
130-
private boolean processLevel(Map<String, Object> level, String field, ArrayList<Object> extracted, boolean documentHasObjectArrays) {
131-
if (field.contains(".") == false) {
132-
var value = level.get(field);
133-
processLeafLevel(value, extracted);
134-
return documentHasObjectArrays;
135-
}
136-
137-
var nameInLevel = field.split("\\.")[0];
138-
var entry = level.get(nameInLevel);
139-
if (entry instanceof Map<?, ?> m) {
140-
return processLevel((Map<String, Object>) m, field.substring(field.indexOf('.') + 1), extracted, documentHasObjectArrays);
141-
}
142-
if (entry instanceof List<?> l) {
143-
for (var object : l) {
144-
processLevel((Map<String, Object>) object, field.substring(field.indexOf('.') + 1), extracted, true);
145-
}
146-
return true;
147-
}
148-
149-
assert false : "unexpected document structure";
150-
return false;
151-
}
152-
153-
private void processLeafLevel(Object value, ArrayList<Object> extracted) {
154-
if (value instanceof List<?> l) {
155-
if (l.size() > 0 && l.get(0) instanceof Double) {
156-
// this must be a single point in array form
157-
// we'll put it into a different form here to make our lives a bit easier while implementing `expected`
158-
extracted.add(Map.of("type", "point", "coordinates", l));
159-
} else {
160-
// this is actually an array of points but there could still be points in array form inside
161-
for (var arrayValue : l) {
162-
processLeafLevel(arrayValue, extracted);
163-
}
164-
}
165-
} else {
166-
extracted.add(value);
167-
}
168-
}
169-
170108
@SuppressWarnings("unchecked")
171109
private GeoPoint convert(Object value, GeoPoint nullValue, boolean needsMultifieldAdjustment) {
172110
if (value == null) {

0 commit comments

Comments
 (0)