Search code examples
elasticsearchelasticsearch-painless

Update mapping of an index from a simple mapping to an object mapping


Hi I am new to elasticsearch 7.9 update mapping, I came accross a use case where I have to update a simple field mapping to an object mapping, before I apply the query I created a simple example to test my purpose, here is what I have as an initial index mapping:

{
  "myindex" : {
    "mappings" : {
      "properties" : {
        "flag" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "title" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

I want to update the field name flag to tag and add to it a nested field called id which will contain the value of the field flag of the initial index myindex, I did the following steps :

  1. created the new index mynewindex with the following mapping :
PUT mynewindex/_mapping
{
"properties" : {
        "tag" : {
          "properties": {
            "id" : {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword"
                }
              }
            }
          }
        },
        "title" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword"
            }
          }
        }
      }
}
  1. and use reindex API:
POST _reindex
{
  "source": {
    "index": "myindex"
  },
  "dest": {
    "index": "mynewindex"
  },
  "script": {
    "source": "ctx._source.tag.id = ctx._source.remove(\"flag\")"
  }
}

which gave me this error :

{
  "error" : {
    "root_cause" : [
      {
        "type" : "script_exception",
        "reason" : "runtime error",
        "script_stack" : [
          "ctx._source.tag.id = ctx._source.remove(\"flag\")",
          "               ^---- HERE"
        ],
        "script" : "ctx._source.tag.id = ctx._source.remove(\"flag\")",
        "lang" : "painless",
        "position" : {
          "offset" : 15,
          "start" : 0,
          "end" : 47
        }
      }
    ],
    "type" : "script_exception",
    "reason" : "runtime error",
    "script_stack" : [
      "ctx._source.tag.id = ctx._source.remove(\"flag\")",
      "               ^---- HERE"
    ],
    "script" : "ctx._source.tag.id = ctx._source.remove(\"flag\")",
    "lang" : "painless",
    "position" : {
      "offset" : 15,
      "start" : 0,
      "end" : 47
    },
    "caused_by" : {
      "type" : "null_pointer_exception",
      "reason" : "Cannot invoke \"Object.getClass()\" because \"callArgs[0]\" is null"
    }
  },
  "status" : 400
}

The painless script found here in elastic doc, as I expected the dot notation to work, any suggestions or workaround to make it work!


Solution

  • Since tag is null it is giving null pointer, you have to create a map first.

    Below should work

    POST _reindex
    {
      "source": {
        "index": "myindex"
      },
      "dest": {
        "index": "mynewindex"
      },
      "script" : {
        "source": """
            if(ctx._source.tag == null) {
              ctx._source.tag = new HashMap();
            }
            if(ctx._source.flag != null) {
              ctx._source.tag.id = ctx._source.remove("flag")
            }
          """,
        "lang": "painless"
      }
    }