copy_to
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 _source field 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_1
tofield_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 dynamic set to
true
, a non-existent target field will be dynamically added to the index mappings. - If
dynamic
is set tofalse
, the target field will not be added to the index mappings, and the value will not be copied. If
dynamic
is set tostrict
, copying to a non-existent field will result in an error.If the target field is nested, then
copy_to
fields 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, |