# How can I change an existing field type using Python?

**URL:** <https://discuss.elastic.co/t/how-can-i-change-an-existing-field-type-using-python/156968>\
**Category:** Elasticsearch\
**Created:** [November 16, 2018, 3:37am UTC](https://discuss.elastic.co/t/how-can-i-change-an-existing-field-type-using-python/156968 "2018-11-16T03:37:37Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![seanthegeek](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/seanthegeek/32/33421_2.png) [@seanthegeek](https://discuss.elastic.co/u/seanthegeek)\
**Post date:** [November 16, 2018, 3:37am UTC](https://discuss.elastic.co/t/how-can-i-change-an-existing-field-type-using-python/156968/1 "2018-11-16T03:37:38Z")

</div>

Hi Everyone,

I have an open source project that uses Elasticsearch and Kibana to visualize DMARC data for almost a year now.

> **[GitHub - domainaware/parsedmarc: A Python package and CLI for parsing...](https://github.com/domainaware/parsedmarc)**
>
> A Python package and CLI for parsing aggregate and forensic DMARC reports - GitHub - domainaware/parsedmarc: A Python package and CLI for parsing aggregate and forensic DMARC reports

Just recently, a user found a bug where I mapped a field to a `long` when it should be `text` (it went unnoticed for so long because the value is _almost_ always `"0"`.

> <https://github.com/domainaware/parsedmarc/issues/31>
>
> Fresh Install, Ubuntu 18.04.1
> 
> Python 3.6.6
> parsedmarc 4.3.8
> elasticsearch: …6.4.3
> 
> Reports seem to grab okay via IMAP, but fail when trying to import to elasticsearch.
> 
> Traceback (most recent call last):
> File "/usr/local/bin/parsedmarc", line 11, in \<module\>
> sys.exit(\_main())
> File "/opt/venvs/parsedmarc/site-packages/parsedmarc/cli.py", line 333, in \_main
> process\_reports(results)
> File "/opt/venvs/parsedmarc/site-packages/parsedmarc/cli.py", line 42, in process\_reports
> report, index=es\_aggregate\_index)
> File "/opt/venvs/parsedmarc/site-packages/parsedmarc/elastic.py", line 292, in save\_aggregate\_report\_to\_elasticsearch
> agg\_doc.save()
> File "/opt/venvs/parsedmarc/site-packages/parsedmarc/elastic.py", line 88, in save
> return super().save(\*\* kwargs)
> File "/opt/venvs/parsedmarc/site-packages/elasticsearch\_dsl/document.py", line 383, in save
> self.full\_clean()
> File "/opt/venvs/parsedmarc/site-packages/elasticsearch\_dsl/utils.py", line 444, in full\_clean
> self.clean\_fields()
> File "/opt/venvs/parsedmarc/site-packages/elasticsearch\_dsl/utils.py", line 430, in clean\_fields
> data = field.clean(data)
> File "/opt/venvs/parsedmarc/site-packages/elasticsearch\_dsl/field.py", line 207, in clean
> data.full\_clean()
> File "/opt/venvs/parsedmarc/site-packages/elasticsearch\_dsl/utils.py", line 444, in full\_clean
> self.clean\_fields()
> File "/opt/venvs/parsedmarc/site-packages/elasticsearch\_dsl/utils.py", line 430, in clean\_fields
> data = field.clean(data)
> File "/opt/venvs/parsedmarc/site-packages/elasticsearch\_dsl/field.py", line 95, in clean
> data = self.deserialize(data)
> File "/opt/venvs/parsedmarc/site-packages/elasticsearch\_dsl/field.py", line 91, in deserialize
> return self.\_deserialize(data)
> File "/opt/venvs/parsedmarc/site-packages/elasticsearch\_dsl/field.py", line 314, in \_deserialize
> return int(data)
> ValueError: invalid literal for int() with base 10: '0:1:d:s'

So now I need to find a way to correct this field type in every user's index and Kibana index pattern, preferably in a fully automated way.

My attempt at doing this failed, but hopefully it gives you a good idea of what I'm going for:

```python
def migrate_indexes(aggregate_indexes=None, forensic_indexes=None):
    """
    Updates index mappings

    Args:
        aggregate_indexes (list): A list of aggregate index names
        forensic_indexes (list): A list of forensic index names
    """
    if aggregate_indexes is None:
        aggregate_indexes = []
    if forensic_indexes is None:
        forensic_indexes = []
    for aggregate_index_name in aggregate_indexes:
        aggregate_index = Index(aggregate_index_name)
        body = { "properties": {"published_policy.fo": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            }
        }
        }
        doc = "doc"
        fo_field = "published_policy.fo"
        fo = "fo"
        fo_mapping = aggregate_index.get_field_mapping(fields=[fo_field])[
            aggregate_index_name]["mappings"][doc][fo_field]["mapping"][fo]
        fo_type = fo_mapping["type"]
        if fo_type == "long":
            aggregate_index.put_mapping(doc_type=doc, body=body)
    for forensic_index in forensic_indexes:
        pass

```

> elasticsearch.exceptions.RequestError: RequestError(400, 'illegal\_argument\_exception', 'mapper [published\_policy.fo] of different type, current\_type [long], merged\_type [text]')

What am I doing wrong, and how can I fix this mess?

---

<div class="post-metadata">

**Author:** ![warkolm](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/warkolm/32/39224_2.png) [@warkolm](https://discuss.elastic.co/u/warkolm)\
**Post date:** [November 16, 2018, 3:38am UTC](https://discuss.elastic.co/t/how-can-i-change-an-existing-field-type-using-python/156968/2 "2018-11-16T03:38:58Z")

</div>

You cannot change a mapping once it is in place.  
Your best option would be to use a template and then update that, so future indices use the correct format.

---

<div class="post-metadata">

**Author:** ![seanthegeek](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/seanthegeek/32/33421_2.png) [@seanthegeek](https://discuss.elastic.co/u/seanthegeek)\
**Post date:** [November 16, 2018, 3:44am UTC](https://discuss.elastic.co/t/how-can-i-change-an-existing-field-type-using-python/156968/3 "2018-11-16T03:44:29Z")

</div>

Thanks for the very fast reply. Is there any way to copy the existing data over to a new index with the correct mapping, so I don't lose data?

---

<div class="post-metadata">

**Author:** ![warkolm](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/warkolm/32/39224_2.png) [@warkolm](https://discuss.elastic.co/u/warkolm)\
**Post date:** [November 16, 2018, 4:03am UTC](https://discuss.elastic.co/t/how-can-i-change-an-existing-field-type-using-python/156968/4 "2018-11-16T04:03:59Z")

</div>

You can do a reindex into a new index, then delete the old index and put an alias on the new index so it can still be queried via the original name.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [December 14, 2018, 4:04am UTC](https://discuss.elastic.co/t/how-can-i-change-an-existing-field-type-using-python/156968/5 "2018-12-14T04:04:06Z")

</div>

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.
