I need to remove a field in all the documents indexed to Elasticsearch. How can I do it?
-
5By default it's not possible, because right now Lucene doesn't support that. Basically you can only put or remove whole Lucene documents from Lucene indices. 1 Get the first version of your doc 2 remove the field 3 push this new version of your doc. – backtrack Mar 12 '15 at 05:16
-
Thanks for sharing https://stackoverflow.com/a/53771354/8392866 Thiagofalcao. This is great! – Mark Apr 03 '19 at 14:56
-
The only way I could complete this was by remapping the index with the deleted field value. Check out https://stackoverflow.com/a/38874129/13543225 – j7skov Jan 11 '22 at 16:19
8 Answers
What @backtrack told is true , but then there is a very convenient way of doing this in Elasticsearch. Elasticsearch will abstract out the internal complexity of the deletion. You need to use update API to achieve this -
curl -XPOST 'localhost:9200/test/type1/1/_update' -d '{
"script" : "ctx._source.remove(\"name_of_field\")"
}'
You can find more documentation here.
Note: As of Elastic Search 6 you are required to include a content-type header:
-H 'Content-Type: application/json'

- 1
- 1

- 18,633
- 8
- 63
- 77
-
4What is the performance of this if you have a billion documents with this field? – Henley Jul 14 '16 at 20:00
-
1The actual document will get removed and a new one will get added for each of such change. – Vineeth Mohan Jul 15 '16 at 06:54
-
1Notice for ElasticSearch 5.0: you should use a named parameter instead of the hardcoded name. Parametes are faster and they won't break script's compilation limit. See [documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-scripting-using.html#prefer-params). – Antony Zh Nov 10 '16 at 13:05
-
2@VineethMohan will it also remove the mapping too ? so if i query test/type1/_mapping, will it show 'name_of_field' ? so basically, i want to remove and add the same filed name with diff type. Is it possible wit this ? – lrathod Jan 16 '19 at 04:21
-
Additionally if you are referencing nested fields with hyphens, you can use `ctx._source[\"my-field\"].remove(\"subfield\")`. – Martin Foot Nov 16 '21 at 13:34
Elasticsearch added update_by_query
in 2.3. This experimental interface allows you to do the update against all the documents that match a query.
Internally elasticsearch does a scan/scroll to collect batches of documents and then update them like the bulk update interface. This is faster than doing it manually with your own scan/scroll interface due to not having the overhead of network and serialization. Each record must be loaded into ram, modified and then written.
Yesterday I removed a large field from my ES cluster. I saw sustained throughput of 10,000 records per second during the update_by_query, constrained by CPU rather than IO.
Look into setting conflicts=proceed
if the cluster has other update traffic, or the whole job will stop when it hits a ConflictError
when one of the records is updated underneath one of the batches.
Similarly setting wait_for_completion=false
will cause the update_by_query to run via the tasks interface. Otherwise the job will terminate if the connection is closed.
url:
http://localhost:9200/INDEX/TYPE/_update_by_query?wait_for_completion=false&conflicts=proceed
POST body:
{
"script": "ctx._source.remove('name_of_field')",
"query": {
"bool": {
"must": [
{
"exists": {
"field": "name_of_field"
}
}
]
}
}
}
As of Elasticsearch 1.43, inline groovy scripting is disabled by default. You'll need to enable it for an inline script like this to work by adding script.inline: true
to your config file.
Or upload the groovy as a script and use the "script": { "file": "scriptname", "lang": "groovy"}
format.

- 3,136
- 22
- 25

- 4,399
- 31
- 30
-
What I don't know yet, is how to reclaim the field_data space used by that field. Hoping a rolling restart will cause the ordinals to be reloaded. – spazm Oct 05 '16 at 21:50
-
3The body needed a slight modification, but otherwise this works perfectly. I had to wrap the script in a JSON object, probably because the API changed a bit. – Peter Jan 08 '18 at 09:22
-
1If my field is part of the array(for e.g [{"name":"test"},{"name":"test1"}] )and I don't know the index of the array for that field So how I can delete the field by using above query. Please Help me into this? – Suraj Dalvi Apr 09 '18 at 05:31
-
1
-
1
You can use _update_by_query
Example 1
index: my_index
field: user.email
POST my_index/_update_by_query?conflicts=proceed
{
"script" : "ctx._source.user.remove('email')",
"query" : {
"exists": { "field": "user.email" }
}
}
Example 2
index: my_index
field: total_items
POST my_index/_update_by_query?conflicts=proceed
{
"script" : "ctx._source.remove('total_items')",
"query" : {
"exists": { "field": "total_items" }
}
}

- 4,463
- 39
- 34
-
Hii, I tried the exact same approach as you mentioned here but it didn't seem working for me. I am a newbie in this area. I have an unwanted field in my index say index name "test_xyz". This contains almost 155154 documents. I want to remove an unwanted field from my index. This is how my index pattern look like in json format {A : {B : {C: } } }. I basically want to remove the B - means C will be automatically remove from my index. In order to do that, I used your first idea. Put A as user, B as email. Can you please help me to solve this? – Maunil Vyas Sep 29 '19 at 19:40
-
Hi @MaunilVyas, It should work: POST my_index/_update_by_query?conflicts=proceed { "script" : "ctx._source.A.remove('B')", "query" : { "exists": { "field": "A.B" } } } If it does not work, you need to reindex data with target index with correct mapping. – Thiago Falcao Sep 30 '19 at 16:56
-
1Thank you for your response. Yes it is working now. I did some minor mistakes! – Maunil Vyas Sep 30 '19 at 18:25
-
-
1hello, is this operation also deleting the field from mapping? It is not, right? – srcnaks May 05 '20 at 10:44
-
Hi @srcnaks in order to remove from mapping, you need to reindex from source index to target index. – Thiago Falcao May 05 '20 at 13:04
-
1This answer helped me understand deletion of *nested* fields. Thanks! – Akhilesh Bhatia Jun 11 '20 at 15:25
-
The previous answers did'nt worked for me.
I had to add the keyword "inline":
POST /my_index/_update_by_query
{
"script": {
"inline": "ctx._source.remove(\"myfield\")"
},
"query" : {
"exists": { "field": "myfield" }
}
}

- 478
- 4
- 6
By default it's not possible, because right now Lucene doesn't support that. Basically you can only put or remove whole Lucene documents from Lucene indices.
- Get the first version of your doc
- remove the field
- push this new version of your doc
This answer is valid for version < ES 5.

- 7,996
- 5
- 52
- 99
-
2@ThomasDecaux, Many thanks. I have answered in 2015 and i know that ES has the ability now. Once again thank you for poining it. – backtrack Jun 21 '18 at 05:18
-
@ThomasDecaux - Indeed that is true. thanks for your valuable feedback. I just added the version. – backtrack Nov 15 '19 at 12:02
For those who stick to bulk API, the alternative to achieve deletion on field(s) of document(s) is to provide extra script in the update
action payload of a bulk API call.
The command part is the same as described in official documentation :
curl -s -H "Content-Type: application/x-ndjson" -H "Accept: application/json; indent=4;" \
--data-binary '@es_bulk_edit_data.json' --request POST \
"http://YOUR_ELASTICSEARCH_HOST:PORT_NUM/OPTIONAL_INDEX/OPTIONAL_TYPE/_bulk?pretty"
In the request body file, you may need to use 2 payloads for the same document, one of them is for creating, updating fields, the other is for deleting fields by script, which may be like this:
// assume you attempt to add one field `artist`, update one field `num_views`,
// and delete one field `useless` in the document with type t1 and ID 123
{"update": {"_type": "t1", "_id": "123"}}
{"doc": {"artist": "new_artist", "num_views": 67}}
{"update": {"_type": "t1", "_id": "123"}}
{"script": {"source": "ctx._source.remove(params.del_field_name)", "lang":"painless", "params":{"del_field_name": "useless"}}}
Note :
- In bulk API,
doc
section cannot be placed withscript
section in the same payload, ElasticSearch seems to refuse to process such payload structure and return error response400 bad request
and reason message would beValidation Failed: 1: can't provide both script and doc;
. That is why I separate deletion and all other operations in 2 payloads. - these are tested on version 5.6 and 6.6, should also get the same result in latest version (v7.10)

- 703
- 8
- 17
PUT /products/_update/1
{
"docs" :{
"price": 12,
"quantity": 3,
"in_stock": 6
}
}
Now if I need to remove "quantity" then:
POST products/_update/1
{
"script": {
"source": "ctx._source.remove(\"quantity\")"
}
}

- 41
- 5
I would like to add to the previous answers that after deleting the field, the size of the index will not change. will have to create a new index or use _reindex api.
curl -X POST "localhost:9200/_reindex?pretty" -H 'Content-Type: application/json' -d'
{
"source": {
"index": "old-index"
},
"dest": {
"index": "new-index"
}}
'

- 504
- 4
- 9
-
1This is not true, after deleting a certain deal of document segments will get merged and disk space is freed. The only thing that remains there is the field in schema. – Arman Ordookhani Aug 09 '23 at 15:12