Skip to content

Commit ccbc3a1

Browse files
committed
Throw an exception if aliases are specified as the target of copy_to.
1 parent e51c9ee commit ccbc3a1

File tree

3 files changed

+47
-7
lines changed

3 files changed

+47
-7
lines changed

docs/reference/mapping/types/alias.asciidoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ field alias to query over multiple target fields in a single clause.
7474
==== Unsupported APIs
7575

7676
Writes to field aliases are not supported: attempting to use an alias in an index or update request
77-
will result in a failure.
77+
will result in a failure. This also precludes aliases from being the target of `copy_to`.
7878

7979
Because alias names are not present in the document source, aliases cannot be used when performing
8080
source filtering. For example, the following request will return an empty result for `_source`:

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

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -832,18 +832,25 @@ private static void parseCopyFields(ParseContext context, List<String> copyToFie
832832

833833
/** Creates an copy of the current field with given field name and boost */
834834
private static void parseCopy(String field, ParseContext context) throws IOException {
835-
FieldMapper fieldMapper = context.docMapper().mappers().getFieldMapper(field);
836-
if (fieldMapper != null) {
837-
fieldMapper.parse(context);
835+
Mapper mapper = context.docMapper().mappers().getMapper(field);
836+
if (mapper != null) {
837+
if (mapper instanceof FieldMapper) {
838+
((FieldMapper) mapper).parse(context);
839+
} else if (mapper instanceof FieldAliasMapper) {
840+
throw new IllegalArgumentException("Cannot copy to a field alias [" + mapper.name() + "].");
841+
} else {
842+
throw new IllegalStateException("The provided mapper [" + mapper.name() +
843+
"] has an unrecognized type [" + mapper.getClass().getSimpleName() + "].");
844+
}
838845
} else {
839846
// The path of the dest field might be completely different from the current one so we need to reset it
840847
context = context.overridePath(new ContentPath(0));
841848

842849
final String[] paths = splitAndValidatePath(field);
843850
final String fieldName = paths[paths.length-1];
844851
Tuple<Integer, ObjectMapper> parentMapperTuple = getDynamicParentMapper(context, paths, null);
845-
ObjectMapper mapper = parentMapperTuple.v2();
846-
parseDynamicValue(context, mapper, fieldName, context.parser().currentToken());
852+
ObjectMapper objectMapper = parentMapperTuple.v2();
853+
parseDynamicValue(context, objectMapper, fieldName, context.parser().currentToken());
847854
for (int i = 0; i < parentMapperTuple.v1(); i++) {
848855
context.path().remove();
849856
}

server/src/test/java/org/elasticsearch/index/mapper/DocumentParserTests.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1390,7 +1390,7 @@ public void testBlankFieldNames() throws Exception {
13901390
assertThat(ExceptionsHelper.detailedMessage(err), containsString("field name cannot be an empty string"));
13911391
}
13921392

1393-
public void testFieldAlias() throws Exception {
1393+
public void testWriteToFieldAlias() throws Exception {
13941394
String mapping = Strings.toString(XContentFactory.jsonBuilder()
13951395
.startObject()
13961396
.startObject("type")
@@ -1419,6 +1419,39 @@ public void testFieldAlias() throws Exception {
14191419
assertEquals("Cannot write to a field alias [alias-field].", exception.getCause().getMessage());
14201420
}
14211421

1422+
public void testCopyToFieldAlias() throws Exception {
1423+
String mapping = Strings.toString(XContentFactory.jsonBuilder()
1424+
.startObject()
1425+
.startObject("type")
1426+
.startObject("properties")
1427+
.startObject("alias-field")
1428+
.field("type", "alias")
1429+
.field("path", "concrete-field")
1430+
.endObject()
1431+
.startObject("concrete-field")
1432+
.field("type", "keyword")
1433+
.endObject()
1434+
.startObject("text-field")
1435+
.field("type", "text")
1436+
.field("copy_to", "alias-field")
1437+
.endObject()
1438+
.endObject()
1439+
.endObject()
1440+
.endObject());
1441+
1442+
DocumentMapperParser mapperParser = createIndex("test").mapperService().documentMapperParser();
1443+
DocumentMapper mapper = mapperParser.parse("type", new CompressedXContent(mapping));
1444+
1445+
BytesReference bytes = BytesReference.bytes(XContentFactory.jsonBuilder()
1446+
.startObject()
1447+
.field("text-field", "value")
1448+
.endObject());
1449+
MapperParsingException exception = expectThrows(MapperParsingException.class,
1450+
() -> mapper.parse(SourceToParse.source("test", "type", "1", bytes, XContentType.JSON)));
1451+
1452+
assertEquals("Cannot copy to a field alias [alias-field].", exception.getCause().getMessage());
1453+
}
1454+
14221455
public void testDynamicDottedFieldNameWithFieldAlias() throws Exception {
14231456
String mapping = Strings.toString(XContentFactory.jsonBuilder()
14241457
.startObject()

0 commit comments

Comments
 (0)