[docs] Migrate docs from AsciiDoc to Markdown (#123507)

* delete asciidoc files

* add migrated files

* fix errors

* Disable docs tests

* Clarify release notes page titles

* Revert "Clarify release notes page titles"

This reverts commit 8be688648d.

* Comment out edternal URI images

* Clean up query languages landing pages, link to conceptual docs

* Add .md to url

* Fixes inference processor nesting.

---------

Co-authored-by: Liam Thompson <32779855+leemthompo@users.noreply.github.com>
Co-authored-by: Liam Thompson <leemthompo@gmail.com>
Co-authored-by: Martijn Laarman <Mpdreamz@gmail.com>
Co-authored-by: István Zoltán Szabó <szabosteve@gmail.com>
This commit is contained in:
Colleen McGinnis 2025-02-27 10:56:14 -06:00 committed by GitHub
parent 2113a3c606
commit b7e3a1e14b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4082 changed files with 141513 additions and 376367 deletions

View file

@ -0,0 +1,5 @@
# Scripting languages
This section contains the Painless scripting language reference.
For an overview of scripting languages in {{es}}, go to [Scripting](docs-content://explore-analyze/scripting.md).

View file

@ -0,0 +1,309 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-walkthrough.html
---
# A brief painless walkthrough [painless-walkthrough]
To illustrate how Painless works, lets load some hockey stats into an Elasticsearch index:
```console
PUT hockey/_bulk?refresh
{"index":{"_id":1}}
{"first":"johnny","last":"gaudreau","goals":[9,27,1],"assists":[17,46,0],"gp":[26,82,1],"born":"1993/08/13"}
{"index":{"_id":2}}
{"first":"sean","last":"monohan","goals":[7,54,26],"assists":[11,26,13],"gp":[26,82,82],"born":"1994/10/12"}
{"index":{"_id":3}}
{"first":"jiri","last":"hudler","goals":[5,34,36],"assists":[11,62,42],"gp":[24,80,79],"born":"1984/01/04"}
{"index":{"_id":4}}
{"first":"micheal","last":"frolik","goals":[4,6,15],"assists":[8,23,15],"gp":[26,82,82],"born":"1988/02/17"}
{"index":{"_id":5}}
{"first":"sam","last":"bennett","goals":[5,0,0],"assists":[8,1,0],"gp":[26,1,0],"born":"1996/06/20"}
{"index":{"_id":6}}
{"first":"dennis","last":"wideman","goals":[0,26,15],"assists":[11,30,24],"gp":[26,81,82],"born":"1983/03/20"}
{"index":{"_id":7}}
{"first":"david","last":"jones","goals":[7,19,5],"assists":[3,17,4],"gp":[26,45,34],"born":"1984/08/10"}
{"index":{"_id":8}}
{"first":"tj","last":"brodie","goals":[2,14,7],"assists":[8,42,30],"gp":[26,82,82],"born":"1990/06/07"}
{"index":{"_id":39}}
{"first":"mark","last":"giordano","goals":[6,30,15],"assists":[3,30,24],"gp":[26,60,63],"born":"1983/10/03"}
{"index":{"_id":10}}
{"first":"mikael","last":"backlund","goals":[3,15,13],"assists":[6,24,18],"gp":[26,82,82],"born":"1989/03/17"}
{"index":{"_id":11}}
{"first":"joe","last":"colborne","goals":[3,18,13],"assists":[6,20,24],"gp":[26,67,82],"born":"1990/01/30"}
```
## Accessing Doc Values from Painless [_accessing_doc_values_from_painless]
Document values can be accessed from a `Map` named `doc`.
For example, the following script calculates a players total goals. This example uses a strongly typed `int` and a `for` loop.
```console
GET hockey/_search
{
"query": {
"function_score": {
"script_score": {
"script": {
"lang": "painless",
"source": """
int total = 0;
for (int i = 0; i < doc['goals'].length; ++i) {
total += doc['goals'][i];
}
return total;
"""
}
}
}
}
}
```
Alternatively, you could do the same thing using a script field instead of a function score:
```console
GET hockey/_search
{
"query": {
"match_all": {}
},
"script_fields": {
"total_goals": {
"script": {
"lang": "painless",
"source": """
int total = 0;
for (int i = 0; i < doc['goals'].length; ++i) {
total += doc['goals'][i];
}
return total;
"""
}
}
}
}
```
The following example uses a Painless script to sort the players by their combined first and last names. The names are accessed using `doc['first'].value` and `doc['last'].value`.
```console
GET hockey/_search
{
"query": {
"match_all": {}
},
"sort": {
"_script": {
"type": "string",
"order": "asc",
"script": {
"lang": "painless",
"source": "doc['first.keyword'].value + ' ' + doc['last.keyword'].value"
}
}
}
}
```
## Missing keys [_missing_keys]
`doc['myfield'].value` throws an exception if the field is missing in a document.
For more dynamic index mappings, you may consider writing a catch equation
```
if (!doc.containsKey('myfield') || doc['myfield'].empty) { return "unavailable" } else { return doc['myfield'].value }
```
## Missing values [_missing_values]
To check if a document is missing a value, you can call `doc['myfield'].size() == 0`.
## Updating Fields with Painless [_updating_fields_with_painless]
You can also easily update fields. You access the original source for a field as `ctx._source.<field-name>`.
First, lets look at the source data for a player by submitting the following request:
```console
GET hockey/_search
{
"query": {
"term": {
"_id": 1
}
}
}
```
To change player 1s last name to `hockey`, simply set `ctx._source.last` to the new value:
```console
POST hockey/_update/1
{
"script": {
"lang": "painless",
"source": "ctx._source.last = params.last",
"params": {
"last": "hockey"
}
}
}
```
You can also add fields to a document. For example, this script adds a new field that contains the players nickname, *hockey*.
```console
POST hockey/_update/1
{
"script": {
"lang": "painless",
"source": """
ctx._source.last = params.last;
ctx._source.nick = params.nick
""",
"params": {
"last": "gaudreau",
"nick": "hockey"
}
}
}
```
## Dates [modules-scripting-painless-dates]
Date fields are exposed as `ZonedDateTime`, so they support methods like `getYear`, `getDayOfWeek` or e.g. getting milliseconds since epoch with `getMillis`. To use these in a script, leave out the `get` prefix and continue with lowercasing the rest of the method name. For example, the following returns every hockey players birth year:
```console
GET hockey/_search
{
"script_fields": {
"birth_year": {
"script": {
"source": "doc.born.value.year"
}
}
}
}
```
## Regular expressions [modules-scripting-painless-regex]
::::{note}
Regexes are enabled by default as the Setting `script.painless.regex.enabled` has a new option, `limited`, the default. This defaults to using regular expressions but limiting the complexity of the regular expressions. Innocuous looking regexes can have staggering performance and stack depth behavior. But still, they remain an amazingly powerful tool. In addition, to `limited`, the setting can be set to `true`, as before, which enables regular expressions without limiting them.To enable them yourself set `script.painless.regex.enabled: true` in `elasticsearch.yml`.
::::
Painlesss native support for regular expressions has syntax constructs:
* `/pattern/`: Pattern literals create patterns. This is the only way to create a pattern in painless. The pattern inside the `/s are just [Java regular expressions](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.md). See [Pattern flags](/reference/scripting-languages/painless/painless-regexes.md#pattern-flags) for more.
* `=~`: The find operator return a `boolean`, `true` if a subsequence of the text matches, `false` otherwise.
* `==~`: The match operator returns a `boolean`, `true` if the text matches, `false` if it doesnt.
Using the find operator (`=~`) you can update all hockey players with "b" in their last name:
```console
POST hockey/_update_by_query
{
"script": {
"lang": "painless",
"source": """
if (ctx._source.last =~ /b/) {
ctx._source.last += "matched";
} else {
ctx.op = "noop";
}
"""
}
}
```
Using the match operator (`==~`) you can update all the hockey players whose names start with a consonant and end with a vowel:
```console
POST hockey/_update_by_query
{
"script": {
"lang": "painless",
"source": """
if (ctx._source.last ==~ /[^aeiou].*[aeiou]/) {
ctx._source.last += "matched";
} else {
ctx.op = "noop";
}
"""
}
}
```
You can use the `Pattern.matcher` directly to get a `Matcher` instance and remove all of the vowels in all of their last names:
```console
POST hockey/_update_by_query
{
"script": {
"lang": "painless",
"source": "ctx._source.last = /[aeiou]/.matcher(ctx._source.last).replaceAll('')"
}
}
```
`Matcher.replaceAll` is just a call to Javas `Matcher`'s [replaceAll](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Matcher.md#replaceAll-java.lang.String-) method so it supports `$1` and `\1` for replacements:
```console
POST hockey/_update_by_query
{
"script": {
"lang": "painless",
"source": "ctx._source.last = /n([aeiou])/.matcher(ctx._source.last).replaceAll('$1')"
}
}
```
If you need more control over replacements you can call `replaceAll` on a `CharSequence` with a `Function<Matcher, String>` that builds the replacement. This does not support `$1` or `\1` to access replacements because you already have a reference to the matcher and can get them with `m.group(1)`.
::::{important}
Calling `Matcher.find` inside of the function that builds the replacement is rude and will likely break the replacement process.
::::
This will make all of the vowels in the hockey players last names upper case:
```console
POST hockey/_update_by_query
{
"script": {
"lang": "painless",
"source": """
ctx._source.last = ctx._source.last.replaceAll(/[aeiou]/, m ->
m.group().toUpperCase(Locale.ROOT))
"""
}
}
```
Or you can use the `CharSequence.replaceFirst` to make the first vowel in their last names upper case:
```console
POST hockey/_update_by_query
{
"script": {
"lang": "painless",
"source": """
ctx._source.last = ctx._source.last.replaceFirst(/[aeiou]/, m ->
m.group().toUpperCase(Locale.ROOT))
"""
}
}
```
Note: all of the `_update_by_query` examples above could really do with a `query` to limit the data that they pull back. While you **could** use a [script query](/reference/query-languages/query-dsl-script-query.md) it wouldnt be as efficient as using any other query because script queries arent able to use the inverted index to limit the documents that they have to check.

View file

@ -0,0 +1,17 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/modules-scripting-painless-dispatch.html
---
# How painless dispatches function [modules-scripting-painless-dispatch]
Painless uses receiver, name, and [arity](https://en.wikipedia.org/wiki/Arity) for method dispatch. For example, `s.foo(a, b)` is resolved by first getting the class of `s` and then looking up the method `foo` with two parameters. This is different from Groovy which uses the [runtime types](https://en.wikipedia.org/wiki/Multiple_dispatch) of the parameters and Java which uses the compile time types of the parameters.
The consequence of this that Painless doesnt support overloaded methods like Java, leading to some trouble when it allows classes from the Java standard library. For example, in Java and Groovy, `Matcher` has two methods: `group(int)` and `group(String)`. Painless cant allow both of these methods because they have the same name and the same number of parameters. So instead it has `group(int)` and `namedGroup(String)`.
We have a few justifications for this different way of dispatching methods:
1. It makes operating on `def` types simpler and, presumably, faster. Using receiver, name, and arity means that when Painless sees a call on a `def` object it can dispatch the appropriate method without having to do expensive comparisons of the types of the parameters. The same is true for invocations with `def` typed parameters.
2. It keeps things consistent. It would be genuinely weird for Painless to behave like Groovy if any `def` typed parameters were involved and Java otherwise. Itd be slow for it to behave like Groovy all the time.
3. It keeps Painless maintainable. Adding the Java or Groovy like method dispatch **feels** like itd add a ton of complexity whichd make maintenance and other improvements much more difficult.

View file

@ -0,0 +1,47 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-analysis-predicate-context.html
---
# Analysis Predicate Context [painless-analysis-predicate-context]
Use a painless script to determine whether or not the current token in an analysis chain matches a predicate.
**Variables**
`params` (`Map`, read-only)
: User-defined parameters passed in as part of the query.
`token.term` (`CharSequence`, read-only)
: The characters of the current token
`token.position` (`int`, read-only)
: The position of the current token
`token.positionIncrement` (`int`, read-only)
: The position increment of the current token
`token.positionLength` (`int`, read-only)
: The position length of the current token
`token.startOffset` (`int`, read-only)
: The start offset of the current token
`token.endOffset` (`int`, read-only)
: The end offset of the current token
`token.type` (`String`, read-only)
: The type of the current token
`token.keyword` (`boolean`, read-only)
: Whether or not the current token is marked as a keyword
**Return**
`boolean`
: Whether or not the current token matches the predicate
**API**
The standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) is available.

View file

@ -0,0 +1,850 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-execute-api.html
---
# Painless API examples [painless-execute-api]
::::{warning}
This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.
::::
The Painless execute API runs a script and returns a result.
## {{api-request-title}} [painless-execute-api-request]
`POST /_scripts/painless/_execute`
## {{api-description-title}} [painless-execute-api-desc]
Use this API to build and test scripts, such as when defining a script for a [runtime field](docs-content://manage-data/data-store/mapping/runtime-fields.md). This API requires very few dependencies, and is especially useful if you dont have permissions to write documents on a cluster.
The API uses several *contexts*, which control how scripts are executed, what variables are available at runtime, and what the return type is.
Each context requires a script, but additional parameters depend on the context youre using for that script.
## {{api-request-body-title}} [painless-execute-api-request-body]
`script`
: (Required, object) The Painless script to execute.
### Properties of `script`
`emit`
: (Required) Accepts the values from the script valuation. Scripts can call the `emit` method multiple times to emit multiple values.
The `emit` method applies only to scripts used in a [runtime fields context](#painless-execute-runtime-context).
:::{important}
The `emit` method cannot accept `null` values. Do not call this method if the referenced fields do not have any values.
:::
::::{dropdown} Signatures of `emit`
The signature for `emit` depends on the `type` of the field.
`boolean`
: `emit(boolean)`
`date`
: `emit(long)`
`double`
: `emit(double)`
`geo_point`
: `emit(double lat, double lon)`
`ip`
: `emit(String)`
`long`
: `emit(long)`
`keyword`
: `emit(String)`
::::
$$$_contexts$$$
`context`
: (Optional, string) The context that the script should run in. Defaults to `painless_test` if no context is specified.
::::::{dropdown} Properties of `context`
`painless_test`
: The default context if no other context is specified. See [test context](#painless-execute-test).
`filter`
: Treats scripts as if they were run inside a `script` query. See [filter context](#painless-execute-filter-context).
`score`
: Treats scripts as if they were run inside a `script_score` function in a `function_score` query. See [score context](#painless-execute-core-context).
$$$painless-execute-runtime-context$$$
:::::{dropdown} Field contexts
The following options are specific to the field contexts.
::::{note}
Result ordering in the field contexts is not guaranteed.
::::
::::{admonition}
`boolean_field`
: The context for [`boolean` fields](/reference/elasticsearch/mapping-reference/boolean.md). The script returns a `true` or `false` response. See [boolean_field context](#painless-runtime-boolean).
`date_field`
: The context for [`date` fields](/reference/elasticsearch/mapping-reference/date.md). `emit` takes a `long` value and the script returns a sorted list of dates. See [date_time context](#painless-runtime-datetime).
`double_field`
: The context for `double` [numeric fields](/reference/elasticsearch/mapping-reference/number.md). The script returns a sorted list of `double` values. See [double_field context](#painless-runtime-double).
`geo_point_field`
: The context for [`geo-point` fields](/reference/elasticsearch/mapping-reference/geo-point.md). `emit` takes two double parameters, the latitude and longitude values, and the script returns an object in GeoJSON format containing the coordinates for the geo point. See [geo_point_field context](#painless-runtime-geo).
`ip_field`
: The context for [`ip` fields](/reference/elasticsearch/mapping-reference/ip.md). The script returns a sorted list of IP addresses. See [ip_field context](#painless-runtime-ip).
`keyword_field`
: The context for [`keyword` fields](/reference/elasticsearch/mapping-reference/keyword.md). The script returns a sorted list of `string` values. See [keyword_field context](#painless-runtime-keyword).
`long_field`
: The context for `long` [numeric fields](/reference/elasticsearch/mapping-reference/number.md). The script returns a sorted list of `long` values. See [long_field context](#painless-runtime-long).
`composite_field`
: The context for `composite` [runtime fields](docs-content://manage-data/data-store/mapping/runtime-fields.md). The script returns a map of values. See [composite_field context](#painless-runtime-composite).
::::
:::::
::::::
`context_setup`
: (Required, object) Additional parameters for the `context`.
::::{note}
This parameter is required for all contexts except `painless_test`, which is the default if no value is provided for `context`.
::::
:::::{dropdown} Properties of `context_setup`
`document`
: (Required, string) Document thats temporarily indexed in-memory and accessible from the script.
`index`
: (Required, string) Index containing a mapping thats compatible with the indexed document. You may specify a remote index by prefixing the index with the remote cluster alias. For example, `remote1:my_index` indicates that you want to execute the painless script against the "my_index" index on the "remote1" cluster. This request will be forwarded to the "remote1" cluster if you have [configured a connection](docs-content://deploy-manage/remote-clusters/remote-clusters-self-managed.md) to that remote cluster.
::::{note}
Wildcards are not accepted in the index expression for this endpoint. The expression `*:myindex` will return the error "No such remote cluster" and the expression `logs*` or `remote1:logs*` will return the error "index not found".
::::
:::::
`params`
: (`Map`, read-only) Specifies any named parameters that are passed into the script as variables.
`query`
: (Optional, object)
::::{note}
This parameter only applies when `score` is specified as the script `context`.
::::
Use this parameter to specify a query for computing a score. Besides deciding whether or not the document matches, the [query clause](/reference/query-languages/query-filter-context.md#query-context) also calculates a relevance score in the `_score` metadata field.
## Test context [painless-execute-test]
The `painless_test` context runs scripts without additional parameters. The only variable that is available is `params`, which can be used to access user defined values. The result of the script is always converted to a string.
Because the default context is `painless_test`, you dont need to specify the `context` or `context_setup`.
### Request [_request]
```console
POST /_scripts/painless/_execute
{
"script": {
"source": "params.count / params.total",
"params": {
"count": 100.0,
"total": 1000.0
}
}
}
```
### Response [_response]
```console-result
{
"result": "0.1"
}
```
## Filter context [painless-execute-filter-context]
The `filter` context treats scripts as if they were run inside a `script` query. For testing purposes, a document must be provided so that it will be temporarily indexed in-memory and is accessible from the script. More precisely, the `_source`, stored fields and doc values of such a document are available to the script being tested.
### Request [_request_2]
```console
PUT /my-index-000001
{
"mappings": {
"properties": {
"field": {
"type": "keyword"
}
}
}
}
```
```console
POST /_scripts/painless/_execute
{
"script": {
"source": "doc['field'].value.length() <= params.max_length",
"params": {
"max_length": 4
}
},
"context": "filter",
"context_setup": {
"index": "my-index-000001",
"document": {
"field": "four"
}
}
}
```
### Response [_response_2]
```console-result
{
"result": true
}
```
## Score context [painless-execute-core-context]
The `score` context treats scripts as if they were run inside a `script_score` function in a `function_score` query.
### Request [_request_3]
```console
PUT /my-index-000001
{
"mappings": {
"properties": {
"field": {
"type": "keyword"
},
"rank": {
"type": "long"
}
}
}
}
```
```console
POST /_scripts/painless/_execute
{
"script": {
"source": "doc['rank'].value / params.max_rank",
"params": {
"max_rank": 5.0
}
},
"context": "score",
"context_setup": {
"index": "my-index-000001",
"document": {
"rank": 4
}
}
}
```
### Response [_response_3]
```console-result
{
"result": 0.8
}
```
## Field contexts [painless-execute-runtime-field-context]
The field contexts treat scripts as if they were run inside the [`runtime_mappings` section](docs-content://manage-data/data-store/mapping/define-runtime-fields-in-search-request.md) of a search query. You can use field contexts to test scripts for different field types, and then include those scripts anywhere that theyre supported, such as [runtime fields](/reference/scripting-languages/painless/use-painless-scripts-in-runtime-fields.md).
Choose a field context based on the data type you want to return.
### `boolean_field` [painless-runtime-boolean]
Use the `boolean_field` field context when you want to return a `true` or `false` value from a script valuation. [Boolean fields](/reference/elasticsearch/mapping-reference/boolean.md) accept `true` and `false` values, but can also accept strings that are interpreted as either true or false.
Lets say you have data for the top 100 science fiction books of all time. You want to write scripts that return a boolean response such as whether books exceed a certain page count, or if a book was published after a specific year.
Consider that your data is structured like this:
```console
PUT /my-index-000001
{
"mappings": {
"properties": {
"name": {
"type": "keyword"
},
"author": {
"type": "keyword"
},
"release_date": {
"type": "date"
},
"page_count": {
"type": "double"
}
}
}
}
```
You can then write a script in the `boolean_field` context that indicates whether a book was published before the year 1972:
```console
POST /_scripts/painless/_execute
{
"script": {
"source": """
emit(doc['release_date'].value.year < 1972);
"""
},
"context": "boolean_field",
"context_setup": {
"index": "my-index-000001",
"document": {
"name": "Dune",
"author": "Frank Herbert",
"release_date": "1965-06-01",
"page_count": 604
}
}
}
```
Because *Dune* was published in 1965, the result returns as `true`:
```console-result
{
"result" : [
true
]
}
```
Similarly, you could write a script that determines whether the first name of an author exceeds a certain number of characters. The following script operates on the `author` field to determine whether the authors first name contains at least one character, but is less than five characters:
```console
POST /_scripts/painless/_execute
{
"script": {
"source": """
int space = doc['author'].value.indexOf(' ');
emit(space > 0 && space < 5);
"""
},
"context": "boolean_field",
"context_setup": {
"index": "my-index-000001",
"document": {
"name": "Dune",
"author": "Frank Herbert",
"release_date": "1965-06-01",
"page_count": 604
}
}
}
```
Because `Frank` is five characters, the response returns `false` for the script valuation:
```console-result
{
"result" : [
false
]
}
```
### `date_time` [painless-runtime-datetime]
Several options are available for using [using datetime in Painless](/reference/scripting-languages/painless/using-datetime-in-painless.md). In this example, youll estimate when a particular author starting writing a book based on its release date and the writing speed of that author. The example makes some assumptions, but shows to write a script that operates on a date while incorporating additional information.
Add the following fields to your index mapping to get started:
```console
PUT /my-index-000001
{
"mappings": {
"properties": {
"name": {
"type": "keyword"
},
"author": {
"type": "keyword"
},
"release_date": {
"type": "date"
},
"page_count": {
"type": "long"
}
}
}
}
```
The following script makes the incredible assumption that when writing a book, authors just write each page and dont do research or revisions. Further, the script assumes that the average time it takes to write a page is eight hours.
The script retrieves the `author` and makes another fantastic assumption to either divide or multiply the `pageTime` value based on the authors perceived writing speed (yet another wild assumption).
The script subtracts the release date value (in milliseconds) from the calculation of `pageTime` times the `page_count` to determine approximately (based on numerous assumptions) when the author began writing the book.
```console
POST /_scripts/painless/_execute
{
"script": {
"source": """
String author = doc['author'].value;
long pageTime = 28800000; <1>
if (author == 'Robert A. Heinlein') {
pageTime /= 2; <2>
} else if (author == 'Alastair Reynolds') {
pageTime *= 2; <3>
}
emit(doc['release_date'].value.toInstant().toEpochMilli() - pageTime * doc['page_count'].value);
"""
},
"context": "date_field",
"context_setup": {
"index": "my-index-000001",
"document": {
"name": "Revelation Space",
"author": "Alastair Reynolds",
"release_date": "2000-03-15",
"page_count": 585
}
}
}
```
1. Eight hours, represented in milliseconds
2. Incredibly fast writing from Robert A. Heinlein
3. Alastair Reynolds writes space operas at a much slower speed
In this case, the author is Alastair Reynolds. Based on a release date of `2000-03-15`, the script calculates that the author started writing `Revelation Space` on 19 February 1999. Writing a 585 page book in just over one year is pretty impressive!
```console-result
{
"result" : [
"1999-02-19T00:00:00.000Z"
]
}
```
### `double_field` [painless-runtime-double]
Use the `double_field` context for [numeric data](/reference/elasticsearch/mapping-reference/number.md) of type `double`. For example, lets say you have sensor data that includes a `voltage` field with values like 5.6. After indexing millions of documents, you discover that the sensor with model number `QVKC92Q` is under reporting its voltage by a factor of 1.7. Rather than reindex your data, you can fix it with a runtime field.
You need to multiply this value, but only for sensors that match a specific model number.
Add the following fields to your index mapping. The `voltage` field is a sub-field of the `measures` object.
```console
PUT my-index-000001
{
"mappings": {
"properties": {
"@timestamp": {
"type": "date"
},
"model_number": {
"type": "keyword"
},
"measures": {
"properties": {
"voltage": {
"type": "double"
}
}
}
}
}
}
```
The following script matches on any documents where the `model_number` equals `QVKC92Q`, and then multiplies the `voltage` value by `1.7`. This script is useful when you want to select specific documents and only operate on values that match the specified criteria.
```console
POST /_scripts/painless/_execute
{
"script": {
"source": """
if (doc['model_number'].value.equals('QVKC92Q'))
{emit(1.7 * params._source['measures']['voltage']);}
else{emit(params._source['measures']['voltage']);}
"""
},
"context": "double_field",
"context_setup": {
"index": "my-index-000001",
"document": {
"@timestamp": 1516470094000,
"model_number": "QVKC92Q",
"measures": {
"voltage": 5.6
}
}
}
}
```
The result includes the calculated voltage, which was determined by multiplying the original value of `5.6` by `1.7`:
```console-result
{
"result" : [
9.52
]
}
```
### `geo_point_field` [painless-runtime-geo]
[Geo-point](/reference/elasticsearch/mapping-reference/geo-point.md) fields accept latitude-longitude pairs. You can define a geo-point field in several ways, and include values for latitude and longitude in the document for your script.
If you already have a known geo-point, its simpler to clearly state the positions of `lat` and `lon` in your index mappings.
```console
PUT /my-index-000001/
{
"mappings": {
"properties": {
"lat": {
"type": "double"
},
"lon": {
"type": "double"
}
}
}
}
```
You can then use the `geo_point_field` runtime field context to write a script that retrieves the `lat` and `lon` values.
```console
POST /_scripts/painless/_execute
{
"script": {
"source": """
emit(doc['lat'].value, doc['lon'].value);
"""
},
"context": "geo_point_field",
"context_setup": {
"index": "my-index-000001",
"document": {
"lat": 41.12,
"lon": -71.34
}
}
}
```
Because youre working with a geo-point field type, the response includes results that are formatted as `coordinates`.
```console-result
{
"result" : [
{
"coordinates" : [
-71.34,
41.12
],
"type" : "Point"
}
]
}
```
::::{note}
The emit function for [geo-point](/reference/elasticsearch/mapping-reference/geo-point.md) fields takes two parameters ordered with `lat` before `lon`, but the output GeoJSON format orders the `coordinates` as `[ lon, lat ]`.
::::
### `ip_field` [painless-runtime-ip]
The `ip_field` context is useful for data that includes IP addresses of type [`ip`](/reference/elasticsearch/mapping-reference/ip.md). For example, lets say you have a `message` field from an Apache log. This field contains an IP address, but also other data that you dont need.
You can add the `message` field to your index mappings as a `wildcard` to accept pretty much any data you want to put in that field.
```console
PUT /my-index-000001/
{
"mappings": {
"properties": {
"message": {
"type": "wildcard"
}
}
}
}
```
You can then define a runtime script with a grok pattern that extracts structured fields out of the `message` field.
The script matches on the `%{{COMMONAPACHELOG}}` log pattern, which understands the structure of Apache logs. If the pattern matches, the script emits the value matching the IP address. If the pattern doesnt match (`clientip != null`), the script just returns the field value without crashing.
```console
POST /_scripts/painless/_execute
{
"script": {
"source": """
String clientip=grok('%{COMMONAPACHELOG}').extract(doc["message"].value)?.clientip;
if (clientip != null) emit(clientip);
"""
},
"context": "ip_field",
"context_setup": {
"index": "my-index-000001",
"document": {
"message": "40.135.0.0 - - [30/Apr/2020:14:30:17 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"
}
}
}
```
The response includes only the IP address, ignoring all of the other data in the `message` field.
```console-result
{
"result" : [
"40.135.0.0"
]
}
```
### `keyword_field` [painless-runtime-keyword]
[Keyword fields](/reference/elasticsearch/mapping-reference/keyword.md) are often used in sorting, aggregations, and term-level queries.
Lets say you have a timestamp. You want to calculate the day of the week based on that value and return it, such as `Thursday`. The following request adds a `@timestamp` field of type `date` to the index mappings:
```console
PUT /my-index-000001
{
"mappings": {
"properties": {
"@timestamp": {
"type": "date"
}
}
}
}
```
To return the equivalent day of week based on your timestamp, you can create a script in the `keyword_field` runtime field context:
```console
POST /_scripts/painless/_execute
{
"script": {
"source": """
emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ENGLISH));
"""
},
"context": "keyword_field",
"context_setup": {
"index": "my-index-000001",
"document": {
"@timestamp": "2020-04-30T14:31:43-05:00"
}
}
}
```
The script operates on the value provided for the `@timestamp` field to calculate and return the day of the week:
```console-result
{
"result" : [
"Thursday"
]
}
```
### `long_field` [painless-runtime-long]
Lets say you have sensor data that a `measures` object. This object includes a `start` and `end` field, and you want to calculate the difference between those values.
The following request adds a `measures` object to the mappings with two fields, both of type `long`:
```console
PUT /my-index-000001/
{
"mappings": {
"properties": {
"measures": {
"properties": {
"start": {
"type": "long"
},
"end": {
"type": "long"
}
}
}
}
}
}
```
You can then define a script that assigns values to the `start` and `end` fields and operate on them. The following script extracts the value for the `end` field from the `measures` object and subtracts it from the `start` field:
```console
POST /_scripts/painless/_execute
{
"script": {
"source": """
emit(doc['measures.end'].value - doc['measures.start'].value);
"""
},
"context": "long_field",
"context_setup": {
"index": "my-index-000001",
"document": {
"measures": {
"voltage": "4.0",
"start": "400",
"end": "8625309"
}
}
}
}
```
The response includes the calculated value from the script valuation:
```console-result
{
"result" : [
8624909
]
}
```
### `composite_field` [painless-runtime-composite]
Lets say you have logging data with a raw `message` field which you want to split in multiple sub-fields that can be accessed separately.
The following request adds a `message` field to the mappings of type `keyword`:
```console
PUT /my-index-000001/
{
"mappings": {
"properties": {
"message": {
"type" : "keyword"
}
}
}
}
```
You can then define a script that splits such message field into subfields using the grok function:
```console
POST /_scripts/painless/_execute
{
"script": {
"source": "emit(grok(\"%{COMMONAPACHELOG}\").extract(doc[\"message\"].value));"
},
"context": "composite_field",
"context_setup": {
"index": "my-index-000001",
"document": {
"timestamp":"2020-04-30T14:31:27-05:00",
"message":"252.0.0.0 - - [30/Apr/2020:14:31:27 -0500] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"
}
}
}
```
The response includes the values that the script emitted:
```console-result
{
"result" : {
"composite_field.timestamp" : [
"30/Apr/2020:14:31:27 -0500"
],
"composite_field.auth" : [
"-"
],
"composite_field.response" : [
"200"
],
"composite_field.ident" : [
"-"
],
"composite_field.httpversion" : [
"1.0"
],
"composite_field.verb" : [
"GET"
],
"composite_field.bytes" : [
"24736"
],
"composite_field.clientip" : [
"252.0.0.0"
],
"composite_field.request" : [
"/images/hm_bg.jpg"
]
}
}
```

View file

@ -0,0 +1,86 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-bucket-script-agg-context.html
---
# Bucket script aggregation context [painless-bucket-script-agg-context]
Use a Painless script in an [`bucket_script` pipeline aggregation](/reference/data-analysis/aggregations/search-aggregations-pipeline-bucket-script-aggregation.md) to calculate a value as a result in a bucket.
## Variables [_variables]
`params` (`Map`, read-only)
: User-defined parameters passed in as part of the query. The parameters include values defined as part of the `buckets_path`.
## Return [_return]
numeric
: The calculated value as the result.
## API [_api]
The standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) is available.
## Example [_example]
To run this example, first follow the steps in [context examples](/reference/scripting-languages/painless/painless-context-examples.md).
The painless context in a `bucket_script` aggregation provides a `params` map. This map contains both user-specified custom values, as well as the values from other aggregations specified in the `buckets_path` property.
This example takes the values from a min and max aggregation, calculates the difference, and adds the user-specified base_cost to the result:
```painless
(params.max - params.min) + params.base_cost
```
Note that the values are extracted from the `params` map. In context, the aggregation looks like this:
```console
GET /seats/_search
{
"size": 0,
"aggs": {
"theatres": {
"terms": {
"field": "theatre",
"size": 10
},
"aggs": {
"min_cost": {
"min": {
"field": "cost"
}
},
"max_cost": {
"max": {
"field": "cost"
}
},
"spread_plus_base": {
"bucket_script": {
"buckets_path": { <1>
"min": "min_cost",
"max": "max_cost"
},
"script": {
"params": {
"base_cost": 5 <2>
},
"source": "(params.max - params.min) + params.base_cost"
}
}
}
}
}
}
}
```
1. The `buckets_path` points to two aggregations (`min_cost`, `max_cost`) and adds `min`/`max` variables to the `params` map
2. The user-specified `base_cost` is also added to the scripts `params` map

View file

@ -0,0 +1,82 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-bucket-selector-agg-context.html
---
# Bucket selector aggregation context [painless-bucket-selector-agg-context]
Use a Painless script in an [`bucket_selector` aggregation](/reference/data-analysis/aggregations/search-aggregations-pipeline-bucket-selector-aggregation.md) to determine if a bucket should be retained or filtered out.
## Variables [_variables_2]
`params` (`Map`, read-only)
: User-defined parameters passed in as part of the query. The parameters include values defined as part of the `buckets_path`.
## Return [_return_2]
boolean
: True if the bucket should be retained, false if the bucket should be filtered out.
## API [_api_2]
The standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) is available.
## Example [_example_2]
To run this example, first follow the steps in [context examples](/reference/scripting-languages/painless/painless-context-examples.md).
The painless context in a `bucket_selector` aggregation provides a `params` map. This map contains both user-specified custom values, as well as the values from other aggregations specified in the `buckets_path` property.
Unlike some other aggregation contexts, the `bucket_selector` context must return a boolean `true` or `false`.
This example finds the max of each bucket, adds a user-specified base_cost, and retains all of the buckets that are greater than `10`.
```painless
params.max + params.base_cost > 10
```
Note that the values are extracted from the `params` map. The script is in the form of an expression that returns `true` or `false`. In context, the aggregation looks like this:
```console
GET /seats/_search
{
"size": 0,
"aggs": {
"theatres": {
"terms": {
"field": "theatre",
"size": 10
},
"aggs": {
"max_cost": {
"max": {
"field": "cost"
}
},
"filtering_agg": {
"bucket_selector": {
"buckets_path": { <1>
"max": "max_cost"
},
"script": {
"params": {
"base_cost": 5 <2>
},
"source": "params.max + params.base_cost > 10"
}
}
}
}
}
}
}
```
1. The `buckets_path` points to the max aggregations (`max_cost`) and adds `max` variables to the `params` map
2. The user-specified `base_cost` is also added to the `params` map

View file

@ -0,0 +1,350 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-casting.html
---
# Casting [painless-casting]
A cast converts the value of an original type to the equivalent value of a target type. An implicit cast infers the target type and automatically occurs during certain [operations](/reference/scripting-languages/painless/painless-operators.md). An explicit cast specifies the target type and forcefully occurs as its own operation. Use the `cast operator '()'` to specify an explicit cast.
Refer to the [cast table](#allowed-casts) for a quick reference on all allowed casts.
**Errors**
* If during a cast there exists no equivalent value for the target type.
* If an implicit cast is given, but an explicit cast is required.
**Grammar**
```text
cast: '(' TYPE ')' expression
```
**Examples**
* Valid casts.
```painless
int i = (int)5L; <1>
Map m = new HashMap(); <2>
HashMap hm = (HashMap)m; <3>
```
1. declare `int i`; explicit cast `long 5` to `int 5``int 5`; store `int 5` to `i`
2. declare `Map m`; allocate `HashMap` instance → `HashMap reference`; implicit cast `HashMap reference` to `Map reference``Map reference`; store `Map reference` to `m`
3. declare `HashMap hm`; load from `m``Map reference`; explicit cast `Map reference` to `HashMap reference``HashMap reference`; store `HashMap reference` to `hm`
## Numeric Type Casting [numeric-type-casting]
A [numeric type](/reference/scripting-languages/painless/painless-types.md#primitive-types) cast converts the value of an original numeric type to the equivalent value of a target numeric type. A cast between two numeric type values results in data loss when the value of the original numeric type is larger than the target numeric type can accommodate. A cast between an integer type value and a floating point type value can result in precision loss.
The allowed casts for values of each numeric type are shown as a row in the following table:
| | | | | | | | |
| --- | --- | --- | --- | --- | --- | --- | --- |
| | byte | short | char | int | long | float | double |
| byte | | implicit | implicit | implicit | implicit | implicit | implicit |
| short | explicit | | explicit | implicit | implicit | implicit | implicit |
| char | explicit | explicit | | implicit | implicit | implicit | implicit |
| int | explicit | explicit | explicit | | implicit | implicit | implicit |
| long | explicit | explicit | explicit | explicit | | implicit | implicit |
| float | explicit | explicit | explicit | explicit | explicit | | implicit |
| double | explicit | explicit | explicit | explicit | explicit | explicit | |
**Examples**
* Valid numeric type casts.
```painless
int a = 1; <1>
long b = a; <2>
short c = (short)b; <3>
double e = (double)a; <4>
```
1. declare `int a`; store `int 1` to `a`
2. declare `long b`; load from `a``int 1`; implicit cast `int 1` to `long 1``long 1`; store `long 1` to `b`
3. declare `short c`; load from `b``long 1`; explicit cast `long 1` to `short 1``short 1`; store `short 1` value to `c`
4. declare `double e`; load from `a``int 1`; explicit cast `int 1` to `double 1.0`; store `double 1.0` to `e`; (note the explicit cast is extraneous since an implicit cast is valid)
* Invalid numeric type casts resulting in errors.
```painless
int a = 1.0; // error <1>
int b = 2; <2>
byte c = b; // error <3>
```
1. declare `int i`; **error** → cannot implicit cast `double 1.0` to `int 1`; (note an explicit cast is valid)
2. declare `int b`; store `int 2` to `b`
3. declare byte `c`; load from `b``int 2`; **error** → cannot implicit cast `int 2` to `byte 2`; (note an explicit cast is valid)
## Reference Type Casting [reference-type-casting]
A [reference type](/reference/scripting-languages/painless/painless-types.md#reference-types) cast converts the value of an original reference type to the equivalent value of a target reference type. An implicit cast between two reference type values is allowed when the original reference type is a descendant of the target type. An explicit cast between two reference type values is allowed when the original type is a descendant of the target type or the target type is a descendant of the original type.
**Examples**
* Valid reference type casts.
```painless
List x; <1>
ArrayList y = new ArrayList(); <2>
x = y; <3>
y = (ArrayList)x; <4>
x = (List)y; <5>
```
1. declare `List x`; store default value `null` to `x`
2. declare `ArrayList y`; allocate `ArrayList` instance → `ArrayList reference`; store `ArrayList reference` to `y`;
3. load from `y``ArrayList reference`; implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `x`; (note `ArrayList` is a descendant of `List`)
4. load from `x``List reference`; explicit cast `List reference` to `ArrayList reference``ArrayList reference`; store `ArrayList reference` to `y`;
5. load from `y``ArrayList reference`; explicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `x`; (note the explicit cast is extraneous, and an implicit cast is valid)
* Invalid reference type casts resulting in errors.
```painless
List x = new ArrayList(); <1>
ArrayList y = x; // error <2>
Map m = (Map)x; // error <3>
```
1. declare `List x`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `x`
2. declare `ArrayList y`; load from `x``List reference`; **error** → cannot implicit cast `List reference` to `ArrayList reference`; (note an explicit cast is valid since `ArrayList` is a descendant of `List`)
3. declare `ArrayList y`; load from `x``List reference`; **error** → cannot explicit cast `List reference` to `Map reference`; (note no cast is valid since neither `List` nor `Map` is a descendant of the other)
## Dynamic Type Casting [dynamic-type-casting]
A [dynamic (`def`) type](/reference/scripting-languages/painless/painless-types.md#dynamic-types) cast converts the value of an original `def` type to the equivalent value of any target type or converts the value of any original type to the equivalent value of a target `def` type.
An implicit cast from any original type value to a `def` type value is always allowed. An explicit cast from any original type value to a `def` type value is always allowed but never necessary.
An implicit or explicit cast from an original `def` type value to any target type value is allowed if and only if the cast is normally allowed based on the current type value the `def` type value represents.
**Examples**
* Valid dynamic type casts with any original type to a target `def` type.
```painless
def d0 = 3; <1>
d0 = new ArrayList(); <2>
Object o = new HashMap(); <3>
def d1 = o; <4>
int i = d1.size(); <5>
```
1. declare `def d0`; implicit cast `int 3` to `def`; store `int 3` to `d0`
2. allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `def``def`; store `def` to `d0`
3. declare `Object o`; allocate `HashMap` instance → `HashMap reference`; implicit cast `HashMap reference` to `Object reference``Object reference`; store `Object reference` to `o`
4. declare `def d1`; load from `o``Object reference`; implicit cast `Object reference` to `def``def`; store `def` to `d1`
5. declare `int i`; load from `d1``def`; implicit cast `def` to `HashMap reference` → HashMap reference`; call `size` on `HashMap reference` → `int 0`; store `int 0` to `i`; (note `def` was implicit cast to `HashMap reference` since `HashMap` is the child-most descendant type value that the `def` type value represents)
* Valid dynamic type casts with an original `def` type to any target type.
```painless
def d = 1.0; <1>
int i = (int)d; <2>
d = 1; <3>
float f = d; <4>
d = new ArrayList(); <5>
List l = d; <6>
```
1. declare `def d`; implicit cast `double 1.0` to `def``def`; store `def` to `d`
2. declare `int i`; load from `d``def`; implicit cast `def` to `double 1.0``double 1.0`; explicit cast `double 1.0` to `int 1``int 1`; store `int 1` to `i`; (note the explicit cast is necessary since a `double` type value is not converted to an `int` type value implicitly)
3. store `int 1` to `d`; (note the switch in the type `d` represents from `double` to `int`)
4. declare `float i`; load from `d``def`; implicit cast `def` to `int 1``int 1`; implicit cast `int 1` to `float 1.0``float 1.0`; store `float 1.0` to `f`
5. allocate `ArrayList` instance → `ArrayList reference`; store `ArrayList reference` to `d`; (note the switch in the type `d` represents from `int` to `ArrayList`)
6. declare `List l`; load from `d``def`; implicit cast `def` to `ArrayList reference``ArrayList reference`; implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `l`
* Invalid dynamic type casts resulting in errors.
```painless
def d = 1; <1>
short s = d; // error <2>
d = new HashMap(); <3>
List l = d; // error <4>
```
1. declare `def d`; implicit cast `int 1` to `def``def`; store `def` to `d`
2. declare `short s`; load from `d``def`; implicit cast `def` to `int 1``int 1`; **error** → cannot implicit cast `int 1` to `short 1`; (note an explicit cast is valid)
3. allocate `HashMap` instance → `HashMap reference`; implicit cast `HashMap reference` to `def``def`; store `def` to `d`
4. declare `List l`; load from `d``def`; implicit cast `def` to `HashMap reference`; **error** → cannot implicit cast `HashMap reference` to `List reference`; (note no cast is valid since neither `HashMap` nor `List` is a descendant of the other)
## String to Character Casting [string-character-casting]
Use the cast operator to convert a [`String` type](/reference/scripting-languages/painless/painless-types.md#string-type) value into a [`char` type](/reference/scripting-languages/painless/painless-types.md#primitive-types) value.
**Errors**
* If the `String` type value isnt one character in length.
* If the `String` type value is `null`.
**Examples**
* Casting string literals into `char` type values.
```painless
char c = (char)"C"; <1>
c = (char)'c'; <2>
```
1. declare `char c`; explicit cast `String "C"` to `char C``char C`; store `char C` to `c`
2. explicit cast `String 'c'` to `char c``char c`; store `char c` to `c`
* Casting a `String` reference into a `char` type value.
```painless
String s = "s"; <1>
char c = (char)s; <2>
```
1. declare `String s`; store `String "s"` to `s`;
2. declare `char c` load from `s``String "s"`; explicit cast `String "s"` to `char s``char s`; store `char s` to `c`
## Character to String Casting [character-string-casting]
Use the cast operator to convert a [`char` type](/reference/scripting-languages/painless/painless-types.md#primitive-types) value into a [`String` type](/reference/scripting-languages/painless/painless-types.md#string-type) value.
**Examples**
* Casting a `String` reference into a `char` type value.
```painless
char c = 65; <1>
String s = (String)c; <2>
```
1. declare `char c`; store `char 65` to `c`;
2. declare `String s` load from `c``char A`; explicit cast `char A` to `String "A"``String "A"`; store `String "A"` to `s`
## Boxing and Unboxing [boxing-unboxing]
Boxing is a special type of cast used to convert a primitive type to its corresponding reference type. Unboxing is the reverse used to convert a reference type to its corresponding primitive type.
Implicit boxing/unboxing occurs during the following operations:
* Conversions between a `def` type and a primitive type are implicitly boxed/unboxed as necessary, though this is referred to as an implicit cast throughout the documentation.
* Method/function call arguments are implicitly boxed/unboxed as necessary.
* A primitive type value is implicitly boxed when a reference type method is called on it.
Explicit boxing/unboxing is not allowed. Use the reference type API to explicitly convert a primitive type value to its respective reference type value and vice versa.
**Errors**
* If an explicit cast is made to box/unbox a primitive type.
**Examples**
* Uses of implicit boxing/unboxing.
```painless
List l = new ArrayList(); <1>
l.add(1); <2>
Integer I = Integer.valueOf(0); <3>
int i = l.get(i); <4>
```
1. declare `List l`; allocate `ArrayList` instance → `ArrayList reference`; store `ArrayList reference` to `l`;
2. load from `l``List reference`; implicit cast `int 1` to `def``def`; call `add` on `List reference` with arguments (`def`); (note internally `int 1` is boxed to `Integer 1` to store as a `def` type value)
3. declare `Integer I`; call `valueOf` on `Integer` with arguments of (`int 0`) → `Integer 0`; store `Integer 0` to `I`;
4. declare `int i`; load from `I``Integer 0`; unbox `Integer 0``int 0`; load from `l``List reference`; call `get` on `List reference` with arguments (`int 0`) → `def`; implicit cast `def` to `int 1``int 1`; store `int 1` to `i`; (note internally `int 1` is unboxed from `Integer 1` when loaded from a `def` type value)
* Uses of invalid boxing/unboxing resulting in errors.
```painless
Integer x = 1; // error <1>
Integer y = (Integer)1; // error <2>
int a = Integer.valueOf(1); // error <3>
int b = (int)Integer.valueOf(1); // error <4>
```
1. declare `Integer x`; **error** → cannot implicit box `int 1` to `Integer 1` during assignment
2. declare `Integer y`; **error** → cannot explicit box `int 1` to `Integer 1` during assignment
3. declare `int a`; call `valueOf` on `Integer` with arguments of (`int 1`) → `Integer 1`; **error** → cannot implicit unbox `Integer 1` to `int 1` during assignment
4. declare `int a`; call `valueOf` on `Integer` with arguments of (`int 1`) → `Integer 1`; **error** → cannot explicit unbox `Integer 1` to `int 1` during assignment
## Promotion [promotion]
Promotion is when a single value is implicitly cast to a certain type or multiple values are implicitly cast to the same type as required for evaluation by certain operations. Each operation that requires promotion has a promotion table that shows all required implicit casts based on the type(s) of value(s). A value promoted to a `def` type at compile-time is promoted again at run-time based on the type the `def` value represents.
**Errors**
* If a specific operation cannot find an allowed promotion type for the type(s) of value(s) given.
**Examples**
* Uses of promotion.
```painless
double d = 2 + 2.0; <1>
def x = 1; <2>
float f = x + 2.0F; <3>
```
1. declare `double d`; promote `int 2` and `double 2.0 @0`: result `double`; implicit cast `int 2` to `double 2.0 @1``double 2.0 @1`; add `double 2.0 @1` and `double 2.0 @0``double 4.0`; store `double 4.0` to `d`
2. declare `def x`; implicit cast `int 1` to `def``def`; store `def` to `x`;
3. declare `float f`; load from `x``def`; implicit cast `def` to `int 1``int 1`; promote `int 1` and `float 2.0`: result `float`; implicit cast `int 1` to `float 1.0``float `1.0`; add `float 1.0` and `float 2.0` → `float 3.0`; store `float 3.0` to `f`; (note this example illustrates promotion done at run-time as promotion done at compile-time would have resolved to a `def` type value)
## Allowed Casts [allowed-casts]
The following tables show all allowed casts. Read the tables row by row, where the original type is shown in the first column, and each subsequent column indicates whether a cast to the specified target type is implicit (I), explicit (E), boxed/unboxed for methods only (A), a reference type cast (@), or is not allowed (-). See [reference type casting](#reference-type-casting) for allowed reference type casts.
**Primitive/Reference Types**
| | | | | | | | | | | | | | | | | | | | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| | O | N | T | b | y | s | c | i | j | f | d | B | Y | S | C | I | J | F | D | R | def |
| Object ( O ) | | @ | @ | - | - | - | - | - | - | - | - | @ | @ | @ | @ | @ | @ | @ | @ | @ | I |
| Number ( N ) | I | | - | - | - | - | - | - | - | - | - | - | @ | @ | - | @ | @ | @ | @ | @ | I |
| String ( T ) | I | - | | - | - | - | - | - | - | - | - | - | - | - | E | - | - | - | - | - | I |
| boolean ( b ) | A | - | - | | - | - | - | - | - | - | - | A | - | - | - | - | - | - | - | - | I |
| byte ( y ) | A | A | - | - | | I | E | I | I | I | I | - | A | A | - | A | A | A | A | - | I |
| short ( s ) | A | A | - | - | E | | E | I | I | I | I | - | - | A | - | A | A | A | A | - | I |
| char ( c ) | A | - | E | - | E | E | | I | I | I | I | - | - | - | A | A | A | A | A | - | I |
| int ( i ) | A | A | - | - | E | E | E | | I | I | I | - | - | - | - | A | A | A | A | - | I |
| long ( j ) | A | A | - | - | E | E | E | E | | I | I | - | - | - | - | - | A | A | A | - | I |
| float ( f ) | A | A | - | - | E | E | E | E | E | | I | - | - | - | - | - | - | A | A | - | I |
| double ( d ) | A | A | - | - | E | E | E | E | E | E | | - | - | - | - | - | - | - | A | - | I |
| Boolean ( B ) | A | - | - | A | - | - | - | - | - | - | - | | - | - | - | - | - | - | - | @ | I |
| Byte ( Y ) | A | I | - | - | A | A | - | A | A | A | A | - | | A | - | A | A | A | A | @ | I |
| Short ( S ) | A | I | - | - | - | A | - | A | A | A | A | - | - | | - | A | A | A | A | @ | I |
| Character ( C ) | A | - | - | - | - | - | A | A | A | A | A | - | - | - | | A | A | A | A | @ | I |
| Integer ( I ) | A | - | - | - | - | - | - | A | A | A | A | - | - | - | - | | A | A | A | @ | I |
| Long ( J ) | A | - | - | - | - | - | - | - | A | A | A | - | - | - | - | - | | A | A | @ | I |
| Float ( F ) | A | - | - | - | - | - | - | - | - | A | A | - | - | - | - | - | - | | A | @ | I |
| Double ( D ) | A | - | - | - | - | - | - | - | - | - | A | - | - | - | - | - | - | - | | @ | I |
| Reference ( R ) | I | @ | @ | - | - | - | - | - | - | - | - | @ | @ | @ | @ | @ | @ | @ | @ | @ | I |
**`def` Type**
| | | | | | | | | | | | | | | | | | | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| | O | N | T | b | y | s | c | i | j | f | d | B | Y | S | C | I | J | F | D | R |
| def as String | I | - | I | - | - | - | E | - | - | - | - | - | - | - | E | - | - | - | - | @ |
| def as boolean/Boolean | I | - | - | I | - | - | - | - | - | - | - | I | - | - | - | - | - | - | - | @ |
| def as byte/Byte | I | - | - | - | I | I | E | I | I | I | I | - | I | I | E | I | I | I | I | @ |
| def as short/Short | I | - | - | - | E | I | E | I | I | I | I | - | E | I | E | I | I | I | I | @ |
| def as char/Character | I | - | - | - | E | E | I | I | I | I | I | - | E | E | I | I | I | I | I | @ |
| def as int/Integer | I | - | - | - | E | E | E | I | I | I | I | - | E | E | E | I | I | I | I | @ |
| def as long/Long | I | - | - | - | E | E | E | E | I | I | I | - | E | E | E | E | I | I | I | @ |
| def as float/Float | I | - | - | - | E | E | E | E | E | I | I | - | E | E | E | E | E | I | I | @ |
| def as double/Double | I | - | - | - | E | E | E | E | E | E | I | - | E | E | E | E | E | E | I | @ |
| def as Reference | @ | @ | @ | - | - | - | - | - | - | - | - | @ | @ | @ | @ | @ | @ | @ | @ | @ |

View file

@ -0,0 +1,50 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-comments.html
---
# Comments [painless-comments]
Use a comment to annotate or explain code within a script. Use the `//` token anywhere on a line to specify a single-line comment. All characters from the `//` token to the end of the line are ignored. Use an opening `/*` token and a closing `*/` token to specify a multi-line comment. Multi-line comments can start anywhere on a line, and all characters in between the `/*` token and `*/` token are ignored. A comment is included anywhere within a script.
**Grammar**
```text
SINGLE_LINE_COMMENT: '//' .*? [\n\r];
MULTI_LINE_COMMENT: '/*' .*? '*/';
```
**Examples**
* Single-line comments.
```painless
// single-line comment
int value; // single-line comment
```
* Multi-line comments.
```painless
/* multi-
line
comment */
int value; /* multi-
line
comment */ value = 0;
int value; /* multi-line
comment */
/* multi-line
comment */ int value;
int value; /* multi-line
comment */ value = 0;
int value; /* multi-line comment */ value = 0;
```

View file

@ -0,0 +1,116 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-context-examples.html
---
# Context example data [painless-context-examples]
Complete the following steps to index the `seat` sample data into {{es}}. You can run any of the context examples against this sample data after you configure it.
Each document in the `seat` data contains the following fields:
`theatre` ([`keyword`](/reference/elasticsearch/mapping-reference/keyword.md))
: The name of the theater the play is in.
`play` ([`keyword`](/reference/elasticsearch/mapping-reference/keyword.md))
: The name of the play.
`actors` ([`keyword`](/reference/elasticsearch/mapping-reference/keyword.md))
: A list of actors in the play.
`date` ([`keyword`](/reference/elasticsearch/mapping-reference/keyword.md))
: The date of the play as a keyword.
`time` ([`keyword`](/reference/elasticsearch/mapping-reference/keyword.md))
: The time of the play as a keyword.
`cost` ([`long`](/reference/elasticsearch/mapping-reference/number.md))
: The cost of the ticket for the seat.
`row` ([`long`](/reference/elasticsearch/mapping-reference/number.md))
: The row of the seat.
`number` ([`long`](/reference/elasticsearch/mapping-reference/number.md))
: The number of the seat within a row.
`sold` ([`boolean`](/reference/elasticsearch/mapping-reference/boolean.md))
: Whether or not the seat is sold.
`datetime` ([`date`](/reference/elasticsearch/mapping-reference/date.md))
: The date and time of the play as a date object.
## Prerequisites [_prerequisites]
Start an [{{es}} instance](docs-content://deploy-manage/deploy/self-managed/installing-elasticsearch.md), and then access the [Console](docs-content://explore-analyze/query-filter/tools/console.md) in {{kib}}.
## Configure the `seat` sample data [_configure_the_seat_sample_data]
1. From the {{kib}} Console, create [mappings](docs-content://manage-data/data-store/mapping.md) for the sample data:
```console
PUT /seats
{
"mappings": {
"properties": {
"theatre": { "type": "keyword" },
"play": { "type": "keyword" },
"actors": { "type": "keyword" },
"date": { "type": "keyword" },
"time": { "type": "keyword" },
"cost": { "type": "double" },
"row": { "type": "integer" },
"number": { "type": "integer" },
"sold": { "type": "boolean" },
"datetime": { "type": "date" }
}
}
}
```
2. Configure a script ingest processor that parses each document as {{es}} ingests the `seat` data. The following ingest script processes the `date` and `time` fields and stores the result in a `datetime` field:
```console
PUT /_ingest/pipeline/seats
{
"description": "update datetime for seats",
"processors": [
{
"script": {
"source": "String[] dateSplit = ctx.date.splitOnToken('-'); String year = dateSplit[0].trim(); String month = dateSplit[1].trim(); if (month.length() == 1) { month = '0' + month; } String day = dateSplit[2].trim(); if (day.length() == 1) { day = '0' + day; } boolean pm = ctx.time.substring(ctx.time.length() - 2).equals('PM'); String[] timeSplit = ctx.time.substring(0, ctx.time.length() - 2).splitOnToken(':'); int hours = Integer.parseInt(timeSplit[0].trim()); int minutes = Integer.parseInt(timeSplit[1].trim()); if (pm) { hours += 12; } String dts = year + '-' + month + '-' + day + 'T' + (hours < 10 ? '0' + hours : '' + hours) + ':' + (minutes < 10 ? '0' + minutes : '' + minutes) + ':00+08:00'; ZonedDateTime dt = ZonedDateTime.parse(dts, DateTimeFormatter.ISO_OFFSET_DATE_TIME); ctx.datetime = dt.getLong(ChronoField.INSTANT_SECONDS)*1000L;"
}
}
]
}
```
3. Ingest some sample data using the `seats` ingest pipeline that you defined in the previous step.
```console
POST seats/_bulk?pipeline=seats&refresh=true
{"create":{"_index":"seats","_id":"1"}}
{"theatre":"Skyline","play":"Rent","actors":["James Holland","Krissy Smith","Joe Muir","Ryan Earns"],"date":"2021-4-1","time":"3:00PM","cost":37,"row":1,"number":7,"sold":false}
{"create":{"_index":"seats","_id":"2"}}
{"theatre":"Graye","play":"Rent","actors":["Dave Christmas"],"date":"2021-4-1","time":"3:00PM","cost":30,"row":3,"number":5,"sold":false}
{"create":{"_index":"seats","_id":"3"}}
{"theatre":"Graye","play":"Rented","actors":["Dave Christmas"],"date":"2021-4-1","time":"3:00PM","cost":33,"row":2,"number":6,"sold":false}
{"create":{"_index":"seats","_id":"4"}}
{"theatre":"Skyline","play":"Rented","actors":["James Holland","Krissy Smith","Joe Muir","Ryan Earns"],"date":"2021-4-1","time":"3:00PM","cost":20,"row":5,"number":2,"sold":false}
{"create":{"_index":"seats","_id":"5"}}
{"theatre":"Down Port","play":"Pick It Up","actors":["Joel Madigan","Jessica Brown","Baz Knight","Jo Hangum","Rachel Grass","Phoebe Miller"],"date":"2018-4-2","time":"8:00PM","cost":27.5,"row":3,"number":2,"sold":false}
{"create":{"_index":"seats","_id":"6"}}
{"theatre":"Down Port","play":"Harriot","actors":["Phoebe Miller","Sarah Notch","Brayden Green","Joshua Iller","Jon Hittle","Rob Kettleman","Laura Conrad","Simon Hower","Nora Blue","Mike Candlestick","Jacey Bell"],"date":"2018-8-7","time":"8:00PM","cost":30,"row":1,"number":10,"sold":false}
{"create":{"_index":"seats","_id":"7"}}
{"theatre":"Skyline","play":"Auntie Jo","actors":["Jo Hangum","Jon Hittle","Rob Kettleman","Laura Conrad","Simon Hower","Nora Blue"],"date":"2018-10-2","time":"5:40PM","cost":22.5,"row":7,"number":10,"sold":false}
{"create":{"_index":"seats","_id":"8"}}
{"theatre":"Skyline","play":"Test Run","actors":["Joe Muir","Ryan Earns","Joel Madigan","Jessica Brown"],"date":"2018-8-5","time":"7:30PM","cost":17.5,"row":11,"number":12,"sold":true}
{"create":{"_index":"seats","_id":"9"}}
{"theatre":"Skyline","play":"Sunnyside Down","actors":["Krissy Smith","Joe Muir","Ryan Earns","Nora Blue","Mike Candlestick","Jacey Bell"],"date":"2018-6-12","time":"4:00PM","cost":21.25,"row":8,"number":15,"sold":true}
{"create":{"_index":"seats","_id":"10"}}
{"theatre":"Graye","play":"Line and Single","actors":["Nora Blue","Mike Candlestick"],"date":"2018-6-5","time":"2:00PM","cost":30,"row":1,"number":2,"sold":false}
{"create":{"_index":"seats","_id":"11"}}
{"theatre":"Graye","play":"Hamilton","actors":["Lin-Manuel Miranda","Leslie Odom Jr."],"date":"2018-6-5","time":"2:00PM","cost":5000,"row":1,"number":20,"sold":true}
```

View file

@ -0,0 +1,56 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-contexts.html
---
# Painless contexts [painless-contexts]
A Painless script is evaluated within a context. Each context has values that are available as local variables, an allowlist that controls the available classes, and the methods and fields within those classes (API), and if and what type of value is returned.
Painless scripts typically run within one of the contexts in the following table. Before using a Painless context, [configure the example data](/reference/scripting-languages/painless/painless-context-examples.md). Each context example is configured to operate on this data.
| Name | Painless Documentation | Elasticsearch Documentation |
| --- | --- | --- |
| Runtime field | [Painless Documentation](/reference/scripting-languages/painless/painless-runtime-fields-context.md) | [Elasticsearch Documentation](docs-content://manage-data/data-store/mapping/runtime-fields.md) |
| Ingest processor | [Painless Documentation](/reference/scripting-languages/painless/painless-ingest-processor-context.md) | [Elasticsearch Documentation](/reference/ingestion-tools/enrich-processor/script-processor.md) |
| Update | [Painless Documentation](/reference/scripting-languages/painless/painless-update-context.md) | [Elasticsearch Documentation](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-update) |
| Update by query | [Painless Documentation](/reference/scripting-languages/painless/painless-update-by-query-context.md) | [Elasticsearch Documentation](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-update-by-query) |
| Reindex | [Painless Documentation](/reference/scripting-languages/painless/painless-reindex-context.md) | [Elasticsearch Documentation](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-reindex) |
| Sort | [Painless Documentation](/reference/scripting-languages/painless/painless-sort-context.md) | [Elasticsearch Documentation](/reference/elasticsearch/rest-apis/sort-search-results.md) |
| Similarity | [Painless Documentation](/reference/scripting-languages/painless/painless-similarity-context.md) | [Elasticsearch Documentation](/reference/elasticsearch/index-settings/similarity.md) |
| Weight | [Painless Documentation](/reference/scripting-languages/painless/painless-weight-context.md) | [Elasticsearch Documentation](/reference/elasticsearch/index-settings/similarity.md) |
| Score | [Painless Documentation](/reference/scripting-languages/painless/painless-score-context.md) | [Elasticsearch Documentation](/reference/query-languages/query-dsl-function-score-query.md) |
| Field | [Painless Documentation](/reference/scripting-languages/painless/painless-field-context.md) | [Elasticsearch Documentation](/reference/elasticsearch/rest-apis/retrieve-selected-fields.md#script-fields) |
| Filter | [Painless Documentation](/reference/scripting-languages/painless/painless-filter-context.md) | [Elasticsearch Documentation](/reference/query-languages/query-dsl-script-query.md) |
| Minimum should match | [Painless Documentation](/reference/scripting-languages/painless/painless-min-should-match-context.md) | [Elasticsearch Documentation](/reference/query-languages/query-dsl-terms-set-query.md) |
| Metric aggregation initialization | [Painless Documentation](/reference/scripting-languages/painless/painless-metric-agg-init-context.md) | [Elasticsearch Documentation](/reference/data-analysis/aggregations/search-aggregations-metrics-scripted-metric-aggregation.md) |
| Metric aggregation map | [Painless Documentation](/reference/scripting-languages/painless/painless-metric-agg-map-context.md) | [Elasticsearch Documentation](/reference/data-analysis/aggregations/search-aggregations-metrics-scripted-metric-aggregation.md) |
| Metric aggregation combine | [Painless Documentation](/reference/scripting-languages/painless/painless-metric-agg-combine-context.md) | [Elasticsearch Documentation](/reference/data-analysis/aggregations/search-aggregations-metrics-scripted-metric-aggregation.md) |
| Metric aggregation reduce | [Painless Documentation](/reference/scripting-languages/painless/painless-metric-agg-reduce-context.md) | [Elasticsearch Documentation](/reference/data-analysis/aggregations/search-aggregations-metrics-scripted-metric-aggregation.md) |
| Bucket script aggregation | [Painless Documentation](/reference/scripting-languages/painless/painless-bucket-script-agg-context.md) | [Elasticsearch Documentation](/reference/data-analysis/aggregations/search-aggregations-pipeline-bucket-script-aggregation.md) |
| Bucket selector aggregation | [Painless Documentation](/reference/scripting-languages/painless/painless-bucket-selector-agg-context.md) | [Elasticsearch Documentation](/reference/data-analysis/aggregations/search-aggregations-pipeline-bucket-selector-aggregation.md) |
| Watcher condition | [Painless Documentation](/reference/scripting-languages/painless/painless-watcher-condition-context.md) | [Elasticsearch Documentation](docs-content://explore-analyze/alerts-cases/watcher/condition-script.md) |
| Watcher transform | [Painless Documentation](/reference/scripting-languages/painless/painless-watcher-transform-context.md) | [Elasticsearch Documentation](docs-content://explore-analyze/alerts-cases/watcher/transform-script.md) |

View file

@ -0,0 +1,72 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-debugging.html
---
# Painless debugging [painless-debugging]
## Debug.Explain [_debug_explain]
Painless doesnt have a [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) and while itd be nice for it to have one day, it wouldnt tell you the whole story around debugging painless scripts embedded in Elasticsearch because the data that the scripts have access to or "context" is so important. For now the best way to debug embedded scripts is by throwing exceptions at choice places. While you can throw your own exceptions (`throw new Exception('whatever')`), Painlesss sandbox prevents you from accessing useful information like the type of an object. So Painless has a utility method, `Debug.explain` which throws the exception for you. For example, you can use [`_explain`](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-explain) to explore the context available to a [script query](/reference/query-languages/query-dsl-script-query.md).
```console
PUT /hockey/_doc/1?refresh
{"first":"johnny","last":"gaudreau","goals":[9,27,1],"assists":[17,46,0],"gp":[26,82,1]}
POST /hockey/_explain/1
{
"query": {
"script": {
"script": "Debug.explain(doc.goals)"
}
}
}
```
Which shows that the class of `doc.first` is `org.elasticsearch.index.fielddata.ScriptDocValues.Longs` by responding with:
```console-result
{
"error": {
"type": "script_exception",
"to_string": "[1, 9, 27]",
"painless_class": "org.elasticsearch.index.fielddata.ScriptDocValues.Longs",
"java_class": "org.elasticsearch.index.fielddata.ScriptDocValues$Longs",
...
},
"status": 400
}
```
You can use the same trick to see that `_source` is a `LinkedHashMap` in the `_update` API:
```console
POST /hockey/_update/1
{
"script": "Debug.explain(ctx._source)"
}
```
The response looks like:
```console-result
{
"error" : {
"root_cause": ...,
"type": "illegal_argument_exception",
"reason": "failed to execute script",
"caused_by": {
"type": "script_exception",
"to_string": "{gp=[26, 82, 1], last=gaudreau, assists=[17, 46, 0], first=johnny, goals=[9, 27, 1]}",
"painless_class": "java.util.LinkedHashMap",
"java_class": "java.util.LinkedHashMap",
...
}
},
"status": 400
}
```
Once you have a class you can go to [*Painless API Reference*](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference.html) to see a list of available methods.

View file

@ -0,0 +1,122 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-field-context.html
---
# Field context [painless-field-context]
Use a Painless script to create a [script field](/reference/elasticsearch/rest-apis/retrieve-selected-fields.md#script-fields) to return a customized value for each document in the results of a query.
**Variables**
`params` (`Map`, read-only)
: User-defined parameters passed in as part of the query.
`doc` (`Map`, read-only)
: Contains the fields of the specified document where each field is a `List` of values.
[`params['_source']`](/reference/elasticsearch/mapping-reference/mapping-source-field.md) (`Map`, read-only)
: Contains extracted JSON in a `Map` and `List` structure for the fields existing in a stored document.
**Return**
`Object`
: The customized value for each document.
**API**
Both the standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) and [Specialized Field API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-field.html) are available.
**Example**
To run this example, first follow the steps in [context examples](/reference/scripting-languages/painless/painless-context-examples.md).
You can then use these two example scripts to compute custom information for each search hit and output it to two new fields.
The first script gets the doc value for the `datetime` field and calls the `getDayOfWeekEnum` function to determine the corresponding day of the week.
```painless
doc['datetime'].value.getDayOfWeekEnum().getDisplayName(TextStyle.FULL, Locale.ROOT)
```
The second script calculates the number of actors. Actors' names are stored as a keyword array in the `actors` field.
```painless
doc['actors'].size() <1>
```
1. By default, doc values are not available for `text` fields. If `actors` was a `text` field, you could still calculate the number of actors by extracting values from `_source` with `params['_source']['actors'].size()`.
The following request returns the calculated day of week and the number of actors that appear in each play:
```console
GET seats/_search
{
"size": 2,
"query": {
"match_all": {}
},
"script_fields": {
"day-of-week": {
"script": {
"source": "doc['datetime'].value.getDayOfWeekEnum().getDisplayName(TextStyle.FULL, Locale.ENGLISH)"
}
},
"number-of-actors": {
"script": {
"source": "doc['actors'].size()"
}
}
}
}
```
```console-result
{
"took" : 68,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 11,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "seats",
"_id" : "1",
"_score" : 1.0,
"fields" : {
"day-of-week" : [
"Thursday"
],
"number-of-actors" : [
4
]
}
},
{
"_index" : "seats",
"_id" : "2",
"_score" : 1.0,
"fields" : {
"day-of-week" : [
"Thursday"
],
"number-of-actors" : [
1
]
}
}
]
}
}
```

View file

@ -0,0 +1,58 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-filter-context.html
---
# Filter context [painless-filter-context]
Use a Painless script as a [filter](/reference/query-languages/query-dsl-script-query.md) in a query to include and exclude documents.
**Variables**
`params` (`Map`, read-only)
: User-defined parameters passed in as part of the query.
`doc` (`Map`, read-only)
: Contains the fields of the current document where each field is a `List` of values.
**Return**
`boolean`
: Return `true` if the current document should be returned as a result of the query, and `false` otherwise.
**API**
The standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) is available.
**Example**
To run this example, first follow the steps in [context examples](/reference/scripting-languages/painless/painless-context-examples.md).
This script finds all unsold documents that cost less than $25.
```painless
doc['sold'].value == false && doc['cost'].value < 25
```
Defining `cost` as a script parameter enables the cost to be configured in the script query request. For example, the following request finds all available theatre seats for evening performances that are under $25.
```console
GET seats/_search
{
"query": {
"bool": {
"filter": {
"script": {
"script": {
"source": "doc['sold'].value == false && doc['cost'].value < params.cost",
"params": {
"cost": 25
}
}
}
}
}
}
}
```

View file

@ -0,0 +1,19 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-functions.html
---
# Functions [painless-functions]
A function is a named piece of code comprised of one-to-many statements to perform a specific task. A function is called multiple times in a single script to repeat its specific task. A parameter is a named type value available as a [variable](/reference/scripting-languages/painless/painless-variables.md) within the statement(s) of a function. A function specifies zero-to-many parameters, and when a function is called a value is specified per parameter. An argument is a value passed into a function at the point of call. A function specifies a return type value, though if the type is [void](/reference/scripting-languages/painless/painless-types.md#void-type) then no value is returned. Any non-void type return value is available for use within an [operation](/reference/scripting-languages/painless/painless-operators.md) or is discarded otherwise.
You can declare functions at the beginning of a Painless script, for example:
```painless
boolean isNegative(def x) { x < 0 }
...
if (isNegative(someVar)) {
...
}
```

View file

@ -0,0 +1,35 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-identifiers.html
---
# Identifiers [painless-identifiers]
Use an identifier as a named token to specify a [variable](/reference/scripting-languages/painless/painless-variables.md), [type](/reference/scripting-languages/painless/painless-types.md), [field](/reference/scripting-languages/painless/painless-operators-reference.md#field-access-operator), [method](/reference/scripting-languages/painless/painless-operators-reference.md#method-call-operator), or [function](/reference/scripting-languages/painless/painless-functions.md).
**Errors**
If a [keyword](/reference/scripting-languages/painless/painless-keywords.md) is used as an identifier.
**Grammar**
```text
ID: [_a-zA-Z] [_a-zA-Z-0-9]*;
```
**Examples**
* Variations of identifiers.
```painless
a
Z
id
list
list0
MAP25
_map25
Map_25
```

View file

@ -0,0 +1,119 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-ingest-processor-context.html
---
# Ingest processor context [painless-ingest-processor-context]
Use a Painless script in an [ingest processor](/reference/ingestion-tools/enrich-processor/script-processor.md) to modify documents upon insertion.
**Variables**
`params` (`Map`, read-only)
: User-defined parameters passed in as part of the query.
[`ctx['_index']`](/reference/elasticsearch/mapping-reference/mapping-index-field.md) (`String`)
: The name of the index.
`ctx` (`Map`)
: Contains extracted JSON in a `Map` and `List` structure for the fields that are part of the document.
**Side Effects**
[`ctx['_index']`](/reference/elasticsearch/mapping-reference/mapping-index-field.md)
: Modify this to change the destination index for the current document.
`ctx` (`Map`)
: Modify the values in the `Map/List` structure to add, modify, or delete the fields of a document.
**Return**
void
: No expected return value.
**API**
Both the standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) and [Specialized Ingest API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-ingest.html) are available.
**Example**
To run this example, first follow the steps in [context examples](/reference/scripting-languages/painless/painless-context-examples.md).
The seat data contains:
* A date in the format `YYYY-MM-DD` where the second digit of both month and day is optional.
* A time in the format HH:MM* where the second digit of both hours and minutes is optional. The star (*) represents either the `String` `AM` or `PM`.
The following ingest script processes the date and time `Strings` and stores the result in a `datetime` field.
```painless
String[] dateSplit = ctx.date.splitOnToken("-"); <1>
String year = dateSplit[0].trim();
String month = dateSplit[1].trim();
if (month.length() == 1) { <2>
month = "0" + month;
}
String day = dateSplit[2].trim();
if (day.length() == 1) { <3>
day = "0" + day;
}
boolean pm = ctx.time.substring(ctx.time.length() - 2).equals("PM"); <4>
String[] timeSplit = ctx.time.substring(0,
ctx.time.length() - 2).splitOnToken(":"); <5>
int hours = Integer.parseInt(timeSplit[0].trim());
int minutes = Integer.parseInt(timeSplit[1].trim());
if (pm) { <6>
hours += 12;
}
String dts = year + "-" + month + "-" + day + "T" +
(hours < 10 ? "0" + hours : "" + hours) + ":" +
(minutes < 10 ? "0" + minutes : "" + minutes) +
":00+08:00"; <7>
ZonedDateTime dt = ZonedDateTime.parse(
dts, DateTimeFormatter.ISO_OFFSET_DATE_TIME); <8>
ctx.datetime = dt.getLong(ChronoField.INSTANT_SECONDS)*1000L; <9>
```
1. Uses the `splitOnToken` function to separate the date `String` from the seat data into year, month, and day `Strings`.
NOTE : The use of the `ctx` ingest processor context variable to retrieve the data from the `date` field.
2. Appends the [string literal](/reference/scripting-languages/painless/painless-literals.md#string-literals) `"0"` value to a single digit month since the format of the seat data allows for this case.
3. Appends the [string literal](/reference/scripting-languages/painless/painless-literals.md#string-literals) `"0"` value to a single digit day since the format of the seat data allows for this case.
4. Sets the [`boolean type`](/reference/scripting-languages/painless/painless-types.md#primitive-types) [variable](/reference/scripting-languages/painless/painless-variables.md) to `true` if the time `String` is a time in the afternoon or evening.
NOTE: The use of the `ctx` ingest processor context variable to retrieve the data from the `time` field.
5. Uses the `splitOnToken` function to separate the time `String` from the seat data into hours and minutes `Strings`.
NOTE: The use of the `substring` method to remove the `AM` or `PM` portion of the time `String`. The use of the `ctx` ingest processor context variable to retrieve the data from the `date` field.
6. If the time `String` is an afternoon or evening value adds the [integer literal](/reference/scripting-languages/painless/painless-literals.md#integer-literals) `12` to the existing hours to move to a 24-hour based time.
7. Builds a new time `String` that is parsable using existing API methods.
8. Creates a `ZonedDateTime` [reference type](/reference/scripting-languages/painless/painless-types.md#reference-types) value by using the API method `parse` to parse the new time `String`.
9. Sets the datetime field `datetime` to the number of milliseconds retrieved from the API method `getLong`.
NOTEL The use of the `ctx` ingest processor context variable to set the field `datetime`. Manipulate each documents fields with the `ctx` variable as each document is indexed.
Submit the following request:
```console
PUT /_ingest/pipeline/seats
{
"description": "update datetime for seats",
"processors": [
{
"script": {
"source": "String[] dateSplit = ctx.date.splitOnToken('-'); String year = dateSplit[0].trim(); String month = dateSplit[1].trim(); if (month.length() == 1) { month = '0' + month; } String day = dateSplit[2].trim(); if (day.length() == 1) { day = '0' + day; } boolean pm = ctx.time.substring(ctx.time.length() - 2).equals('PM'); String[] timeSplit = ctx.time.substring(0, ctx.time.length() - 2).splitOnToken(':'); int hours = Integer.parseInt(timeSplit[0].trim()); int minutes = Integer.parseInt(timeSplit[1].trim()); if (pm) { hours += 12; } String dts = year + '-' + month + '-' + day + 'T' + (hours < 10 ? '0' + hours : '' + hours) + ':' + (minutes < 10 ? '0' + minutes : '' + minutes) + ':00+08:00'; ZonedDateTime dt = ZonedDateTime.parse(dts, DateTimeFormatter.ISO_OFFSET_DATE_TIME); ctx.datetime = dt.getLong(ChronoField.INSTANT_SECONDS)*1000L;"
}
}
]
}
```

View file

@ -0,0 +1,21 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-keywords.html
---
# Keywords [painless-keywords]
Keywords are reserved tokens for built-in language features.
**Errors**
* If a keyword is used as an [identifier](/reference/scripting-languages/painless/painless-identifiers.md).
**Keywords**
| | | | | |
| --- | --- | --- | --- | --- |
| if | else | while | do | for |
| in | continue | break | return | new |
| try | catch | throw | this | instanceof |

View file

@ -0,0 +1,19 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-lambdas.html
---
# Lambdas [painless-lambdas]
Lambda expressions and method references work the same as in [Java](https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.md).
```painless
list.removeIf(item -> item == 2);
list.removeIf((int item) -> item == 2);
list.removeIf((int item) -> { item == 2 });
list.sort((x, y) -> x - y);
list.sort(Integer::compare);
```
You can make method references to functions within the script with `this`, for example `list.sort(this::mycompare)`.

View file

@ -0,0 +1,29 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-lang-spec.html
---
# Painless language specification [painless-lang-spec]
Painless is a scripting language designed for security and performance. Painless syntax is similar to Java syntax along with some additional features such as dynamic typing, Map and List accessor shortcuts, and array initializers. As a direct comparison to Java, there are some important differences, especially related to the casting model. For more detailed conceptual information about the basic constructs that Painless and Java share, refer to the corresponding topics in the [Java Language Specification](https://docs.oracle.com/javase/specs/jls/se8/html/index.md).
Painless scripts are parsed and compiled using the [ANTLR4](https://www.antlr.org/) and [ASM](https://asm.ow2.org/) libraries. Scripts are compiled directly into Java Virtual Machine (JVM) byte code and executed against a standard JVM. This specification uses ANTLR4 grammar notation to describe the allowed syntax. However, the actual Painless grammar is more compact than what is shown here.

View file

@ -0,0 +1,110 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-literals.html
---
# Literals [painless-literals]
Use a literal to specify a value directly in an [operation](/reference/scripting-languages/painless/painless-operators.md).
## Integers [integer-literals]
Use an integer literal to specify an integer type value in decimal, octal, or hex notation of a [primitive type](/reference/scripting-languages/painless/painless-types.md#primitive-types) `int`, `long`, `float`, or `double`. Use the following single letter designations to specify the primitive type: `l` or `L` for `long`, `f` or `F` for `float`, and `d` or `D` for `double`. If not specified, the type defaults to `int`. Use `0` as a prefix to specify an integer literal as octal, and use `0x` or `0X` as a prefix to specify an integer literal as hex.
**Grammar**
```text
INTEGER: '-'? ( '0' | [1-9] [0-9]* ) [lLfFdD]?;
OCTAL: '-'? '0' [0-7]+ [lL]?;
HEX: '-'? '0' [xX] [0-9a-fA-F]+ [lL]?;
```
**Examples**
* Integer literals.
```painless
0 <1>
0D <2>
1234L <3>
-90f <4>
-022 <5>
0xF2A <6>
```
1. `int 0`
2. `double 0.0`
3. `long 1234`
4. `float -90.0`
5. `int -18` in octal
6. `int 3882` in hex
## Floats [float-literals]
Use a floating point literal to specify a floating point type value of a [primitive type](/reference/scripting-languages/painless/painless-types.md#primitive-types) `float` or `double`. Use the following single letter designations to specify the primitive type: `f` or `F` for `float` and `d` or `D` for `double`. If not specified, the type defaults to `double`.
**Grammar**
```text
DECIMAL: '-'? ( '0' | [1-9] [0-9]* ) (DOT [0-9]+)? EXPONENT? [fFdD]?;
EXPONENT: ( [eE] [+\-]? [0-9]+ );
```
**Examples**
* Floating point literals.
```painless
0.0 <1>
1E6 <2>
0.977777 <3>
-126.34 <4>
89.9F <5>
```
1. `double 0.0`
2. `double 1000000.0` in exponent notation
3. `double 0.977777`
4. `double -126.34`
5. `float 89.9`
## Strings [string-literals]
Use a string literal to specify a [`String` type](/reference/scripting-languages/painless/painless-types.md#string-type) value with either single-quotes or double-quotes. Use a `\"` token to include a double-quote as part of a double-quoted string literal. Use a `\'` token to include a single-quote as part of a single-quoted string literal. Use a `\\` token to include a backslash as part of any string literal.
**Grammar**
```text
STRING: ( '"' ( '\\"' | '\\\\' | ~[\\"] )*? '"' )
| ( '\'' ( '\\\'' | '\\\\' | ~[\\'] )*? '\'' );
```
**Examples**
* String literals using single-quotes.
```painless
'single-quoted string literal'
'\'single-quoted with escaped single-quotes\' and backslash \\'
'single-quoted with non-escaped "double-quotes"'
```
* String literals using double-quotes.
```painless
"double-quoted string literal"
"\"double-quoted with escaped double-quotes\" and backslash: \\"
"double-quoted with non-escaped 'single-quotes'"
```
## Characters [character-literals]
Character literals are not specified directly. Instead, use the [cast operator](/reference/scripting-languages/painless/painless-casting.md#string-character-casting) to convert a `String` type value into a `char` type value.

View file

@ -0,0 +1,26 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-metric-agg-combine-context.html
---
# Metric aggregation combine context [painless-metric-agg-combine-context]
Use a Painless script to [combine](/reference/data-analysis/aggregations/search-aggregations-metrics-scripted-metric-aggregation.md) values for use in a scripted metric aggregation. A combine script is run once per shard following a [map script](/reference/scripting-languages/painless/painless-metric-agg-map-context.md) and is optional as part of a full metric aggregation.
**Variables**
`params` (`Map`, read-only)
: User-defined parameters passed in as part of the query.
`state` (`Map`)
: `Map` with values available from the prior map script.
**Return**
`List`, `Map`, `String`, or primitive
: A value collected for use in a [reduce script](/reference/scripting-languages/painless/painless-metric-agg-reduce-context.md). If no reduce script is specified, the value is used as part of the result.
**API**
The standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) is available.

View file

@ -0,0 +1,31 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-metric-agg-init-context.html
---
# Metric aggregation initialization context [painless-metric-agg-init-context]
Use a Painless script to [initialize](/reference/data-analysis/aggregations/search-aggregations-metrics-scripted-metric-aggregation.md) values for use in a scripted metric aggregation. An initialization script is run prior to document collection once per shard and is optional as part of the full metric aggregation.
**Variables**
`params` (`Map`, read-only)
: User-defined parameters passed in as part of the query.
`state` (`Map`)
: Empty `Map` used to add values for use in a [map script](/reference/scripting-languages/painless/painless-metric-agg-map-context.md).
**Side Effects**
`state` (`Map`)
: Add values to this `Map` to for use in a map. Additional values must be of the type `Map`, `List`, `String` or primitive.
**Return**
`void`
: No expected return value.
**API**
The standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) is available.

View file

@ -0,0 +1,37 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-metric-agg-map-context.html
---
# Metric aggregation map context [painless-metric-agg-map-context]
Use a Painless script to [map](/reference/data-analysis/aggregations/search-aggregations-metrics-scripted-metric-aggregation.md) values for use in a scripted metric aggregation. A map script is run once per collected document following an optional [initialization script](/reference/scripting-languages/painless/painless-metric-agg-init-context.md) and is required as part of a full metric aggregation.
**Variables**
`params` (`Map`, read-only)
: User-defined parameters passed in as part of the query.
`state` (`Map`)
: `Map` used to add values for processing in a [combine script](./painless-metric-agg-combine-context.md) or to be returned from the aggregation.
`doc` (`Map`, read-only)
: Contains the fields of the current document where each field is a `List` of values.
`_score` (`double` read-only)
: The similarity score of the current document.
**Side Effects**
`state` (`Map`)
: Use this `Map` to add values for processing in a combine script. Additional values must be of the type `Map`, `List`, `String` or primitive. The same `state` `Map` is shared between all aggregated documents on a given shard. If an initialization script is provided as part of the aggregation then values added from the initialization script are available. If no combine script is specified, values must be directly stored in `state` in a usable form. If no combine script and no [reduce script](/reference/scripting-languages/painless/painless-metric-agg-reduce-context.md) are specified, the `state` values are used as the result.
**Return**
`void`
: No expected return value.
**API**
The standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) is available.

View file

@ -0,0 +1,26 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-metric-agg-reduce-context.html
---
# Metric aggregation reduce context [painless-metric-agg-reduce-context]
Use a Painless script to [reduce](/reference/data-analysis/aggregations/search-aggregations-metrics-scripted-metric-aggregation.md) values to produce the result of a scripted metric aggregation. A reduce script is run once on the coordinating node following a [combine script](/reference/scripting-languages/painless/painless-metric-agg-combine-context.md) (or a [map script](/reference/scripting-languages/painless/painless-metric-agg-map-context.md) if no combine script is specified) and is optional as part of a full metric aggregation.
**Variables**
`params` (`Map`, read-only)
: User-defined parameters passed in as part of the query.
`states` (`Map`)
: `Map` with values available from the prior combine script (or a map script if no combine script is specified).
**Return**
`List`, `Map`, `String`, or primitive
: A value used as the result.
**API**
The standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) is available.

View file

@ -0,0 +1,68 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-min-should-match-context.html
---
# Minimum should match context [painless-min-should-match-context]
Use a Painless script to specify the [minimum](/reference/query-languages/query-dsl-terms-set-query.md) number of terms that a specified field needs to match with for a document to be part of the query results.
**Variables**
`params` (`Map`, read-only)
: User-defined parameters passed in as part of the query.
`params['num_terms']` (`int`, read-only)
: The number of terms specified to match with.
`doc` (`Map`, read-only)
: Contains the fields of the current document where each field is a `List` of values.
**Return**
`int`
: The minimum number of terms required to match the current document.
**API**
The standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) is available.
**Example**
To run this example, first follow the steps in [context examples](/reference/scripting-languages/painless/painless-context-examples.md).
Imagine that you want to find seats to performances by your favorite actors. You have a list of favorite actors in mind, and you want to find performances where the cast includes at least a certain number of them.
To achieve this result, use a `terms_set` query with `minimum_should_match_script`. To make the query request more configurable, you can define `min_actors_to_see` as a script parameter.
To ensure that the parameter `min_actors_to_see` doesnt exceed the number of favorite actors, you can use `num_terms` to get the number of actors in the list and `Math.min` to get the lesser of the two.
```painless
Math.min(params['num_terms'], params['min_actors_to_see'])
```
The following request finds seats to performances with at least two of the three specified actors.
```console
GET seats/_search
{
"query": {
"terms_set": {
"actors": {
"terms": [
"smith",
"earns",
"black"
],
"minimum_should_match_script": {
"source": "Math.min(params['num_terms'], params['min_actors_to_see'])",
"params": {
"min_actors_to_see": 2
}
}
}
}
}
}
```

View file

@ -0,0 +1,170 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-operators-array.html
---
# Operators: Array [painless-operators-array]
## Array Initialization [array-initialization-operator]
Use the `array initialization operator '[] {}'` to allocate a single-dimensional [array type](/reference/scripting-languages/painless/painless-types.md#array-type) instance to the heap with a set of pre-defined elements. Each value used to initialize an element in the array type instance is cast to the specified element type value upon insertion. The order of specified values is maintained.
**Errors**
* If a value is not castable to the specified type value.
**Grammar**
```text
array_initialization: 'new' TYPE '[' ']' '{' expression_list '}'
| 'new' TYPE '[' ']' '{' '}';
expression_list: expression (',' expression);
```
**Example:**
* Array initialization with static values.
```painless
int[] x = new int[] {1, 2, 3}; <1>
```
1. declare `int[] x`; allocate `1-d int array` instance with `length [3]``1-d int array reference`; store `int 1` to `index [0]` of `1-d int array reference`; store `int 2` to `index [1]` of `1-d int array reference`; store `int 3` to `index [2]` of `1-d int array reference`; store `1-d int array reference` to `x`;
* Array initialization with non-static values.
```painless
int i = 1; <1>
long l = 2L; <2>
float f = 3.0F; <3>
double d = 4.0; <4>
String s = "5"; <5>
def array = new def[] {i, l, f*d, s}; <6>
```
1. declare `int i`; store `int 1` to `i`
2. declare `long l`; store `long 2` to `l`
3. declare `float f`; store `float 3.0` to `f`
4. declare `double d`; store `double 4.0` to `d`
5. declare `String s`; store `String "5"` to `s`
6. declare `def array`; allocate `1-d def array` instance with `length [4]``1-d def array reference`; load from `i``int 1`; implicit cast `int 1` to `def``def`; store `def` to `index [0]` of `1-d def array reference`; load from `l``long 2`; implicit cast `long 2` to `def``def`; store `def` to `index [1]` of `1-d def array reference`; load from `f``float 3.0`; load from `d``double 4.0`; promote `float 3.0` and `double 4.0`: result `double`; implicit cast `float 3.0` to `double 3.0``double 3.0`; multiply `double 3.0` and `double 4.0``double 12.0`; implicit cast `double 12.0` to `def``def`; store `def` to `index [2]` of `1-d def array reference`; load from `s``String "5"`; implicit cast `String "5"` to `def``def`; store `def` to `index [3]` of `1-d def array reference`; implicit cast `1-d int array reference` to `def``def`; store `def` to `array`
## Array Access [array-access-operator]
Use the `array access operator '[]'` to store a value to or load a value from an [array type](/reference/scripting-languages/painless/painless-types.md#array-type) value. Each element of an array type value is accessed with an `int` type value to specify the index to store/load. The range of elements within an array that are accessible is `[0, size)` where size is the number of elements specified at the time of allocation. Use a negative `int` type value as an index to access an element in reverse from the end of an array type value within a range of `[-size, -1]`.
**Errors**
* If a value other than an `int` type value or a value that is castable to an `int` type value is provided as an index.
* If an element is accessed outside of the valid ranges.
**Grammar**
```text
brace_access: '[' expression ']'
```
**Examples**
* Array access with a single-dimensional array.
```painless
int[] x = new int[2]; <1>
x[0] = 2; <2>
x[1] = 5; <3>
int y = x[0] + x[1]; <4>
int z = 1; <5>
int i = x[z]; <6>
```
1. declare `int[] x`; allocate `1-d int array` instance with `length [2]``1-d int array reference`; store `1-d int array reference` to `x`
2. load from `x``1-d int array reference`; store `int 2` to `index [0]` of `1-d int array reference`;
3. load from `x``1-d int array reference`; store `int 5` to `index [1]` of `1-d int array reference`;
4. declare `int y`; load from `x``1-d int array reference`; load from `index [0]` of `1-d int array reference``int 2`; load from `x``1-d int array reference`; load from `index [1]` of `1-d int array reference``int 5`; add `int 2` and `int 5``int 7`; store `int 7` to `y`
5. declare `int z`; store `int 1` to `z`;
6. declare `int i`; load from `x``1-d int array reference`; load from `z``int 1`; load from `index [1]` of `1-d int array reference``int 5`; store `int 5` to `i`;
* Array access with the `def` type.
```painless
def d = new int[2]; <1>
d[0] = 2; <2>
d[1] = 5; <3>
def x = d[0] + d[1]; <4>
def y = 1; <5>
def z = d[y]; <6>
```
1. declare `def d`; allocate `1-d int array` instance with `length [2]``1-d int array reference`; implicit cast `1-d int array reference` to `def``def`; store `def` to `d`
2. load from `d``def` implicit cast `def` to `1-d int array reference``1-d int array reference`; store `int 2` to `index [0]` of `1-d int array reference`;
3. load from `d``def` implicit cast `def` to `1-d int array reference``1-d int array reference`; store `int 5` to `index [1]` of `1-d int array reference`;
4. declare `int x`; load from `d``def` implicit cast `def` to `1-d int array reference``1-d int array reference`; load from `index [0]` of `1-d int array reference``int 2`; load from `d``def` implicit cast `def` to `1-d int array reference``1-d int array reference`; load from `index [1]` of `1-d int array reference``int 5`; add `int 2` and `int 5``int 7`; implicit cast `int 7` to `def``def`; store `def` to `x`
5. declare `def y`; implicit cast `int 1` to `def``def`; store `def` to `y`;
6. declare `int i`; load from `d``def` implicit cast `def` to `1-d int array reference``1-d int array reference`; load from `y``def`; implicit cast `def` to `int 1``int 1`; load from `index [1]` of `1-d int array reference``int 5`; implicit cast `int 5` to `def`; store `def` to `z`;
* Array access with a multi-dimensional array.
```painless
int[][][] ia3 = new int[2][3][4]; <1>
ia3[1][2][3] = 99; <2>
int i = ia3[1][2][3]; <3>
```
1. declare `int[][][] ia`; allocate `3-d int array` instance with length `[2, 3, 4]``3-d int array reference`; store `3-d int array reference` to `ia3`
2. load from `ia3``3-d int array reference`; store `int 99` to `index [1, 2, 3]` of `3-d int array reference`
3. declare `int i`; load from `ia3``3-d int array reference`; load from `index [1, 2, 3]` of `3-d int array reference``int 99`; store `int 99` to `i`
## Array Length [array-length-operator]
An array type value contains a read-only member field named `length`. The `length` field stores the size of the array as an `int` type value where size is the number of elements specified at the time of allocation. Use the [field access operator](/reference/scripting-languages/painless/painless-operators-reference.md#field-access-operator) to load the field `length` from an array type value.
**Examples**
* Access the `length` field.
```painless
int[] x = new int[10]; <1>
int l = x.length; <2>
```
1. declare `int[] x`; allocate `1-d int array` instance with `length [2]``1-d int array reference`; store `1-d int array reference` to `x`
2. declare `int l`; load `x``1-d int array reference`; load `length` from `1-d int array reference``int 10`; store `int 10` to `l`;
## New Array [new-array-operator]
Use the `new array operator 'new []'` to allocate an array type instance to the heap. Specify the element type following the `new` token. Specify each dimension with the `[` and `]` tokens following the element type name. The size of each dimension is specified by an `int` type value in between each set of `[` and `]` tokens.
**Errors**
* If a value other than an `int` type value or a value that is castable to an `int` type value is specified for a dimensions size.
**Grammar**
```text
new_array: 'new' TYPE ('[' expression ']')+;
```
**Examples**
* Allocation of different array types.
```painless
int[] x = new int[5]; <1>
x = new int[10]; <2>
int y = 2; <3>
def z = new def[y][y*2]; <4>
```
1. declare `int[] x`; allocate `1-d int array` instance with `length [5]``1-d int array reference`; store `1-d int array reference` to `x`
2. allocate `1-d int array` instance with `length [10]``1-d int array reference`; store `1-d int array reference` to `x`
3. declare `int y`; store `int 2` to `y`;
4. declare `def z`; load from `y``int 2 @0`; load from `y``int 2 @1`; multiply `int 2 @1` by `int 2 @2``int 4`; allocate `2-d int array` instance with length `[2, 4]``2-d int array reference`; implicit cast `2-d int array reference` to `def``def`; store `def` to `z`;

View file

@ -0,0 +1,888 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-operators-boolean.html
---
# Operators: Boolean [painless-operators-boolean]
## Boolean Not [boolean-not-operator]
Use the `boolean not operator '!'` to NOT a `boolean` type value where `true` is flipped to `false` and `false` is flipped to `true`.
**Errors**
* If a value other than a `boolean` type value or a value that is castable to a `boolean` type value is given.
**Truth**
| original | result |
| --- | --- |
| true | false |
| false | true |
**Grammar**
```text
boolean_not: '!' expression;
```
**Examples**
* Boolean not with the `boolean` type.
```painless
boolean x = !false; <1>
boolean y = !x; <2>
```
1. declare `boolean x`; boolean not `boolean false``boolean true`; store `boolean true` to `x`
2. declare `boolean y`; load from `x``boolean true`; boolean not `boolean true``boolean false`; store `boolean false` to `y`
* Boolean not with the `def` type.
```painless
def y = true; <1>
def z = !y; <2>
```
1. declare `def y`; implicit cast `boolean true` to `def``def`; store `true` to `y`
2. declare `def z`; load from `y``def`; implicit cast `def` to `boolean true` → boolean `true`; boolean not `boolean true``boolean false`; implicit cast `boolean false` to `def``def`; store `def` to `z`
## Greater Than [greater-than-operator]
Use the `greater than operator '>'` to COMPARE two numeric type values where a resultant `boolean` type value is `true` if the left-hand side value is greater than to the right-hand side value and `false` otherwise.
**Errors**
* If either the evaluated left-hand side or the evaluated right-hand side is a non-numeric value.
**Grammar**
```text
greater_than: expression '>' expression;
```
**Promotion**
| | | | | | | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| | byte | short | char | int | long | float | double | def |
| byte | int | int | int | int | long | float | double | def |
| short | int | int | int | int | long | float | double | def |
| char | int | int | int | int | long | float | double | def |
| int | int | int | int | int | long | float | double | def |
| long | long | long | long | long | long | float | double | def |
| float | float | float | float | float | float | float | double | def |
| double | double | double | double | double | double | double | double | def |
| def | def | def | def | def | def | def | def | def |
**Examples**
* Greater than with different numeric types.
```painless
boolean x = 5 > 4; <1>
double y = 6.0; <2>
x = 6 > y; <3>
```
1. declare `boolean x`; greater than `int 5` and `int 4``boolean true`; store `boolean true` to `x`;
2. declare `double y`; store `double 6.0` to `y`;
3. load from `y``double 6.0 @0`; promote `int 6` and `double 6.0`: result `double`; implicit cast `int 6` to `double 6.0 @1``double 6.0 @1`; greater than `double 6.0 @1` and `double 6.0 @0``boolean false`; store `boolean false` to `x`
* Greater than with `def` type.
```painless
int x = 5; <1>
def y = 7.0; <2>
def z = y > 6.5; <3>
def a = x > y; <4>
```
1. declare `int x`; store `int 5` to `x`
2. declare `def y`; implicit cast `double 7.0` to `def``def`; store `def` to `y`
3. declare `def z`; load from `y``def`; implicit cast `def` to `double 7.0``double 7.0`; greater than `double 7.0` and `double 6.5``boolean true`; implicit cast `boolean true` to `def``def`; store `def` to `z`
4. declare `def a`; load from `y``def`; implicit cast `def` to `double 7.0``double 7.0`; load from `x``int 5`; promote `int 5` and `double 7.0`: result `double`; implicit cast `int 5` to `double 5.0``double 5.0`; greater than `double 5.0` and `double 7.0``boolean false`; implicit cast `boolean false` to `def``def`; store `def` to `z`
## Greater Than Or Equal [greater-than-or-equal-operator]
Use the `greater than or equal operator '>='` to COMPARE two numeric type values where a resultant `boolean` type value is `true` if the left-hand side value is greater than or equal to the right-hand side value and `false` otherwise.
**Errors**
* If either the evaluated left-hand side or the evaluated right-hand side is a non-numeric value.
**Grammar**
```text
greater_than_or_equal: expression '>=' expression;
```
**Promotion**
| | | | | | | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| | byte | short | char | int | long | float | double | def |
| byte | int | int | int | int | long | float | double | def |
| short | int | int | int | int | long | float | double | def |
| char | int | int | int | int | long | float | double | def |
| int | int | int | int | int | long | float | double | def |
| long | long | long | long | long | long | float | double | def |
| float | float | float | float | float | float | float | double | def |
| double | double | double | double | double | double | double | double | def |
| def | def | def | def | def | def | def | def | def |
**Examples**
* Greater than or equal with different numeric types.
```painless
boolean x = 5 >= 4; <1>
double y = 6.0; <2>
x = 6 >= y; <3>
```
1. declare `boolean x`; greater than or equal `int 5` and `int 4``boolean true`; store `boolean true` to `x`
2. declare `double y`; store `double 6.0` to `y`
3. load from `y``double 6.0 @0`; promote `int 6` and `double 6.0`: result `double`; implicit cast `int 6` to `double 6.0 @1``double 6.0 @1`; greater than or equal `double 6.0 @1` and `double 6.0 @0``boolean true`; store `boolean true` to `x`
* Greater than or equal with the `def` type.
```painless
int x = 5; <1>
def y = 7.0; <2>
def z = y >= 7.0; <3>
def a = x >= y; <4>
```
1. declare `int x`; store `int 5` to `x`;
2. declare `def y` implicit cast `double 7.0` to `def``def`; store `def` to `y`
3. declare `def z`; load from `y``def`; implicit cast `def` to `double 7.0 @0``double 7.0 @0`; greater than or equal `double 7.0 @0` and `double 7.0 @1``boolean true`; implicit cast `boolean true` to `def``def`; store `def` to `z`
4. declare `def a`; load from `y``def`; implicit cast `def` to `double 7.0``double 7.0`; load from `x``int 5`; promote `int 5` and `double 7.0`: result `double`; implicit cast `int 5` to `double 5.0``double 5.0`; greater than or equal `double 5.0` and `double 7.0``boolean false`; implicit cast `boolean false` to `def``def`; store `def` to `z`
## Less Than [less-than-operator]
Use the `less than operator '<'` to COMPARE two numeric type values where a resultant `boolean` type value is `true` if the left-hand side value is less than to the right-hand side value and `false` otherwise.
**Errors**
* If either the evaluated left-hand side or the evaluated right-hand side is a non-numeric value.
**Grammar**
```text
less_than: expression '<' expression;
```
**Promotion**
| | | | | | | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| | byte | short | char | int | long | float | double | def |
| byte | int | int | int | int | long | float | double | def |
| short | int | int | int | int | long | float | double | def |
| char | int | int | int | int | long | float | double | def |
| int | int | int | int | int | long | float | double | def |
| long | long | long | long | long | long | float | double | def |
| float | float | float | float | float | float | float | double | def |
| double | double | double | double | double | double | double | double | def |
| def | def | def | def | def | def | def | def | def |
**Examples**
* Less than with different numeric types.
```painless
boolean x = 5 < 4; <1>
double y = 6.0; <2>
x = 6 < y; <3>
```
1. declare `boolean x`; less than `int 5` and `int 4``boolean false`; store `boolean false` to `x`
2. declare `double y`; store `double 6.0` to `y`
3. load from `y``double 6.0 @0`; promote `int 6` and `double 6.0`: result `double`; implicit cast `int 6` to `double 6.0 @1``double 6.0 @1`; less than `double 6.0 @1` and `double 6.0 @0``boolean false`; store `boolean false` to `x`
* Less than with the `def` type.
```painless
int x = 5; <1>
def y = 7.0; <2>
def z = y < 6.5; <3>
def a = x < y; <4>
```
1. declare `int x`; store `int 5` to `x`
2. declare `def y`; implicit cast `double 7.0` to `def``def`; store `def` to `y`
3. declare `def z`; load from `y``def`; implicit cast `def` to `double 7.0``double 7.0`; less than `double 7.0` and `double 6.5``boolean false`; implicit cast `boolean false` to `def``def`; store `def` to `z`
4. declare `def a`; load from `y``def`; implicit cast `def` to `double 7.0``double 7.0`; load from `x``int 5`; promote `int 5` and `double 7.0`: result `double`; implicit cast `int 5` to `double 5.0``double 5.0`; less than `double 5.0` and `double 7.0``boolean true`; implicit cast `boolean true` to `def``def`; store `def` to `z`
## Less Than Or Equal [less-than-or-equal-operator]
Use the `less than or equal operator '<='` to COMPARE two numeric type values where a resultant `boolean` type value is `true` if the left-hand side value is less than or equal to the right-hand side value and `false` otherwise.
**Errors**
* If either the evaluated left-hand side or the evaluated right-hand side is a non-numeric value.
**Grammar**
```text
greater_than_or_equal: expression '<=' expression;
```
**Promotion**
| | | | | | | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| | byte | short | char | int | long | float | double | def |
| byte | int | int | int | int | long | float | double | def |
| short | int | int | int | int | long | float | double | def |
| char | int | int | int | int | long | float | double | def |
| int | int | int | int | int | long | float | double | def |
| long | long | long | long | long | long | float | double | def |
| float | float | float | float | float | float | float | double | def |
| double | double | double | double | double | double | double | double | def |
| def | def | def | def | def | def | def | def | def |
**Examples**
* Less than or equal with different numeric types.
```painless
boolean x = 5 <= 4; <1>
double y = 6.0; <2>
x = 6 <= y; <3>
```
1. declare `boolean x`; less than or equal `int 5` and `int 4``boolean false`; store `boolean true` to `x`
2. declare `double y`; store `double 6.0` to `y`
3. load from `y``double 6.0 @0`; promote `int 6` and `double 6.0`: result `double`; implicit cast `int 6` to `double 6.0 @1``double 6.0 @1`; less than or equal `double 6.0 @1` and `double 6.0 @0``boolean true`; store `boolean true` to `x`
* Less than or equal with the `def` type.
```painless
int x = 5; <1>
def y = 7.0; <2>
def z = y <= 7.0; <3>
def a = x <= y; <4>
```
1. declare `int x`; store `int 5` to `x`;
2. declare `def y`; implicit cast `double 7.0` to `def``def`; store `def` to `y`;
3. declare `def z`; load from `y``def`; implicit cast `def` to `double 7.0 @0``double 7.0 @0`; less than or equal `double 7.0 @0` and `double 7.0 @1``boolean true`; implicit cast `boolean true` to `def``def`; store `def` to `z`
4. declare `def a`; load from `y``def`; implicit cast `def` to `double 7.0``double 7.0`; load from `x``int 5`; promote `int 5` and `double 7.0`: result `double`; implicit cast `int 5` to `double 5.0``double 5.0`; less than or equal `double 5.0` and `double 7.0``boolean true`; implicit cast `boolean true` to `def``def`; store `def` to `z`
## Instanceof [instanceof-operator]
Use the `instanceof operator` to COMPARE the variable/field type to a specified reference type using the reference type name where a resultant `boolean` type value is `true` if the variable/field type is the same as or a descendant of the specified reference type and false otherwise.
**Errors**
* If the reference type name doesnt exist as specified by the right-hand side.
**Grammar**
```text
instance_of: ID 'instanceof' TYPE;
```
**Examples**
* Instance of with different reference types.
```painless
Map m = new HashMap(); <1>
boolean a = m instanceof HashMap; <2>
boolean b = m instanceof Map; <3>
```
1. declare `Map m`; allocate `HashMap` instance → `HashMap reference`; implicit cast `HashMap reference` to `Map reference`; store `Map reference` to `m`
2. declare `boolean a`; load from `m``Map reference`; implicit cast `Map reference` to `HashMap reference``HashMap reference`; instanceof `HashMap reference` and `HashMap``boolean true`; store `boolean true` to `a`
3. declare `boolean b`; load from `m``Map reference`; implicit cast `Map reference` to `HashMap reference``HashMap reference`; instanceof `HashMap reference` and `Map``boolean true`; store `true` to `b`; (note `HashMap` is a descendant of `Map`)
* Instance of with the `def` type.
```painless
def d = new ArrayList(); <1>
boolean a = d instanceof List; <2>
boolean b = d instanceof Map; <3>
```
1. declare `def d`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `def``def`; store `def` to `d`
2. declare `boolean a`; load from `d``def`; implicit cast `def` to `ArrayList reference``ArrayList reference`; instanceof `ArrayList reference` and `List``boolean true`; store `boolean true` to `a`; (note `ArrayList` is a descendant of `List`)
3. declare `boolean b`; load from `d``def`; implicit cast `def` to `ArrayList reference``ArrayList reference`; instanceof `ArrayList reference` and `Map``boolean false`; store `boolean false` to `a`; (note `ArrayList` is not a descendant of `Map`)
## Equality Equals [equality-equals-operator]
Use the `equality equals operator '=='` to COMPARE two values where a resultant `boolean` type value is `true` if the two values are equal and `false` otherwise. The member method, `equals`, is implicitly called when the values are reference type values where the first value is the target of the call and the second value is the argument. This operation is null-safe where if both values are `null` the resultant `boolean` type value is `true`, and if only one value is `null` the resultant `boolean` type value is `false`. A valid comparison is between `boolean` type values, numeric type values, or reference type values.
**Errors**
* If a comparison is made between a `boolean` type value and numeric type value.
* If a comparison is made between a primitive type value and a reference type value.
**Grammar**
```text
equality_equals: expression '==' expression;
```
**Promotion**
| | | | | | | | | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| | boolean | byte | short | char | int | long | float | double | Reference | def |
| boolean | boolean | - | - | - | - | - | - | - | - | def |
| byte | - | int | int | int | int | long | float | double | - | def |
| short | - | int | int | int | int | long | float | double | - | def |
| char | - | int | int | int | int | long | float | double | - | def |
| int | - | int | int | int | int | long | float | double | - | def |
| long | - | long | long | long | long | long | float | double | - | def |
| float | - | float | float | float | float | float | float | double | - | def |
| double | - | double | double | double | double | double | double | double | - | def |
| Reference | - | - | - | - | - | - | - | - | Object | def |
| def | def | def | def | def | def | def | def | def | def | def |
**Examples**
* Equality equals with the `boolean` type.
```painless
boolean a = true; <1>
boolean b = false; <2>
a = a == false; <3>
b = a == b; <4>
```
1. declare `boolean a`; store `boolean true` to `a`
2. declare `boolean b`; store `boolean false` to `b`
3. load from `a``boolean true`; equality equals `boolean true` and `boolean false``boolean false`; store `boolean false` to `a`
4. load from `a``boolean false @0`; load from `b``boolean false @1`; equality equals `boolean false @0` and `boolean false @1``boolean false`; store `boolean false` to `b`
* Equality equals with primitive types.
```painless
int a = 1; <1>
double b = 2.0; <2>
boolean c = a == b; <3>
c = 1 == a; <4>
```
1. declare `int a`; store `int 1` to `a`
2. declare `double b`; store `double 1.0` to `b`
3. declare `boolean c`; load from `a``int 1`; load from `b``double 2.0`; promote `int 1` and `double 2.0`: result `double`; implicit cast `int 1` to `double 1.0``double `1.0`; equality equals `double 1.0` and `double 2.0` → `boolean false`; store `boolean false` to `c`
4. load from `a``int 1 @1`; equality equals `int 1 @0` and `int 1 @1``boolean true`; store `boolean true` to `c`
* Equal equals with reference types.
```painless
List a = new ArrayList(); <1>
List b = new ArrayList(); <2>
a.add(1); <3>
boolean c = a == b; <4>
b.add(1); <5>
c = a == b; <6>
```
1. declare `List a`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `a`
2. declare `List b`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `b`
3. load from `a``List reference`; call `add` on `List reference` with arguments (`int 1)`
4. declare `boolean c`; load from `a``List reference @0`; load from `b``List reference @1`; call `equals` on `List reference @0` with arguments (`List reference @1`) → `boolean false`; store `boolean false` to `c`
5. load from `b``List reference`; call `add` on `List reference` with arguments (`int 1`)
6. load from `a``List reference @0`; load from `b``List reference @1`; call `equals` on `List reference @0` with arguments (`List reference @1`) → `boolean true`; store `boolean true` to `c`
* Equality equals with `null`.
```painless
Object a = null; <1>
Object b = null; <2>
boolean c = a == null; <3>
c = a == b; <4>
b = new Object(); <5>
c = a == b; <6>
```
1. declare `Object a`; store `null` to `a`
2. declare `Object b`; store `null` to `b`
3. declare `boolean c`; load from `a``null @0`; equality equals `null @0` and `null @1``boolean true`; store `boolean true` to `c`
4. load from `a``null @0`; load from `b``null @1`; equality equals `null @0` and `null @1``boolean true`; store `boolean true` to `c`
5. allocate `Object` instance → `Object reference`; store `Object reference` to `b`
6. load from `a``Object reference`; load from `b``null`; call `equals` on `Object reference` with arguments (`null`) → `boolean false`; store `boolean false` to `c`
* Equality equals with the `def` type.
```painless
def a = 0; <1>
def b = 1; <2>
boolean c = a == b; <3>
def d = new HashMap(); <4>
def e = new ArrayList(); <5>
c = d == e; <6>
```
1. declare `def a`; implicit cast `int 0` to `def``def`; store `def` to `a`;
2. declare `def b`; implicit cast `int 1` to `def``def`; store `def` to `b`;
3. declare `boolean c`; load from `a``def`; implicit cast `a` to `int 0``int 0`; load from `b``def`; implicit cast `b` to `int 1``int 1`; equality equals `int 0` and `int 1``boolean false`; store `boolean false` to `c`
4. declare `def d`; allocate `HashMap` instance → `HashMap reference`; implicit cast `HashMap reference` to `def``def` store `def` to `d`;
5. declare `def e`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `def``def` store `def` to `d`;
6. load from `d``def`; implicit cast `def` to `HashMap reference``HashMap reference`; load from `e``def`; implicit cast `def` to `ArrayList reference``ArrayList reference`; call `equals` on `HashMap reference` with arguments (`ArrayList reference`) → `boolean false`; store `boolean false` to `c`
## Equality Not Equals [equality-not-equals-operator]
Use the `equality not equals operator '!='` to COMPARE two values where a resultant `boolean` type value is `true` if the two values are NOT equal and `false` otherwise. The member method, `equals`, is implicitly called when the values are reference type values where the first value is the target of the call and the second value is the argument with the resultant `boolean` type value flipped. This operation is `null-safe` where if both values are `null` the resultant `boolean` type value is `false`, and if only one value is `null` the resultant `boolean` type value is `true`. A valid comparison is between boolean type values, numeric type values, or reference type values.
**Errors**
* If a comparison is made between a `boolean` type value and numeric type value.
* If a comparison is made between a primitive type value and a reference type value.
**Grammar**
```text
equality_not_equals: expression '!=' expression;
```
**Promotion**
| | | | | | | | | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| | boolean | byte | short | char | int | long | float | double | Reference | def |
| boolean | boolean | - | - | - | - | - | - | - | - | def |
| byte | - | int | int | int | int | long | float | double | - | def |
| short | - | int | int | int | int | long | float | double | - | def |
| char | - | int | int | int | int | long | float | double | - | def |
| int | - | int | int | int | int | long | float | double | - | def |
| long | - | long | long | long | long | long | float | double | - | def |
| float | - | float | float | float | float | float | float | double | - | def |
| double | - | double | double | double | double | double | double | double | - | def |
| Reference | - | - | - | - | - | - | - | - | Object | def |
| def | def | def | def | def | def | def | def | def | def | def |
**Examples**
* Equality not equals with the `boolean` type.
```painless
boolean a = true; <1>
boolean b = false; <2>
a = a != false; <3>
b = a != b; <4>
```
1. declare `boolean a`; store `boolean true` to `a`
2. declare `boolean b`; store `boolean false` to `b`
3. load from `a``boolean true`; equality not equals `boolean true` and `boolean false``boolean true`; store `boolean true` to `a`
4. load from `a``boolean true`; load from `b``boolean false`; equality not equals `boolean true` and `boolean false``boolean true`; store `boolean true` to `b`
* Equality not equals with primitive types.
```painless
int a = 1; <1>
double b = 2.0; <2>
boolean c = a != b; <3>
c = 1 != a; <4>
```
1. declare `int a`; store `int 1` to `a`
2. declare `double b`; store `double 1.0` to `b`
3. declare `boolean c`; load from `a``int 1`; load from `b``double 2.0`; promote `int 1` and `double 2.0`: result `double`; implicit cast `int 1` to `double 1.0``double `1.0`; equality not equals `double 1.0` and `double 2.0` → `boolean true`; store `boolean true` to `c`
4. load from `a``int 1 @1`; equality not equals `int 1 @0` and `int 1 @1``boolean false`; store `boolean false` to `c`
* Equality not equals with reference types.
```painless
List a = new ArrayList(); <1>
List b = new ArrayList(); <2>
a.add(1); <3>
boolean c = a == b; <4>
b.add(1); <5>
c = a == b; <6>
```
1. declare `List a`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `a`
2. declare `List b`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `b`
3. load from `a``List reference`; call `add` on `List reference` with arguments (`int 1)`
4. declare `boolean c`; load from `a``List reference @0`; load from `b``List reference @1`; call `equals` on `List reference @0` with arguments (`List reference @1`) → `boolean false`; boolean not `boolean false``boolean true` store `boolean true` to `c`
5. load from `b``List reference`; call `add` on `List reference` with arguments (`int 1`)
6. load from `a``List reference @0`; load from `b``List reference @1`; call `equals` on `List reference @0` with arguments (`List reference @1`) → `boolean true`; boolean not `boolean true``boolean false`; store `boolean false` to `c`
* Equality not equals with `null`.
```painless
Object a = null; <1>
Object b = null; <2>
boolean c = a == null; <3>
c = a == b; <4>
b = new Object(); <5>
c = a == b; <6>
```
1. declare `Object a`; store `null` to `a`
2. declare `Object b`; store `null` to `b`
3. declare `boolean c`; load from `a``null @0`; equality not equals `null @0` and `null @1``boolean false`; store `boolean false` to `c`
4. load from `a``null @0`; load from `b``null @1`; equality not equals `null @0` and `null @1``boolean false`; store `boolean false` to `c`
5. allocate `Object` instance → `Object reference`; store `Object reference` to `b`
6. load from `a``Object reference`; load from `b``null`; call `equals` on `Object reference` with arguments (`null`) → `boolean false`; boolean not `boolean false``boolean true`; store `boolean true` to `c`
* Equality not equals with the `def` type.
```painless
def a = 0; <1>
def b = 1; <2>
boolean c = a == b; <3>
def d = new HashMap(); <4>
def e = new ArrayList(); <5>
c = d == e; <6>
```
1. declare `def a`; implicit cast `int 0` to `def``def`; store `def` to `a`;
2. declare `def b`; implicit cast `int 1` to `def``def`; store `def` to `b`;
3. declare `boolean c`; load from `a``def`; implicit cast `a` to `int 0``int 0`; load from `b``def`; implicit cast `b` to `int 1``int 1`; equality equals `int 0` and `int 1``boolean false`; store `boolean false` to `c`
4. declare `def d`; allocate `HashMap` instance → `HashMap reference`; implicit cast `HashMap reference` to `def``def` store `def` to `d`;
5. declare `def e`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `def``def` store `def` to `d`;
6. load from `d``def`; implicit cast `def` to `HashMap reference``HashMap reference`; load from `e``def`; implicit cast `def` to `ArrayList reference``ArrayList reference`; call `equals` on `HashMap reference` with arguments (`ArrayList reference`) → `boolean false`; store `boolean false` to `c`
## Identity Equals [identity-equals-operator]
Use the `identity equals operator '==='` to COMPARE two values where a resultant `boolean` type value is `true` if the two values are equal and `false` otherwise. A reference type value is equal to another reference type value if both values refer to same instance on the heap or if both values are `null`. A valid comparison is between `boolean` type values, numeric type values, or reference type values.
**Errors**
* If a comparison is made between a `boolean` type value and numeric type value.
* If a comparison is made between a primitive type value and a reference type value.
**Grammar**
```text
identity_equals: expression '===' expression;
```
**Promotion**
| | | | | | | | | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| | boolean | byte | short | char | int | long | float | double | Reference | def |
| boolean | boolean | - | - | - | - | - | - | - | - | def |
| byte | - | int | int | int | int | long | float | double | - | def |
| short | - | int | int | int | int | long | float | double | - | def |
| char | - | int | int | int | int | long | float | double | - | def |
| int | - | int | int | int | int | long | float | double | - | def |
| long | - | long | long | long | long | long | float | double | - | def |
| float | - | float | float | float | float | float | float | double | - | def |
| double | - | double | double | double | double | double | double | double | - | def |
| Reference | - | - | - | - | - | - | - | - | Object | def |
| def | def | def | def | def | def | def | def | def | def | def |
**Examples**
* Identity equals with reference types.
```painless
List a = new ArrayList(); <1>
List b = new ArrayList(); <2>
List c = a; <3>
boolean c = a === b; <4>
c = a === c; <5>
```
1. declare `List a`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `a`
2. declare `List b`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `b`
3. load from `a``List reference`; store `List reference` to `c`
4. declare `boolean c`; load from `a``List reference @0`; load from `b``List reference @1`; identity equals `List reference @0` and `List reference @1``boolean false` store `boolean false` to `c`
5. load from `a``List reference @0`; load from `c``List reference @1`; identity equals `List reference @0` and `List reference @1``boolean true` store `boolean true` to `c` (note `List reference @0` and `List reference @1` refer to the same instance)
* Identity equals with `null`.
```painless
Object a = null; <1>
Object b = null; <2>
boolean c = a === null; <3>
c = a === b; <4>
b = new Object(); <5>
c = a === b; <6>
```
1. declare `Object a`; store `null` to `a`
2. declare `Object b`; store `null` to `b`
3. declare `boolean c`; load from `a``null @0`; identity equals `null @0` and `null @1``boolean true`; store `boolean true` to `c`
4. load from `a``null @0`; load from `b``null @1`; identity equals `null @0` and `null @1``boolean true`; store `boolean true` to `c`
5. allocate `Object` instance → `Object reference`; store `Object reference` to `b`
6. load from `a``Object reference`; load from `b``null`; identity equals `Object reference` and `null``boolean false`; store `boolean false` to `c`
* Identity equals with the `def` type.
```painless
def a = new HashMap(); <1>
def b = new ArrayList(); <2>
boolean c = a === b; <3>
b = a; <4>
c = a === b; <5>
```
1. declare `def d`; allocate `HashMap` instance → `HashMap reference`; implicit cast `HashMap reference` to `def``def` store `def` to `d`
2. declare `def e`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `def``def` store `def` to `d`
3. declare `boolean c`; load from `a``def`; implicit cast `def` to `HashMap reference``HashMap reference`; load from `b``def`; implicit cast `def` to `ArrayList reference``ArrayList reference`; identity equals `HashMap reference` and `ArrayList reference``boolean false`; store `boolean false` to `c`
4. load from `a``def`; store `def` to `b`
5. load from `a``def`; implicit cast `def` to `HashMap reference @0``HashMap reference @0`; load from `b``def`; implicit cast `def` to `HashMap reference @1``HashMap reference @1`; identity equals `HashMap reference @0` and `HashMap reference @1``boolean true`; store `boolean true` to `b`; (note `HashMap reference @0` and `HashMap reference @1` refer to the same instance)
## Identity Not Equals [identity-not-equals-operator]
Use the `identity not equals operator '!=='` to COMPARE two values where a resultant `boolean` type value is `true` if the two values are NOT equal and `false` otherwise. A reference type value is not equal to another reference type value if both values refer to different instances on the heap or if one value is `null` and the other is not. A valid comparison is between `boolean` type values, numeric type values, or reference type values.
**Errors**
* If a comparison is made between a `boolean` type value and numeric type value.
* If a comparison is made between a primitive type value and a reference type value.
**Grammar**
```text
identity_not_equals: expression '!==' expression;
```
**Promotion**
| | | | | | | | | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| | boolean | byte | short | char | int | long | float | double | Reference | def |
| boolean | boolean | - | - | - | - | - | - | - | - | def |
| byte | - | int | int | int | int | long | float | double | - | def |
| short | - | int | int | int | int | long | float | double | - | def |
| char | - | int | int | int | int | long | float | double | - | def |
| int | - | int | int | int | int | long | float | double | - | def |
| long | - | long | long | long | long | long | float | double | - | def |
| float | - | float | float | float | float | float | float | double | - | def |
| double | - | double | double | double | double | double | double | double | - | def |
| Reference | - | - | - | - | - | - | - | - | Object | def |
| def | def | def | def | def | def | def | def | def | def | def |
**Examples**
* Identity not equals with reference type values.
```painless
List a = new ArrayList(); <1>
List b = new ArrayList(); <2>
List c = a; <3>
boolean c = a !== b; <4>
c = a !== c; <5>
```
1. declare `List a`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `a`
2. declare `List b`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `b`
3. load from `a``List reference`; store `List reference` to `c`
4. declare `boolean c`; load from `a``List reference @0`; load from `b``List reference @1`; identity not equals `List reference @0` and `List reference @1``boolean true` store `boolean true` to `c`
5. load from `a``List reference @0`; load from `c``List reference @1`; identity not equals `List reference @0` and `List reference @1``boolean false` store `boolean false` to `c` (note `List reference @0` and `List reference @1` refer to the same instance)
* Identity not equals with `null`.
```painless
Object a = null; <1>
Object b = null; <2>
boolean c = a !== null; <3>
c = a !== b; <4>
b = new Object(); <5>
c = a !== b; <6>
```
1. declare `Object a`; store `null` to `a`
2. declare `Object b`; store `null` to `b`
3. declare `boolean c`; load from `a``null @0`; identity not equals `null @0` and `null @1``boolean false`; store `boolean false` to `c`
4. load from `a``null @0`; load from `b``null @1`; identity not equals `null @0` and `null @1``boolean false`; store `boolean false` to `c`
5. allocate `Object` instance → `Object reference`; store `Object reference` to `b`
6. load from `a``Object reference`; load from `b``null`; identity not equals `Object reference` and `null``boolean true`; store `boolean true` to `c`
* Identity not equals with the `def` type.
```painless
def a = new HashMap(); <1>
def b = new ArrayList(); <2>
boolean c = a !== b; <3>
b = a; <4>
c = a !== b; <5>
```
1. declare `def d`; allocate `HashMap` instance → `HashMap reference`; implicit cast `HashMap reference` to `def``def` store `def` to `d`
2. declare `def e`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `def``def` store `def` to `d`
3. declare `boolean c`; load from `a``def`; implicit cast `def` to `HashMap reference``HashMap reference`; load from `b``def`; implicit cast `def` to `ArrayList reference``ArrayList reference`; identity not equals `HashMap reference` and `ArrayList reference``boolean true`; store `boolean true` to `c`
4. load from `a``def`; store `def` to `b`
5. load from `a``def`; implicit cast `def` to `HashMap reference @0``HashMap reference @0`; load from `b``def`; implicit cast `def` to `HashMap reference @1``HashMap reference @1`; identity not equals `HashMap reference @0` and `HashMap reference @1``boolean false`; store `boolean false` to `b`; (note `HashMap reference @0` and `HashMap reference @1` refer to the same instance)
## Boolean Xor [boolean-xor-operator]
Use the `boolean xor operator '^'` to XOR together two `boolean` type values where if one `boolean` type value is `true` and the other is `false` the resultant `boolean` type value is `true` and `false` otherwise.
**Errors**
* If either evaluated value is a value other than a `boolean` type value or a value that is castable to a `boolean` type value.
**Truth**
| | | |
| --- | --- | --- |
| | true | false |
| true | false | true |
| false | true | false |
**Grammar**
```text
boolean_xor: expression '^' expression;
```
**Examples**
* Boolean xor with the `boolean` type.
```painless
boolean x = false; <1>
boolean y = x ^ true; <2>
y = y ^ x; <3>
```
1. declare `boolean x`; store `boolean false` to `x`
2. declare `boolean y`; load from `x``boolean false` boolean xor `boolean false` and `boolean true``boolean true`; store `boolean true` to `y`
3. load from `y``boolean true @0`; load from `x``boolean true @1`; boolean xor `boolean true @0` and `boolean true @1``boolean false`; store `boolean false` to `y`
* Boolean xor with the `def` type.
```painless
def x = false; <1>
def y = x ^ true; <2>
y = y ^ x; <3>
```
1. declare `def x`; implicit cast `boolean false` to `def``def`; store `def` to `x`
2. declare `def y`; load from `x``def`; implicit cast `def` to `boolean false``boolean false`; boolean xor `boolean false` and `boolean true``boolean true`; implicit cast `boolean true` to `def``def`; store `def` to `y`
3. load from `y``def`; implicit cast `def` to `boolean true @0``boolean true @0`; load from `x``def`; implicit cast `def` to `boolean true @1``boolean true @1`; boolean xor `boolean true @0` and `boolean true @1``boolean false`; implicit cast `boolean false``def`; store `def` to `y`
## Boolean And [boolean-and-operator]
Use the `boolean and operator '&&'` to AND together two `boolean` type values where if both `boolean` type values are `true` the resultant `boolean` type value is `true` and `false` otherwise.
**Errors**
* If either evaluated value is a value other than a `boolean` type value or a value that is castable to a `boolean` type value.
**Truth**
| | | |
| --- | --- | --- |
| | true | false |
| true | true | false |
| false | false | false |
**Grammar**
```text
boolean_and: expression '&&' expression;
```
**Examples**
* Boolean and with the `boolean` type.
```painless
boolean x = true; <1>
boolean y = x && true; <2>
x = false; <3>
y = y && x; <4>
```
1. declare `boolean x`; store `boolean true` to `x`
2. declare `boolean y`; load from `x``boolean true @0`; boolean and `boolean true @0` and `boolean true @1``boolean true`; store `boolean true` to `y`
3. store `boolean false` to `x`
4. load from `y``boolean true`; load from `x``boolean false`; boolean and `boolean true` and `boolean false``boolean false`; store `boolean false` to `y`
* Boolean and with the `def` type.
```painless
def x = true; <1>
def y = x && true; <2>
x = false; <3>
y = y && x; <4>
```
1. declare `def x`; implicit cast `boolean true` to `def``def`; store `def` to `x`
2. declare `def y`; load from `x``def`; implicit cast `def` to `boolean true @0``boolean true @0`; boolean and `boolean true @0` and `boolean true @1``boolean true`; implicit cast `boolean true` to `def``def`; store `def` to `y`
3. implicit cast `boolean false` to `def``def`; store `def` to `x`;
4. load from `y``def`; implicit cast `def` to `boolean true``boolean true`; load from `x``def`; implicit cast `def` to `boolean false``boolean false`; boolean and `boolean true` and `boolean false``boolean false`; implicit cast `boolean false``def`; store `def` to `y`
## Boolean Or [boolean-or-operator]
Use the `boolean or operator '||'` to OR together two `boolean` type values where if either one of the `boolean` type values is `true` the resultant `boolean` type value is `true` and `false` otherwise.
**Errors**
* If either evaluated value is a value other than a `boolean` type value or a value that is castable to a `boolean` type value.
**Truth**
| | | |
| --- | --- | --- |
| | true | false |
| true | true | true |
| false | true | false |
**Grammar:**
```text
boolean_and: expression '||' expression;
```
**Examples**
* Boolean or with the `boolean` type.
```painless
boolean x = false; <1>
boolean y = x || true; <2>
y = false; <3>
y = y || x; <4>
```
1. declare `boolean x`; store `boolean false` to `x`
2. declare `boolean y`; load from `x``boolean false`; boolean or `boolean false` and `boolean true``boolean true`; store `boolean true` to `y`
3. store `boolean false` to `y`
4. load from `y``boolean false @0`; load from `x``boolean false @1`; boolean or `boolean false @0` and `boolean false @1``boolean false`; store `boolean false` to `y`
* Boolean or with the `def` type.
```painless
def x = false; <1>
def y = x || true; <2>
y = false; <3>
y = y || x; <4>
```
1. declare `def x`; implicit cast `boolean false` to `def``def`; store `def` to `x`
2. declare `def y`; load from `x``def`; implicit cast `def` to `boolean false``boolean true`; boolean or `boolean false` and `boolean true``boolean true`; implicit cast `boolean true` to `def``def`; store `def` to `y`
3. implicit cast `boolean false` to `def``def`; store `def` to `y`;
4. load from `y``def`; implicit cast `def` to `boolean false @0``boolean false @0`; load from `x``def`; implicit cast `def` to `boolean false @1``boolean false @1`; boolean or `boolean false @0` and `boolean false @1``boolean false`; implicit cast `boolean false``def`; store `def` to `y`

View file

@ -0,0 +1,294 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-operators-general.html
---
# Operators: General [painless-operators-general]
## Precedence [precedence-operator]
Use the `precedence operator '()'` to guarantee the order of evaluation for an expression. An expression encapsulated by the precedence operator (enclosed in parentheses) overrides existing precedence relationships between operators and is evaluated prior to other expressions in inward-to-outward order.
**Grammar**
```text
precedence: '(' expression ')';
```
**Examples**
* Precedence with numeric operators.
```painless
int x = (5+4)*6; <1>
int y = 12/(x-50); <2>
```
1. declare `int x`; add `int 5` and `int 4``int 9`; multiply `int 9` and `int 6``int 54`; store `int 54` to `x`; (note the add is evaluated before the multiply due to the precedence operator)
2. declare `int y`; load from `x``int 54`; subtract `int 50` from `int 54``int 4`; divide `int 12` by `int 4``int 3`; store `int 3` to `y`; (note the subtract is evaluated before the divide due to the precedence operator)
## Function Call [function-call-operator]
Use the `function call operator ()` to call an existing function. A [function call](/reference/scripting-languages/painless/painless-functions.md) is defined within a script.
**Grammar**
```text
function_call: ID '(' ( expression (',' expression)* )? ')'';
```
**Examples**
* A function call.
```painless
int add(int x, int y) { <1>
return x + y;
}
int z = add(1, 2); <2>
```
1. define function `add` that returns `int` and has parameters (`int x`, `int y`)
2. declare `int z`; call `add` with arguments (`int 1`, `int 2`) → `int 3`; store `int 3` to `z`
## Cast [cast-operator]
An explicit cast converts the value of an original type to the equivalent value of a target type forcefully as an operation. Use the `cast operator '()'` to specify an explicit cast. Refer to [casting](/reference/scripting-languages/painless/painless-casting.md) for more information.
## Conditional [conditional-operator]
A conditional consists of three expressions. The first expression is evaluated with an expected boolean result type. If the first expression evaluates to true then the second expression will be evaluated. If the first expression evaluates to false then the third expression will be evaluated. The second and third expressions will be [promoted](/reference/scripting-languages/painless/painless-casting.md#promotion) if the evaluated values are not the same type. Use the `conditional operator '? :'` as a shortcut to avoid the need for a full if/else branch in certain expressions.
**Errors**
* If the first expression does not evaluate to a boolean type value.
* If the values for the second and third expressions cannot be promoted.
**Grammar**
```text
conditional: expression '?' expression ':' expression;
```
**Promotion**
| | | | | | | | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| | byte | short | char | int | long | float | double | Reference | def |
| byte | int | int | int | int | long | float | double | - | def |
| short | int | int | int | int | long | float | double | - | def |
| char | int | int | int | int | long | float | double | - | def |
| int | int | int | int | int | long | float | double | - | def |
| long | long | long | long | long | long | float | double | - | def |
| float | float | float | float | float | float | float | double | - | def |
| double | double | double | double | double | double | double | double | - | def |
| Reference | - | - | - | - | - | - | - | Object @ | def |
| def | def | def | def | def | def | def | def | def | def |
@ If the two reference type values are the same then this promotion will not occur.
**Examples**
* Evaluation of conditionals.
```painless
boolean b = true; <1>
int x = b ? 1 : 2; <2>
List y = x > 1 ? new ArrayList() : null; <3>
def z = x < 2 ? x : 2.0; <4>
```
1. declare `boolean b`; store `boolean true` to `b`
2. declare `int x`; load from `b``boolean true` evaluate 1st expression: `int 1``int 1`; store `int 1` to `x`
3. declare `List y`; load from `x``int 1`; `int 1` greater than `int 1``boolean false`; evaluate 2nd expression: `null``null`; store `null` to `y`;
4. declare `def z`; load from `x``int 1`; `int 1` less than `int 2``boolean true`; evaluate 1st expression: load from `x``int 1`; promote `int 1` and `double 2.0`: result `double`; implicit cast `int 1` to `double 1.0``double 1.0`; implicit cast `double 1.0` to `def``def`; store `def` to `z`;
## Assignment [assignment-operator]
Use the `assignment operator '='` to store a value in a variable or reference type member field for use in subsequent operations. Any operation that produces a value can be assigned to any variable/field as long as the [types](/reference/scripting-languages/painless/painless-types.md) are the same or the resultant type can be [implicitly cast](/reference/scripting-languages/painless/painless-casting.md) to the variable/field type.
See [variable assignment](/reference/scripting-languages/painless/painless-variables.md#variable-assignment) for examples using variables.
**Errors**
* If the type of value is unable to match the type of variable or field.
**Grammar**
```text
assignment: field '=' expression
```
**Examples**
The examples use the following reference type definition:
```painless
name:
Example
non-static member fields:
* int x
* def y
* List z
```
* Field assignments of different type values.
```painless
Example example = new Example(); <1>
example.x = 1; <2>
example.y = 2.0; <3>
example.z = new ArrayList(); <4>
```
1. declare `Example example`; allocate `Example` instance → `Example reference`; store `Example reference` to `example`
2. load from `example``Example reference`; store `int 1` to `x` of `Example reference`
3. load from `example``Example reference`; implicit cast `double 2.0` to `def``def`; store `def` to `y` of `Example reference`
4. load from `example``Example reference`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `z` of `Example reference`
* A field assignment from a field access.
```painless
Example example = new Example(); <1>
example.x = 1; <2>
example.y = example.x; <3>
```
1. declare `Example example`; allocate `Example` instance → `Example reference`; store `Example reference` to `example`
2. load from `example``Example reference`; store `int 1` to `x` of `Example reference`
3. load from `example``Example reference @0`; load from `example``Example reference @1`; load from `x` of `Example reference @1``int 1`; implicit cast `int 1` to `def``def`; store `def` to `y` of `Example reference @0`; (note `Example reference @0` and `Example reference @1` are the same)
## Compound Assignment [compound-assignment-operator]
Use the `compound assignment operator '$='` as a shortcut for an assignment where a binary operation would occur between the variable/field as the left-hand side expression and a separate right-hand side expression.
A compound assignment is equivalent to the expression below where V is the variable/field and T is the type of variable/member.
```painless
V = (T)(V op expression);
```
**Operators**
The table below shows the available operators for use in a compound assignment. Each operator follows the casting/promotion rules according to their regular definition. For numeric operations there is an extra implicit cast when necessary to return the promoted numeric type value to the original numeric type value of the variable/field and can result in data loss.
| | |
| --- | --- |
| Operator | Compound Symbol |
| Multiplication | *= |
| Division | /= |
| Remainder | %= |
| Addition | += |
| Subtraction | -= |
| Left Shift | <<= |
| Right Shift | >>= |
| Unsigned Right Shift | >>>= |
| Bitwise And | &= |
| Boolean And | &= |
| Bitwise Xor | ^= |
| Boolean Xor | ^= |
| Bitwise Or | &#124;= |
| Boolean Or | &#124;= |
| String Concatenation | += |
**Errors**
* If the type of value is unable to match the type of variable or field.
**Grammar**
```text
compound_assignment: ( ID | field ) '$=' expression;
```
Note the use of the `$=` represents the use of any of the possible binary operators.
**Examples**
* Compound assignment for each numeric operator.
```painless
int i = 10; <1>
i *= 2; <2>
i /= 5; <3>
i %= 3; <4>
i += 5; <5>
i -= 5; <6>
i <<= 2; <7>
i >>= 1; <8>
i >>>= 1; <9>
i &= 15; <10>
i ^= 12; <11>
i |= 2; <12>
```
1. declare `int i`; store `int 10` to `i`
2. load from `i``int 10`; multiply `int 10` and `int 2``int 20`; store `int 20` to `i`; (note this is equivalent to `i = i*2`)
3. load from `i``int 20`; divide `int 20` by `int 5``int 4`; store `int 4` to `i`; (note this is equivalent to `i = i/5`)
4. load from `i``int 4`; remainder `int 4` by `int 3``int 1`; store `int 1` to `i`; (note this is equivalent to `i = i%3`)
5. load from `i``int 1`; add `int 1` and `int 5``int 6`; store `int 6` to `i`; (note this is equivalent to `i = i+5`)
6. load from `i``int 6`; subtract `int 5` from `int 6``int 1`; store `int 1` to `i`; (note this is equivalent to `i = i-5`)
7. load from `i``int 1`; left shift `int 1` by `int 2``int 4`; store `int 4` to `i`; (note this is equivalent to `i = i<<2`)
8. load from `i``int 4`; right shift `int 4` by `int 1``int 2`; store `int 2` to `i`; (note this is equivalent to `i = i>>1`)
9. load from `i``int 2`; unsigned right shift `int 2` by `int 1``int 1`; store `int 1` to `i`; (note this is equivalent to `i = i>>>1`)
10. load from `i``int 1`; bitwise and `int 1` and `int 15``int 1`; store `int 1` to `i`; (note this is equivalent to `i = i&2`)
11. load from `i``int 1`; bitwise xor `int 1` and `int 12``int 13`; store `int 13` to `i`; (note this is equivalent to `i = i^2`)
12. load from `i``int 13`; bitwise or `int 13` and `int 2``int 15`; store `int 15` to `i`; (note this is equivalent to `i = i|2`)
* Compound assignment for each boolean operator.
```painless
boolean b = true; <1>
b &= false; <2>
b ^= false; <3>
b |= true; <4>
```
1. declare `boolean b`; store `boolean true` in `b`;
2. load from `b``boolean true`; boolean and `boolean true` and `boolean false``boolean false`; store `boolean false` to `b`; (note this is equivalent to `b = b && false`)
3. load from `b``boolean false`; boolean xor `boolean false` and `boolean false``boolean false`; store `boolean false` to `b`; (note this is equivalent to `b = b ^ false`)
4. load from `b``boolean true`; boolean or `boolean false` and `boolean true``boolean true`; store `boolean true` to `b`; (note this is equivalent to `b = b || true`)
* A compound assignment with the string concatenation operator.
```painless
String s = 'compound'; <1>
s += ' assignment'; <2>
```
1. declare `String s`; store `String 'compound'` to `s`;
2. load from `s``String 'compound'`; string concat `String 'compound'` and `String ' assignment''``String 'compound assignment'`; store `String 'compound assignment'` to `s`; (note this is equivalent to `s = s + ' assignment'`)
* A compound assignment with the `def` type.
```painless
def x = 1; <1>
x += 2; <2>
```
1. declare `def x`; implicit cast `int 1` to `def`; store `def` to `x`;
2. load from `x``def`; implicit cast `def` to `int 1``int 1`; add `int 1` and `int 2``int 3`; implicit cast `int 3` to `def``def`; store `def` to `x`; (note this is equivalent to `x = x+2`)
* A compound assignment with an extra implicit cast.
```painless
byte b = 1; <1>
b += 2; <2>
```
1. declare `byte b`; store `byte 1` to `x`;
2. load from `x``byte 1`; implicit cast `byte 1 to `int 1` → `int 1`; add `int 1` and `int 2` → `int 3`; implicit cast `int 3` to `byte 3` → `byte 3`; store `byte 3` to `b`; (note this is equivalent to `b = b+2`)

View file

@ -0,0 +1,964 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-operators-numeric.html
---
# Operators: Numeric [painless-operators-numeric]
## Post Increment [post-increment-operator]
Use the `post increment operator '++'` to INCREASE the value of a numeric type variable/field by `1`. An extra implicit cast is necessary to return the promoted numeric type value to the original numeric type value of the variable/field for the following types: `byte`, `short`, and `char`. If a variable/field is read as part of an expression the value is loaded prior to the increment.
**Errors**
* If the variable/field is a non-numeric type.
**Grammar**
```text
post_increment: ( variable | field ) '++';
```
**Promotion**
| original | promoted | implicit |
| --- | --- | --- |
| byte | int | byte |
| short | int | short |
| char | int | char |
| int | int | |
| long | long | |
| float | float | |
| double | double | |
| def | def | |
**Examples**
* Post increment with different numeric types.
```painless
short i = 0; <1>
i++; <2>
long j = 1; <3>
long k; <4>
k = j++; <5>
```
1. declare `short i`; store `short 0` to `i`
2. load from `i``short 0`; promote `short 0`: result `int`; add `int 0` and `int 1``int 1`; implicit cast `int 1` to `short 1`; store `short 1` to `i`
3. declare `long j`; implicit cast `int 1` to `long 1``long 1`; store `long 1` to `j`
4. declare `long k`; store default `long 0` to `k`
5. load from `j``long 1`; store `long 1` to `k`; add `long 1` and `long 1``long 2`; store `long 2` to `j`
* Post increment with the `def` type.
```painless
def x = 1; <1>
x++; <2>
```
1. declare `def x`; implicit cast `int 1` to `def``def`; store `def` to `x`
2. load from `x``def`; implicit cast `def` to `int 1`; add `int 1` and `int 1``int 2`; implicit cast `int 2` to `def`; store `def` to `x`
## Post Decrement [post-decrement-operator]
Use the `post decrement operator '--'` to DECREASE the value of a numeric type variable/field by `1`. An extra implicit cast is necessary to return the promoted numeric type value to the original numeric type value of the variable/field for the following types: `byte`, `short`, and `char`. If a variable/field is read as part of an expression the value is loaded prior to the decrement.
**Errors**
* If the variable/field is a non-numeric type.
**Grammar**
```text
post_decrement: ( variable | field ) '--';
```
**Promotion**
| original | promoted | implicit |
| --- | --- | --- |
| byte | int | byte |
| short | int | short |
| char | int | char |
| int | int | |
| long | long | |
| float | float | |
| double | double | |
| def | def | |
**Examples**
* Post decrement with different numeric types.
```painless
short i = 0; <1>
i--; <2>
long j = 1; <3>
long k; <4>
k = j--; <5>
```
1. declare `short i`; store `short 0` to `i`
2. load from `i``short 0`; promote `short 0`: result `int`; subtract `int 1` from `int 0``int -1`; implicit cast `int -1` to `short -1`; store `short -1` to `i`
3. declare `long j`; implicit cast `int 1` to `long 1``long 1`; store `long 1` to `j`
4. declare `long k`; store default `long 0` to `k`
5. load from `j``long 1`; store `long 1` to `k`; subtract `long 1` from `long 1``long 0`; store `long 0` to `j`
* Post decrement with the `def` type.
```painless
def x = 1; <1>
x--; <2>
```
1. declare `def x`; implicit cast `int 1` to `def``def`; store `def` to `x`
2. load from `x``def`; implicit cast `def` to `int 1`; subtract `int 1` from `int 1``int 0`; implicit cast `int 0` to `def`; store `def` to `x`
## Pre Increment [pre-increment-operator]
Use the `pre increment operator '++'` to INCREASE the value of a numeric type variable/field by `1`. An extra implicit cast is necessary to return the promoted numeric type value to the original numeric type value of the variable/field for the following types: `byte`, `short`, and `char`. If a variable/field is read as part of an expression the value is loaded after the increment.
**Errors**
* If the variable/field is a non-numeric type.
**Grammar**
```text
pre_increment: '++' ( variable | field );
```
**Promotion**
| original | promoted | implicit |
| --- | --- | --- |
| byte | int | byte |
| short | int | short |
| char | int | char |
| int | int | |
| long | long | |
| float | float | |
| double | double | |
| def | def | |
**Examples**
* Pre increment with different numeric types.
```painless
short i = 0; <1>
++i; <2>
long j = 1; <3>
long k; <4>
k = ++j; <5>
```
1. declare `short i`; store `short 0` to `i`
2. load from `i``short 0`; promote `short 0`: result `int`; add `int 0` and `int 1``int 1`; implicit cast `int 1` to `short 1`; store `short 1` to `i`
3. declare `long j`; implicit cast `int 1` to `long 1``long 1`; store `long 1` to `j`
4. declare `long k`; store default `long 0` to `k`
5. load from `j``long 1`; add `long 1` and `long 1``long 2`; store `long 2` to `j`; store `long 2` to `k`
* Pre increment with the `def` type.
```painless
def x = 1; <1>
++x; <2>
```
1. declare `def x`; implicit cast `int 1` to `def``def`; store `def` to `x`
2. load from `x``def`; implicit cast `def` to `int 1`; add `int 1` and `int 1``int 2`; implicit cast `int 2` to `def`; store `def` to `x`
## Pre Decrement [pre-decrement-operator]
Use the `pre decrement operator '--'` to DECREASE the value of a numeric type variable/field by `1`. An extra implicit cast is necessary to return the promoted numeric type value to the original numeric type value of the variable/field for the following types: `byte`, `short`, and `char`. If a variable/field is read as part of an expression the value is loaded after the decrement.
**Errors**
* If the variable/field is a non-numeric type.
**Grammar**
```text
pre_decrement: '--' ( variable | field );
```
**Promotion**
| original | promoted | implicit |
| --- | --- | --- |
| byte | int | byte |
| short | int | short |
| char | int | char |
| int | int | |
| long | long | |
| float | float | |
| double | double | |
| def | def | |
**Examples**
* Pre decrement with different numeric types.
```painless
short i = 0; <1>
--i; <2>
long j = 1; <3>
long k; <4>
k = --j; <5>
```
1. declare `short i`; store `short 0` to `i`
2. load from `i``short 0`; promote `short 0`: result `int`; subtract `int 1` from `int 0``int -1`; implicit cast `int -1` to `short -1`; store `short -1` to `i`
3. declare `long j`; implicit cast `int 1` to `long 1``long 1`; store `long 1` to `j`
4. declare `long k`; store default `long 0` to `k`
5. load from `j``long 1`; subtract `long 1` from `long 1``long 0`; store `long 0` to `j` store `long 0` to `k`;
* Pre decrement operator with the `def` type.
```painless
def x = 1; <1>
--x; <2>
```
1. declare `def x`; implicit cast `int 1` to `def``def`; store `def` to `x`
2. load from `x``def`; implicit cast `def` to `int 1`; subtract `int 1` from `int 1``int 0`; implicit cast `int 0` to `def`; store `def` to `x`
## Unary Positive [unary-positive-operator]
Use the `unary positive operator '+'` to the preserve the IDENTITY of a numeric type value.
**Errors**
* If the value is a non-numeric type.
**Grammar**
```text
unary_positive: '+' expression;
```
**Examples**
* Unary positive with different numeric types.
```painless
int x = +1; <1>
long y = +x; <2>
```
1. declare `int x`; identity `int 1``int 1`; store `int 1` to `x`
2. declare `long y`; load from `x``int 1`; identity `int 1``int 1`; implicit cast `int 1` to `long 1``long 1`; store `long 1` to `y`
* Unary positive with the `def` type.
```painless
def z = +1; <1>
int i = +z; <2>
```
1. declare `def z`; identity `int 1``int 1`; implicit cast `int 1` to `def`; store `def` to `z`
2. declare `int i`; load from `z``def`; implicit cast `def` to `int 1`; identity `int 1``int 1`; store `int 1` to `i`;
## Unary Negative [unary-negative-operator]
Use the `unary negative operator '-'` to NEGATE a numeric type value.
**Errors**
* If the value is a non-numeric type.
**Grammar**
```text
unary_negative: '-' expression;
```
**Examples**
* Unary negative with different numeric types.
```painless
int x = -1; <1>
long y = -x; <2>
```
1. declare `int x`; negate `int 1``int -1`; store `int -1` to `x`
2. declare `long y`; load from `x``int 1`; negate `int -1``int 1`; implicit cast `int 1` to `long 1``long 1`; store `long 1` to `y`
* Unary negative with the `def` type.
```painless
def z = -1; <1>
int i = -z; <2>
```
1. declare `def z`; negate `int 1``int -1`; implicit cast `int -1` to `def`; store `def` to `z`
2. declare `int i`; load from `z``def`; implicit cast `def` to `int -1`; negate `int -1``int 1`; store `int 1` to `i`;
## Bitwise Not [bitwise-not-operator]
Use the `bitwise not operator '~'` to NOT each bit in an integer type value where a `1-bit` is flipped to a resultant `0-bit` and a `0-bit` is flipped to a resultant `1-bit`.
**Errors**
* If the value is a non-integer type.
**Bits**
| original | result |
| --- | --- |
| 1 | 0 |
| 0 | 1 |
**Grammar**
```text
bitwise_not: '~' expression;
```
**Promotion**
| original | promoted |
| --- | --- |
| byte | int |
| short | int |
| char | int |
| int | int |
| long | long |
| def | def |
**Examples**
* Bitwise not with different numeric types.
```painless
byte b = 1; <1>
int i = ~b; <2>
long l = ~i; <3>
```
1. declare `byte x`; store `byte 1` to b
2. declare `int i`; load from `b``byte 1`; implicit cast `byte 1` to `int 1``int 1`; bitwise not `int 1``int -2`; store `int -2` to `i`
3. declare `long l`; load from `i``int -2`; implicit cast `int -2` to `long -2``long -2`; bitwise not `long -2``long 1`; store `long 1` to `l`
* Bitwise not with the `def` type.
```painless
def d = 1; <1>
def e = ~d; <2>
```
1. declare `def d`; implicit cast `int 1` to `def``def`; store `def` to `d`;
2. declare `def e`; load from `d``def`; implicit cast `def` to `int 1``int 1`; bitwise not `int 1``int -2`; implicit cast `int 1` to `def``def`; store `def` to `e`
## Multiplication [multiplication-operator]
Use the `multiplication operator '*'` to MULTIPLY together two numeric type values. Rules for resultant overflow and NaN values follow the JVM specification.
**Errors**
* If either of the values is a non-numeric type.
**Grammar**
```text
multiplication: expression '*' expression;
```
**Promotion**
| | | | | | | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| | byte | short | char | int | long | float | double | def |
| byte | int | int | int | int | long | float | double | def |
| short | int | int | int | int | long | float | double | def |
| char | int | int | int | int | long | float | double | def |
| int | int | int | int | int | long | float | double | def |
| long | long | long | long | long | long | float | double | def |
| float | float | float | float | float | float | float | double | def |
| double | double | double | double | double | double | double | double | def |
| def | def | def | def | def | def | def | def | def |
**Examples**
* Multiplication with different numeric types.
```painless
int i = 5*4; <1>
double d = i*7.0; <2>
```
1. declare `int i`; multiply `int 4` by `int 5``int 20`; store `int 20` in `i`
2. declare `double d`; load from `int i``int 20`; promote `int 20` and `double 7.0`: result `double`; implicit cast `int 20` to `double 20.0``double 20.0`; multiply `double 20.0` by `double 7.0``double 140.0`; store `double 140.0` to `d`
* Multiplication with the `def` type.
```painless
def x = 5*4; <1>
def y = x*2; <2>
```
1. declare `def x`; multiply `int 5` by `int 4``int 20`; implicit cast `int 20` to `def``def`; store `def` in `x`
2. declare `def y`; load from `x``def`; implicit cast `def` to `int 20`; multiply `int 20` by `int 2``int 40`; implicit cast `int 40` to `def``def`; store `def` to `y`
## Division [division-operator]
Use the `division operator '/'` to DIVIDE one numeric type value by another. Rules for NaN values and division by zero follow the JVM specification. Division with integer values drops the remainder of the resultant value.
**Errors**
* If either of the values is a non-numeric type.
* If a left-hand side integer type value is divided by a right-hand side integer type value of `0`.
**Grammar**
```text
division: expression '/' expression;
```
**Promotion**
| | | | | | | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| | byte | short | char | int | long | float | double | def |
| byte | int | int | int | int | long | float | double | def |
| short | int | int | int | int | long | float | double | def |
| char | int | int | int | int | long | float | double | def |
| int | int | int | int | int | long | float | double | def |
| long | long | long | long | long | long | float | double | def |
| float | float | float | float | float | float | float | double | def |
| double | double | double | double | double | double | double | double | def |
| def | def | def | def | def | def | def | def | def |
**Examples**
* Division with different numeric types.
```painless
int i = 29/4; <1>
double d = i/7.0; <2>
```
1. declare `int i`; divide `int 29` by `int 4``int 7`; store `int 7` in `i`
2. declare `double d`; load from `int i``int 7`; promote `int 7` and `double 7.0`: result `double`; implicit cast `int 7` to `double 7.0``double 7.0`; divide `double 7.0` by `double 7.0``double 1.0`; store `double 1.0` to `d`
* Division with the `def` type.
```painless
def x = 5/4; <1>
def y = x/2; <2>
```
1. declare `def x`; divide `int 5` by `int 4``int 1`; implicit cast `int 1` to `def``def`; store `def` in `x`
2. declare `def y`; load from `x``def`; implicit cast `def` to `int 1`; divide `int 1` by `int 2``int 0`; implicit cast `int 0` to `def``def`; store `def` to `y`
## Remainder [remainder-operator]
Use the `remainder operator '%'` to calculate the REMAINDER for division between two numeric type values. Rules for NaN values and division by zero follow the JVM specification.
**Errors**
* If either of the values is a non-numeric type.
**Grammar**
```text
remainder: expression '%' expression;
```
**Promotion**
| | | | | | | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| | byte | short | char | int | long | float | double | def |
| byte | int | int | int | int | long | float | double | def |
| short | int | int | int | int | long | float | double | def |
| char | int | int | int | int | long | float | double | def |
| int | int | int | int | int | long | float | double | def |
| long | long | long | long | long | long | float | double | def |
| float | float | float | float | float | float | float | double | def |
| double | double | double | double | double | double | double | double | def |
| def | def | def | def | def | def | def | def | def |
**Examples**
* Remainder with different numeric types.
```painless
int i = 29%4; <1>
double d = i%7.0; <2>
```
1. declare `int i`; remainder `int 29` by `int 4``int 1`; store `int 7` in `i`
2. declare `double d`; load from `int i``int 1`; promote `int 1` and `double 7.0`: result `double`; implicit cast `int 1` to `double 1.0``double 1.0`; remainder `double 1.0` by `double 7.0``double 1.0`; store `double 1.0` to `d`
* Remainder with the `def` type.
```painless
def x = 5%4; <1>
def y = x%2; <2>
```
1. declare `def x`; remainder `int 5` by `int 4``int 1`; implicit cast `int 1` to `def``def`; store `def` in `x`
2. declare `def y`; load from `x``def`; implicit cast `def` to `int 1`; remainder `int 1` by `int 2``int 1`; implicit cast `int 1` to `def``def`; store `def` to `y`
## Addition [addition-operator]
Use the `addition operator '+'` to ADD together two numeric type values. Rules for resultant overflow and NaN values follow the JVM specification.
**Errors**
* If either of the values is a non-numeric type.
**Grammar**
```text
addition: expression '+' expression;
```
**Promotion**
| | | | | | | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| | byte | short | char | int | long | float | double | def |
| byte | int | int | int | int | long | float | double | def |
| short | int | int | int | int | long | float | double | def |
| char | int | int | int | int | long | float | double | def |
| int | int | int | int | int | long | float | double | def |
| long | long | long | long | long | long | float | double | def |
| float | float | float | float | float | float | float | double | def |
| double | double | double | double | double | double | double | double | def |
| def | def | def | def | def | def | def | def | def |
**Examples**
* Addition operator with different numeric types.
```painless
int i = 29+4; <1>
double d = i+7.0; <2>
```
1. declare `int i`; add `int 29` and `int 4``int 33`; store `int 33` in `i`
2. declare `double d`; load from `int i``int 33`; promote `int 33` and `double 7.0`: result `double`; implicit cast `int 33` to `double 33.0``double 33.0`; add `double 33.0` and `double 7.0``double 40.0`; store `double 40.0` to `d`
* Addition with the `def` type.
```painless
def x = 5+4; <1>
def y = x+2; <2>
```
1. declare `def x`; add `int 5` and `int 4``int 9`; implicit cast `int 9` to `def``def`; store `def` in `x`
2. declare `def y`; load from `x``def`; implicit cast `def` to `int 9`; add `int 9` and `int 2``int 11`; implicit cast `int 11` to `def``def`; store `def` to `y`
## Subtraction [subtraction-operator]
Use the `subtraction operator '-'` to SUBTRACT a right-hand side numeric type value from a left-hand side numeric type value. Rules for resultant overflow and NaN values follow the JVM specification.
**Errors**
* If either of the values is a non-numeric type.
**Grammar**
```text
subtraction: expression '-' expression;
```
**Promotion**
| | | | | | | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| | byte | short | char | int | long | float | double | def |
| byte | int | int | int | int | long | float | double | def |
| short | int | int | int | int | long | float | double | def |
| char | int | int | int | int | long | float | double | def |
| int | int | int | int | int | long | float | double | def |
| long | long | long | long | long | long | float | double | def |
| float | float | float | float | float | float | float | double | def |
| double | double | double | double | double | double | double | double | def |
| def | def | def | def | def | def | def | def | def |
**Examples**
* Subtraction with different numeric types.
```painless
int i = 29-4; <1>
double d = i-7.5; <2>
```
1. declare `int i`; subtract `int 4` from `int 29``int 25`; store `int 25` in `i`
2. declare `double d` load from `int i``int 25`; promote `int 25` and `double 7.5`: result `double`; implicit cast `int 25` to `double 25.0``double 25.0`; subtract `double 33.0` by `double 7.5``double 25.5`; store `double 25.5` to `d`
* Subtraction with the `def` type.
```painless
def x = 5-4; <1>
def y = x-2; <2>
```
1. declare `def x`; subtract `int 4` and `int 5``int 1`; implicit cast `int 1` to `def``def`; store `def` in `x`
2. declare `def y`; load from `x``def`; implicit cast `def` to `int 1`; subtract `int 2` from `int 1``int -1`; implicit cast `int -1` to `def``def`; store `def` to `y`
## Left Shift [left-shift-operator]
Use the `left shift operator '<<'` to SHIFT lower order bits to higher order bits in a left-hand side integer type value by the distance specified in a right-hand side integer type value.
**Errors**
* If either of the values is a non-integer type.
* If the right-hand side value cannot be cast to an int type.
**Grammar**
```text
left_shift: expression '<<' expression;
```
**Promotion**
The left-hand side integer type value is promoted as specified in the table below. The right-hand side integer type value is always implicitly cast to an `int` type value and truncated to the number of bits of the promoted type value.
| original | promoted |
| --- | --- |
| byte | int |
| short | int |
| char | int |
| int | int |
| long | long |
| def | def |
**Examples**
* Left shift with different integer types.
```painless
int i = 4 << 1; <1>
long l = i << 2L; <2>
```
1. declare `int i`; left shift `int 4` by `int 1``int 8`; store `int 8` in `i`
2. declare `long l` load from `int i``int 8`; implicit cast `long 2` to `int 2``int 2`; left shift `int 8` by `int 2``int 32`; implicit cast `int 32` to `long 32``long 32`; store `long 32` to `l`
* Left shift with the `def` type.
```painless
def x = 4 << 2; <1>
def y = x << 1; <2>
```
1. declare `def x`; left shift `int 4` by `int 2``int 16`; implicit cast `int 16` to `def``def`; store `def` in `x`
2. declare `def y`; load from `x``def`; implicit cast `def` to `int 16`; left shift `int 16` by `int 1``int 32`; implicit cast `int 32` to `def``def`; store `def` to `y`
## Right Shift [right-shift-operator]
Use the `right shift operator '>>'` to SHIFT higher order bits to lower order bits in a left-hand side integer type value by the distance specified in a right-hand side integer type value. The highest order bit of the left-hand side integer type value is preserved.
**Errors**
* If either of the values is a non-integer type.
* If the right-hand side value cannot be cast to an int type.
**Grammar**
```text
right_shift: expression '>>' expression;
```
**Promotion**
The left-hand side integer type value is promoted as specified in the table below. The right-hand side integer type value is always implicitly cast to an `int` type value and truncated to the number of bits of the promoted type value.
| original | promoted |
| --- | --- |
| byte | int |
| short | int |
| char | int |
| int | int |
| long | long |
| def | def |
**Examples**
* Right shift with different integer types.
```painless
int i = 32 >> 1; <1>
long l = i >> 2L; <2>
```
1. declare `int i`; right shift `int 32` by `int 1``int 16`; store `int 16` in `i`
2. declare `long l` load from `int i``int 16`; implicit cast `long 2` to `int 2``int 2`; right shift `int 16` by `int 2``int 4`; implicit cast `int 4` to `long 4``long 4`; store `long 4` to `l`
* Right shift with the `def` type.
```painless
def x = 16 >> 2; <1>
def y = x >> 1; <2>
```
1. declare `def x`; right shift `int 16` by `int 2``int 4`; implicit cast `int 4` to `def``def`; store `def` in `x`
2. declare `def y`; load from `x``def`; implicit cast `def` to `int 4`; right shift `int 4` by `int 1``int 2`; implicit cast `int 2` to `def``def`; store `def` to `y`
## Unsigned Right Shift [unsigned-right-shift-operator]
Use the `unsigned right shift operator '>>>'` to SHIFT higher order bits to lower order bits in a left-hand side integer type value by the distance specified in a right-hand side type integer value. The highest order bit of the left-hand side integer type value is **not** preserved.
**Errors**
* If either of the values is a non-integer type.
* If the right-hand side value cannot be cast to an int type.
**Grammar**
```text
unsigned_right_shift: expression '>>>' expression;
```
**Promotion**
The left-hand side integer type value is promoted as specified in the table below. The right-hand side integer type value is always implicitly cast to an `int` type value and truncated to the number of bits of the promoted type value.
| original | promoted |
| --- | --- |
| byte | int |
| short | int |
| char | int |
| int | int |
| long | long |
| def | def |
**Examples**
* Unsigned right shift with different integer types.
```painless
int i = -1 >>> 29; <1>
long l = i >>> 2L; <2>
```
1. declare `int i`; unsigned right shift `int -1` by `int 29``int 7`; store `int 7` in `i`
2. declare `long l` load from `int i``int 7`; implicit cast `long 2` to `int 2``int 2`; unsigned right shift `int 7` by `int 2``int 3`; implicit cast `int 3` to `long 3``long 3`; store `long 3` to `l`
* Unsigned right shift with the `def` type.
```painless
def x = 16 >>> 2; <1>
def y = x >>> 1; <2>
```
1. declare `def x`; unsigned right shift `int 16` by `int 2``int 4`; implicit cast `int 4` to `def``def`; store `def` in `x`
2. declare `def y`; load from `x``def`; implicit cast `def` to `int 4`; unsigned right shift `int 4` by `int 1``int 2`; implicit cast `int 2` to `def``def`; store `def` to `y`
## Bitwise And [bitwise-and-operator]
Use the `bitwise and operator '&'` to AND together each bit within two integer type values where if both bits at the same index are `1` the resultant bit is `1` and `0` otherwise.
**Errors**
* If either of the values is a non-integer type.
**Bits**
| | | |
| --- | --- | --- |
| | 1 | 0 |
| 1 | 1 | 0 |
| 0 | 0 | 0 |
**Grammar**
```text
bitwise_and: expression '&' expression;
```
**Promotion**
| | | | | | | |
| --- | --- | --- | --- | --- | --- | --- |
| | byte | short | char | int | long | def |
| byte | int | int | int | int | long | def |
| short | int | int | int | int | long | def |
| char | int | int | int | int | long | def |
| int | int | int | int | int | long | def |
| long | long | long | long | long | long | def |
| def | def | def | def | def | def | def |
**Examples**
* Bitwise and with different integer types.
```painless
int i = 5 & 6; <1>
long l = i & 5L; <2>
```
1. declare `int i`; bitwise and `int 5` and `int 6``int 4`; store `int 4` in `i`
2. declare `long l` load from `int i``int 4`; promote `int 4` and `long 5`: result `long`; implicit cast `int 4` to `long 4``long 4`; bitwise and `long 4` and `long 5``long 4`; store `long 4` to `l`
* Bitwise and with the `def` type.
```painless
def x = 15 & 6; <1>
def y = x & 5; <2>
```
1. declare `def x`; bitwise and `int 15` and `int 6``int 6`; implicit cast `int 6` to `def``def`; store `def` in `x`
2. declare `def y`; load from `x``def`; implicit cast `def` to `int 6`; bitwise and `int 6` and `int 5``int 4`; implicit cast `int 4` to `def``def`; store `def` to `y`
## Bitwise Xor [bitwise-xor-operator]
Use the `bitwise xor operator '^'` to XOR together each bit within two integer type values where if one bit is a `1` and the other bit is a `0` at the same index the resultant bit is `1` otherwise the resultant bit is `0`.
**Errors**
* If either of the values is a non-integer type.
**Bits**
The following table illustrates the resultant bit from the xoring of two bits.
| | | |
| --- | --- | --- |
| | 1 | 0 |
| 1 | 0 | 1 |
| 0 | 1 | 0 |
**Grammar**
```text
bitwise_xor: expression '^' expression;
```
**Promotion**
| | | | | | | |
| --- | --- | --- | --- | --- | --- | --- |
| | byte | short | char | int | long | def |
| byte | int | int | int | int | long | def |
| short | int | int | int | int | long | def |
| char | int | int | int | int | long | def |
| int | int | int | int | int | long | def |
| long | long | long | long | long | long | def |
| def | def | def | def | def | def | def |
**Examples**
* Bitwise xor with different integer types.
```painless
int i = 5 ^ 6; <1>
long l = i ^ 5L; <2>
```
1. declare `int i`; bitwise xor `int 5` and `int 6``int 3`; store `int 3` in `i`
2. declare `long l` load from `int i``int 4`; promote `int 3` and `long 5`: result `long`; implicit cast `int 3` to `long 3``long 3`; bitwise xor `long 3` and `long 5``long 6`; store `long 6` to `l`
* Bitwise xor with the `def` type.
```painless
def x = 15 ^ 6; <1>
def y = x ^ 5; <2>
```
1. declare `def x`; bitwise xor `int 15` and `int 6``int 9`; implicit cast `int 9` to `def``def`; store `def` in `x`
2. declare `def y`; load from `x``def`; implicit cast `def` to `int 9`; bitwise xor `int 9` and `int 5``int 12`; implicit cast `int 12` to `def``def`; store `def` to `y`
## Bitwise Or [bitwise-or-operator]
Use the `bitwise or operator '|'` to OR together each bit within two integer type values where if at least one bit is a `1` at the same index the resultant bit is `1` otherwise the resultant bit is `0`.
**Errors**
* If either of the values is a non-integer type.
**Bits**
The following table illustrates the resultant bit from the oring of two bits.
| | | |
| --- | --- | --- |
| | 1 | 0 |
| 1 | 1 | 1 |
| 0 | 1 | 0 |
**Grammar**
```text
bitwise_or: expression '|' expression;
```
**Promotion**
| | | | | | | |
| --- | --- | --- | --- | --- | --- | --- |
| | byte | short | char | int | long | def |
| byte | int | int | int | int | long | def |
| short | int | int | int | int | long | def |
| char | int | int | int | int | long | def |
| int | int | int | int | int | long | def |
| long | long | long | long | long | long | def |
| def | def | def | def | def | def | def |
**Examples**
* Bitwise or with different integer types.
```painless
int i = 5 | 6; <1>
long l = i | 8L; <2>
```
1. declare `int i`; bitwise or `int 5` and `int 6``int 7`; store `int 7` in `i`
2. declare `long l` load from `int i``int 7`; promote `int 7` and `long 8`: result `long`; implicit cast `int 7` to `long 7``long 7`; bitwise or `long 7` and `long 8``long 15`; store `long 15` to `l`
* Bitwise or with the `def` type.
```painless
def x = 5 ^ 6; <1>
def y = x ^ 8; <2>
```
1. declare `def x`; bitwise or `int 5` and `int 6``int 7`; implicit cast `int 7` to `def``def`; store `def` in `x`
2. declare `def y`; load from `x``def`; implicit cast `def` to `int 7`; bitwise or `int 7` and `int 8``int 15`; implicit cast `int 15` to `def``def`; store `def` to `y`

View file

@ -0,0 +1,480 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-operators-reference.html
---
# Operators: Reference [painless-operators-reference]
## Method Call [method-call-operator]
Use the `method call operator '()'` to call a member method on a [reference type](/reference/scripting-languages/painless/painless-types.md#reference-types) value. Implicit [boxing/unboxing](/reference/scripting-languages/painless/painless-casting.md#boxing-unboxing) is evaluated as necessary per argument during the method call. When a method call is made on a target `def` type value, the parameters and return type value are considered to also be of the `def` type and are evaluated at run-time.
An overloaded method is one that shares the same name with two or more methods. A method is overloaded based on arity where the same name is re-used for multiple methods as long as the number of parameters differs.
**Errors**
* If the reference type value is `null`.
* If the member method name doesnt exist for a given reference type value.
* If the number of arguments passed in is different from the number of specified parameters.
* If the arguments cannot be implicitly cast or implicitly boxed/unboxed to the correct type values for the parameters.
**Grammar**
```text
method_call: '.' ID arguments;
arguments: '(' (expression (',' expression)*)? ')';
```
**Examples**
* Method calls on different reference types.
```painless
Map m = new HashMap(); <1>
m.put(1, 2); <2>
int z = m.get(1); <3>
def d = new ArrayList(); <4>
d.add(1); <5>
int i = Integer.parseInt(d.get(0).toString()); <6>
```
1. declare `Map m`; allocate `HashMap` instance → `HashMap reference`; store `HashMap reference` to `m`
2. load from `m``Map reference`; implicit cast `int 1` to `def``def`; implicit cast `int 2` to `def``def`; call `put` on `Map reference` with arguments (`int 1`, `int 2`)
3. declare `int z`; load from `m``Map reference`; call `get` on `Map reference` with arguments (`int 1`) → `def`; implicit cast `def` to `int 2``int 2`; store `int 2` to `z`
4. declare `def d`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList` to `def``def`; store `def` to `d`
5. load from `d``def`; implicit cast `def` to `ArrayList reference``ArrayList reference` call `add` on `ArrayList reference` with arguments (`int 1`);
6. declare `int i`; load from `d``def`; implicit cast `def` to `ArrayList reference``ArrayList reference` call `get` on `ArrayList reference` with arguments (`int 1`) → `def`; implicit cast `def` to `Integer 1 reference``Integer 1 reference`; call `toString` on `Integer 1 reference``String '1'`; call `parseInt` on `Integer` with arguments (`String '1'`) → `int 1`; store `int 1` in `i`;
## Field Access [field-access-operator]
Use the `field access operator '.'` to store a value to or load a value from a [reference type](/reference/scripting-languages/painless/painless-types.md#reference-types) member field.
**Errors**
* If the reference type value is `null`.
* If the member field name doesnt exist for a given reference type value.
**Grammar**
```text
field_access: '.' ID;
```
**Examples**
The examples use the following reference type definition:
```painless
name:
Example
non-static member fields:
* int x
* def y
* List z
```
* Field access with the `Example` type.
```painless
Example example = new Example(); <1>
example.x = 1; <2>
example.y = example.x; <3>
example.z = new ArrayList(); <4>
example.z.add(1); <5>
example.x = example.z.get(0); <6>
```
1. declare `Example example`; allocate `Example` instance → `Example reference`; store `Example reference` to `example`
2. load from `example``Example reference`; store `int 1` to `x` of `Example reference`
3. load from `example``Example reference @0`; load from `example``Example reference @1`; load from `x` of `Example reference @1``int 1`; implicit cast `int 1` to `def``def`; store `def` to `y` of `Example reference @0`; (note `Example reference @0` and `Example reference @1` are the same)
4. load from `example``Example reference`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `z` of `Example reference`
5. load from `example``Example reference`; load from `z` of `Example reference``List reference`; call `add` on `List reference` with arguments (`int 1`)
6. load from `example``Example reference @0`; load from `example``Example reference @1`; load from `z` of `Example reference @1``List reference`; call `get` on `List reference` with arguments (`int 0`) → `int 1`; store `int 1` in `x` of `List reference @0`; (note `Example reference @0` and `Example reference @1` are the same)
## Null Safe [null-safe-operator]
Use the `null safe operator '?.'` instead of the method call operator or field access operator to ensure a reference type value is `non-null` before a method call or field access. A `null` value will be returned if the reference type value is `null`, otherwise the method call or field access is evaluated.
**Errors**
* If the method call return type value or the field access type value is not a reference type value and is not implicitly castable to a reference type value.
**Grammar**
```text
null_safe: null_safe_method_call
| null_safe_field_access
;
null_safe_method_call: '?.' ID arguments;
arguments: '(' (expression (',' expression)*)? ')';
null_safe_field_access: '?.' ID;
```
**Examples**
The examples use the following reference type definition:
```painless
name:
Example
non-static member methods:
* List factory()
non-static member fields:
* List x
```
* Null safe without a `null` value.
```painless
Example example = new Example(); <1>
List x = example?.factory(); <2>
```
1. declare `Example example`; allocate `Example` instance → `Example reference`; store `Example reference` to `example`
2. declare `List x`; load from `example``Example reference`; null safe call `factory` on `Example reference``List reference`; store `List reference` to `x`;
* Null safe with a `null` value;
```painless
Example example = null; <1>
List x = example?.x; <2>
```
1. declare `Example example`; store `null` to `example`
2. declare `List x`; load from `example``Example reference`; null safe access `x` on `Example reference``null`; store `null` to `x`; (note the **null safe operator** returned `null` because `example` is `null`)
## List Initialization [list-initialization-operator]
Use the `list initialization operator '[]'` to allocate an `List` type instance to the heap with a set of pre-defined values. Each value used to initialize the `List` type instance is cast to a `def` type value upon insertion into the `List` type instance using the `add` method. The order of the specified values is maintained.
**Grammar**
```text
list_initialization: '[' expression (',' expression)* ']'
| '[' ']';
```
**Examples**
* List initialization of an empty `List` type value.
```painless
List empty = []; <1>
```
1. declare `List empty`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `empty`
* List initialization with static values.
```painless
List list = [1, 2, 3]; <1>
```
1. declare `List list`; allocate `ArrayList` instance → `ArrayList reference`; call `add` on `ArrayList reference` with arguments(`int 1`); call `add` on `ArrayList reference` with arguments(`int 2`); call `add` on `ArrayList reference` with arguments(`int 3`); implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `list`
* List initialization with non-static values.
```painless
int i = 1; <1>
long l = 2L; <2>
float f = 3.0F; <3>
double d = 4.0; <4>
String s = "5"; <5>
List list = [i, l, f*d, s]; <6>
```
1. declare `int i`; store `int 1` to `i`
2. declare `long l`; store `long 2` to `l`
3. declare `float f`; store `float 3.0` to `f`
4. declare `double d`; store `double 4.0` to `d`
5. declare `String s`; store `String "5"` to `s`
6. declare `List list`; allocate `ArrayList` instance → `ArrayList reference`; load from `i``int 1`; call `add` on `ArrayList reference` with arguments(`int 1`); load from `l``long 2`; call `add` on `ArrayList reference` with arguments(`long 2`); load from `f``float 3.0`; load from `d``double 4.0`; promote `float 3.0` and `double 4.0`: result `double`; implicit cast `float 3.0` to `double 3.0``double 3.0`; multiply `double 3.0` and `double 4.0``double 12.0`; call `add` on `ArrayList reference` with arguments(`double 12.0`); load from `s``String "5"`; call `add` on `ArrayList reference` with arguments(`String "5"`); implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `list`
## List Access [list-access-operator]
Use the `list access operator '[]'` as a shortcut for a `set` method call or `get` method call made on a `List` type value.
**Errors**
* If a value other than a `List` type value is accessed.
* If a non-integer type value is used as an index for a `set` method call or `get` method call.
**Grammar**
```text
list_access: '[' expression ']'
```
**Examples**
* List access with the `List` type.
```painless
List list = new ArrayList(); <1>
list.add(1); <2>
list.add(2); <3>
list.add(3); <4>
list[0] = 2; <5>
list[1] = 5; <6>
int x = list[0] + list[1]; <7>
int y = 1; <8>
int z = list[y]; <9>
```
1. declare `List list`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `list`
2. load from `list``List reference`; call `add` on `List reference` with arguments(`int 1`)
3. load from `list``List reference`; call `add` on `List reference` with arguments(`int 2`)
4. load from `list``List reference`; call `add` on `List reference` with arguments(`int 3`)
5. load from `list``List reference`; call `set` on `List reference` with arguments(`int 0`, `int 2`)
6. load from `list``List reference`; call `set` on `List reference` with arguments(`int 1`, `int 5`)
7. declare `int x`; load from `list``List reference`; call `get` on `List reference` with arguments(`int 0`) → `def`; implicit cast `def` to `int 2``int 2`; load from `list``List reference`; call `get` on `List reference` with arguments(`int 1`) → `def`; implicit cast `def` to `int 5``int 5`; add `int 2` and `int 5``int 7`; store `int 7` to `x`
8. declare `int y`; store `int 1` int `y`
9. declare `int z`; load from `list``List reference`; load from `y``int 1`; call `get` on `List reference` with arguments(`int 1`) → `def`; implicit cast `def` to `int 5``int 5`; store `int 5` to `z`
* List access with the `def` type.
```painless
def d = new ArrayList(); <1>
d.add(1); <2>
d.add(2); <3>
d.add(3); <4>
d[0] = 2; <5>
d[1] = 5; <6>
def x = d[0] + d[1]; <7>
def y = 1; <8>
def z = d[y]; <9>
```
1. declare `List d`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `def``def`; store `def` to `d`
2. load from `d``def`; implicit cast `def` to `ArrayList reference``ArrayList reference`; call `add` on `ArrayList reference` with arguments(`int 1`)
3. load from `d``def`; implicit cast `def` to `ArrayList reference``ArrayList reference`; call `add` on `ArrayList reference` with arguments(`int 2`)
4. load from `d``def`; implicit cast `def` to `ArrayList reference``ArrayList reference`; call `add` on `ArrayList reference` with arguments(`int 3`)
5. load from `d``def`; implicit cast `def` to `ArrayList reference``ArrayList reference`; call `set` on `ArrayList reference` with arguments(`int 0`, `int 2`)
6. load from `d``def`; implicit cast `def` to `ArrayList reference``ArrayList reference`; call `set` on `ArrayList reference` with arguments(`int 1`, `int 5`)
7. declare `def x`; load from `d``def`; implicit cast `def` to `ArrayList reference``ArrayList reference`; call `get` on `ArrayList reference` with arguments(`int 0`) → `def`; implicit cast `def` to `int 2``int 2`; load from `d``def`; implicit cast `def` to `ArrayList reference``ArrayList reference`; call `get` on `ArrayList reference` with arguments(`int 1`) → `def`; implicit cast `def` to `int 2``int 2`; add `int 2` and `int 5``int 7`; store `int 7` to `x`
8. declare `int y`; store `int 1` int `y`
9. declare `int z`; load from `d``ArrayList reference`; load from `y``def`; implicit cast `def` to `int 1``int 1`; call `get` on `ArrayList reference` with arguments(`int 1`) → `def`; store `def` to `z`
## Map Initialization [map-initialization-operator]
Use the `map initialization operator '[:]'` to allocate a `Map` type instance to the heap with a set of pre-defined values. Each pair of values used to initialize the `Map` type instance are cast to `def` type values upon insertion into the `Map` type instance using the `put` method.
**Grammar**
```text
map_initialization: '[' key_pair (',' key_pair)* ']'
| '[' ':' ']';
key_pair: expression ':' expression
```
**Examples**
* Map initialization of an empty `Map` type value.
```painless
Map empty = [:]; <1>
```
1. declare `Map empty`; allocate `HashMap` instance → `HashMap reference`; implicit cast `HashMap reference` to `Map reference``Map reference`; store `Map reference` to `empty`
* Map initialization with static values.
```painless
Map map = [1:2, 3:4, 5:6]; <1>
```
1. declare `Map map`; allocate `HashMap` instance → `HashMap reference`; call `put` on `HashMap reference` with arguments(`int 1`, `int 2`); call `put` on `HashMap reference` with arguments(`int 3`, `int 4`); call `put` on `HashMap reference` with arguments(`int 5`, `int 6`); implicit cast `HashMap reference` to `Map reference``Map reference`; store `Map reference` to `map`
* Map initialization with non-static values.
```painless
byte b = 0; <1>
int i = 1; <2>
long l = 2L; <3>
float f = 3.0F; <4>
double d = 4.0; <5>
String s = "5"; <6>
Map map = [b:i, l:f*d, d:s]; <7>
```
1. declare `byte b`; store `byte 0` to `b`
2. declare `int i`; store `int 1` to `i`
3. declare `long l`; store `long 2` to `l`
4. declare `float f`; store `float 3.0` to `f`
5. declare `double d`; store `double 4.0` to `d`
6. declare `String s`; store `String "5"` to `s`
7. declare `Map map`; allocate `HashMap` instance → `HashMap reference`; load from `b``byte 0`; load from `i``int 1`; call `put` on `HashMap reference` with arguments(`byte 0`, `int 1`); load from `l``long 2`; load from `f``float 3.0`; load from `d``double 4.0`; promote `float 3.0` and `double 4.0`: result `double`; implicit cast `float 3.0` to `double 3.0``double 3.0`; multiply `double 3.0` and `double 4.0``double 12.0`; call `put` on `HashMap reference` with arguments(`long 2`, `double 12.0`); load from `d``double 4.0`; load from `s``String "5"`; call `put` on `HashMap reference` with arguments(`double 4.0`, `String "5"`); implicit cast `HashMap reference` to `Map reference``Map reference`; store `Map reference` to `map`
## Map Access [map-access-operator]
Use the `map access operator '[]'` as a shortcut for a `put` method call or `get` method call made on a `Map` type value.
**Errors**
* If a value other than a `Map` type value is accessed.
**Grammar**
```text
map_access: '[' expression ']'
```
**Examples**
* Map access with the `Map` type.
```painless
Map map = new HashMap(); <1>
map['value2'] = 2; <2>
map['value5'] = 5; <3>
int x = map['value2'] + map['value5']; <4>
String y = 'value5'; <5>
int z = x[z]; <6>
```
1. declare `Map map`; allocate `HashMap` instance → `HashMap reference`; implicit cast `HashMap reference` to `Map reference``Map reference`; store `Map reference` to `map`
2. load from `map``Map reference`; call `put` on `Map reference` with arguments(`String 'value2'`, `int 2`)
3. load from `map``Map reference`; call `put` on `Map reference` with arguments(`String 'value5'`, `int 5`)
4. declare `int x`; load from `map``Map reference`; call `get` on `Map reference` with arguments(`String 'value2'`) → `def`; implicit cast `def` to `int 2``int 2`; load from `map``Map reference`; call `get` on `Map reference` with arguments(`String 'value5'`) → `def`; implicit cast `def` to `int 5``int 5`; add `int 2` and `int 5``int 7`; store `int 7` to `x`
5. declare `String y`; store `String 'value5'` to `y`
6. declare `int z`; load from `map``Map reference`; load from `y``String 'value5'`; call `get` on `Map reference` with arguments(`String 'value5'`) → `def`; implicit cast `def` to `int 5``int 5`; store `int 5` to `z`
* Map access with the `def` type.
```painless
def d = new HashMap(); <1>
d['value2'] = 2; <2>
d['value5'] = 5; <3>
int x = d['value2'] + d['value5']; <4>
String y = 'value5'; <5>
def z = d[y]; <6>
```
1. declare `def d`; allocate `HashMap` instance → `HashMap reference`; implicit cast `HashMap reference` to `def``def`; store `def` to `d`
2. load from `d``def`; implicit cast `def` to `HashMap reference``HashMap reference`; call `put` on `HashMap reference` with arguments(`String 'value2'`, `int 2`)
3. load from `d``def`; implicit cast `def` to `HashMap reference``HashMap reference`; call `put` on `HashMap reference` with arguments(`String 'value5'`, `int 5`)
4. declare `int x`; load from `d``def`; implicit cast `def` to `HashMap reference``HashMap reference`; call `get` on `HashMap reference` with arguments(`String 'value2'`) → `def`; implicit cast `def` to `int 2``int 2`; load from `d``def`; call `get` on `HashMap reference` with arguments(`String 'value5'`) → `def`; implicit cast `def` to `int 5``int 5`; add `int 2` and `int 5``int 7`; store `int 7` to `x`
5. declare `String y`; store `String 'value5'` to `y`
6. declare `def z`; load from `d``def`; load from `y``String 'value5'`; call `get` on `HashMap reference` with arguments(`String 'value5'`) → `def`; store `def` to `z`
## New Instance [new-instance-operator]
Use the `new instance operator 'new ()'` to allocate a [reference type](/reference/scripting-languages/painless/painless-types.md#reference-types) instance to the heap and call a specified constructor. Implicit [boxing/unboxing](/reference/scripting-languages/painless/painless-casting.md#boxing-unboxing) is evaluated as necessary per argument during the constructor call.
An overloaded constructor is one that shares the same name with two or more constructors. A constructor is overloaded based on arity where the same reference type name is re-used for multiple constructors as long as the number of parameters differs.
**Errors**
* If the reference type name doesnt exist for instance allocation.
* If the number of arguments passed in is different from the number of specified parameters.
* If the arguments cannot be implicitly cast or implicitly boxed/unboxed to the correct type values for the parameters.
**Grammar**
```text
new_instance: 'new' TYPE '(' (expression (',' expression)*)? ')';
```
**Examples**
* Allocation of new instances with different types.
```painless
Map m = new HashMap(); <1>
def d = new ArrayList(); <2>
def e = new HashMap(m); <3>
```
1. declare `Map m`; allocate `HashMap` instance → `HashMap reference`; implicit cast `HashMap reference` to `Map reference``Map reference`; store `Map reference` to `m`;
2. declare `def d`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `def``def`; store `def` to `d`;
3. declare `def e`; load from `m``Map reference`; allocate `HashMap` instance with arguments (`Map reference`) → `HashMap reference`; implicit cast `HashMap reference` to `def``def`; store `def` to `e`;
## String Concatenation [string-concatenation-operator]
Use the `string concatenation operator '+'` to concatenate two values together where at least one of the values is a [`String` type](/reference/scripting-languages/painless/painless-types.md#string-type).
**Grammar**
```text
concatenate: expression '+' expression;
```
**Examples**
* String concatenation with different primitive types.
```painless
String x = "con"; <1>
String y = x + "cat"; <2>
String z = 4 + 5 + x; <3>
```
1. declare `String x`; store `String "con"` to `x`;
2. declare `String y`; load from `x``String "con"`; concat `String "con"` and `String "cat"``String "concat"`; store `String "concat"` to `y`
3. declare `String z`; add `int 4` and `int 5``int 9`; concat `int 9` and `String "9concat"`; store `String "9concat"` to `z`; (note the addition is done prior to the concatenation due to precedence and associativity of the specific operations)
* String concatenation with the `def` type.
```painless
def d = 2; <1>
d = "con" + d + "cat"; <2>
```
1. declare `def`; implicit cast `int 2` to `def``def`; store `def` in `d`;
2. concat `String "con"` and `int 2``String "con2"`; concat `String "con2"` and `String "cat"``String "con2cat"` implicit cast `String "con2cat"` to `def``def`; store `def` to `d`; (note the switch in type of `d` from `int` to `String`)
## Elvis [elvis-operator]
An elvis consists of two expressions. The first expression is evaluated with to check for a `null` value. If the first expression evaluates to `null` then the second expression is evaluated and its value used. If the first expression evaluates to `non-null` then the resultant value of the first expression is used. Use the `elvis operator '?:'` as a shortcut for the conditional operator.
**Errors**
* If the first expression or second expression cannot produce a `null` value.
**Grammar**
```text
elvis: expression '?:' expression;
```
**Examples**
* Elvis with different reference types.
```painless
List x = new ArrayList(); <1>
List y = x ?: new ArrayList(); <2>
y = null; <3>
List z = y ?: new ArrayList(); <4>
```
1. declare `List x`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `x`;
2. declare `List y`; load `x``List reference`; `List reference` equals `null``false`; evaluate 1st expression: `List reference``List reference`; store `List reference` to `y`
3. store `null` to `y`;
4. declare `List z`; load `y``List reference`; `List reference` equals `null``true`; evaluate 2nd expression: allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `z`;

View file

@ -0,0 +1,64 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-operators.html
---
# Operators [painless-operators]
An operator is the most basic action that can be taken to evaluate values in a script. An expression is one-to-many consecutive operations. Precedence is the order in which an operator will be evaluated relative to another operator. Associativity is the direction within an expression in which a specific operator is evaluated. The following table lists all available operators:
| | | | | |
| --- | --- | --- | --- | --- |
| **Operator** | **Category** | **Symbol(s)** | **Precedence** | **Associativity** |
| [Precedence](/reference/scripting-languages/painless/painless-operators-general.md#precedence-operator) | [General](/reference/scripting-languages/painless/painless-operators-general.md) | () | 0 | left → right |
| [Method Call](/reference/scripting-languages/painless/painless-operators-reference.md#method-call-operator) | [Reference](/reference/scripting-languages/painless/painless-operators-reference.md) | . () | 1 | left → right |
| [Field Access](/reference/scripting-languages/painless/painless-operators-reference.md#field-access-operator) | [Reference](/reference/scripting-languages/painless/painless-operators-reference.md) | . | 1 | left → right |
| [Null Safe](/reference/scripting-languages/painless/painless-operators-reference.md#null-safe-operator) | [Reference](/reference/scripting-languages/painless/painless-operators-reference.md) | ?. | 1 | left → right |
| [Function Call](/reference/scripting-languages/painless/painless-operators-general.md#function-call-operator) | [General](/reference/scripting-languages/painless/painless-operators-general.md) | () | 1 | left → right |
| [Array Initialization](/reference/scripting-languages/painless/painless-operators-array.md#array-initialization-operator) | [Array](/reference/scripting-languages/painless/painless-operators-array.md) | [] {} | 1 | left → right |
| [Array Access](/reference/scripting-languages/painless/painless-operators-array.md#array-access-operator) | [Array](/reference/scripting-languages/painless/painless-operators-array.md) | [] | 1 | left → right |
| [Array Length](/reference/scripting-languages/painless/painless-operators-array.md#array-length-operator) | [Array](/reference/scripting-languages/painless/painless-operators-array.md) | . | 1 | left → right |
| [List Initialization](/reference/scripting-languages/painless/painless-operators-reference.md#list-initialization-operator) | [Reference](/reference/scripting-languages/painless/painless-operators-reference.md) | [] | 1 | left → right |
| [List Access](/reference/scripting-languages/painless/painless-operators-reference.md#list-access-operator) | [Reference](/reference/scripting-languages/painless/painless-operators-reference.md) | [] | 1 | left → right |
| [Map Initialization](/reference/scripting-languages/painless/painless-operators-reference.md#map-initialization-operator) | [Reference](/reference/scripting-languages/painless/painless-operators-reference.md) | [:] | 1 | left → right |
| [Map Access](/reference/scripting-languages/painless/painless-operators-reference.md#map-access-operator) | [Reference](/reference/scripting-languages/painless/painless-operators-reference.md) | [] | 1 | left → right |
| [Post Increment](/reference/scripting-languages/painless/painless-operators-numeric.md#post-increment-operator) | [Numeric](/reference/scripting-languages/painless/painless-operators-numeric.md) | ++ | 1 | left → right |
| [Post Decrement](/reference/scripting-languages/painless/painless-operators-numeric.md#post-decrement-operator) | [Numeric](/reference/scripting-languages/painless/painless-operators-numeric.md) |  —  | 1 | left → right |
| [Pre Increment](/reference/scripting-languages/painless/painless-operators-numeric.md#pre-increment-operator) | [Numeric](/reference/scripting-languages/painless/painless-operators-numeric.md) | ++ | 2 | right → left |
| [Pre Decrement](/reference/scripting-languages/painless/painless-operators-numeric.md#pre-decrement-operator) | [Numeric](/reference/scripting-languages/painless/painless-operators-numeric.md) |  —  | 2 | right → left |
| [Unary Positive](/reference/scripting-languages/painless/painless-operators-numeric.md#unary-positive-operator) | [Numeric](/reference/scripting-languages/painless/painless-operators-numeric.md) | + | 2 | right → left |
| [Unary Negative](/reference/scripting-languages/painless/painless-operators-numeric.md#unary-negative-operator) | [Numeric](/reference/scripting-languages/painless/painless-operators-numeric.md) | - | 2 | right → left |
| [Boolean Not](/reference/scripting-languages/painless/painless-operators-boolean.md#boolean-not-operator) | [Boolean](/reference/scripting-languages/painless/painless-operators-boolean.md) | ! | 2 | right → left |
| [Bitwise Not](/reference/scripting-languages/painless/painless-operators-numeric.md#bitwise-not-operator) | [Numeric](/reference/scripting-languages/painless/painless-operators-numeric.md) | ~ | 2 | right → left |
| [Cast](/reference/scripting-languages/painless/painless-operators-general.md#cast-operator) | [General](/reference/scripting-languages/painless/painless-operators-general.md) | () | 3 | right → left |
| [New Instance](/reference/scripting-languages/painless/painless-operators-reference.md#new-instance-operator) | [Reference](/reference/scripting-languages/painless/painless-operators-reference.md) | new () | 3 | right → left |
| [New Array](/reference/scripting-languages/painless/painless-operators-array.md#new-array-operator) | [Array](/reference/scripting-languages/painless/painless-operators-array.md) | new [] | 3 | right → left |
| [Multiplication](/reference/scripting-languages/painless/painless-operators-numeric.md#multiplication-operator) | [Numeric](/reference/scripting-languages/painless/painless-operators-numeric.md) | * | 4 | left → right |
| [Division](/reference/scripting-languages/painless/painless-operators-numeric.md#division-operator) | [Numeric](/reference/scripting-languages/painless/painless-operators-numeric.md) | / | 4 | left → right |
| [Remainder](/reference/scripting-languages/painless/painless-operators-numeric.md#remainder-operator) | [Numeric](/reference/scripting-languages/painless/painless-operators-numeric.md) | % | 4 | left → right |
| [String Concatenation](/reference/scripting-languages/painless/painless-operators-reference.md#string-concatenation-operator) | [Reference](/reference/scripting-languages/painless/painless-operators-reference.md) | + | 5 | left → right |
| [Addition](/reference/scripting-languages/painless/painless-operators-numeric.md#addition-operator) | [Numeric](/reference/scripting-languages/painless/painless-operators-numeric.md) | + | 5 | left → right |
| [Subtraction](/reference/scripting-languages/painless/painless-operators-numeric.md#subtraction-operator) | [Numeric](/reference/scripting-languages/painless/painless-operators-numeric.md) | - | 5 | left → right |
| [Left Shift](/reference/scripting-languages/painless/painless-operators-numeric.md#left-shift-operator) | [Numeric](/reference/scripting-languages/painless/painless-operators-numeric.md) | << | 6 | left → right |
| [Right Shift](/reference/scripting-languages/painless/painless-operators-numeric.md#right-shift-operator) | [Numeric](/reference/scripting-languages/painless/painless-operators-numeric.md) | >> | 6 | left → right |
| [Unsigned Right Shift](/reference/scripting-languages/painless/painless-operators-numeric.md#unsigned-right-shift-operator) | [Numeric](/reference/scripting-languages/painless/painless-operators-numeric.md) | >>> | 6 | left → right |
| [Greater Than](/reference/scripting-languages/painless/painless-operators-boolean.md#greater-than-operator) | [Boolean](/reference/scripting-languages/painless/painless-operators-boolean.md) | > | 7 | left → right |
| [Greater Than Or Equal](/reference/scripting-languages/painless/painless-operators-boolean.md#greater-than-or-equal-operator) | [Boolean](/reference/scripting-languages/painless/painless-operators-boolean.md) | >= | 7 | left → right |
| [Less Than](/reference/scripting-languages/painless/painless-operators-boolean.md#less-than-operator) | [Boolean](/reference/scripting-languages/painless/painless-operators-boolean.md) | < | 7 | left → right |
| [Less Than Or Equal](/reference/scripting-languages/painless/painless-operators-boolean.md#less-than-or-equal-operator) | [Boolean](/reference/scripting-languages/painless/painless-operators-boolean.md) | <= | 7 | left → right |
| [Instanceof](/reference/scripting-languages/painless/painless-operators-boolean.md#instanceof-operator) | [Boolean](/reference/scripting-languages/painless/painless-operators-boolean.md) | instanceof | 8 | left → right |
| [Equality Equals](/reference/scripting-languages/painless/painless-operators-boolean.md#equality-equals-operator) | [Boolean](/reference/scripting-languages/painless/painless-operators-boolean.md) | == | 9 | left → right |
| [Equality Not Equals](/reference/scripting-languages/painless/painless-operators-boolean.md#equality-not-equals-operator) | [Boolean](/reference/scripting-languages/painless/painless-operators-boolean.md) | != | 9 | left → right |
| [Identity Equals](/reference/scripting-languages/painless/painless-operators-boolean.md#identity-equals-operator) | [Boolean](/reference/scripting-languages/painless/painless-operators-boolean.md) | === | 9 | left → right |
| [Identity Not Equals](/reference/scripting-languages/painless/painless-operators-boolean.md#identity-not-equals-operator) | [Boolean](/reference/scripting-languages/painless/painless-operators-boolean.md) | !== | 9 | left → right |
| [Bitwise And](/reference/scripting-languages/painless/painless-operators-numeric.md#bitwise-and-operator) | [Numeric](/reference/scripting-languages/painless/painless-operators-numeric.md) | & | 10 | left → right |
| [Boolean Xor](/reference/scripting-languages/painless/painless-operators-boolean.md#boolean-xor-operator) | [Boolean](/reference/scripting-languages/painless/painless-operators-boolean.md) | ^ | 11 | left → right |
| [Bitwise Xor](/reference/scripting-languages/painless/painless-operators-numeric.md#bitwise-xor-operator) | [Numeric](/reference/scripting-languages/painless/painless-operators-numeric.md) | ^ | 11 | left → right |
| [Bitwise Or](/reference/scripting-languages/painless/painless-operators-numeric.md#bitwise-or-operator) | [Numeric](/reference/scripting-languages/painless/painless-operators-numeric.md) | &#124; | 12 | left → right |
| [Boolean And](/reference/scripting-languages/painless/painless-operators-boolean.md#boolean-and-operator) | [Boolean](/reference/scripting-languages/painless/painless-operators-boolean.md) | && | 13 | left → right |
| [Boolean Or](/reference/scripting-languages/painless/painless-operators-boolean.md#boolean-or-operator) | [Boolean](/reference/scripting-languages/painless/painless-operators-boolean.md) | &#124;&#124; | 14 | left → right |
| [Conditional](/reference/scripting-languages/painless/painless-operators-general.md#conditional-operator) | [General](/reference/scripting-languages/painless/painless-operators-general.md) | ? : | 15 | right → left |
| [Elvis](/reference/scripting-languages/painless/painless-operators-reference.md#elvis-operator) | [General](/reference/scripting-languages/painless/painless-operators-general.md) | ?: | 16 | right → left |
| [Assignment](/reference/scripting-languages/painless/painless-operators-general.md#assignment-operator) | [General](/reference/scripting-languages/painless/painless-operators-general.md) | = | 17 | right → left |
| [Compound Assignment](/reference/scripting-languages/painless/painless-operators-general.md#compound-assignment-operator) | [General](/reference/scripting-languages/painless/painless-operators-general.md) | $= | 17 | right → left |

View file

@ -0,0 +1,34 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-regexes.html
---
# Regexes [painless-regexes]
Regular expression constants are directly supported. To ensure fast performance, this is the only mechanism for creating patterns. Regular expressions are always constants and compiled efficiently a single time.
```painless
Pattern p = /[aeiou]/
```
::::{warning}
A poorly written regular expression can significantly slow performance. If possible, avoid using regular expressions, particularly in frequently run scripts.
::::
## Pattern flags [pattern-flags]
You can define flags on patterns in Painless by adding characters after the trailing `/` like `/foo/i` or `/foo \w #comment/iUx`. Painless exposes all of the flags from Javas [ Pattern class](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.md) using these characters:
| Character | Java Constant | Example |
| --- | --- | --- |
| `c` | CANON_EQ | `'å' ==~ /å/c` (open in hex editor to see) |
| `i` | CASE_INSENSITIVE | `'A' ==~ /a/i` |
| `l` | LITERAL | `'[a]' ==~ /[a]/l` |
| `m` | MULTILINE | `'a\nb\nc' =~ /^b$/m` |
| `s` | DOTALL (aka single line) | `'a\nb\nc' =~ /.b./s` |
| `U` | UNICODE_CHARACTER_CLASS | `'Ɛ' ==~ /\\w/U` |
| `u` | UNICODE_CASE | `'Ɛ' ==~ /ɛ/iu` |
| `x` | COMMENTS (aka extended) | `'a' ==~ /a #comment/x` |

View file

@ -0,0 +1,61 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-reindex-context.html
---
# Reindex context [painless-reindex-context]
Use a Painless script in a [reindex](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-reindex) operation to add, modify, or delete fields within each document in an original index as its reindexed into a target index.
**Variables**
`params` (`Map`, read-only)
: User-defined parameters passed in as part of the query.
`ctx['op']` (`String`)
: The name of the operation.
[`ctx['_routing']`](/reference/elasticsearch/mapping-reference/mapping-routing-field.md) (`String`)
: The value used to select a shard for document storage.
[`ctx['_index']`](/reference/elasticsearch/mapping-reference/mapping-index-field.md) (`String`)
: The name of the index.
[`ctx['_id']`](/reference/elasticsearch/mapping-reference/mapping-id-field.md) (`String`)
: The unique document id.
`ctx['_version']` (`int`)
: The current version of the document.
[`ctx['_source']`](/reference/elasticsearch/mapping-reference/mapping-source-field.md) (`Map`)
: Contains extracted JSON in a `Map` and `List` structure for the fields existing in a stored document.
**Side Effects**
`ctx['op']`
: Use the default of `index` to update a document. Set to `noop` to specify no operation or `delete` to delete the current document from the index.
[`ctx['_routing']`](/reference/elasticsearch/mapping-reference/mapping-routing-field.md)
: Modify this to change the routing value for the current document.
[`ctx['_index']`](/reference/elasticsearch/mapping-reference/mapping-index-field.md)
: Modify this to change the destination index for the current document.
[`ctx['_id']`](/reference/elasticsearch/mapping-reference/mapping-id-field.md)
: Modify this to change the id for the current document.
`ctx['_version']` (`int`)
: Modify this to modify the version for the current document.
[`ctx['_source']`](/reference/elasticsearch/mapping-reference/mapping-source-field.md)
: Modify the values in the `Map/List` structure to add, modify, or delete the fields of a document.
**Return**
`void`
: No expected return value.
**API**
The standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) is available.

View file

@ -0,0 +1,175 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-runtime-fields-context.html
---
# Runtime fields context [painless-runtime-fields-context]
Use a Painless script to calculate and emit [runtime field](/reference/scripting-languages/painless/use-painless-scripts-in-runtime-fields.md) values.
See the [runtime fields](docs-content://manage-data/data-store/mapping/runtime-fields.md) documentation for more information about how to use runtime fields.
**Methods**
$$$runtime-emit-method$$$
`emit`
: (Required) Accepts the values from the script valuation. Scripts can call the `emit` method multiple times to emit multiple values.
The `emit` method applies only to scripts used in a [runtime fields context](/reference/scripting-languages/painless/painless-api-examples.md#painless-execute-runtime-context).
::::{important}
The `emit` method cannot accept `null` values. Do not call this method if the referenced fields do not have any values.
::::
::::{dropdown} Signatures of `emit`
The signature for `emit` depends on the `type` of the field.
`boolean`
: `emit(boolean)`
`date`
: `emit(long)`
`double`
: `emit(double)`
`geo_point`
: `emit(double lat, double lon)`
`ip`
: `emit(String)`
`long`
: `emit(long)`
`keyword`
: `emit(String)`
::::
`grok`
: Defines a [grok pattern](/reference/ingestion-tools/enrich-processor/grok-processor.md) to extract structured fields out of a single text field within a document. A grok pattern is like a regular expression that supports aliased expressions that can be reused. See [Define a runtime field with a grok pattern](docs-content://manage-data/data-store/mapping/explore-data-with-runtime-fields.md#runtime-examples-grok).
::::{dropdown} Properties of `grok`
`extract`
: Indicates the values to return. This method applies only to `grok` and `dissect` methods.
::::
`dissect`
: Defines a [dissect pattern](/reference/ingestion-tools/enrich-processor/dissect-processor.md). Dissect operates much like grok, but does not accept regular expressions. See [Define a runtime field with a dissect pattern](docs-content://manage-data/data-store/mapping/explore-data-with-runtime-fields.md#runtime-examples-dissect).
::::{dropdown} Properties of `dissect`
`extract`
: Indicates the values to return. This method applies only to `grok` and `dissect` methods.
::::
**Variables**
`params` (`Map`, read-only)
: User-defined parameters passed in as part of the query.
`doc` (`Map`, read-only)
: Contains the fields of the specified document where each field is a `List` of values.
[`params['_source']`](/reference/elasticsearch/mapping-reference/mapping-source-field.md) (`Map`, read-only)
: Contains extracted JSON in a `Map` and `List` structure for the fields existing in a stored document.
**Return**
`void`
: No expected return value.
**API**
Both the standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) and [Specialized Field API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-field.html) are available.
**Example**
To run the examples, first follow the steps in [context examples](/reference/scripting-languages/painless/painless-context-examples.md).
Then, run the following request to define a runtime field named `day_of_week`. This field contains a script with the same `source` defined in [Field context](/reference/scripting-languages/painless/painless-field-context.md), but also uses an `emit` function that runtime fields require when defining a Painless script.
Because `day_of_week` is a runtime field, it isnt indexed, and the included script only runs at query time:
```console
PUT seats/_mapping
{
"runtime": {
"day_of_week": {
"type": "keyword",
"script": {
"source": "emit(doc['datetime'].value.getDayOfWeekEnum().toString())"
}
}
}
}
```
After defining the runtime field and script in the mappings, you can run a query that includes a terms aggregation for `day_of_week`. When the query runs, {{es}} evaluates the included Painless script and dynamically generates a value based on the script definition:
```console
GET seats/_search
{
"size": 0,
"fields": [
"time",
"day_of_week"
],
"aggs": {
"day_of_week": {
"terms": {
"field": "day_of_week",
"size": 10
}
}
}
}
```
The response includes `day_of_week` for each hit. {{es}} calculates the value for this field dynamically at search time by operating on the `datetime` field defined in the mappings.
```console-result
{
...
"hits" : {
"total" : {
"value" : 11,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"day_of_week" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "TUESDAY",
"doc_count" : 5
},
{
"key" : "THURSDAY",
"doc_count" : 4
},
{
"key" : "MONDAY",
"doc_count" : 1
},
{
"key" : "SUNDAY",
"doc_count" : 1
}
]
}
}
}
```

View file

@ -0,0 +1,55 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-score-context.html
---
# Score context [painless-score-context]
Use a Painless script in a [function score](/reference/query-languages/query-dsl-function-score-query.md) to apply a new score to documents returned from a query.
**Variables**
`params` (`Map`, read-only)
: User-defined parameters passed in as part of the query.
`doc` (`Map`, read-only)
: Contains the fields of the current document. For single-valued fields, the value can be accessed via `doc['fieldname'].value`. For multi-valued fields, this returns the first value; other values can be accessed via `doc['fieldname'].get(index)`
`_score` (`double` read-only)
: The similarity score of the current document.
**Return**
`double`
: The score for the current document.
**API**
Both the standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) and [Specialized Score API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-score.html) are available.
**Example**
To run this example, first follow the steps in [context examples](/reference/scripting-languages/painless/painless-context-examples.md).
The following query finds all unsold seats, with lower *row* values scored higher.
```console
GET /seats/_search
{
"query": {
"function_score": {
"query": {
"match": {
"sold": "false"
}
},
"script_score": {
"script": {
"source": "1.0 / doc['row'].value"
}
}
}
}
}
```

View file

@ -0,0 +1,9 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-scripts.html
---
# Scripts [painless-scripts]
Scripts are composed of one-to-many [statements](/reference/scripting-languages/painless/painless-statements.md) and are run in a sandbox that determines what local variables are immediately available along with what APIs are allowed.

View file

@ -0,0 +1,51 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-similarity-context.html
---
# Similarity context [painless-similarity-context]
Use a Painless script to create a [similarity](/reference/elasticsearch/index-settings/similarity.md) equation for scoring documents in a query.
**Variables**
`weight` (`float`, read-only)
: The weight as calculated by a [weight script](/reference/scripting-languages/painless/painless-weight-context.md)
`query.boost` (`float`, read-only)
: The boost value if provided by the query. If this is not provided the value is `1.0f`.
`field.docCount` (`long`, read-only)
: The number of documents that have a value for the current field.
`field.sumDocFreq` (`long`, read-only)
: The sum of all terms that exist for the current field. If this is not available the value is `-1`.
`field.sumTotalTermFreq` (`long`, read-only)
: The sum of occurrences in the index for all the terms that exist in the current field. If this is not available the value is `-1`.
`term.docFreq` (`long`, read-only)
: The number of documents that contain the current term in the index.
`term.totalTermFreq` (`long`, read-only)
: The total occurrences of the current term in the index.
`doc.length` (`long`, read-only)
: The number of tokens the current document has in the current field. This is decoded from the stored [norms](/reference/elasticsearch/mapping-reference/norms.md) and may be approximate for long fields
`doc.freq` (`long`, read-only)
: The number of occurrences of the current term in the current document for the current field.
Note that the `query`, `field`, and `term` variables are also available to the [weight context](/reference/scripting-languages/painless/painless-weight-context.md). They are more efficiently used there, as they are constant for all documents.
For queries that contain multiple terms, the script is called once for each term with that terms calculated weight, and the results are summed. Note that some terms might have a `doc.freq` value of `0` on a document, for example if a query uses synonyms.
**Return**
`double`
: The similarity score for the current document.
**API**
The standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) is available.

View file

@ -0,0 +1,59 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-sort-context.html
---
# Sort context [painless-sort-context]
Use a Painless script to [sort](/reference/elasticsearch/rest-apis/sort-search-results.md) the documents in a query.
**Variables**
`params` (`Map`, read-only)
: User-defined parameters passed in as part of the query.
`doc` (`Map`, read-only)
: Contains the fields of the current document. For single-valued fields, the value can be accessed via `doc['fieldname'].value`. For multi-valued fields, this returns the first value; other values can be accessed via `doc['fieldname'].get(index)`
`_score` (`double` read-only)
: The similarity score of the current document.
**Return**
`double` or `String`
: The sort key. The return type depends on the value of the `type` parameter in the script sort config (`"number"` or `"string"`).
**API**
The standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) is available.
**Example**
To run this example, first follow the steps in [context examples](/reference/scripting-languages/painless/painless-context-examples.md).
To sort results by the length of the `theatre` field, submit the following query:
```console
GET /_search
{
"query": {
"term": {
"sold": "true"
}
},
"sort": {
"_script": {
"type": "number",
"script": {
"lang": "painless",
"source": "doc['theatre'].value.length() * params.factor",
"params": {
"factor": 1.1
}
},
"order": "asc"
}
}
}
```

View file

@ -0,0 +1,64 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-statements.html
---
# Statements [painless-statements]
Painless supports all of Javas [ control flow statements](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/flow.md) except the `switch` statement.
## Conditional statements [_conditional_statements]
### If / Else [_if_else]
```painless
if (doc[item].size() == 0) {
// do something if "item" is missing
} else if (doc[item].value == 'something') {
// do something if "item" value is: something
} else {
// do something else
}
```
## Loop statements [_loop_statements]
### For [_for]
Painless also supports the `for in` syntax:
```painless
for (def item : list) {
// do something
}
```
```painless
for (item in list) {
// do something
}
```
### While [_while]
```painless
while (ctx._source.item < condition) {
// do something
}
```
### Do-While [_do_while]
```painless
do {
// do something
}
while (ctx._source.item < condition)
```

View file

@ -0,0 +1,261 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-types.html
---
# Types [painless-types]
A type is a classification of data used to define the properties of a value. These properties specify what data a value represents and the rules for how a value is evaluated during an [operation](/reference/scripting-languages/painless/painless-operators.md). Each type belongs to one of the following categories: [primitive](#primitive-types), [reference](#reference-types), or [dynamic](#dynamic-types).
## Primitive Types [primitive-types]
A primitive type represents basic data built natively into the JVM and is allocated to non-heap memory. Declare a primitive type [variable](/reference/scripting-languages/painless/painless-variables.md) or access a primitive type member field (from a reference type instance), and assign it a primitive type value for evaluation during later operations. The default value for a newly-declared primitive type variable is listed as part of the definitions below. A primitive type value is copied during an assignment or as an argument for a method/function call.
A primitive type has a corresponding reference type (also known as a boxed type). Use the [field access operator](/reference/scripting-languages/painless/painless-operators-reference.md#field-access-operator) or [method call operator](/reference/scripting-languages/painless/painless-operators-reference.md#method-call-operator) on a primitive type value to force evaluation as its corresponding reference type value.
The following primitive types are available. The corresponding reference type is listed in parentheses. For example, `Byte` is the reference type for the `byte` primitive type:
::::{dropdown} Available primitive types
:name: available-primitive-types
`byte` (`Byte`)
: 8-bit, signed, twos complement integer. Range: [`-128`, `127`]. Default: `0`.
`short` (`Short`)
: 16-bit, signed, twos complement integer. Range: [`-32768`, `32767`]. Default: `0`.
`char` (`Character`)
: 16-bit, unsigned, Unicode character. Range: [`0`, `65535`]. Default: `0` or `\u0000`.
`int` (`Integer`)
: 32-bit, signed, twos complement integer. Range: [`-2^31`, `2^31-1`]. Default: `0`.
`long` (`Long`)
: 64-bit, signed, twos complement integer. Range: [`-2^63`, `2^63-1`]. Default: `0`.
`float (`Float`)`
: 32-bit, signed, single-precision, IEEE 754 floating point number. Default `0.0`.
`double` (`Double`)
: 64-bit, signed, double-precision, IEEE 754 floating point number. Default: `0.0`.
`boolean` (`Boolean`)
: logical quantity with two possible values of `true` and `false`. Default: `false`.
::::
**Examples**
* Primitive types used in declaration, declaration and assignment.
```painless
int i = 1; <1>
double d; <2>
boolean b = true; <3>
```
1. declare `int i`; store `int 1` to `i`
2. declare `double d`; store default `double 0.0` to `d`
3. declare `boolean b`; store `boolean true` to `b`
* Method call on a primitive type using the corresponding reference type.
```painless
int i = 1; <1>
i.toString(); <2>
```
1. declare `int i`; store `int 1` to `i`
2. load from `i``int 1`; box `int 1``Integer 1 reference`; call `toString` on `Integer 1 reference``String '1'`
## Reference Types [reference-types]
A reference type is a named construct (object), potentially representing multiple pieces of data (member fields) and logic to manipulate that data (member methods), defined as part of the application programming interface (API) for scripts.
A reference type instance is a single set of data for one reference type object allocated to the heap. Use the [new instance operator](/reference/scripting-languages/painless/painless-operators-reference.md#new-instance-operator) to allocate a reference type instance. Use a reference type instance to load from, store to, and manipulate complex data.
A reference type value refers to a reference type instance, and multiple reference type values may refer to the same reference type instance. A change to a reference type instance will affect all reference type values referring to that specific instance.
Declare a reference type [variable](/reference/scripting-languages/painless/painless-variables.md) or access a reference type member field (from a reference type instance), and assign it a reference type value for evaluation during later operations. The default value for a newly-declared reference type variable is `null`. A reference type value is shallow-copied during an assignment or as an argument for a method/function call. Assign `null` to a reference type variable to indicate the reference type value refers to no reference type instance. The JVM will garbage collect a reference type instance when it is no longer referred to by any reference type values. Pass `null` as an argument to a method/function call to indicate the argument refers to no reference type instance.
A reference type object defines zero-to-many of each of the following:
static member field
: A static member field is a named and typed piece of data. Each reference type **object** contains one set of data representative of its static member fields. Use the [field access operator](/reference/scripting-languages/painless/painless-operators-reference.md#field-access-operator) in correspondence with the reference type object name to access a static member field for loading and storing to a specific reference type **object**. No reference type instance allocation is necessary to use a static member field.
non-static member field
: A non-static member field is a named and typed piece of data. Each reference type **instance** contains one set of data representative of its reference type objects non-static member fields. Use the [field access operator](/reference/scripting-languages/painless/painless-operators-reference.md#field-access-operator) for loading and storing to a non-static member field of a specific reference type **instance**. An allocated reference type instance is required to use a non-static member field.
static member method
: A static member method is a [function](/reference/scripting-languages/painless/painless-functions.md) called on a reference type **object**. Use the [method call operator](/reference/scripting-languages/painless/painless-operators-reference.md#method-call-operator) in correspondence with the reference type object name to call a static member method. No reference type instance allocation is necessary to use a static member method.
non-static member method
: A non-static member method is a [function](/reference/scripting-languages/painless/painless-functions.md) called on a reference type **instance**. A non-static member method called on a reference type instance can load from and store to non-static member fields of that specific reference type instance. Use the [method call operator](/reference/scripting-languages/painless/painless-operators-reference.md#method-call-operator) in correspondence with a specific reference type instance to call a non-static member method. An allocated reference type instance is required to use a non-static member method.
constructor
: A constructor is a special type of [function](/reference/scripting-languages/painless/painless-functions.md) used to allocate a reference type **instance** defined by a specific reference type **object**. Use the [new instance operator](/reference/scripting-languages/painless/painless-operators-reference.md#new-instance-operator) to allocate a reference type instance.
A reference type object follows a basic inheritance model. Consider types A and B. Type A is considered to be a parent of B, and B a child of A, if B inherits (is able to access as its own) all of As non-static members. Type B is considered a descendant of A if there exists a recursive parent-child relationship from B to A with none to many types in between. In this case, B inherits all of As non-static members along with all of the non-static members of the types in between. Type B is also considered to be a type A in both relationships.
**Examples**
* Reference types evaluated in several different operations.
```painless
List l = new ArrayList(); <1>
l.add(1); <2>
int i = l.get(0) + 2; <3>
```
1. declare `List l`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `l`
2. load from `l``List reference`; implicit cast `int 1` to `def``def` call `add` on `List reference` with arguments (`def`)
3. declare `int i`; load from `l``List reference`; call `get` on `List reference` with arguments (`int 0`) → `def`; implicit cast `def` to `int 1``int 1`; add `int 1` and `int 2``int 3`; store `int 3` to `i`
* Sharing a reference type instance.
```painless
List l0 = new ArrayList(); <1>
List l1 = l0; <2>
l0.add(1); <3>
l1.add(2); <4>
int i = l1.get(0) + l0.get(1); <5>
```
1. declare `List l0`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `l0`
2. declare `List l1`; load from `l0``List reference`; store `List reference` to `l1` (note `l0` and `l1` refer to the same instance known as a shallow-copy)
3. load from `l0``List reference`; implicit cast `int 1` to `def``def` call `add` on `List reference` with arguments (`def`)
4. load from `l1``List reference`; implicit cast `int 2` to `def``def` call `add` on `List reference` with arguments (`def`)
5. declare `int i`; load from `l0``List reference`; call `get` on `List reference` with arguments (`int 0`) → `def @0`; implicit cast `def @0` to `int 1``int 1`; load from `l1``List reference`; call `get` on `List reference` with arguments (`int 1`) → `def @1`; implicit cast `def @1` to `int 2``int 2`; add `int 1` and `int 2``int 3`; store `int 3` to `i`;
* Using the static members of a reference type.
```painless
int i = Integer.MAX_VALUE; <1>
long l = Long.parseLong("123L"); <2>
```
1. declare `int i`; load from `MAX_VALUE` on `Integer``int 2147483647`; store `int 2147483647` to `i`
2. declare `long l`; call `parseLong` on `Long` with arguments (`long 123`) → `long 123`; store `long 123` to `l`
## Dynamic Types [dynamic-types]
A dynamic type value can represent the value of any primitive type or reference type using a single type name `def`. A `def` type value mimics the behavior of whatever value it represents at run-time and will always represent the child-most descendant type value of any type value when evaluated during operations.
Declare a `def` type [variable](/reference/scripting-languages/painless/painless-variables.md) or access a `def` type member field (from a reference type instance), and assign it any type of value for evaluation during later operations. The default value for a newly-declared `def` type variable is `null`. A `def` type variable or method/function parameter can change the type it represents during the compilation and evaluation of a script.
Using the `def` type can have a slight impact on performance. Use only primitive types and reference types directly when performance is critical.
**Errors**
* If a `def` type value represents an inappropriate type for evaluation of an operation at run-time.
**Examples**
* General uses of the `def` type.
```painless
def dp = 1; <1>
def dr = new ArrayList(); <2>
dr = dp; <3>
```
1. declare `def dp`; implicit cast `int 1` to `def``def`; store `def` to `dp`
2. declare `def dr`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `def``def`; store `def` to `dr`
3. load from `dp``def`; store `def` to `dr`; (note the switch in the type `dr` represents from `ArrayList` to `int`)
* A `def` type value representing the child-most descendant of a value.
```painless
Object l = new ArrayList(); <1>
def d = l; <2>
d.ensureCapacity(10); <3>
```
1. declare `Object l`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `Object reference``Object reference`; store `Object reference` to `l`
2. declare `def d`; load from `l``Object reference`; implicit cast `Object reference` to `def``def`; store `def` to `d`;
3. load from `d``def`; implicit cast `def` to `ArrayList reference``ArrayList reference`; call `ensureCapacity` on `ArrayList reference` with arguments (`int 10`); (note `def` was implicit cast to `ArrayList reference` since ArrayList` is the child-most descendant type value that the `def` type value represents)
## String Type [string-type]
The `String` type is a specialized reference type that does not require explicit allocation. Use a [string literal](/reference/scripting-languages/painless/painless-literals.md#string-literals) to directly evaluate a `String` type value. While not required, the [new instance operator](/reference/scripting-languages/painless/painless-operators-reference.md#new-instance-operator) can allocate `String` type instances.
**Examples**
* General use of the `String` type.
```painless
String r = "some text"; <1>
String s = 'some text'; <2>
String t = new String("some text"); <3>
String u; <4>
```
1. declare `String r`; store `String "some text"` to `r`
2. declare `String s`; store `String 'some text'` to `s`
3. declare `String t`; allocate `String` instance with arguments (`String "some text"`) → `String "some text"`; store `String "some text"` to `t`
4. declare `String u`; store default `null` to `u`
## void Type [void-type]
The `void` type represents the concept of a lack of type. Use the `void` type to indicate a function returns no value.
**Examples**
* Use of the `void` type in a function.
```painless
void addToList(List l, def d) {
l.add(d);
}
```
## Array Type [array-type]
An array type is a specialized reference type where an array type instance contains a series of values allocated to the heap. Each value in an array type instance is defined as an element. All elements in an array type instance are of the same type (element type) specified as part of declaration. Each element is assigned an index within the range `[0, length)` where length is the total number of elements allocated for an array type instance.
Use the [new array operator](/reference/scripting-languages/painless/painless-operators-array.md#new-array-operator) or the [array initialization operator](/reference/scripting-languages/painless/painless-operators-array.md#array-initialization-operator) to allocate an array type instance. Declare an array type [variable](/reference/scripting-languages/painless/painless-variables.md) or access an array type member field (from a reference type instance), and assign it an array type value for evaluation during later operations. The default value for a newly-declared array type variable is `null`. An array type value is shallow-copied during an assignment or as an argument for a method/function call. Assign `null` to an array type variable to indicate the array type value refers to no array type instance. The JVM will garbage collect an array type instance when it is no longer referred to by any array type values. Pass `null` as an argument to a method/function call to indicate the argument refers to no array type instance.
Use the [array length operator](/reference/scripting-languages/painless/painless-operators-array.md#array-length-operator) to retrieve the length of an array type value as an `int` type value. Use the [array access operator](/reference/scripting-languages/painless/painless-operators-array.md#array-access-operator) to load from and store to an individual element within an array type instance.
When an array type instance is allocated with multiple dimensions using the range `[2, d]` where `d >= 2`, each element within each dimension in the range `[1, d-1]` is also an array type. The element type of each dimension, `n`, is an array type with the number of dimensions equal to `d-n`. For example, consider `int[][][]` with 3 dimensions. Each element in the 3rd dimension, `d-3`, is the primitive type `int`. Each element in the 2nd dimension, `d-2`, is the array type `int[]`. And each element in the 1st dimension, `d-1` is the array type `int[][]`.
**Examples**
* General use of single-dimensional arrays.
```painless
int[] x; <1>
float[] y = new float[10]; <2>
def z = new float[5]; <3>
y[9] = 1.0F; <4>
z[0] = y[9]; <5>
```
1. declare `int[] x`; store default `null` to `x`
2. declare `float[] y`; allocate `1-d float array` instance with `length [10]``1-d float array reference`; store `1-d float array reference` to `y`
3. declare `def z`; allocate `1-d float array` instance with `length [5]``1-d float array reference`; implicit cast `1-d float array reference` to `def``def`; store `def` to `z`
4. load from `y``1-d float array reference`; store `float 1.0` to `index [9]` of `1-d float array reference`
5. load from `y``1-d float array reference @0`; load from `index [9]` of `1-d float array reference @0``float 1.0`; load from `z``def`; implicit cast `def` to `1-d float array reference @1``1-d float array reference @1`; store `float 1.0` to `index [0]` of `1-d float array reference @1`
* General use of a multi-dimensional array.
```painless
int[][][] ia3 = new int[2][3][4]; <1>
ia3[1][2][3] = 99; <2>
int i = ia3[1][2][3]; <3>
```
1. declare `int[][][] ia`; allocate `3-d int array` instance with length `[2, 3, 4]``3-d int array reference`; store `3-d int array reference` to `ia3`
2. load from `ia3``3-d int array reference`; store `int 99` to `index [1, 2, 3]` of `3-d int array reference`
3. declare `int i`; load from `ia3``3-d int array reference`; load from `index [1, 2, 3]` of `3-d int array reference``int 99`; store `int 99` to `i`

View file

@ -0,0 +1,86 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-update-by-query-context.html
---
# Update by query context [painless-update-by-query-context]
Use a Painless script in an [update by query](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-update-by-query) operation to add, modify, or delete fields within each of a set of documents collected as the result of query.
**Variables**
`params` (`Map`, read-only)
: User-defined parameters passed in as part of the query.
`ctx['op']` (`String`)
: The name of the operation.
[`ctx['_routing']`](/reference/elasticsearch/mapping-reference/mapping-routing-field.md) (`String`, read-only)
: The value used to select a shard for document storage.
[`ctx['_index']`](/reference/elasticsearch/mapping-reference/mapping-index-field.md) (`String`, read-only)
: The name of the index.
[`ctx['_id']`](/reference/elasticsearch/mapping-reference/mapping-id-field.md) (`String`, read-only)
: The unique document id.
`ctx['_version']` (`int`, read-only)
: The current version of the document.
[`ctx['_source']`](/reference/elasticsearch/mapping-reference/mapping-source-field.md) (`Map`)
: Contains extracted JSON in a `Map` and `List` structure for the fields existing in a stored document.
**Side Effects**
`ctx['op']`
: Use the default of `index` to update a document. Set to `none` to specify no operation or `delete` to delete the current document from the index.
[`ctx['_source']`](/reference/elasticsearch/mapping-reference/mapping-source-field.md)
: Modify the values in the `Map/List` structure to add, modify, or delete the fields of a document.
**Return**
`void`
: No expected return value.
**API**
The standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) is available.
**Example**
To run this example, first follow the steps in [context examples](/reference/scripting-languages/painless/painless-context-examples.md).
The following query finds all seats in a specific section that have not been sold and lowers the price by 2:
```console
POST /seats/_update_by_query
{
"query": {
"bool": {
"filter": [
{
"range": {
"row": {
"lte": 3
}
}
},
{
"match": {
"sold": false
}
}
]
}
},
"script": {
"source": "ctx._source.cost -= params.discount",
"lang": "painless",
"params": {
"discount": 2
}
}
}
```

View file

@ -0,0 +1,71 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-update-context.html
---
# Update context [painless-update-context]
Use a Painless script in an [update](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-update) operation to add, modify, or delete fields within a single document.
**Variables**
`params` (`Map`, read-only)
: User-defined parameters passed in as part of the query.
`ctx['op']` (`String`)
: The name of the operation.
[`ctx['_routing']`](/reference/elasticsearch/mapping-reference/mapping-routing-field.md) (`String`, read-only)
: The value used to select a shard for document storage.
[`ctx['_index']`](/reference/elasticsearch/mapping-reference/mapping-index-field.md) (`String`, read-only)
: The name of the index.
[`ctx['_id']`](/reference/elasticsearch/mapping-reference/mapping-id-field.md) (`String`, read-only)
: The unique document id.
`ctx['_version']` (`int`, read-only)
: The current version of the document.
`ctx['_now']` (`long`, read-only)
: The current timestamp in milliseconds.
[`ctx['_source']`](/reference/elasticsearch/mapping-reference/mapping-source-field.md) (`Map`)
: Contains extracted JSON in a `Map` and `List` structure for the fields existing in a stored document.
**Side Effects**
`ctx['op']`
: Use the default of `index` to update a document. Set to `none` to specify no operation or `delete` to delete the current document from the index.
[`ctx['_source']`](/reference/elasticsearch/mapping-reference/mapping-source-field.md)
: Modify the values in the `Map/List` structure to add, modify, or delete the fields of a document.
**Return**
`void`
: No expected return value.
**API**
The standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) is available.
**Example**
To run this example, first follow the steps in [context examples](/reference/scripting-languages/painless/painless-context-examples.md).
The following query updates a document to be sold, and sets the cost to the actual price paid after discounts:
```console
POST /seats/_update/3
{
"script": {
"source": "ctx._source.sold = true; ctx._source.cost = params.sold_cost",
"lang": "painless",
"params": {
"sold_cost": 26
}
}
}
```

View file

@ -0,0 +1,141 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-variables.html
---
# Variables [painless-variables]
A variable loads and stores a value for evaluation during [operations](/reference/scripting-languages/painless/painless-operators.md).
## Declaration [variable-declaration]
Declare a variable before use with the format of [type](/reference/scripting-languages/painless/painless-types.md) followed by [identifier](/reference/scripting-languages/painless/painless-identifiers.md). Declare an [array type](/reference/scripting-languages/painless/painless-types.md#array-type) variable using an opening `[` token and a closing `]` token for each dimension directly after the identifier. Specify a comma-separated list of identifiers following the type to declare multiple variables in a single statement. Use an [assignment operator](#variable-assignment) combined with a declaration to immediately assign a value to a variable. A variable not immediately assigned a value will have a default value assigned implicitly based on the type.
**Errors**
* If a variable is used prior to or without declaration.
**Grammar**
```text
declaration : type ID assignment? (',' ID assignment?)*;
type: ID ('.' ID)* ('[' ']')*;
assignment: '=' expression;
```
**Examples**
* Different variations of variable declaration.
```painless
int x; <1>
List y; <2>
int x, y = 5, z; <3>
def d; <4>
int i = 10; <5>
float[] f; <6>
Map[][] m; <7>
```
1. declare `int x`; store default `null` to `x`
2. declare `List y`; store default `null` to `y`
3. declare `int x`; store default `int 0` to `x`; declare `int y`; store `int 5` to `y`; declare `int z`; store default `int 0` to `z`;
4. declare `def d`; store default `null` to `d`
5. declare `int i`; store `int 10` to `i`
6. declare `float[] f`; store default `null` to `f`
7. declare `Map[][] m`; store default `null` to `m`
## Assignment [variable-assignment]
Use the `assignment operator '='` to store a value in a variable for use in subsequent operations. Any operation that produces a value can be assigned to any variable as long as the [types](/reference/scripting-languages/painless/painless-types.md) are the same or the resultant type can be [implicitly cast](/reference/scripting-languages/painless/painless-casting.md) to the variable type.
**Errors**
* If the type of value is unable to match the type of variable.
**Grammar**
```text
assignment: ID '=' expression
```
**Examples**
* Variable assignment with an integer literal.
```painless
int i; <1>
i = 10; <2>
```
1. declare `int i`; store default `int 0` to `i`
2. store `int 10` to `i`
* Declaration combined with immediate assignment.
```painless
int i = 10; <1>
double j = 2.0; <2>
```
1. declare `int i`; store `int 10` to `i`
2. declare `double j`; store `double 2.0` to `j`
* Assignment of one variable to another using primitive type values.
```painless
int i = 10; <1>
int j = i; <2>
```
1. declare `int i`; store `int 10` to `i`
2. declare `int j`; load from `i``int 10`; store `int 10` to `j`
* Assignment with reference types using the [new instance operator](/reference/scripting-languages/painless/painless-operators-reference.md#new-instance-operator).
```painless
ArrayList l = new ArrayList(); <1>
Map m = new HashMap(); <2>
```
1. declare `ArrayList l`; allocate `ArrayList` instance → `ArrayList reference`; store `ArrayList reference` to `l`
2. declare `Map m`; allocate `HashMap` instance → `HashMap reference`; implicit cast `HashMap reference` to `Map reference``Map reference`; store `Map reference` to `m`
* Assignment of one variable to another using reference type values.
```painless
List l = new ArrayList(); <1>
List k = l; <2>
List m; <3>
m = k; <4>
```
1. declare `List l`; allocate `ArrayList` instance → `ArrayList reference`; implicit cast `ArrayList reference` to `List reference``List reference`; store `List reference` to `l`
2. declare `List k`; load from `l``List reference`; store `List reference` to `k`; (note `l` and `k` refer to the same instance known as a shallow-copy)
3. declare `List m`; store default `null` to `m`
4. load from `k``List reference`; store `List reference` to `m`; (note `l`, `k`, and `m` refer to the same instance)
* Assignment with array type variables using the [new array operator](/reference/scripting-languages/painless/painless-operators-array.md#new-array-operator).
```painless
int[] ia1; <1>
ia1 = new int[2]; <2>
ia1[0] = 1; <3>
int[] ib1 = ia1; <4>
int[][] ic2 = new int[2][5]; <5>
ic2[1][3] = 2; <6>
ic2[0] = ia1; <7>
```
1. declare `int[] ia1`; store default `null` to `ia1`
2. allocate `1-d int array` instance with `length [2]``1-d int array reference`; store `1-d int array reference` to `ia1`
3. load from `ia1``1-d int array reference`; store `int 1` to `index [0]` of `1-d int array reference`
4. declare `int[] ib1`; load from `ia1``1-d int array reference`; store `1-d int array reference` to `ib1`; (note `ia1` and `ib1` refer to the same instance known as a shallow copy)
5. declare `int[][] ic2`; allocate `2-d int array` instance with `length [2, 5]``2-d int array reference`; store `2-d int array reference` to `ic2`
6. load from `ic2``2-d int array reference`; store `int 2` to `index [1, 3]` of `2-d int array reference`
7. load from `ia1``1-d int array reference`; load from `ic2``2-d int array reference`; store `1-d int array reference` to `index [0]` of `2-d int array reference`; (note `ia1`, `ib1`, and `index [0]` of `ia2` refer to the same instance)

View file

@ -0,0 +1,161 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-watcher-condition-context.html
---
# Watcher condition context [painless-watcher-condition-context]
Use a Painless script as a [watch condition](docs-content://explore-analyze/alerts-cases/watcher/condition-script.md) that determines whether to execute a watch or a particular action within a watch. Condition scripts return a Boolean value to indicate the status of the condition.
The following variables are available in all watcher contexts.
**Variables**
`params` (`Map`, read-only)
: User-defined parameters passed in as part of the query.
`ctx['watch_id']` (`String`, read-only)
: The id of the watch.
`ctx['id']` (`String`, read-only)
: The server generated unique identifier for the run watch.
`ctx['metadata']` (`Map`, read-only)
: Metadata can be added to the top level of the watch definition. This is user defined and is typically used to consolidate duplicate values in a watch.
`ctx['execution_time']` (`ZonedDateTime`, read-only)
: The time the watch began execution.
`ctx['trigger']['scheduled_time']` (`ZonedDateTime`, read-only)
: The scheduled trigger time for the watch. This is the time the watch should be executed.
`ctx['trigger']['triggered_time']` (`ZonedDateTime`, read-only)
: The actual trigger time for the watch. This is the time the watch was triggered for execution.
`ctx['payload']` (`Map`, read-only)
: The accessible watch data based upon the [watch input](docs-content://explore-analyze/alerts-cases/watcher/input.md).
**Return**
`boolean`
: Expects `true` if the condition is met, and `false` if it is not.
**API**
The standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) is available.
**Example**
To run the examples, first follow the steps in [context examples](/reference/scripting-languages/painless/painless-context-examples.md).
```console
POST _watcher/watch/_execute
{
"watch" : {
"trigger" : { "schedule" : { "interval" : "24h" } },
"input" : {
"search" : {
"request" : {
"indices" : [ "seats" ],
"body" : {
"query" : {
"term": { "sold": "true"}
},
"aggs" : {
"theatres" : {
"terms" : { "field" : "play" },
"aggs" : {
"money" : {
"sum": { "field" : "cost" }
}
}
}
}
}
}
}
},
"condition" : {
"script" :
"""
return ctx.payload.aggregations.theatres.buckets.stream() <1>
.filter(theatre -> theatre.money.value < 15000 ||
theatre.money.value > 50000) <2>
.count() > 0 <3>
"""
},
"actions" : {
"my_log" : {
"logging" : {
"text" : "The output of the search was : {{ctx.payload.aggregations.theatres.buckets}}"
}
}
}
}
}
```
1. The Java Stream API is used in the condition. This API allows manipulation of the elements of the list in a pipeline.
2. The stream filter removes items that do not meet the filter criteria.
3. If there is at least one item in the list, the condition evaluates to true and the watch is executed.
The following action condition script controls execution of the my_log action based on the value of the seats sold for the plays in the data set. The script aggregates the total sold seats for each play and returns true if there is at least one play that has sold over $10,000.
```console
POST _watcher/watch/_execute
{
"watch" : {
"trigger" : { "schedule" : { "interval" : "24h" } },
"input" : {
"search" : {
"request" : {
"indices" : [ "seats" ],
"body" : {
"query" : {
"term": { "sold": "true"}
},
"size": 0,
"aggs" : {
"theatres" : {
"terms" : { "field" : "play" },
"aggs" : {
"money" : {
"sum": {
"field" : "cost",
"script": {
"source": "doc.cost.value * doc.number.value"
}
}
}
}
}
}
}
}
}
},
"actions" : {
"my_log" : {
"condition": { <1>
"script" :
"""
return ctx.payload.aggregations.theatres.buckets.stream()
.anyMatch(theatre -> theatre.money.value > 10000) <2>
"""
},
"logging" : {
"text" : "At least one play has grossed over $10,000: {{ctx.payload.aggregations.theatres.buckets}}"
}
}
}
}
}
```
This example uses a nearly identical condition as the previous example. The differences below are subtle and are worth calling out.
1. The location of the condition is no longer at the top level, but is within an individual action.
2. Instead of a filter, `anyMatch` is used to return a boolean value

View file

@ -0,0 +1,339 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-watcher-transform-context.html
---
# Watcher transform context [painless-watcher-transform-context]
Use a Painless script as a [watch transform](docs-content://explore-analyze/alerts-cases/watcher/transform-script.md) to transform a payload into a new payload for further use in the watch. Transform scripts return an Object value of the new payload.
The following variables are available in all watcher contexts.
**Variables**
`params` (`Map`, read-only)
: User-defined parameters passed in as part of the query.
`ctx['watch_id']` (`String`, read-only)
: The id of the watch.
`ctx['id']` (`String`, read-only)
: The server generated unique identifier for the run watch.
`ctx['metadata']` (`Map`, read-only)
: Metadata can be added to the top level of the watch definition. This is user defined and is typically used to consolidate duplicate values in a watch.
`ctx['execution_time']` (`ZonedDateTime`, read-only)
: The time the watch began execution.
`ctx['trigger']['scheduled_time']` (`ZonedDateTime`, read-only)
: The scheduled trigger time for the watch. This is the time the watch should be executed.
`ctx['trigger']['triggered_time']` (`ZonedDateTime`, read-only)
: The actual trigger time for the watch. This is the time the watch was triggered for execution.
`ctx['payload']` (`Map`, read-only)
: The accessible watch data based upon the [watch input](docs-content://explore-analyze/alerts-cases/watcher/input.md).
**Return**
`Object`
: The new payload.
**API**
The standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) is available.
**Example**
To run the examples, first follow the steps in [context examples](/reference/scripting-languages/painless/painless-context-examples.md).
```console
POST _watcher/watch/_execute
{
"watch" : {
"trigger" : { "schedule" : { "interval" : "24h" } },
"input" : {
"search" : {
"request" : {
"indices" : [ "seats" ],
"body" : {
"query" : { "term": { "sold": "true"} },
"aggs" : {
"theatres" : {
"terms" : { "field" : "play" },
"aggs" : {
"money" : {
"sum": { "field" : "cost" }
}
}
}
}
}
}
}
},
"transform" : {
"script":
"""
return [
'money_makers': ctx.payload.aggregations.theatres.buckets.stream() <1>
.filter(t -> { <2>
return t.money.value > 50000
})
.map(t -> { <3>
return ['play': t.key, 'total_value': t.money.value ]
}).collect(Collectors.toList()), <4>
'duds' : ctx.payload.aggregations.theatres.buckets.stream() <5>
.filter(t -> {
return t.money.value < 15000
})
.map(t -> {
return ['play': t.key, 'total_value': t.money.value ]
}).collect(Collectors.toList())
]
"""
},
"actions" : {
"my_log" : {
"logging" : {
"text" : "The output of the payload was transformed to {{ctx.payload}}"
}
}
}
}
}
```
1. The Java Stream API is used in the transform. This API allows manipulation of the elements of the list in a pipeline.
2. The stream filter removes items that do not meet the filter criteria.
3. The stream map transforms each element into a new object.
4. The collector reduces the stream to a `java.util.List`.
5. This is done again for the second set of values in the transform.
The following action transform changes each value in the mod_log action into a `String`. This transform does not change the values in the unmod_log action.
```console
POST _watcher/watch/_execute
{
"watch" : {
"trigger" : { "schedule" : { "interval" : "24h" } },
"input" : {
"search" : {
"request" : {
"indices" : [ "seats" ],
"body" : {
"query" : {
"term": { "sold": "true"}
},
"aggs" : {
"theatres" : {
"terms" : { "field" : "play" },
"aggs" : {
"money" : {
"sum": { "field" : "cost" }
}
}
}
}
}
}
}
},
"actions" : {
"mod_log" : {
"transform": { <1>
"script" :
"""
def formatter = NumberFormat.getCurrencyInstance();
return [
'msg': ctx.payload.aggregations.theatres.buckets.stream()
.map(t-> formatter.format(t.money.value) + ' for the play ' + t.key)
.collect(Collectors.joining(", "))
]
"""
},
"logging" : {
"text" : "The output of the payload was transformed to: {{ctx.payload.msg}}"
}
},
"unmod_log" : { <2>
"logging" : {
"text" : "The output of the payload was not transformed and this value should not exist: {{ctx.payload.msg}}"
}
}
}
}
}
```
This example uses the streaming API in a very similar manner. The differences below are subtle and worth calling out.
1. The location of the transform is no longer at the top level, but is within an individual action.
2. A second action that does not transform the payload is given for reference.
The following example shows scripted watch and action transforms within the context of a complete watch. This watch also uses a scripted [condition](/reference/scripting-languages/painless/painless-watcher-condition-context.md).
```console
POST _watcher/watch/_execute
{
"watch" : {
"metadata" : { "high_threshold": 4000, "low_threshold": 1000 },
"trigger" : { "schedule" : { "interval" : "24h" } },
"input" : {
"search" : {
"request" : {
"indices" : [ "seats" ],
"body" : {
"query" : {
"term": { "sold": "true"}
},
"aggs" : {
"theatres" : {
"terms" : { "field" : "play" },
"aggs" : {
"money" : {
"sum": {
"field" : "cost",
"script": {
"source": "doc.cost.value * doc.number.value"
}
}
}
}
}
}
}
}
}
},
"condition" : {
"script" :
"""
return ctx.payload.aggregations.theatres.buckets.stream()
.anyMatch(theatre -> theatre.money.value < ctx.metadata.low_threshold ||
theatre.money.value > ctx.metadata.high_threshold)
"""
},
"transform" : {
"script":
"""
return [
'money_makers': ctx.payload.aggregations.theatres.buckets.stream()
.filter(t -> {
return t.money.value > ctx.metadata.high_threshold
})
.map(t -> {
return ['play': t.key, 'total_value': t.money.value ]
}).collect(Collectors.toList()),
'duds' : ctx.payload.aggregations.theatres.buckets.stream()
.filter(t -> {
return t.money.value < ctx.metadata.low_threshold
})
.map(t -> {
return ['play': t.key, 'total_value': t.money.value ]
}).collect(Collectors.toList())
]
"""
},
"actions" : {
"log_money_makers" : {
"condition": {
"script" : "return ctx.payload.money_makers.size() > 0"
},
"transform": {
"script" :
"""
def formatter = NumberFormat.getCurrencyInstance();
return [
'plays_value': ctx.payload.money_makers.stream()
.map(t-> formatter.format(t.total_value) + ' for the play ' + t.play)
.collect(Collectors.joining(", "))
]
"""
},
"logging" : {
"text" : "The following plays contain the highest grossing total income: {{ctx.payload.plays_value}}"
}
},
"log_duds" : {
"condition": {
"script" : "return ctx.payload.duds.size() > 0"
},
"transform": {
"script" :
"""
def formatter = NumberFormat.getCurrencyInstance();
return [
'plays_value': ctx.payload.duds.stream()
.map(t-> formatter.format(t.total_value) + ' for the play ' + t.play)
.collect(Collectors.joining(", "))
]
"""
},
"logging" : {
"text" : "The following plays need more advertising due to their low total income: {{ctx.payload.plays_value}}"
}
}
}
}
}
```
The following example shows the use of metadata and transforming dates into a readable format.
```console
POST _watcher/watch/_execute
{
"watch" : {
"metadata" : { "min_hits": 10 },
"trigger" : { "schedule" : { "interval" : "24h" } },
"input" : {
"search" : {
"request" : {
"indices" : [ "seats" ],
"body" : {
"query" : {
"term": { "sold": "true"}
},
"aggs" : {
"theatres" : {
"terms" : { "field" : "play" },
"aggs" : {
"money" : {
"sum": { "field" : "cost" }
}
}
}
}
}
}
}
},
"condition" : {
"script" :
"""
return ctx.payload.hits.total > ctx.metadata.min_hits
"""
},
"transform" : {
"script" :
"""
def theDate = ZonedDateTime.ofInstant(ctx.execution_time.toInstant(), ctx.execution_time.getZone());
return ['human_date': DateTimeFormatter.RFC_1123_DATE_TIME.format(theDate),
'aggregations': ctx.payload.aggregations]
"""
},
"actions" : {
"my_log" : {
"logging" : {
"text" : "The watch was successfully executed on {{ctx.payload.human_date}} and contained {{ctx.payload.aggregations.theatres.buckets.size}} buckets"
}
}
}
}
}
```

View file

@ -0,0 +1,40 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-weight-context.html
---
# Weight context [painless-weight-context]
Use a Painless script to create a [weight](/reference/elasticsearch/index-settings/similarity.md) for use in a [similarity script](/reference/scripting-languages/painless/painless-similarity-context.md). The weight makes up the part of the similarity calculation that is independent of the document being scored, and so can be built up front and cached.
Queries that contain multiple terms calculate a separate weight for each term.
**Variables**
`query.boost` (`float`, read-only)
: The boost value if provided by the query. If this is not provided the value is `1.0f`.
`field.docCount` (`long`, read-only)
: The number of documents that have a value for the current field.
`field.sumDocFreq` (`long`, read-only)
: The sum of all terms that exist for the current field. If this is not available the value is `-1`.
`field.sumTotalTermFreq` (`long`, read-only)
: The sum of occurrences in the index for all the terms that exist in the current field. If this is not available the value is `-1`.
`term.docFreq` (`long`, read-only)
: The number of documents that contain the current term in the index.
`term.totalTermFreq` (`long`, read-only)
: The total occurrences of the current term in the index.
**Return**
`double`
: A scoring factor used across all documents.
**API**
The standard [Painless API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html) is available.

View file

@ -0,0 +1,25 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/index.html
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-guide.html
---
# Painless [painless-guide]
*Painless* is a simple, secure scripting language designed specifically for use with Elasticsearch. It is the default scripting language for Elasticsearch and can safely be used for inline and stored scripts. For a jump start into Painless, see [A Brief Painless Walkthrough](/reference/scripting-languages/painless/brief-painless-walkthrough.md). For a detailed description of the Painless syntax and language features, see the [Painless Language Specification](/reference/scripting-languages/painless/painless-language-specification.md).
You can use Painless anywhere scripts are used in Elasticsearch. Painless provides:
* Fast performance: Painless scripts [ run several times faster](https://benchmarks.elastic.co/index.md#search_qps_scripts) than the alternatives.
* Safety: Fine-grained allowlist with method call/field granularity. See the [Painless API Reference](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference.html) for a complete list of available classes and methods.
* Optional typing: Variables and parameters can use explicit types or the dynamic `def` type.
* Syntax: Extends a subset of Javas syntax to provide additional scripting language features.
* Optimizations: Designed specifically for Elasticsearch scripting.

View file

@ -0,0 +1,78 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-runtime-fields.html
---
# Use painless scripts in runtime fields [painless-runtime-fields]
A runtime field is a field that is evaluated at query time. When you define a runtime field, you can immediately use it in search requests, aggregations, filtering, and sorting.
When defining a runtime field, you can include a Painless script that is evaluated at query time. This script has access to the entire context of a document, including the original document [`_source` field](docs-content://explore-analyze/scripting/modules-scripting-fields.md) and any mapped fields plus their values. At query time, the script runs and generates values for each scripted field that is included in the query.
You can map a runtime field in the `runtime` section under the mapping definition, or define runtime fields that exist only as part of a search request. The script syntax is the same, regardless of where you define the runtime field.
::::{important}
When defining a Painless script to use with runtime fields, you must include `emit` to return calculated values.
::::
## Define a runtime field in the mapping [painless-runtime-fields-mapping]
Add a `runtime` section under the [mapping definition](docs-content://manage-data/data-store/mapping/map-runtime-field.md) to explore your data without indexing fields.
The script in the following request extracts the day of the week from the `@timestamp` field, which is defined as a `date` type. The script calculates the day of the week based on the value of `@timestamp`, and uses `emit` to return the calculated value.
```console
PUT my-index/
{
"mappings": {
"runtime": {
"day_of_week": {
"type": "keyword",
"script": {
"source":
"""emit(doc['@timestamp'].value.dayOfWeekEnum
.getDisplayName(TextStyle.FULL, Locale.ROOT))"""
}
}
},
"properties": {
"@timestamp": {"type": "date"}
}
}
}
```
## Define a runtime field only in a search request [painless-runtime-fields-query]
Use runtime fields in a search request to create a field that exists [only as part of the query](docs-content://manage-data/data-store/mapping/define-runtime-fields-in-search-request.md). You can also [override field values](docs-content://manage-data/data-store/mapping/override-field-values-at-query-time.md) at query time for existing fields without modifying the field itself.
This flexibility allows you to experiment with your data schema and fix mistakes in your index mapping without reindexing your data.
In the following request, the values for the `day_of_week` field are calculated dynamically, and only within the context of this search request:
```console
GET my-index/_search
{
"runtime_mappings": {
"day_of_week": {
"type": "keyword",
"script": {
"source":
"""emit(doc['@timestamp'].value.dayOfWeekEnum
.getDisplayName(TextStyle.FULL, Locale.ROOT))"""
}
}
},
"aggs": {
"day_of_week": {
"terms": {
"field": "day_of_week"
}
}
}
}
```

View file

@ -0,0 +1,811 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-datetime.html
---
# Using datetime in Painless [painless-datetime]
## Datetime API [_datetime_api]
Datetimes in Painless use the standard Java libraries and are available through the Painless [Shared API](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared.html). Most of the classes from the following Java packages are available to use in Painless scripts:
* [java.time](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared-java-time.html)
* [java.time.chrono](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared-java-time-chrono.html)
* [java.time.format](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared-java-time-format.html)
* [java.time.temporal](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared-java-time-temporal.html)
* [java.time.zone](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared-java-time-zone.html)
## Datetime Representation [_datetime_representation]
Datetimes in Painless are most commonly represented as a numeric value, a string value, or a complex value.
numeric
: a datetime representation as a number from a starting offset called an epoch; in Painless this is typically a [long](/reference/scripting-languages/painless/painless-types.md#primitive-types) as milliseconds since an epoch of 1970-01-01 00:00:00 Zulu Time
string
: a datetime representation as a sequence of characters defined by a standard format or a custom format; in Painless this is typically a [String](/reference/scripting-languages/painless/painless-types.md#string-type) of the standard format [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)
complex
: a datetime representation as a complex type ([object](/reference/scripting-languages/painless/painless-types.md#reference-types)) that abstracts away internal details of how the datetime is stored and often provides utilities for modification and comparison; in Painless this is typically a [ZonedDateTime](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared-java-time.html#painless-api-reference-shared-ZonedDateTime)
Switching between different representations of datetimes is often necessary to achieve a scripts objective(s). A typical pattern in a script is to switch a numeric or string datetime to a complex datetime, modify or compare the complex datetime, and then switch it back to a numeric or string datetime for storage or to return a result.
## Datetime Parsing and Formatting [_datetime_parsing_and_formatting]
Datetime parsing is a switch from a string datetime to a complex datetime, and datetime formatting is a switch from a complex datetime to a string datetime.
A [DateTimeFormatter](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared-java-time-format.html#painless-api-reference-shared-DateTimeFormatter) is a complex type ([object](/reference/scripting-languages/painless/painless-types.md#reference-types)) that defines the allowed sequence of characters for a string datetime. Datetime parsing and formatting often require a DateTimeFormatter. For more information about how to use a DateTimeFormatter see the [Java documentation](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/format/DateTimeFormatter.md).
### Datetime Parsing Examples [_datetime_parsing_examples]
* parse from milliseconds
```painless
String milliSinceEpochString = "434931330000";
long milliSinceEpoch = Long.parseLong(milliSinceEpochString);
Instant instant = Instant.ofEpochMilli(milliSinceEpoch);
ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, ZoneId.of('Z'));
```
* parse from ISO 8601
```painless
String datetime = '1983-10-13T22:15:30Z';
ZonedDateTime zdt = ZonedDateTime.parse(datetime); <1>
```
1. Note the parse method uses ISO 8601 by default.
* parse from RFC 1123
```painless
String datetime = 'Thu, 13 Oct 1983 22:15:30 GMT';
ZonedDateTime zdt = ZonedDateTime.parse(datetime,
DateTimeFormatter.RFC_1123_DATE_TIME); <1>
```
1. Note the use of a built-in DateTimeFormatter.
* parse from a custom format
```painless
String datetime = 'custom y 1983 m 10 d 13 22:15:30 Z';
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(
"'custom' 'y' yyyy 'm' MM 'd' dd HH:mm:ss VV");
ZonedDateTime zdt = ZonedDateTime.parse(datetime, dtf); <1>
```
1. Note the use of a custom DateTimeFormatter.
### Datetime Formatting Examples [_datetime_formatting_examples]
* format to ISO 8601
```painless
ZonedDateTime zdt =
ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z'));
String datetime = zdt.format(DateTimeFormatter.ISO_INSTANT); <1>
```
1. Note the use of a built-in DateTimeFormatter.
* format to a custom format
```painless
ZonedDateTime zdt =
ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z'));
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(
"'date:' yyyy/MM/dd 'time:' HH:mm:ss");
String datetime = zdt.format(dtf); <1>
```
1. Note the use of a custom DateTimeFormatter.
## Datetime Conversion [_datetime_conversion]
Datetime conversion is a switch from a numeric datetime to a complex datetime and vice versa.
### Datetime Conversion Examples [_datetime_conversion_examples]
* convert from milliseconds
```painless
long milliSinceEpoch = 434931330000L;
Instant instant = Instant.ofEpochMilli(milliSinceEpoch);
ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, ZoneId.of('Z'));
```
* convert to milliseconds
```painless
ZonedDateTime zdt =
ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z'));
long milliSinceEpoch = zdt.toInstant().toEpochMilli();
```
## Datetime Pieces [_datetime_pieces]
Datetime representations often contain the data to extract individual datetime pieces such as year, hour, timezone, etc. Use individual pieces of a datetime to create a complex datetime, and use a complex datetime to extract individual pieces.
### Datetime Pieces Examples [_datetime_pieces_examples]
* create a complex datetime from pieces
```painless
int year = 1983;
int month = 10;
int day = 13;
int hour = 22;
int minutes = 15;
int seconds = 30;
int nanos = 0;
ZonedDateTime zdt = ZonedDateTime.of(
year, month, day, hour, minutes, seconds, nanos, ZoneId.of('Z'));
```
* extract pieces from a complex datetime
```painless
ZonedDateTime zdt =
ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 100, ZoneId.of(tz));
int year = zdt.getYear();
int month = zdt.getMonthValue();
int day = zdt.getDayOfMonth();
int hour = zdt.getHour();
int minutes = zdt.getMinute();
int seconds = zdt.getSecond();
int nanos = zdt.getNano();
```
## Datetime Modification [_datetime_modification]
Use either a numeric datetime or a complex datetime to do modification such as adding several seconds to a datetime or subtracting several days from a datetime. Use standard [numeric operators](/reference/scripting-languages/painless/painless-operators-numeric.md) to modify a numeric datetime. Use [methods](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared-java-time.html#painless-api-reference-shared-ZonedDateTime) (or fields) to modify a complex datetime. Note many complex datetimes are immutable so upon modification a new complex datetime is created that requires [assignment](/reference/scripting-languages/painless/painless-variables.md#variable-assignment) or immediate use.
### Datetime Modification Examples [_datetime_modification_examples]
* Subtract three seconds from a numeric datetime in milliseconds
```painless
long milliSinceEpoch = 434931330000L;
milliSinceEpoch = milliSinceEpoch - 1000L*3L;
```
* Add three days to a complex datetime
```painless
ZonedDateTime zdt =
ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z'));
ZonedDateTime updatedZdt = zdt.plusDays(3);
```
* Subtract 125 minutes from a complex datetime
```painless
ZonedDateTime zdt =
ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z'));
ZonedDateTime updatedZdt = zdt.minusMinutes(125);
```
* Set the year on a complex datetime
```painless
ZonedDateTime zdt =
ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z'));
ZonedDateTime updatedZdt = zdt.withYear(1976);
```
## Datetime Difference (Elapsed Time) [_datetime_difference_elapsed_time]
Use either two numeric datetimes or two complex datetimes to calculate the difference (elapsed time) between two different datetimes. Use [subtraction](/reference/scripting-languages/painless/painless-operators-numeric.md#subtraction-operator) to calculate the difference between two numeric datetimes of the same time unit such as milliseconds. For complex datetimes there is often a method or another complex type ([object](/reference/scripting-languages/painless/painless-types.md#reference-types)) available to calculate the difference. Use [ChronoUnit](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared-java-time-temporal.html#painless-api-reference-shared-ChronoUnit) to calculate the difference between two complex datetimes if supported.
### Datetime Difference Examples [_datetime_difference_examples]
* Difference in milliseconds between two numeric datetimes
```painless
long startTimestamp = 434931327000L;
long endTimestamp = 434931330000L;
long differenceInMillis = endTimestamp - startTimestamp;
```
* Difference in milliseconds between two complex datetimes
```painless
ZonedDateTime zdt1 =
ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 11000000, ZoneId.of('Z'));
ZonedDateTime zdt2 =
ZonedDateTime.of(1983, 10, 13, 22, 15, 35, 0, ZoneId.of('Z'));
long differenceInMillis = ChronoUnit.MILLIS.between(zdt1, zdt2);
```
* Difference in days between two complex datetimes
```painless
ZonedDateTime zdt1 =
ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 11000000, ZoneId.of('Z'));
ZonedDateTime zdt2 =
ZonedDateTime.of(1983, 10, 17, 22, 15, 35, 0, ZoneId.of('Z'));
long differenceInDays = ChronoUnit.DAYS.between(zdt1, zdt2);
```
## Datetime Comparison [_datetime_comparison]
Use either two numeric datetimes or two complex datetimes to do a datetime comparison. Use standard [comparison operators](/reference/scripting-languages/painless/painless-operators-boolean.md) to compare two numeric datetimes of the same time unit such as milliseconds. For complex datetimes there is often a method or another complex type ([object](/reference/scripting-languages/painless/painless-types.md#reference-types)) available to do the comparison.
### Datetime Comparison Examples [_datetime_comparison_examples]
* Greater than comparison of two numeric datetimes in milliseconds
```painless
long timestamp1 = 434931327000L;
long timestamp2 = 434931330000L;
if (timestamp1 > timestamp2) {
// handle condition
}
```
* Equality comparison of two complex datetimes
```painless
ZonedDateTime zdt1 =
ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z'));
ZonedDateTime zdt2 =
ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z'));
if (zdt1.equals(zdt2)) {
// handle condition
}
```
* Less than comparison of two complex datetimes
```painless
ZonedDateTime zdt1 =
ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z'));
ZonedDateTime zdt2 =
ZonedDateTime.of(1983, 10, 17, 22, 15, 35, 0, ZoneId.of('Z'));
if (zdt1.isBefore(zdt2)) {
// handle condition
}
```
* Greater than comparison of two complex datetimes
```painless
ZonedDateTime zdt1 =
ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z'));
ZonedDateTime zdt2 =
ZonedDateTime.of(1983, 10, 17, 22, 15, 35, 0, ZoneId.of('Z'));
if (zdt1.isAfter(zdt2)) {
// handle condition
}
```
## Datetime Zone [_datetime_zone]
Both string datetimes and complex datetimes have a timezone with a default of `UTC`. Numeric datetimes do not have enough explicit information to have a timezone, so `UTC` is always assumed. Use [methods](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared-java-time.html#painless-api-reference-shared-ZonedDateTime) (or fields) in conjunction with a [ZoneId](https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-api-reference-shared-java-time.html#painless-api-reference-shared-ZoneId) to change the timezone for a complex datetime. Parse a string datetime into a complex datetime to change the timezone, and then format the complex datetime back into a desired string datetime. Note many complex datetimes are immutable so upon modification a new complex datetime is created that requires [assignment](/reference/scripting-languages/painless/painless-variables.md#variable-assignment) or immediate use.
### Datetime Zone Examples [_datetime_zone_examples]
* Modify the timezone for a complex datetime
```painless
ZonedDateTime utc =
ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z'));
ZonedDateTime pst = utc.withZoneSameInstant(ZoneId.of('America/Los_Angeles'));
```
* Modify the timezone for a string datetime
```painless
String gmtString = 'Thu, 13 Oct 1983 22:15:30 GMT';
ZonedDateTime gmtZdt = ZonedDateTime.parse(gmtString,
DateTimeFormatter.RFC_1123_DATE_TIME); <1>
ZonedDateTime pstZdt =
gmtZdt.withZoneSameInstant(ZoneId.of('America/Los_Angeles'));
String pstString = pstZdt.format(DateTimeFormatter.RFC_1123_DATE_TIME);
```
1. Note the use of a built-in DateTimeFormatter.
## Datetime Input [_datetime_input]
There are several common ways datetimes are used as input for a script determined by the [Painless context](/reference/scripting-languages/painless/painless-contexts.md). Typically, datetime input will be accessed from parameters specified by the user, from an original source document, or from an indexed document.
### Datetime Input From User Parameters [_datetime_input_from_user_parameters]
Use the [params section](docs-content://explore-analyze/scripting/modules-scripting-using.md) during script specification to pass in a numeric datetime or string datetime as a script input. Access to user-defined parameters within a script is dependent on the Painless context, though, the parameters are most commonly accessible through an input called `params`.
**Examples**
* Parse a numeric datetime from user parameters to a complex datetime
* Input:
```JSON
...
"script": {
...
"params": {
"input_datetime": 434931327000
}
}
...
```
* Script:
```painless
long inputDateTime = params['input_datetime'];
Instant instant = Instant.ofEpochMilli(inputDateTime);
ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, ZoneId.of('Z'));
```
* Parse a string datetime from user parameters to a complex datetime
* Input:
```JSON
...
"script": {
...
"params": {
"input_datetime": "custom y 1983 m 10 d 13 22:15:30 Z"
}
}
...
```
* Script:
```painless
String datetime = params['input_datetime'];
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(
"'custom' 'y' yyyy 'm' MM 'd' dd HH:mm:ss VV");
ZonedDateTime zdt = ZonedDateTime.parse(datetime, dtf); <1>
```
1. Note the use of a custom DateTimeFormatter.
### Datetime Input From a Source Document [_datetime_input_from_a_source_document]
Use an original [source](/reference/elasticsearch/mapping-reference/mapping-source-field.md) document as a script input to access a numeric datetime or string datetime for a specific field within that document. Access to an original source document within a script is dependent on the Painless context and is not always available. An original source document is most commonly accessible through an input called `ctx['_source']` or `params['_source']`.
**Examples**
* Parse a numeric datetime from a sourced document to a complex datetime
* Input:
```JSON
{
...
"input_datetime": 434931327000
...
}
```
* Script:
```painless
long inputDateTime = ctx['_source']['input_datetime']; <1>
Instant instant = Instant.ofEpochMilli(inputDateTime);
ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, ZoneId.of('Z'));
```
1. Note access to `_source` is dependent on the Painless context.
* Parse a string datetime from a sourced document to a complex datetime
* Input:
```JSON
{
...
"input_datetime": "1983-10-13T22:15:30Z"
...
}
```
* Script:
```painless
String datetime = params['_source']['input_datetime']; <1>
ZonedDateTime zdt = ZonedDateTime.parse(datetime); <2>
```
1. Note access to `_source` is dependent on the Painless context.
2. Note the parse method uses ISO 8601 by default.
### Datetime Input From an Indexed Document [_datetime_input_from_an_indexed_document]
Use an indexed document as a script input to access a complex datetime for a specific field within that document where the field is mapped as a [standard date](/reference/elasticsearch/mapping-reference/date.md) or a [nanosecond date](/reference/elasticsearch/mapping-reference/date_nanos.md). Numeric datetime fields mapped as [numeric](/reference/elasticsearch/mapping-reference/number.md) and string datetime fields mapped as [keyword](/reference/elasticsearch/mapping-reference/keyword.md) are accessible through an indexed document as well. Access to an indexed document within a script is dependent on the Painless context and is not always available. An indexed document is most commonly accessible through an input called `doc`.
**Examples**
* Format a complex datetime from an indexed document to a string datetime
* Assumptions:
* The field `input_datetime` exists in all indexes as part of the query
* All indexed documents contain the field `input_datetime`
* Mappings:
```JSON
{
"mappings": {
...
"properties": {
...
"input_datetime": {
"type": "date"
}
...
}
...
}
}
```
* Script:
```painless
ZonedDateTime input = doc['input_datetime'].value;
String output = input.format(DateTimeFormatter.ISO_INSTANT); <1>
```
1. Note the use of a built-in DateTimeFormatter.
* Find the difference between two complex datetimes from an indexed document
* Assumptions:
* The fields `start` and `end` may **not** exist in all indexes as part of the query
* The fields `start` and `end` may **not** have values in all indexed documents
* Mappings:
```JSON
{
"mappings": {
...
"properties": {
...
"start": {
"type": "date"
},
"end": {
"type": "date"
}
...
}
...
}
}
```
* Script:
```painless
if (doc.containsKey('start') && doc.containsKey('end')) { <1>
if (doc['start'].size() > 0 && doc['end'].size() > 0) { <2>
ZonedDateTime start = doc['start'].value;
ZonedDateTime end = doc['end'].value;
long differenceInMillis = ChronoUnit.MILLIS.between(start, end);
// handle difference in times
} else {
// handle fields without values
}
} else {
// handle index with missing fields
}
```
1. When a querys results span multiple indexes, some indexes may not contain a specific field. Use the `containsKey` method call on the `doc` input to ensure a field exists as part of the index for the current document.
2. Some fields within a document may have no values. Use the `size` method call on a field within the `doc` input to ensure that field has at least one value for the current document.
## Datetime Now [_datetime_now]
Under most Painless contexts the current datetime, `now`, is not supported. There are two primary reasons for this. The first is that scripts are often run once per document, so each time the script is run a different `now` is returned. The second is that scripts are often run in a distributed fashion without a way to appropriately synchronize `now`. Instead, pass in a user-defined parameter with either a string datetime or numeric datetime for `now`. A numeric datetime is preferred as there is no need to parse it for comparison.
### Datetime Now Examples [_datetime_now_examples]
* Use a numeric datetime as `now`
* Assumptions:
* The field `input_datetime` exists in all indexes as part of the query
* All indexed documents contain the field `input_datetime`
* Mappings:
```JSON
{
"mappings": {
...
"properties": {
...
"input_datetime": {
"type": "date"
}
...
}
...
}
}
```
* Input:
```JSON
...
"script": {
...
"params": {
"now": <generated numeric datetime in milliseconds since epoch>
}
}
...
```
* Script:
```painless
long now = params['now'];
ZonedDateTime inputDateTime = doc['input_datetime'];
long millisDateTime = inputDateTime.toInstant().toEpochMilli();
long elapsedTime = now - millisDateTime;
```
* Use a string datetime as `now`
* Assumptions:
* The field `input_datetime` exists in all indexes as part of the query
* All indexed documents contain the field `input_datetime`
* Mappings:
```JSON
{
"mappings": {
...
"properties": {
...
"input_datetime": {
"type": "date"
}
...
}
...
}
}
```
* Input:
```JSON
...
"script": {
...
"params": {
"now": "<generated string datetime in ISO-8601>"
}
}
...
```
* Script:
```painless
String nowString = params['now'];
ZonedDateTime nowZdt = ZonedDateTime.parse(nowString); <1>
long now = ZonedDateTime.toInstant().toEpochMilli();
ZonedDateTime inputDateTime = doc['input_datetime'];
long millisDateTime = zdt.toInstant().toEpochMilli();
long elapsedTime = now - millisDateTime;
```
1. Note this parses the same string datetime every time the script runs. Use a numeric datetime to avoid a significant performance hit.
## Datetime Examples in Contexts [_datetime_examples_in_contexts]
### Load the Example Data [_load_the_example_data]
Run the following curl commands to load the data necessary for the context examples into an Elasticsearch cluster:
1. Create [mappings](docs-content://manage-data/data-store/mapping.md) for the sample data.
```console
PUT /messages
{
"mappings": {
"properties": {
"priority": {
"type": "integer"
},
"datetime": {
"type": "date"
},
"message": {
"type": "text"
}
}
}
}
```
2. Load the sample data.
```console
POST /_bulk
{ "index" : { "_index" : "messages", "_id" : "1" } }
{ "priority": 1, "datetime": "2019-07-17T12:13:14Z", "message": "m1" }
{ "index" : { "_index" : "messages", "_id" : "2" } }
{ "priority": 1, "datetime": "2019-07-24T01:14:59Z", "message": "m2" }
{ "index" : { "_index" : "messages", "_id" : "3" } }
{ "priority": 2, "datetime": "1983-10-14T00:36:42Z", "message": "m3" }
{ "index" : { "_index" : "messages", "_id" : "4" } }
{ "priority": 3, "datetime": "1983-10-10T02:15:15Z", "message": "m4" }
{ "index" : { "_index" : "messages", "_id" : "5" } }
{ "priority": 3, "datetime": "1983-10-10T17:18:19Z", "message": "m5" }
{ "index" : { "_index" : "messages", "_id" : "6" } }
{ "priority": 1, "datetime": "2019-08-03T17:19:31Z", "message": "m6" }
{ "index" : { "_index" : "messages", "_id" : "7" } }
{ "priority": 3, "datetime": "2019-08-04T17:20:00Z", "message": "m7" }
{ "index" : { "_index" : "messages", "_id" : "8" } }
{ "priority": 2, "datetime": "2019-08-04T18:01:01Z", "message": "m8" }
{ "index" : { "_index" : "messages", "_id" : "9" } }
{ "priority": 3, "datetime": "1983-10-10T19:00:45Z", "message": "m9" }
{ "index" : { "_index" : "messages", "_id" : "10" } }
{ "priority": 2, "datetime": "2019-07-23T23:39:54Z", "message": "m10" }
```
### Day-of-the-Week Bucket Aggregation Example [_day_of_the_week_bucket_aggregation_example]
The following example uses a [terms aggregation](/reference/data-analysis/aggregations/search-aggregations-bucket-terms-aggregation.md#search-aggregations-bucket-terms-aggregation-script) as part of the [bucket script aggregation context](/reference/scripting-languages/painless/painless-bucket-script-agg-context.md) to display the number of messages from each day-of-the-week.
```console
GET /messages/_search?pretty=true
{
"aggs": {
"day-of-week-count": {
"terms": {
"script": "return doc[\"datetime\"].value.getDayOfWeekEnum();"
}
}
}
}
```
### Morning/Evening Bucket Aggregation Example [_morningevening_bucket_aggregation_example]
The following example uses a [terms aggregation](/reference/data-analysis/aggregations/search-aggregations-bucket-terms-aggregation.md#search-aggregations-bucket-terms-aggregation-script) as part of the [bucket script aggregation context](/reference/scripting-languages/painless/painless-bucket-script-agg-context.md) to display the number of messages received in the morning versus the evening.
```console
GET /messages/_search?pretty=true
{
"aggs": {
"am-pm-count": {
"terms": {
"script": "return doc[\"datetime\"].value.getHour() < 12 ? \"AM\" : \"PM\";"
}
}
}
}
```
### Age of a Message Script Field Example [_age_of_a_message_script_field_example]
The following example uses a [script field](/reference/elasticsearch/rest-apis/retrieve-selected-fields.md#script-fields) as part of the [field context](/reference/scripting-languages/painless/painless-field-context.md) to display the elapsed time between "now" and when a message was received.
```console
GET /_search?pretty=true
{
"query": {
"match_all": {}
},
"script_fields": {
"message_age": {
"script": {
"source": "ZonedDateTime now = ZonedDateTime.ofInstant(Instant.ofEpochMilli(params[\"now\"]), ZoneId.of(\"Z\")); ZonedDateTime mdt = doc[\"datetime\"].value; String age; long years = mdt.until(now, ChronoUnit.YEARS); age = years + \"Y \"; mdt = mdt.plusYears(years); long months = mdt.until(now, ChronoUnit.MONTHS); age += months + \"M \"; mdt = mdt.plusMonths(months); long days = mdt.until(now, ChronoUnit.DAYS); age += days + \"D \"; mdt = mdt.plusDays(days); long hours = mdt.until(now, ChronoUnit.HOURS); age += hours + \"h \"; mdt = mdt.plusHours(hours); long minutes = mdt.until(now, ChronoUnit.MINUTES); age += minutes + \"m \"; mdt = mdt.plusMinutes(minutes); long seconds = mdt.until(now, ChronoUnit.SECONDS); age += hours + \"s\"; return age;",
"params": {
"now": 1574005645830
}
}
}
}
}
```
The following shows the script broken into multiple lines:
```painless
ZonedDateTime now = ZonedDateTime.ofInstant(
Instant.ofEpochMilli(params['now']), ZoneId.of('Z')); <1>
ZonedDateTime mdt = doc['datetime'].value; <2>
String age;
long years = mdt.until(now, ChronoUnit.YEARS); <3>
age = years + 'Y '; <4>
mdt = mdt.plusYears(years); <5>
long months = mdt.until(now, ChronoUnit.MONTHS);
age += months + 'M ';
mdt = mdt.plusMonths(months);
long days = mdt.until(now, ChronoUnit.DAYS);
age += days + 'D ';
mdt = mdt.plusDays(days);
long hours = mdt.until(now, ChronoUnit.HOURS);
age += hours + 'h ';
mdt = mdt.plusHours(hours);
long minutes = mdt.until(now, ChronoUnit.MINUTES);
age += minutes + 'm ';
mdt = mdt.plusMinutes(minutes);
long seconds = mdt.until(now, ChronoUnit.SECONDS);
age += hours + 's';
return age; <6>
```
1. Parse the datetime "now" as input from the user-defined params.
2. Store the datetime the message was received as a `ZonedDateTime`.
3. Find the difference in years between "now" and the datetime the message was received.
4. Add the difference in years later returned in the format `Y <years> ...` for the age of a message.
5. Add the years so only the remainder of the months, days, etc. remain as the difference between "now" and the datetime the message was received. Repeat this pattern until the desired granularity is reached (seconds in this example).
6. Return the age of the message in the format `Y <years> M <months> D <days> h <hours> m <minutes> s <seconds>`.

View file

@ -0,0 +1,117 @@
---
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-ingest.html
---
# Using ingest processors in Painless [painless-ingest]
Some [ingest processors](/reference/ingestion-tools/enrich-processor/index.md) expose behavior through Painless methods that can be called in Painless scripts that execute in ingest pipelines.
## Method usage [_method_usage]
All ingest methods available in Painless are scoped to the `Processors` namespace. For example:
```console
POST /_ingest/pipeline/_simulate?verbose
{
"pipeline": {
"processors": [
{
"script": {
"lang": "painless",
"source": """
long bytes = Processors.bytes(ctx.size);
ctx.size_in_bytes = bytes;
"""
}
}
]
},
"docs": [
{
"_source": {
"size": "1kb"
}
}
]
}
```
## Ingest methods reference [_ingest_methods_reference]
### Byte conversion [_byte_conversion]
Use the [bytes processor](/reference/ingestion-tools/enrich-processor/bytes-processor.md) to return the number of bytes in the human-readable byte value supplied in the `value` parameter.
```painless
long bytes(String value);
```
### Lowercase conversion [_lowercase_conversion]
Use the [lowercase processor](/reference/ingestion-tools/enrich-processor/lowercase-processor.md) to convert the supplied string in the `value` parameter to its lowercase equivalent.
```painless
String lowercase(String value);
```
### Uppercase conversion [_uppercase_conversion]
Use the [uppercase processor](/reference/ingestion-tools/enrich-processor/uppercase-processor.md) to convert the supplied string in the `value` parameter to its uppercase equivalent.
```painless
String uppercase(String value);
```
### JSON parsing [_json_parsing]
Use the [JSON processor](/reference/ingestion-tools/enrich-processor/json-processor.md) to convert JSON strings to structured JSON objects. The first `json` method accepts a map and a key. The processor converts the JSON string in the map as specified by the `key` parameter to structured JSON content. That content is added directly to the `map` object.
The second `json` method accepts a JSON string in the `value` parameter and returns a structured JSON object.
```painless
void json(Map<String, Object> map, String key);
Object json(Object value);
```
You can then add this object to the document through the context object:
```painless
Object json = Processors.json(ctx.inputJsonString);
ctx.structuredJson = json;
```
### URL decoding [_url_decoding]
Use the [URL decode processor](/reference/ingestion-tools/enrich-processor/urldecode-processor.md) to URL-decode the string supplied in the `value` parameter.
```painless
String urlDecode(String value);
```
### URI decomposition [_uri_decomposition]
Use the [URI parts processor](/reference/ingestion-tools/enrich-processor/uri-parts-processor.md) to decompose the URI string supplied in the `value` parameter. Returns a map of key-value pairs in which the key is the name of the URI component such as `domain` or `path` and the value is the corresponding value for that component.
```painless
String uriParts(String value);
```
### Network community ID [_network_community_id]
Use the [community ID processor](/reference/ingestion-tools/enrich-processor/community-id-processor.md) to compute the network community ID for network flow data.
```painless
String communityId(String sourceIpAddrString, String destIpAddrString, Object ianaNumber, Object transport, Object sourcePort, Object destinationPort, Object icmpType, Object icmpCode, int seed)
String communityId(String sourceIpAddrString, String destIpAddrString, Object ianaNumber, Object transport, Object sourcePort, Object destinationPort, Object icmpType, Object icmpCode)
```

View file

@ -0,0 +1,56 @@
toc:
- file: scripting-languages/index.md
# - file: scripting-languages/reference/painless.md
- file: scripting-languages/painless/painless.md
children:
- file: scripting-languages/painless/brief-painless-walkthrough.md
- file: scripting-languages/painless/use-painless-scripts-in-runtime-fields.md
- file: scripting-languages/painless/using-datetime-in-painless.md
- file: scripting-languages/painless/how-painless-dispatches-function.md
- file: scripting-languages/painless/painless-debugging.md
- file: scripting-languages/painless/painless-api-examples.md
- file: scripting-languages/painless/using-ingest-processors-in-painless.md
- file: scripting-languages/painless/painless-language-specification.md
children:
- file: scripting-languages/painless/painless-comments.md
- file: scripting-languages/painless/painless-keywords.md
- file: scripting-languages/painless/painless-literals.md
- file: scripting-languages/painless/painless-identifiers.md
- file: scripting-languages/painless/painless-variables.md
- file: scripting-languages/painless/painless-types.md
- file: scripting-languages/painless/painless-casting.md
- file: scripting-languages/painless/painless-operators.md
- file: scripting-languages/painless/painless-operators-general.md
- file: scripting-languages/painless/painless-operators-numeric.md
- file: scripting-languages/painless/painless-operators-boolean.md
- file: scripting-languages/painless/painless-operators-reference.md
- file: scripting-languages/painless/painless-operators-array.md
- file: scripting-languages/painless/painless-statements.md
- file: scripting-languages/painless/painless-scripts.md
- file: scripting-languages/painless/painless-functions.md
- file: scripting-languages/painless/painless-lambdas.md
- file: scripting-languages/painless/painless-regexes.md
- file: scripting-languages/painless/painless-contexts.md
children:
- file: scripting-languages/painless/painless-context-examples.md
- file: scripting-languages/painless/painless-runtime-fields-context.md
- file: scripting-languages/painless/painless-ingest-processor-context.md
- file: scripting-languages/painless/painless-update-context.md
- file: scripting-languages/painless/painless-update-by-query-context.md
- file: scripting-languages/painless/painless-reindex-context.md
- file: scripting-languages/painless/painless-sort-context.md
- file: scripting-languages/painless/painless-similarity-context.md
- file: scripting-languages/painless/painless-weight-context.md
- file: scripting-languages/painless/painless-score-context.md
- file: scripting-languages/painless/painless-field-context.md
- file: scripting-languages/painless/painless-filter-context.md
- file: scripting-languages/painless/painless-min-should-match-context.md
- file: scripting-languages/painless/painless-metric-agg-init-context.md
- file: scripting-languages/painless/painless-metric-agg-map-context.md
- file: scripting-languages/painless/painless-metric-agg-combine-context.md
- file: scripting-languages/painless/painless-metric-agg-reduce-context.md
- file: scripting-languages/painless/painless-bucket-script-agg-context.md
- file: scripting-languages/painless/painless-bucket-selector-agg-context.md
- file: scripting-languages/painless/painless-analysis-predicate-context.md
- file: scripting-languages/painless/painless-watcher-condition-context.md
- file: scripting-languages/painless/painless-watcher-transform-context.md