| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638 | [[modules-scripting]]== ScriptingThe scripting module allows to use scripts in order to evaluate customexpressions. For example, scripts can be used to return "script fields"as part of a search request, or can be used to evaluate a custom scorefor a query and so on.The scripting module uses by default http://groovy-lang.org/[groovy](previously http://mvel.codehaus.org/[mvel] in 1.3.x and earlier) as thescripting language with some extensions. Groovy is used since it is extremelyfast and very simple to use..Groovy dynamic scripting off by default from v1.4.3[IMPORTANT]===================================================Groovy dynamic scripting is off by default, preventing dynamic Groovy scriptsfrom being accepted as part of a request or retrieved from the special`.scripts` index. You will still be able to use Groovy scripts stored in filesin the `config/scripts/` directory on every node.To convert an inline script to a file, take this simple scriptas an example:[source,json]-----------------------------------GET /_search{    "script_fields": {        "my_field": {            "inline": "1 + my_var",            "params": {              "my_var": 2            }        }    }}-----------------------------------Save the contents of the `inline` field as a file called `config/scripts/my_script.groovy`on every data node in the cluster:[source,js]-----------------------------------1 + my_var-----------------------------------Now you can access the script by file name (without the extension):[source,json]-----------------------------------GET /_search{    "script_fields": {        "my_field": {            "file": "my_script",            "params": {              "my_var": 2            }        }    }}-----------------------------------===================================================Additional `lang` plugins are provided to allow to execute scripts indifferent languages. All places where a script can be used, a `lang` parametercan be provided to define the language of the script. The following are thesupported scripting languages:[cols="<,<,<",options="header",]|=======================================================================|Language   |Sandboxed |Required plugin|groovy     |no        |built-in|expression |yes       |built-in|mustache   |yes       |built-in|mvel       |no        |https://github.com/elastic/elasticsearch-lang-mvel[elasticsearch-lang-mvel]|javascript |no        |https://github.com/elastic/elasticsearch-lang-javascript[elasticsearch-lang-javascript]|python     |no        |https://github.com/elastic/elasticsearch-lang-python[elasticsearch-lang-python]|=======================================================================To increase security, Elasticsearch does not allow you to specify scripts fornon-sandboxed languages with a request. Instead, scripts must be placed in the`scripts` directory inside the configuration directory (the directory whereelasticsearch.yml is). Scripts placed into this directory will automatically bepicked up and be available to be used. Once a script has been placed in thisdirectory, it can be referenced by name. For example, a script called`calculate-score.groovy` can be referenced in a request like this:[source,sh]--------------------------------------------------$ tree configconfig├── elasticsearch.yml├── logging.yml└── scripts    └── calculate-score.groovy--------------------------------------------------[source,sh]--------------------------------------------------$ cat config/scripts/calculate-score.groovylog(_score * 2) + my_modifier--------------------------------------------------[source,js]--------------------------------------------------curl -XPOST localhost:9200/_search -d '{  "query": {    "function_score": {      "query": {        "match": {          "body": "foo"        }      },      "functions": [        {          "script_score": {            "lang": "groovy",            "file": "calculate-score",            "params": {              "my_modifier": 8            }          }        }      ]    }  }}'--------------------------------------------------The name of the script is derived from the hierarchy of directories itexists under, and the file name without the lang extension. For example,a script placed under `config/scripts/group1/group2/test.py` will benamed `group1_group2_test`.[float]=== Indexed ScriptsElasticsearch allows you to store scripts in an internal index known as`.scripts` and reference them by id. There are REST endpoints to manageindexed scripts as follows:Requests to the scripts endpoint look like :[source,js]-----------------------------------/_scripts/{lang}/{id}-----------------------------------Where the `lang` part is the language the script is in and the `id` part is the idof the script. In the `.scripts` index the type of the document will be set to the `lang`.[source,js]-----------------------------------curl -XPOST localhost:9200/_scripts/groovy/indexedCalculateScore -d '{     "script": "log(_score * 2) + my_modifier"}'-----------------------------------This will create a document with id: `indexedCalculateScore` and type: `groovy` in the`.scripts` index. The type of the document is the language used by the script.This script can be accessed at query time by using the `id` script parameter and passingthe script id:[source,js]--------------------------------------------------curl -XPOST localhost:9200/_search -d '{  "query": {    "function_score": {      "query": {        "match": {          "body": "foo"        }      },      "functions": [        {          "script_score": {            "id": "indexedCalculateScore",            "lang" : "groovy",            "params": {              "my_modifier": 8            }          }        }      ]    }  }}'--------------------------------------------------The script can be viewed by:[source,js]-----------------------------------curl -XGET localhost:9200/_scripts/groovy/indexedCalculateScore-----------------------------------This is rendered as:[source,js]-----------------------------------'{     "script": "log(_score * 2) + my_modifier"}'-----------------------------------Indexed scripts can be deleted by:[source,js]-----------------------------------curl -XDELETE localhost:9200/_scripts/groovy/indexedCalculateScore-----------------------------------[float][[enable-dynamic-scripting]]=== Enabling dynamic scriptingWe recommend running Elasticsearch behind an application or proxy, whichprotects Elasticsearch from the outside world. If users are allowed to runinline scripts (even in a search request) or indexed scripts, then they havethe same access to your box as the user that Elasticsearch is running as. Forthis reason dynamic scripting is allowed only for sandboxed languages by default.First, you should not run Elasticsearch as the `root` user, as this would allowa script to access or do *anything* on your server, without limitations. Second,you should not expose Elasticsearch directly to users, but instead have a proxyapplication inbetween. If you *do* intend to expose Elasticsearch directly toyour users, then you have to decide whether you trust them enough to run scriptson your box or not.It is possible to enable scripts based on their source, forevery script engine, through the following settings that need to be added to the`config/elasticsearch.yml` file on every node.[source,yaml]-----------------------------------script.inline: onscript.indexed: on-----------------------------------While this still allows execution of named scripts provided in the config, or_native_ Java scripts registered through plugins, it also allows users to runarbitrary scripts via the API. Instead of sending the name of the file as thescript, the body of the script can be sent instead or retrieved from the`.scripts` indexed if previously stored.There are three possible configuration values for any of the fine-grainedscript settings:[cols="<,<",options="header",]|=======================================================================|Value |Description| `off` |scripting is turned off completely, in the context of the setting being set.| `on`  |scripting is turned on, in the context of the setting being set.| `sandbox` |scripts may be executed only for languages that are sandboxed|=======================================================================The default values are the following:[source,yaml]-----------------------------------script.inline: sandboxscript.indexed: sandboxscript.file: on-----------------------------------NOTE: Global scripting settings affect the `mustache` scripting language.<<search-template,Search templates>> internally use the `mustache` language,and will still be enabled by default as the `mustache` engine is sandboxed,but they will be enabled/disabled according to fine-grained settingsspecified in `elasticsearch.yml`.It is also possible to control which operations can execute scripts. Thesupported operations are:[cols="<,<",options="header",]|=======================================================================|Value |Description| `aggs`    |Aggregations (wherever they may be used)| `mapping` |Mappings (script transform feature)| `search`  |Search api, Percolator api and Suggester api (e.g filters, script_fields)| `update`  |Update api| `plugin`  |Any plugin that makes use of scripts under the generic `plugin` category|=======================================================================Plugins can also define custom operations that they use scripts for insteadof using the generic `plugin` category. Those operations can be referred toin the following form: `${pluginName}_${operation}`.The following example disables scripting for `update` and `mapping` operations,regardless of the script source, for any engine. Scripts can still beexecuted from sandboxed languages as part of `aggregations`, `search`and plugins execution though, as the above defaults still get applied.[source,yaml]-----------------------------------script.update: offscript.mapping: off-----------------------------------Generic settings get applied in order, operation based ones have precedenceover source based ones. Language specific settings are supported too. Theyneed to be prefixed with the `script.engine.<engine>` prefix and haveprecedence over any other generic settings.[source,yaml]-----------------------------------script.engine.groovy.file.aggs: onscript.engine.groovy.file.mapping: onscript.engine.groovy.file.search: onscript.engine.groovy.file.update: onscript.engine.groovy.file.plugin: onscript.engine.groovy.indexed.aggs: onscript.engine.groovy.indexed.mapping: offscript.engine.groovy.indexed.search: onscript.engine.groovy.indexed.update: offscript.engine.groovy.indexed.plugin: offscript.engine.groovy.inline.aggs: onscript.engine.groovy.inline.mapping: offscript.engine.groovy.inline.search: offscript.engine.groovy.inline.update: offscript.engine.groovy.inline.plugin: off-----------------------------------[float]=== Default Scripting LanguageThe default scripting language (assuming no `lang` parameter is provided) is`groovy`. In order to change it, set the `script.default_lang` to theappropriate language.[float]=== Automatic Script ReloadingThe `config/scripts` directory is scanned periodically for changes.New and changed scripts are reloaded and deleted script are removedfrom preloaded scripts cache. The reload frequency can be specifiedusing `resource.reload.interval` setting, which defaults to `60s`.To disable script reloading completely set `script.auto_reload_enabled`to `false`.[[native-java-scripts]][float]=== Native (Java) ScriptsEven though `groovy` is pretty fast, this allows to register native Java basedscripts for faster execution.In order to allow for scripts, the `NativeScriptFactory` needs to beimplemented that constructs the script that will be executed. There aretwo main types, one that extends `AbstractExecutableScript` and one thatextends `AbstractSearchScript` (probably the one most users will extend,with additional helper classes in `AbstractLongSearchScript`,`AbstractDoubleSearchScript`, and `AbstractFloatSearchScript`).Registering them can either be done by settings, for example:`script.native.my.type` set to `sample.MyNativeScriptFactory` willregister a script named `my`. Another option is in a plugin, access`ScriptModule` and call `registerScript` on it.Executing the script is done by specifying the `lang` as `native`, andthe name of the script as the `script`.Note, the scripts need to be in the classpath of elasticsearch. Onesimple way to do it is to create a directory under plugins (choose adescriptive name), and place the jar / classes files there. They will beautomatically loaded.[float]=== Lucene Expressions Scriptsexperimental[The Lucene expressions module is undergoing significant development and the exposed functionality is likely to change in the future]Lucene's expressions module provides a mechanism to compile a`javascript` expression to bytecode.  This allows very fast execution,as if you had written a `native` script.  Expression scripts can beused in `script_score`, `script_fields`, sort scripts and numeric aggregation scripts.See the link:http://lucene.apache.org/core/4_9_0/expressions/index.html?org/apache/lucene/expressions/js/package-summary.html[expressions module documentation]for details on what operators and functions are available.Variables in `expression` scripts are available to access:* Single valued document fields, e.g. `doc['myfield'].value`* Single valued document fields can also be accessed without `.value` e.g. `doc['myfield']`* Parameters passed into the script, e.g. `mymodifier`* The current document's score, `_score` (only available when used in a `script_score`)Variables in `expression` scripts that are of type `date` may use the following member methods:* getYear()* getMonth()* getDayOfMonth()* getHourOfDay()* getMinutes()* getSeconds()The following example shows the difference in years between the `date` fields date0 and date1:`doc['date1'].getYear() - doc['date0'].getYear()`There are a few limitations relative to other script languages:* Only numeric fields may be accessed* Stored fields are not available* If a field is sparse (only some documents contain a value), documents missing the field will have a value of `0`[float]=== ScoreIn all scripts that can be used in aggregations, the currentdocument's score is accessible in `_score`.[float]=== Computing scores based on terms in scriptssee <<modules-advanced-scripting, advanced scripting documentation>>[float]=== Document FieldsMost scripting revolve around the use of specific document fields data.The `doc['field_name']` can be used to access specific field data withina document (the document in question is usually derived by the contextthe script is used). Document fields are very fast to access since theyend up being loaded into memory (all the relevant field values/tokensare loaded to memory). Note, however, that the `doc[...]` notation onlyallows for simple valued fields (can’t return a json object from it)and makes sense only on non-analyzed or single term based fields.The following data can be extracted from a field:[cols="<,<",options="header",]|=======================================================================|Expression |Description|`doc['field_name'].value` |The native value of the field. For example,if its a short type, it will be short.|`doc['field_name'].values` |The native array values of the field. Forexample, if its a short type, it will be short[]. Remember, a field canhave several values within a single doc. Returns an empty array if thefield has no values.|`doc['field_name'].empty` |A boolean indicating if the field has novalues within the doc.|`doc['field_name'].multiValued` |A boolean indicating that the fieldhas several values within the corpus.|`doc['field_name'].lat` |The latitude of a geo point type.|`doc['field_name'].lon` |The longitude of a geo point type.|`doc['field_name'].lats` |The latitudes of a geo point type.|`doc['field_name'].lons` |The longitudes of a geo point type.|`doc['field_name'].distance(lat, lon)` |The `plane` distance (in meters)of this geo point field from the provided lat/lon.|`doc['field_name'].distanceWithDefault(lat, lon, default)` |The `plane` distance (in meters)of this geo point field from the provided lat/lon with a default value.|`doc['field_name'].distanceInMiles(lat, lon)` |The `plane` distance (inmiles) of this geo point field from the provided lat/lon.|`doc['field_name'].distanceInMilesWithDefault(lat, lon, default)` |The `plane` distance (inmiles) of this geo point field from the provided lat/lon with a default value.|`doc['field_name'].distanceInKm(lat, lon)` |The `plane` distance (inkm) of this geo point field from the provided lat/lon.|`doc['field_name'].distanceInKmWithDefault(lat, lon, default)` |The `plane` distance (inkm) of this geo point field from the provided lat/lon with a default value.|`doc['field_name'].arcDistance(lat, lon)` |The `arc` distance (inmeters) of this geo point field from the provided lat/lon.|`doc['field_name'].arcDistanceWithDefault(lat, lon, default)` |The `arc` distance (inmeters) of this geo point field from the provided lat/lon with a default value.|`doc['field_name'].arcDistanceInMiles(lat, lon)` |The `arc` distance (inmiles) of this geo point field from the provided lat/lon.|`doc['field_name'].arcDistanceInMilesWithDefault(lat, lon, default)` |The `arc` distance (inmiles) of this geo point field from the provided lat/lon with a default value.|`doc['field_name'].arcDistanceInKm(lat, lon)` |The `arc` distance (inkm) of this geo point field from the provided lat/lon.|`doc['field_name'].arcDistanceInKmWithDefault(lat, lon, default)` |The `arc` distance (inkm) of this geo point field from the provided lat/lon with a default value.|`doc['field_name'].factorDistance(lat, lon)` |The distance factor of this geo point field from the provided lat/lon.|`doc['field_name'].factorDistance(lat, lon, default)` |The distance factor of this geo point field from the provided lat/lon with a default value.|`doc['field_name'].geohashDistance(geohash)` |The `arc` distance (in meters)of this geo point field from the provided geohash.|`doc['field_name'].geohashDistanceInKm(geohash)` |The `arc` distance (in km)of this geo point field from the provided geohash.|`doc['field_name'].geohashDistanceInMiles(geohash)` |The `arc` distance (inmiles) of this geo point field from the provided geohash.|=======================================================================[float]=== Stored FieldsStored fields can also be accessed when executing a script. Note, theyare much slower to access compared with document fields, as they are notloaded into memory. They can be simply accessed using`_fields['my_field_name'].value` or `_fields['my_field_name'].values`.[float]=== Accessing the score of a document within a scriptWhen using scripting for calculating the score of a document (for instance, withthe `function_score` query), you can access the score using the `_score`variable inside of a Groovy script.[float]=== Source FieldThe source field can also be accessed when executing a script. Thesource field is loaded per doc, parsed, and then provided to the scriptfor evaluation. The `_source` forms the context under which the sourcefield can be accessed, for example `_source.obj2.obj1.field3`.Accessing `_source` is much slower compared to using `doc`but the data is not loaded into memory. For a single field access `_fields` may befaster than using `_source` due to the extra overhead of potentially parsing large documents.However, `_source` may be faster if you access multiple fields or if the source has already beenloaded for other purposes.[float]=== Groovy Built In FunctionsThere are several built in functions that can be used within scripts.They include:[cols="<,<",options="header",]|=======================================================================|Function |Description|`sin(a)` |Returns the trigonometric sine of an angle.|`cos(a)` |Returns the trigonometric cosine of an angle.|`tan(a)` |Returns the trigonometric tangent of an angle.|`asin(a)` |Returns the arc sine of a value.|`acos(a)` |Returns the arc cosine of a value.|`atan(a)` |Returns the arc tangent of a value.|`toRadians(angdeg)` |Converts an angle measured in degrees to anapproximately equivalent angle measured in radians|`toDegrees(angrad)` |Converts an angle measured in radians to anapproximately equivalent angle measured in degrees.|`exp(a)` |Returns Euler's number _e_ raised to the power of value.|`log(a)` |Returns the natural logarithm (base _e_) of a value.|`log10(a)` |Returns the base 10 logarithm of a value.|`sqrt(a)` |Returns the correctly rounded positive square root of avalue.|`cbrt(a)` |Returns the cube root of a double value.|`IEEEremainder(f1, f2)` |Computes the remainder operation on twoarguments as prescribed by the IEEE 754 standard.|`ceil(a)` |Returns the smallest (closest to negative infinity) valuethat is greater than or equal to the argument and is equal to amathematical integer.|`floor(a)` |Returns the largest (closest to positive infinity) valuethat is less than or equal to the argument and is equal to amathematical integer.|`rint(a)` |Returns the value that is closest in value to the argumentand is equal to a mathematical integer.|`atan2(y, x)` |Returns the angle _theta_ from the conversion ofrectangular coordinates (_x_, _y_) to polar coordinates (r,_theta_).|`pow(a, b)` |Returns the value of the first argument raised to thepower of the second argument.|`round(a)` |Returns the closest _int_ to the argument.|`random()` |Returns a random _double_ value.|`abs(a)` |Returns the absolute value of a value.|`max(a, b)` |Returns the greater of two values.|`min(a, b)` |Returns the smaller of two values.|`ulp(d)` |Returns the size of an ulp of the argument.|`signum(d)` |Returns the signum function of the argument.|`sinh(x)` |Returns the hyperbolic sine of a value.|`cosh(x)` |Returns the hyperbolic cosine of a value.|`tanh(x)` |Returns the hyperbolic tangent of a value.|`hypot(x, y)` |Returns sqrt(_x2_ + _y2_) without intermediate overflowor underflow.|=======================================================================[float]=== Arithmetic precision in MVELWhen dividing two numbers using MVEL based scripts, the engine tries tobe smart and adheres to the default behaviour of java. This means if youdivide two integers (you might have configured the fields as integer inthe mapping), the result will also be an integer. This means, if acalculation like `1/num` is happening in your scripts and `num` is aninteger with the value of `8`, the result is `0` even though you wereexpecting it to be `0.125`. You may need to enforce precision byexplicitly using a double like `1.0/num` in order to get the expectedresult.
 |