Skip to content

Commit 1ec137d

Browse files
authored
Support arrays in fallback synthetic source implementation (#108878)
This PR extends #108222 adding support for arrays.
1 parent 9d52fce commit 1ec137d

File tree

5 files changed

+53
-7
lines changed

5 files changed

+53
-7
lines changed

docs/changelog/108878.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 108878
2+
summary: Support arrays in fallback synthetic source implementation
3+
area: Mapping
4+
type: feature
5+
issues: []

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

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -827,12 +827,25 @@ protected boolean supportsIgnoreMalformed() {
827827
@Override
828828
protected SyntheticSourceSupport syntheticSourceSupport(boolean syntheticSource) {
829829
return new SyntheticSourceSupport() {
830+
@Override
831+
public boolean preservesExactSource() {
832+
return true;
833+
}
834+
830835
public SyntheticSourceExample example(int maxValues) {
831-
String value = rarely()
836+
if (randomBoolean()) {
837+
var value = generateValue();
838+
return new SyntheticSourceExample(value, value, this::mapping);
839+
}
840+
841+
var array = randomList(1, 5, this::generateValue);
842+
return new SyntheticSourceExample(array, array, this::mapping);
843+
}
844+
845+
private Object generateValue() {
846+
return rarely()
832847
? null
833848
: randomList(0, 10, () -> randomAlphaOfLengthBetween(0, 10)).stream().collect(Collectors.joining(" "));
834-
835-
return new SyntheticSourceExample(value, value, this::mapping);
836849
}
837850

838851
private void mapping(XContentBuilder b) throws IOException {

modules/mapper-extras/src/yamlRestTest/resources/rest-api-spec/test/search-as-you-type/30_synthetic_source.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ setup:
3030
body:
3131
a_field: null
3232

33+
- do:
34+
index:
35+
index: test
36+
id: "3"
37+
body:
38+
a_field: ["quick brown", "fox", "jumps"]
39+
3340
- do:
3441
indices.refresh: {}
3542

@@ -46,3 +53,10 @@ setup:
4653
id: "2"
4754

4855
- match: { _source.a_field: null }
56+
57+
- do:
58+
get:
59+
index: test
60+
id: "3"
61+
62+
- match: { _source.a_field: ["quick brown", "fox", "jumps"] }

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,10 @@ private static void parseNonDynamicArray(
625625
) throws IOException {
626626
// Check if we need to record the array source. This only applies to synthetic source.
627627
if (context.mappingLookup().isSourceSynthetic() && context.getClonedSource() == false) {
628-
if ((mapper instanceof ObjectMapper objectMapper && objectMapper.storeArraySource()) || mapper instanceof NestedObjectMapper) {
628+
boolean storeArraySourceEnabled = mapper instanceof ObjectMapper objectMapper && objectMapper.storeArraySource();
629+
boolean fieldWithFallbackSyntheticSource = mapper instanceof FieldMapper fieldMapper
630+
&& fieldMapper.syntheticSourceMode() == FieldMapper.SyntheticSourceMode.FALLBACK;
631+
if (storeArraySourceEnabled || fieldWithFallbackSyntheticSource || mapper instanceof NestedObjectMapper) {
629632
// Clone the DocumentParserContext to parse its subtree twice.
630633
Tuple<DocumentParserContext, XContentBuilder> tuple = XContentDataHelper.cloneSubContext(context);
631634
context.addIgnoredField(

test/framework/src/main/java/org/elasticsearch/index/mapper/MapperTestCase.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,14 @@ private Object expectedParsedForBlockLoader() throws IOException {
10921092
public record SyntheticSourceInvalidExample(Matcher<String> error, CheckedConsumer<XContentBuilder, IOException> mapping) {}
10931093

10941094
public interface SyntheticSourceSupport {
1095+
/**
1096+
* @return True if synthetic source support is implemented to exactly store the source
1097+
* without modifications.
1098+
*/
1099+
default boolean preservesExactSource() {
1100+
return false;
1101+
}
1102+
10951103
/**
10961104
* Examples that should work when source is generated from doc values.
10971105
*/
@@ -1177,7 +1185,7 @@ public final void testSyntheticSourceMany() throws IOException {
11771185
) {
11781186
for (int i = 0; i < count; i++) {
11791187
if (rarely() && supportsEmptyInputArray()) {
1180-
expected[i] = "{}";
1188+
expected[i] = support.preservesExactSource() ? "{\"field\":[]}" : "{}";
11811189
iw.addDocument(mapper.parse(source(b -> b.startArray("field").endArray())).rootDoc());
11821190
continue;
11831191
}
@@ -1236,13 +1244,16 @@ public final void testSyntheticSourceInObject() throws IOException {
12361244
public final void testSyntheticEmptyList() throws IOException {
12371245
assumeTrue("Field does not support [] as input", supportsEmptyInputArray());
12381246
boolean ignoreMalformed = supportsIgnoreMalformed() ? rarely() : false;
1239-
SyntheticSourceExample syntheticSourceExample = syntheticSourceSupport(ignoreMalformed).example(5);
1247+
SyntheticSourceSupport support = syntheticSourceSupport(ignoreMalformed);
1248+
SyntheticSourceExample syntheticSourceExample = support.example(5);
12401249
DocumentMapper mapper = createDocumentMapper(syntheticSourceMapping(b -> {
12411250
b.startObject("field");
12421251
syntheticSourceExample.mapping().accept(b);
12431252
b.endObject();
12441253
}));
1245-
assertThat(syntheticSource(mapper, b -> b.startArray("field").endArray()), equalTo("{}"));
1254+
1255+
var expected = support.preservesExactSource() ? "{\"field\":[]}" : "{}";
1256+
assertThat(syntheticSource(mapper, b -> b.startArray("field").endArray()), equalTo(expected));
12461257
}
12471258

12481259
public final void testSyntheticEmptyListNoDocValuesLoader() throws IOException {

0 commit comments

Comments
 (0)