Using Scripted Conditionals

Hello,

so I've got an index called Hamlet. And in Hamlet there is a field "Speaker" with value of the name of the speaker. So it looks like this:

{
"speaker": "Hamlet"
}

Now I want to make script which will:
Create a script named set_is_hamlet and save it into the cluster state. The script (i) adds a field named is_hamlet to each document, (ii) sets the field to "true" if the document has speaker equals to "HAMLET", (iii) sets the field to "false" otherwise.

How would the script look like?

Not sure what you mean by naming a script, a pipeline can be named but an inline script used in an update_by_query has no name. For the sake of simplicity I'll write the script as for use by the latter. But first a comment:

Index names in Elasticsearch must be lower case (at least up until version 6.8).

So I opened Kibana in my test cluster and created an index named hamlet by adding four small documents of the format you mentioned. E.g:

PUT /hamlet/_doc/1
{
    "speaker": "Ophelia"
}
... etc

The result looks like this:

GET /hamlet/_search
...
  "hits" : {
    "total" : 4,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "hamlet",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "speaker" : "Hamlet"
        }
      },
      {
        "_index" : "hamlet",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 1.0,
        "_source" : {
          "speaker" : "HAMLET"
        }
      },
      {
        "_index" : "hamlet",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "speaker" : "Ophelia"
        }
      },
      {
        "_index" : "hamlet",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "speaker" : "Laertes"
        }
      }
    ]
  }

The final step is to write a small painless script and use it in an _update_by_query, like this:

POST /hamlet/_update_by_query
{
   "script": {
      "lang": "painless",
      "source": """
         if (ctx._source.speaker == "HAMLET") {
            ctx._source.set_is_hamlet = true
         } else {
            ctx._source.set_is_hamlet = false
         }
               """
    }
 }

This correctly found the documents with speaker "HAMLET" and set its set_is_hamlet to true while the rest were set false (notice that Elasticsearch is case sensitive, so only speaker HAMLET gets set_is_hamlet: true):

GET hamlet/_search
...
  "hits" : {
    "total" : 4,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "hamlet",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "set_is_hamlet" : false,
          "speaker" : "Hamlet"
        }
      },
      {
        "_index" : "hamlet",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 1.0,
        "_source" : {
          "set_is_hamlet" : true,
          "speaker" : "HAMLET"
        }
      },
      {
        "_index" : "hamlet",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "set_is_hamlet" : false,
          "speaker" : "Ophelia"
        }
      },
      {
        "_index" : "hamlet",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "set_is_hamlet" : false,
          "speaker" : "Laertes"
        }
      }
    ]
  }

I hope this answered your question.

1 Like

What I meant was to create a templated script and save it into cluster state, using your code below.

POST _scripts/script_hamlet_example
{
   "script": {
      "lang": "painless",
      "source": """
         if (ctx._source.speaker == "HAMLET") {
            ctx._source.set_is_hamlet = true
         } else {
            ctx._source.set_is_hamlet = false
         }
               """
    }
 }

And yes! Thank you for helping, you made it seem so simple :slight_smile:.

1 Like

Oh, I see. I haven't stored scripts to the cluster before, only used them in pipelines or _update_by_query statements.

I'm glad you found your solution :slight_smile:

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