From 04a7c84e8ba45def3d832ddfadbd710229a7e32f Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Mon, 17 Jun 2019 10:58:53 -0700 Subject: [PATCH] Add Painless Docs for Datetime Inputs (#43128) This changes add documentation for accessing datetimes in Painless scripts from the three most common inputs of params, _source, and doc. --- .../painless-guide/painless-datetime.asciidoc | 255 +++++++++++++++++- 1 file changed, 244 insertions(+), 11 deletions(-) diff --git a/docs/painless/painless-guide/painless-datetime.asciidoc b/docs/painless/painless-guide/painless-datetime.asciidoc index 11f38475244..5e98b39aaa7 100644 --- a/docs/painless/painless-guide/painless-datetime.asciidoc +++ b/docs/painless/painless-guide/painless-datetime.asciidoc @@ -66,9 +66,9 @@ ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, ZoneId.of('Z')); [source,Painless] ---- String datetime = '1983-10-13T22:15:30Z'; -ZonedDateTime zdt = ZonedDateTime.parse(datetime); +ZonedDateTime zdt = ZonedDateTime.parse(datetime); <1> ---- -Note the parse method uses ISO 8601 by default. +<1> Note the parse method uses ISO 8601 by default. + * parse from RFC 1123 + @@ -76,9 +76,9 @@ Note the parse method uses ISO 8601 by default. ---- String datetime = 'Thu, 13 Oct 1983 22:15:30 GMT'; ZonedDateTime zdt = ZonedDateTime.parse(datetime, - DateTimeFormatter.RFC_1123_DATE_TIME); + DateTimeFormatter.RFC_1123_DATE_TIME); <1> ---- -Note the use of a built-in DateTimeFormatter. +<1> Note the use of a built-in DateTimeFormatter. + * parse from a custom format + @@ -87,9 +87,9 @@ Note the use of a built-in DateTimeFormatter. 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); +ZonedDateTime zdt = ZonedDateTime.parse(datetime, dtf); <1> ---- -Note the use of a custom DateTimeFormatter. +<1> Note the use of a custom DateTimeFormatter. ===== Datetime Formatting Examples @@ -99,9 +99,9 @@ Note the use of a custom DateTimeFormatter. ---- ZonedDateTime zdt = ZonedDateTime.of(1983, 10, 13, 22, 15, 30, 0, ZoneId.of('Z')); -String datetime = zdt.format(DateTimeFormatter.ISO_INSTANT); +String datetime = zdt.format(DateTimeFormatter.ISO_INSTANT); <1> ---- -Note the use of a built-in DateTimeFormatter. +<1> Note the use of a built-in DateTimeFormatter. + * format to a custom format + @@ -111,9 +111,9 @@ 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); +String datetime = zdt.format(dtf); <1> ---- -Note the use of a custom DateTimeFormatter. +<1> Note the use of a custom DateTimeFormatter. ==== Datetime Conversion @@ -238,7 +238,7 @@ complex datetimes there is often a method or another complex type <> to calculate the difference between two complex datetimes if supported. -===== Elapsed Time Examples +===== Datetime Difference Examples * Difference in milliseconds between two numeric datetimes + @@ -334,3 +334,236 @@ if (zdt1.isAfter(zdt2)) { // handle condition } ---- + +==== Datetime Input + +There are several common ways datetimes are used as input for a script +determined by the <>. 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 + +Use the {ref}/modules-scripting-using.html#_script_parameters[params section] +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: ++ +[source,JSON] +---- +... +"script": { + ... + "params": { + "input_datetime": 434931327000 + } +} +... +---- ++ +** Script: ++ +[source,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: ++ +[source,JSON] +---- +... +"script": { + ... + "params": { + "input_datetime": "custom y 1983 m 10 d 13 22:15:30 Z" + } +} +... +---- ++ +** Script: ++ +[source,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 + +Use an original {ref}/mapping-source-field.html[source] 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: ++ +[source,JSON] +---- +{ + ... + "input_datetime": 434931327000 + ... +} +---- ++ +** Script: ++ +[source,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: ++ +[source,JSON] +---- +{ + ... + "input_datetime": "1983-10-13T22:15:30Z" + ... +} +---- ++ +** Script: ++ +[source,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 + +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 +{ref}/date.html[standard date] or a {ref}/date_nanos.html[nanosecond date]. +Numeric datetime fields mapped as {ref}/number.html[numeric] and string +datetime fields mapped as {ref}/keyword.html[keyword] 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: ++ +[source,JSON] +---- +{ + "mappings": { + ... + "properties": { + ... + "input_datetime": { + "type": "date" + } + ... + } + ... + } +} +---- ++ +** Script: ++ +[source,Painless] +---- +def 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_datetime` and `end_datetime` may *not* exist in all +indexes as part of the query +*** The fields `start_datetime` and `end_datetime` may *not* have values in all +indexed documents ++ +** Mappings: ++ +[source,JSON] +---- +{ + "mappings": { + ... + "properties": { + ... + "start_datetime": { + "type": "date" + }, + "end_datetime": { + "type": "date" + } + ... + } + ... + } +} +---- ++ +** Script: ++ +[source,Painless] +---- +if (doc.containsKey('start_datetime') && doc.containsKey('end_datetime')) { <1> + + if (doc['start_datetime'].size() > 0 && doc['end_datetime'].size() > 0) { <2> + + def startDatetime = doc['start_datetime'].value; + def endDatetime = doc['end_datetime'].value; + long differenceInMillis = + ChronoUnit.MILLIS.between(startDateTime, endDateTime); + + // handle difference in times + } else { + // handle fields without values + } +} else { + // handle index with missing fields +} +---- +<1> When a query's 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 field's 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.