[[modules-scripting-using]]
=== How to use scripts

Wherever scripting is supported in the Elasticsearch API, the syntax follows
the same pattern:

[source,js]
-------------------------------------
  "script": {
    "lang":   "...",  <1>
    "source" | "id": "...", <2>
    "params": { ... } <3>
  }
-------------------------------------
// NOTCONSOLE
<1> The language the script is written in, which defaults to `painless`.
<2> The script itself which may be specified as `source` for an inline script or `id` for a stored script.
<3> Any named parameters that should be passed into the script.

For example, the following script is used in a search request to return a
<<search-request-script-fields, scripted field>>:

[source,js]
-------------------------------------
PUT my_index/_doc/1
{
  "my_field": 5
}

GET my_index/_search
{
  "script_fields": {
    "my_doubled_field": {
      "script": {
        "lang":   "expression",
        "source": "doc['my_field'] * multiplier",
        "params": {
          "multiplier": 2
        }
      }
    }
  }
}
-------------------------------------
// CONSOLE

[float]
=== Script Parameters

`lang`::

    Specifies the language the script is written in.  Defaults to `painless`.


`source`, `id`::

    Specifies the source of the script.  An `inline` script is specified
    `source` as in the example above. A `stored` script is specified `id`
    and is retrieved from the cluster state (see <<modules-scripting-stored-scripts,Stored Scripts>>).


`params`::

    Specifies any named parameters that are passed into the script as
    variables.

[IMPORTANT]
[[prefer-params]]
.Prefer parameters
========================================

The first time Elasticsearch sees a new script, it compiles it and stores the
compiled version in a cache. Compilation can be a heavy process.

If you need to pass variables into the script, you should pass them in as
named `params` instead of hard-coding values into the script itself.  For
example, if you want to be able to multiply a field value by different
multipliers, don't hard-code the multiplier into the script:

[source,js]
----------------------
  "source": "doc['my_field'] * 2"
----------------------
// NOTCONSOLE

Instead, pass it in as a named parameter:

[source,js]
----------------------
  "source": "doc['my_field'] * multiplier",
  "params": {
    "multiplier": 2
  }
----------------------
// NOTCONSOLE

The first version has to be recompiled every time the multiplier changes.  The
second version is only compiled once.

If you compile too many unique scripts within a small amount of time,
Elasticsearch will reject the new dynamic scripts with a
`circuit_breaking_exception` error. By default, up to 15 inline scripts per
minute will be compiled. You can change this setting dynamically by setting
`script.max_compilations_rate`.

========================================

[float]
[[modules-scripting-short-script-form]]
=== Short Script Form
A short script form can be used for brevity. In the short form, `script` is represented
by a string instead of an object. This string contains the source of the script.

Short form:

[source,js]
----------------------
  "script": "ctx._source.likes++"
----------------------
// NOTCONSOLE

The same script in the normal form:

[source,js]
----------------------
  "script": {
    "source": "ctx._source.likes++"
  }
----------------------
// NOTCONSOLE

[float]
[[modules-scripting-stored-scripts]]
=== Stored Scripts

Scripts may be stored in and retrieved from the cluster state using the
`_scripts` end-point.

==== Request Examples

The following are examples of using a stored script that lives at
`/_scripts/{id}`.

First, create the script called `calculate-score` in the cluster state:

[source,js]
-----------------------------------
POST _scripts/calculate-score
{
  "script": {
    "lang": "painless",
    "source": "Math.log(_score * 2) + params.my_modifier"
  }
}
-----------------------------------
// CONSOLE

This same script can be retrieved with:

[source,js]
-----------------------------------
GET _scripts/calculate-score
-----------------------------------
// CONSOLE
// TEST[continued]

Stored scripts can be used by specifying the `id` parameters as follows:

[source,js]
--------------------------------------------------
GET _search
{
  "query": {
    "script": {
      "script": {
        "id": "calculate-score",
        "params": {
          "my_modifier": 2
        }
      }
    }
  }
}
--------------------------------------------------
// CONSOLE
// TEST[continued]

And deleted with:

[source,js]
-----------------------------------
DELETE _scripts/calculate-score
-----------------------------------
// CONSOLE
// TEST[continued]

[float]
[[modules-scripting-using-caching]]
=== Script Caching

All scripts are cached by default so that they only need to be recompiled
when updates occur. By default, scripts do not have a time-based expiration, but
you can change this behavior by using the `script.cache.expire` setting.
You can configure the size of this cache by using the `script.cache.max_size` setting.
By default, the cache size is `100`.

NOTE: The size of scripts is limited to 65,535 bytes. This can be
changed by setting `script.max_size_in_bytes` setting to increase that soft
limit, but if scripts are really large then a
<<modules-scripting-engine,native script engine>> should be considered.
