copy_to
The copy_to parameter allows you to copy the values of multiple fields into a group field, which can then be queried as a single field.
If you often search multiple fields, you can improve search speeds by using copy_to to search fewer fields. See Search as few fields as possible.
For example, the first_name and last_name fields can be copied to the full_name field as follows:
resp = client.indices.create(
index="my-index-000001",
mappings={
"properties": {
"first_name": {
"type": "text",
"copy_to": "full_name"
},
"last_name": {
"type": "text",
"copy_to": "full_name"
},
"full_name": {
"type": "text"
}
}
},
)
print(resp)
resp1 = client.index(
index="my-index-000001",
id="1",
document={
"first_name": "John",
"last_name": "Smith"
},
)
print(resp1)
resp2 = client.search(
index="my-index-000001",
query={
"match": {
"full_name": {
"query": "John Smith",
"operator": "and"
}
}
},
)
print(resp2) response = client.indices.create(
index: 'my-index-000001',
body: {
mappings: {
properties: {
first_name: {
type: 'text',
copy_to: 'full_name'
},
last_name: {
type: 'text',
copy_to: 'full_name'
},
full_name: {
type: 'text'
}
}
}
}
)
puts response
response = client.index(
index: 'my-index-000001',
id: 1,
body: {
first_name: 'John',
last_name: 'Smith'
}
)
puts response
response = client.search(
index: 'my-index-000001',
body: {
query: {
match: {
full_name: {
query: 'John Smith',
operator: 'and'
}
}
}
}
)
puts response const response = await client.indices.create({
index: "my-index-000001",
mappings: {
properties: {
first_name: {
type: "text",
copy_to: "full_name",
},
last_name: {
type: "text",
copy_to: "full_name",
},
full_name: {
type: "text",
},
},
},
});
console.log(response);
const response1 = await client.index({
index: "my-index-000001",
id: 1,
document: {
first_name: "John",
last_name: "Smith",
},
});
console.log(response1);
const response2 = await client.search({
index: "my-index-000001",
query: {
match: {
full_name: {
query: "John Smith",
operator: "and",
},
},
},
});
console.log(response2); PUT my-index-000001
{
"mappings": {
"properties": {
"first_name": {
"type": "text",
"copy_to": "full_name"
},
"last_name": {
"type": "text",
"copy_to": "full_name"
},
"full_name": {
"type": "text"
}
}
}
}
PUT my-index-000001/_doc/1
{
"first_name": "John",
"last_name": "Smith"
}
GET my-index-000001/_search
{
"query": {
"match": {
"full_name": {
"query": "John Smith",
"operator": "and"
}
}
}
} | The values of the | |
| The |
Some important points:
- It is the field value which is copied, not the terms (which result from the analysis process).
- The original
_sourcefield will not be modified to show the copied values. - The same value can be copied to multiple fields, with
"copy_to": [ "field_1", "field_2" ] -
You cannot copy recursively using intermediary fields. The following configuration will not copy data from
field_1tofield_3:resp = client.indices.create( index="bad_example_index", mappings={ "properties": { "field_1": { "type": "text", "copy_to": "field_2" }, "field_2": { "type": "text", "copy_to": "field_3" }, "field_3": { "type": "text" } } }, ) print(resp)const response = await client.indices.create({ index: "bad_example_index", mappings: { properties: { field_1: { type: "text", copy_to: "field_2", }, field_2: { type: "text", copy_to: "field_3", }, field_3: { type: "text", }, }, }, }); console.log(response);PUT bad_example_index { "mappings": { "properties": { "field_1": { "type": "text", "copy_to": "field_2" }, "field_2": { "type": "text", "copy_to": "field_3" }, "field_3": { "type": "text" } } } }Instead, copy to multiple fields from the source field:
resp = client.indices.create( index="good_example_index", mappings={ "properties": { "field_1": { "type": "text", "copy_to": [ "field_2", "field_3" ] }, "field_2": { "type": "text" }, "field_3": { "type": "text" } } }, ) print(resp)const response = await client.indices.create({ index: "good_example_index", mappings: { properties: { field_1: { type: "text", copy_to: ["field_2", "field_3"], }, field_2: { type: "text", }, field_3: { type: "text", }, }, }, }); console.log(response);PUT good_example_index { "mappings": { "properties": { "field_1": { "type": "text", "copy_to": ["field_2", "field_3"] }, "field_2": { "type": "text" }, "field_3": { "type": "text" } } } }
copy_to is not supported for field types where values take the form of objects, e.g. date_range.
Dynamic mapping
Consider the following points when using copy_to with dynamic mappings:
- If the target field does not exist in the index mappings, the usual dynamic mapping behavior applies. By default, with
dynamicset totrue, a non-existent target field will be dynamically added to the index mappings. - If
dynamicis set tofalse, the target field will not be added to the index mappings, and the value will not be copied. -
If
dynamicis set tostrict, copying to a non-existent field will result in an error.-
If the target field is nested, then
copy_tofields must specify the full path to the nested field. Omitting the full path will lead to astrict_dynamic_mapping_exception. Use"copy_to": ["parent_field.child_field"]to correctly target a nested field.For example:
resp = client.indices.create( index="test_index", mappings={ "dynamic": "strict", "properties": { "description": { "properties": { "notes": { "type": "text", "copy_to": [ "description.notes_raw" ], "analyzer": "standard", "search_analyzer": "standard" }, "notes_raw": { "type": "keyword" } } } } }, ) print(resp)const response = await client.indices.create({ index: "test_index", mappings: { dynamic: "strict", properties: { description: { properties: { notes: { type: "text", copy_to: ["description.notes_raw"], analyzer: "standard", search_analyzer: "standard", }, notes_raw: { type: "keyword", }, }, }, }, }, }); console.log(response);PUT /test_index { "mappings": { "dynamic": "strict", "properties": { "description": { "properties": { "notes": { "type": "text", "copy_to": [ "description.notes_raw"], "analyzer": "standard", "search_analyzer": "standard" }, "notes_raw": { "type": "keyword" } } } } } }
-
| The In this example, |
© 2023-2025 Elasticsearch
As of September 2024, Elasticsearch is available under a choice of three licenses: the Server Side Public License (SSPL), the Elastic License, or the AGPLv3 (OSI approved).
Elasticsearch and the Elasticsearch logo are trademarks of Elasticsearch B.V., registered in the U.S. and in other countries.
https://www.elastic.co/guide/en/elasticsearch/reference/8.17/copy-to.html