diff --git a/docs/reference/scripting.asciidoc b/docs/reference/scripting.asciidoc index 170d01512cacc..c2b3748d1a810 100644 --- a/docs/reference/scripting.asciidoc +++ b/docs/reference/scripting.asciidoc @@ -53,6 +53,8 @@ include::scripting/painless.asciidoc[] include::scripting/using.asciidoc[] +include::scripting/access-fields.asciidoc[] + include::scripting/common-script-uses.asciidoc[] include::scripting/fields.asciidoc[] diff --git a/docs/reference/scripting/access-fields.asciidoc b/docs/reference/scripting/access-fields.asciidoc new file mode 100644 index 0000000000000..2e2d44d89881d --- /dev/null +++ b/docs/reference/scripting/access-fields.asciidoc @@ -0,0 +1,127 @@ +[[script-fields-api]] +== Access fields in a document with the `field` API +++++ +Access fields in a document +++++ + +beta::["The `field` API is still in development and should be considered a beta feature. The API is subject to change and this iteration is likely not the final state. For feature status, refer to {es-issue}78920[#78920]."] + +Use the `field` API to access document fields: + +[source,painless] +---- +field('my_field').get() +---- + +This API fundamentally changes how you access documents in Painless. Previously, +you had to access the `doc` map with the field name that you wanted to access: + +[source,painless] +---- +doc['my_field'].value +---- + +Accessing document fields this way didn't handle missing values or missing +mappings, which meant that to write robust Painless scripts, you needed to +include logic to check that both fields and values exist. + +Instead, use the `field` API, which is the preferred approach to access +documents in Painless. The `field` API handles missing values, and will evolve +to abstract access to `_source` and `doc_values`. + +NOTE: Some fields aren't yet compatible with the `fields` API, such as `text` or +`geo` fields. Continue using `doc` to access field types that the `field` API +doesn't support. + +The `field` API returns a `Field` object that iterates over fields with +multiple values, providing access to the underlying value through the +`get()` method, as well as type conversion and helper methods. + +The `field` API returns the default value that you specify, regardless of +whether the field exists or has any values for the current document. +This means that the `field` API can handle missing values without requiring +additional logic. For a reference type such as `keyword`, the default +value can be `null`. For a primitive type such as `boolean` or `long`, the +default value must be a matching primitive type, such as `false` or `1`. + +[discrete] +=== Convenient, simpler access +Instead of explicitly calling the `field` API with the `get()` method, you can +include the `$` shortcut. Just include the `$` symbol, field name, and a default +value, in case the field doesn't have a value: + +[source,painless] +---- +$(‘field’, ) +---- + +With these enhanced capabilities and simplified syntax, you can write scripts +that are shorter, less complex, and easier to read. For example, the following +script uses the outdated syntax to determine the difference in milliseconds +between two complex `datetime` values from an indexed document: + +[source,painless] +---- +if (doc.containsKey('start') && doc.containsKey('end')) { + if (doc['start'].size() > 0 && doc['end'].size() > 0) { + ZonedDateTime start = doc['start'].value; + ZonedDateTime end = doc['end'].value; + return ChronoUnit.MILLIS.between(start, end); + } else { + return -1; + } +} else { + return -1; +} +---- + +Using the `field` API, you can write this same script much more succinctly, +without requiring additional logic to determine whether fields exist before +operating on them: + +[source,painless] +---- +ZonedDateTime start = field('start').get(null); +ZonedDateTime end = field('end').get(null); +return start == null || end == null ? -1 : ChronoUnit.MILLIS.between(start, end) +---- + +[discrete] +=== Supported mapped field types +The following table indicates the mapped field types that the `field` API +supports. For each supported type, values are listed that are returned by the +`field` API (from the `get` and `as` methods) and the `doc` map (from the +`getValue` and `get` methods). + +NOTE: The `fields` API currently doesn't support some fields, but you can still +access those fields through the `doc` map. For the most current list of +supported fields, refer to {es-issue}79105[#79105]. + +[cols="1,1,1,1,1",options="header",] +|======== +|Mapped field type +2+|Returned type from `field` +2+|Returned type from `doc` +h| h|`get` h|`as` h|`getValue` h|`get` + |`binary` |`ByteBuffer` |- |`BytesRef` |`BytesRef` + |`boolean` |`boolean` |- |`boolean` |`Boolean` + |`keyword` |`String` |- |`String` |`String` + |`long` |`long` |- |`long` |`Long` + |`integer` |`int` |- |`long` |`Long` + |`short` |`short` |- |`long` |`Long` + |`byte` |`byte` |- |`long` |`Long` + |`double` |`double` |- |`double` |`Double` + |`scaled_float` |`double` |- |`double` |`Double` + |`half_float` |`float` |- |`double` |`Double` + |`unsigned_long` |`long` |`BigInteger` |`long` |`Long` + |`date` |`ZonedDateTime` |- |`ZonedDateTime` |`ZonedDateTime` + |`date_nanos` |`ZonedDateTime` |- |`ZonedDateTime` |`ZonedDateTime` + |`ip` |`IpAddress` |`String` |`String` |`String` + |`_version` |`long` |- |`long` |`Long` + |`_seq_no` |`long` |- |`long` |`Long` + |`version` |`Version` |`String` |`String` |`String` + |`murmur3` |`long` |- |`long` |`Long` + |`constant_keyword` |`String` |- |`String` |`String` + |`wildcard` |`String` |- |`String` |`String` + |`flattened` |`String` |- |`String` |`String` +|======== \ No newline at end of file diff --git a/docs/reference/scripting/using.asciidoc b/docs/reference/scripting/using.asciidoc index 6e96ae67845ab..d4b4fd91e3e37 100644 --- a/docs/reference/scripting/using.asciidoc +++ b/docs/reference/scripting/using.asciidoc @@ -147,7 +147,7 @@ GET my-index-000001/_search "my_doubled_field": { "script": { "lang": "painless", - "source": "return doc['my_field'].value * params.get('multiplier');", + "source": "doc['my_field'].value * params.get('multiplier');", "params": { "multiplier": 2 } @@ -168,7 +168,7 @@ GET my-index-000001/_search "script_fields": { "my_doubled_field": { "script": { - "source": "doc['my_field'].value * params['multiplier']", + "source": "field('my_field').get(null) * params['multiplier']", "params": { "multiplier": 2 }