From 842fa15f58eef07ba0345bb25a9e73de06ff0c68 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Wed, 13 Jun 2018 08:08:04 -0700 Subject: [PATCH 01/15] Ingest example. --- .../elasticsearch/painless/AdditionTests.java | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/AdditionTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/AdditionTests.java index f124d088bf2f2..7145b1a1023a3 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/AdditionTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/AdditionTests.java @@ -23,8 +23,48 @@ //TODO: NaN/Inf/overflow/... public class AdditionTests extends ScriptTestCase { - public void testBasics() throws Exception { - assertEquals(3.0, exec("double x = 1; byte y = 2; return x + y;")); + public void testBasics() { + assertEquals(15, + exec( "String[] split(String s, char d) {" + + " int count = 0;" + + " for (char c : s.toCharArray()) {" + + " if (c == d) {" + + " ++count;" + + " }" + + " }" + + " if (count == 0) {" + + " return new String[] {s};" + + " }" + + " String[] r = new String[count + 1];" + + " int i0 = 0, i1 = 0;" + + " count = 0;" + + " for (char c : s.toCharArray()) {" + + " if (c == d) {" + + " r[count++] = s.substring(i0, i1);" + + " i0 = i1 + 1;" + + " }" + + " ++i1;" + + " }" + + " r[count] = s.substring(i0, i1);" + + " return r;" + + "}" + + "def x = ['date': '2018-9-1', 'time': '3:00AM'];" + + "String dateSplit[] = split(x.date, '-');" + + "String year = dateSplit[0];" + + "String month = " + + "boolean pm = x.time.substring(x.time.length() - 2).equals('PM');" + + "String[] timeSplit = split(x.time.substring(0, x.time.length() - 2), (char)':');" + + "int hours = Integer.parseInt(timeSplit[0]);" + + "String minutes = timeSplit[1];" + + "if (pm) {" + + " hours += 12;" + + "}" + + "String dts = year + '-' + month + '-' + day + " + + "'T' + (hours < 10 ? '0' + hours : '' + hours) + ':' + minutes + ':00+08:00';" + + "ZonedDateTime dt = ZonedDateTime.parse(dts, DateTimeFormatter.ISO_OFFSET_DATE_TIME);" + + "return dt.getLong(ChronoField.INSTANT_SECONDS)*1000L" + ) + ); } public void testInt() throws Exception { From cd5a5739178af328e57251cfd3d23a6ea0fc9fa1 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Wed, 13 Jun 2018 08:16:29 -0700 Subject: [PATCH 02/15] More progress. --- .../test/java/org/elasticsearch/painless/AdditionTests.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/AdditionTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/AdditionTests.java index 7145b1a1023a3..59bc1fd5aa7cd 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/AdditionTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/AdditionTests.java @@ -51,7 +51,8 @@ public void testBasics() { "def x = ['date': '2018-9-1', 'time': '3:00AM'];" + "String dateSplit[] = split(x.date, '-');" + "String year = dateSplit[0];" + - "String month = " + + "String month = dateSplit[1]" + + "if (month.length() " + "boolean pm = x.time.substring(x.time.length() - 2).equals('PM');" + "String[] timeSplit = split(x.time.substring(0, x.time.length() - 2), (char)':');" + "int hours = Integer.parseInt(timeSplit[0]);" + From 0e069a880ae048ece321ae3547bd8d78e27acee5 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Wed, 13 Jun 2018 09:36:02 -0700 Subject: [PATCH 03/15] Added unit tests for tutorial branch. --- .../resources/checkstyle_suppressions.xml | 1 + .../elasticsearch/painless/AdditionTests.java | 45 +-- .../elasticsearch/painless/TutorialTests.java | 304 ++++++++++++++++++ 3 files changed, 307 insertions(+), 43 deletions(-) create mode 100644 modules/lang-painless/src/test/java/org/elasticsearch/painless/TutorialTests.java diff --git a/buildSrc/src/main/resources/checkstyle_suppressions.xml b/buildSrc/src/main/resources/checkstyle_suppressions.xml index 8ab68b40c0a6b..16a2c383d6b23 100644 --- a/buildSrc/src/main/resources/checkstyle_suppressions.xml +++ b/buildSrc/src/main/resources/checkstyle_suppressions.xml @@ -686,6 +686,7 @@ + diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/AdditionTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/AdditionTests.java index 59bc1fd5aa7cd..f124d088bf2f2 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/AdditionTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/AdditionTests.java @@ -23,49 +23,8 @@ //TODO: NaN/Inf/overflow/... public class AdditionTests extends ScriptTestCase { - public void testBasics() { - assertEquals(15, - exec( "String[] split(String s, char d) {" + - " int count = 0;" + - " for (char c : s.toCharArray()) {" + - " if (c == d) {" + - " ++count;" + - " }" + - " }" + - " if (count == 0) {" + - " return new String[] {s};" + - " }" + - " String[] r = new String[count + 1];" + - " int i0 = 0, i1 = 0;" + - " count = 0;" + - " for (char c : s.toCharArray()) {" + - " if (c == d) {" + - " r[count++] = s.substring(i0, i1);" + - " i0 = i1 + 1;" + - " }" + - " ++i1;" + - " }" + - " r[count] = s.substring(i0, i1);" + - " return r;" + - "}" + - "def x = ['date': '2018-9-1', 'time': '3:00AM'];" + - "String dateSplit[] = split(x.date, '-');" + - "String year = dateSplit[0];" + - "String month = dateSplit[1]" + - "if (month.length() " + - "boolean pm = x.time.substring(x.time.length() - 2).equals('PM');" + - "String[] timeSplit = split(x.time.substring(0, x.time.length() - 2), (char)':');" + - "int hours = Integer.parseInt(timeSplit[0]);" + - "String minutes = timeSplit[1];" + - "if (pm) {" + - " hours += 12;" + - "}" + - "String dts = year + '-' + month + '-' + day + " + - "'T' + (hours < 10 ? '0' + hours : '' + hours) + ':' + minutes + ':00+08:00';" + - "ZonedDateTime dt = ZonedDateTime.parse(dts, DateTimeFormatter.ISO_OFFSET_DATE_TIME);" + - "return dt.getLong(ChronoField.INSTANT_SECONDS)*1000L" - ) - ); + public void testBasics() throws Exception { + assertEquals(3.0, exec("double x = 1; byte y = 2; return x + y;")); } public void testInt() throws Exception { diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/TutorialTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/TutorialTests.java new file mode 100644 index 0000000000000..ba794e06a31c6 --- /dev/null +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/TutorialTests.java @@ -0,0 +1,304 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless; + +public class TutorialTests extends ScriptTestCase { + + // **** Docs Generator Code **** + + /* + + import java.io.FileWriter; + import java.io.IOException; + + public class Generator { + + public final static String[] theatres = new String[] {"Down Port", "Graye", "Skyline", "Courtyard"}; + public final static String[] plays = new String[] {"Driving", "Pick It Up", "Sway and Pull", "Harriot", + "The Busline", "Ants Underground", "Exploria", "Line and Single", "Shafted", "Sunnyside Down", + "Test Run", "Auntie Jo"}; + public final static String[] actors = new String[] {"James Holland", "Krissy Smith", "Joe Muir", "Ryan Earns", + "Joel Madigan", "Jessica Brown", "Baz Knight", "Jo Hangum", "Rachel Grass", "Phoebe Miller", "Sarah Notch", + "Brayden Green", "Joshua Iller", "Jon Hittle", "Rob Kettleman", "Laura Conrad", "Simon Hower", "Nora Blue", + "Mike Candlestick", "Jacey Bell"}; + + public static void writeSeat(FileWriter writer, int id, String theatre, String play, String[] actors, + String date, String time, int row, int number, double cost, boolean sold) throws IOException { + StringBuilder builder = new StringBuilder(); + builder.append("{ \"create\" : { \"_index\" : \"seats\", \"_type\" : \"seat\", \"_id\" : \""); + builder.append(id); + builder.append("\" } }\n"); + builder.append("{ \"theatre\" : \""); + builder.append(theatre); + builder.append("\", \"play\" : \""); + builder.append(play); + builder.append("\", \"actors\": [ \""); + for (String actor : actors) { + builder.append(actor); + if (actor.equals(actors[actors.length - 1]) == false) { + builder.append("\", \""); + } + } + builder.append("\" ], \"date\": \""); + builder.append(date); + builder.append("\", \"time\": \""); + builder.append(time); + builder.append("\", \"row\": "); + builder.append(row); + builder.append(", \"number\": "); + builder.append(number); + builder.append(", \"cost\": "); + builder.append(cost); + builder.append(", \"sold\": "); + builder.append(sold ? "true" : "false"); + builder.append(" }\n"); + writer.write(builder.toString()); + } + + public static void main(String args[]) throws IOException { + FileWriter writer = new FileWriter("/home/jdconrad/test/seats.json"); + int id = 0; + + for (int playCount = 0; playCount < 12; ++playCount) { + String play = plays[playCount]; + String theatre; + String[] actor; + int startMonth; + int endMonth; + String time; + + if (playCount == 0) { + theatre = theatres[0]; + actor = new String[] {actors[0], actors[1], actors[2], actors[3]}; + startMonth = 4; + endMonth = 5; + time = "3:00PM"; + } else if (playCount == 1) { + theatre = theatres[0]; + actor = new String[] {actors[4], actors[5], actors[6], actors[7], actors[8], actors[9]}; + startMonth = 4; + endMonth = 6; + time = "8:00PM"; + } else if (playCount == 2) { + theatre = theatres[0]; + actor = new String[] {actors[0], actors[1], actors[2], actors[3], + actors[4], actors[5], actors[6], actors[7]}; + startMonth = 6; + endMonth = 8; + time = "3:00 PM"; + } else if (playCount == 3) { + theatre = theatres[0]; + actor = new String[] {actors[9], actors[10], actors[11], actors[12], actors[13], actors[14], + actors[15], actors[16], actors[17], actors[18], actors[19]}; + startMonth = 7; + endMonth = 8; + time = "8:00PM"; + } else if (playCount == 4) { + theatre = theatres[0]; + actor = new String[] {actors[13], actors[14], actors[15], actors[17], actors[18], actors[19]}; + startMonth = 8; + endMonth = 10; + time = "3:00PM"; + } else if (playCount == 5) { + theatre = theatres[0]; + actor = new String[] {actors[8], actors[9], actors[10], actors[11], actors[12]}; + startMonth = 8; + endMonth = 10; + time = "8:00PM"; + } else if (playCount == 6) { + theatre = theatres[1]; + actor = new String[] {actors[10], actors[11], actors[12], actors[13], actors[14], actors[15], actors[16]}; + startMonth = 4; + endMonth = 5; + time = "11:00AM"; + } else if (playCount == 7) { + theatre = theatres[1]; + actor = new String[] {actors[17], actors[18]}; + startMonth = 6; + endMonth = 9; + time = "2:00PM"; + } else if (playCount == 8) { + theatre = theatres[1]; + actor = new String[] {actors[0], actors[1], actors[2], actors[3], actors[16]}; + startMonth = 10; + endMonth = 11; + time = "11:00AM"; + } else if (playCount == 9) { + theatre = theatres[2]; + actor = new String[] {actors[1], actors[2], actors[3], actors[17], actors[18], actors[19]}; + startMonth = 3; + endMonth = 6; + time = "4:00PM"; + } else if (playCount == 10) { + theatre = theatres[2]; + actor = new String[] {actors[2], actors[3], actors[4], actors[5]}; + startMonth = 7; + endMonth = 8; + time = "7:30PM"; + } else if (playCount == 11) { + theatre = theatres[2]; + actor = new String[] {actors[7], actors[13], actors[14], actors[15], actors[16], actors[17]}; + startMonth = 9; + endMonth = 12; + time = "5:40PM"; + } else { + throw new RuntimeException("too many plays"); + } + + int rows; + int number; + + if (playCount < 6) { + rows = 3; + number = 12; + } else if (playCount < 9) { + rows = 5; + number = 9; + } else if (playCount < 12) { + rows = 11; + number = 15; + } else { + throw new RuntimeException("too many seats"); + } + + for (int month = startMonth; month <= endMonth; ++month) { + for (int day = 1; day <= 14; ++day) { + for (int row = 1; row <= rows; ++row) { + for (int count = 1; count <= number; ++count) { + String date = "2018-" + month + "-" + day; + double cost = (25 - row) * 1.25; + + writeSeat(writer, ++id, theatre, play, actor, date, time, row, count, cost, false); + } + } + } + } + } + + writer.write("\n"); + writer.close(); + } + } + + */ + + // **** Initial Mappings **** + + /* + + curl -X PUT "localhost:9200/seats" -H 'Content-Type: application/json' -d' + { + "mappings": { + "seat": { + "properties": { + "theatre": { "type": "keyword" }, + "play": { "type": "text" }, + "actors": { "type": "text" }, + "row": { "type": "integer" }, + "number": { "type": "integer" }, + "cost": { "type": "double" }, + "sold": { "type": "boolean" }, + "datetime": { "type": "date" }, + "date": { "type": "keyword" }, + "time": { "type": "keyword" } + } + } + } + } + ' + */ + + // Create Ingest to Modify Dates: + + /* + + curl -X PUT "localhost:9200/_ingest/pipeline/seats" -H 'Content-Type: application/json' -d' + { + "description": "update datetime for seats", + "processors": [ + { + "script": { + "source": "String[] split(String s, char d) { int count = 0; for (char c : s.toCharArray()) { if (c == d) { ++count; } } if (count == 0) { return new String[] {s}; } String[] r = new String[count + 1]; int i0 = 0, i1 = 0; count = 0; for (char c : s.toCharArray()) { if (c == d) { r[count++] = s.substring(i0, i1); i0 = i1 + 1; } ++i1; } r[count] = s.substring(i0, i1); return r; } String[] dateSplit = split(ctx.date, (char)\"-\"); 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 = split(ctx.time.substring(0, ctx.time.length() - 2), (char)\":\"); 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;" + } + } + ] + } + + '*/ + + public void testIngestProcessorScript() { + assertEquals(1535785200000L, + exec("String[] split(String s, char d) {" + + " int count = 0;" + + " for (char c : s.toCharArray()) {" + + " if (c == d) {" + + " ++count;" + + " }" + + " }" + + " if (count == 0) {" + + " return new String[] {s};" + + " }" + + " String[] r = new String[count + 1];" + + " int i0 = 0, i1 = 0;" + + " count = 0;" + + " for (char c : s.toCharArray()) {" + + " if (c == d) {" + + " r[count++] = s.substring(i0, i1);" + + " i0 = i1 + 1;" + + " }" + + " ++i1;" + + " }" + + " r[count] = s.substring(i0, i1);" + + " return r;" + + "}" + + "def x = ['date': '2018-9-1', 'time': '3:00 PM'];" + + "String[] dateSplit = split(x.date, (char)'-');" + + "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 = x.time.substring(x.time.length() - 2).equals('PM');" + + "String[] timeSplit = split(x.time.substring(0, x.time.length() - 2), (char)':');" + + "int hours = Integer.parseInt(timeSplit[0].trim());" + + "String minutes = timeSplit[1].trim();" + + "if (pm) {" + + " hours += 12;" + + "}" + + "String dts = year + '-' + month + '-' + day + " + + "'T' + (hours < 10 ? '0' + hours : '' + hours) + ':' + minutes + ':00+08:00';" + + "ZonedDateTime dt = ZonedDateTime.parse(dts, DateTimeFormatter.ISO_OFFSET_DATE_TIME);" + + "return dt.getLong(ChronoField.INSTANT_SECONDS) * 1000L" + ) + ); + } + + // Post Generated Data: + + /* + + curl -XPOST localhost:9200/seats/seat/_bulk?pipeline=seats -H "Content-Type: application/x-ndjson" --data-binary "@/home/jdconrad/test/seats.json" + + */ +} From 74cb05658a630d4f3945738f005d6fa6375fb176 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Mon, 23 Jul 2018 15:04:28 -0700 Subject: [PATCH 04/15] Add an example for ingest. --- docs/painless/painless-contexts.asciidoc | 10 +- .../painless/painless-contexts/index.asciidoc | 4 +- .../painless-context-examples.asciidoc | 78 ++++++++++ ...painless-ingest-processor-context.asciidoc | 145 +++++++++++++++++- docs/painless/painless-keywords.asciidoc | 2 +- ...ialTests.java => ContextExampleTests.java} | 11 +- 6 files changed, 239 insertions(+), 11 deletions(-) create mode 100644 docs/painless/painless-contexts/painless-context-examples.asciidoc rename modules/lang-painless/src/test/java/org/elasticsearch/painless/{TutorialTests.java => ContextExampleTests.java} (98%) diff --git a/docs/painless/painless-contexts.asciidoc b/docs/painless/painless-contexts.asciidoc index ff46f6bd74dde..a7cd9340b2a16 100644 --- a/docs/painless/painless-contexts.asciidoc +++ b/docs/painless/painless-contexts.asciidoc @@ -2,7 +2,7 @@ == Painless contexts :es_version: https://www.elastic.co/guide/en/elasticsearch/reference/master -:xp_version: https://www.elastic.co/guide/en/x-pack/current +:xp_version: https://www.elastic.co/guide/en/x-pack/master A Painless script is evaluated within a context. Each context has values that are available as local variables, a whitelist that controls the available @@ -17,6 +17,8 @@ specialized code may define new ways to use a Painless script. |==== | Name | Painless Documentation | Elasticsearch Documentation +| Ingest processor | <> + | {es_version}/script-processor.html[Elasticsearch Documentation] | Update | <> | {es_version}/docs-update.html[Elasticsearch Documentation] | Update by query | <> @@ -27,7 +29,7 @@ specialized code may define new ways to use a Painless script. | {es_version}/search-request-sort.html[Elasticsearch Documentation] | Similarity | <> | {es_version}/index-modules-similarity.html[Elasticsearch Documentation] -| Weight | <> +| Weight | <> | {es_version}/index-modules-similarity.html[Elasticsearch Documentation] | Score | <> | {es_version}/query-dsl-function-score-query.html[Elasticsearch Documentation] @@ -47,12 +49,12 @@ specialized code may define new ways to use a Painless script. | {es_version}/search-aggregations-metrics-scripted-metric-aggregation.html[Elasticsearch Documentation] | Bucket aggregation | <> | {es_version}/search-aggregations-pipeline-bucket-script-aggregation.html[Elasticsearch Documentation] -| Ingest processor | <> - | {es_version}/script-processor.html[Elasticsearch Documentation] | Watcher condition | <> | {xp_version}/condition-script.html[Elasticsearch Documentation] | Watcher transform | <> | {xp_version}/transform-script.html[Elasticsearch Documentation] |==== +include::painless-contexts/painless-context-examples.asciidoc[] + include::painless-contexts/index.asciidoc[] diff --git a/docs/painless/painless-contexts/index.asciidoc b/docs/painless/painless-contexts/index.asciidoc index 64e4326e052f2..a9d3982133e1b 100644 --- a/docs/painless/painless-contexts/index.asciidoc +++ b/docs/painless/painless-contexts/index.asciidoc @@ -1,3 +1,5 @@ +include::painless-ingest-processor-context.asciidoc[] + include::painless-update-context.asciidoc[] include::painless-update-by-query-context.asciidoc[] @@ -28,8 +30,6 @@ include::painless-metric-agg-reduce-context.asciidoc[] include::painless-bucket-agg-context.asciidoc[] -include::painless-ingest-processor-context.asciidoc[] - include::painless-watcher-condition-context.asciidoc[] include::painless-watcher-transform-context.asciidoc[] diff --git a/docs/painless/painless-contexts/painless-context-examples.asciidoc b/docs/painless/painless-contexts/painless-context-examples.asciidoc new file mode 100644 index 0000000000000..16e775b1b672c --- /dev/null +++ b/docs/painless/painless-contexts/painless-context-examples.asciidoc @@ -0,0 +1,78 @@ +[[painless-context-examples]] +=== Context examples + +Use the commands below to setup an Elasticsearch cluster to execute the example +scripts for each context where an example is provided. Each example must be +executed in the order of the table in the +<> to work correctly. + + +. Download the seat data for use in the examples. The data is a fictional set of +plays and their locations and times where each individual document represents a +single seat in a theater for a single play. ++ +Each document contains the following values: ++ +`theatre` ({es_version}/keyword.html[`keyword`]):: + The name of the theater the play is in. +`play` ({es_version}/text.html[`text`]):: + The name of the play. +`actors` ({es_version}/text.html[`text`]):: + A list of actors in the play. +`row` ({es_version}/number.html[`integer`]):: + The row of the seat. +`number` ({es_version}/number.html[`integer`]):: + The number of the seat within a row. +`cost` ({es_version}/number.html[`double`]):: + The cost of the ticket for the seat. +`sold` ({es_version}/boolean.html[`boolean`]):: + Whether or not the seat is sold. +`datetime` ({es_version}/date.html[`date`]):: + The date and time of the play as a date object. +`date` ({es_version}/keyword.html[`keyword`]):: + The date of the play as a keyword. +`time` ({es_version}/keyword.html[`keyword`]):: + The time of the play as a keyword. + +. {es_version}/running-elasticsearch.html[Run] an elasticsearch cluster. The +examples assume the cluster is running locally. Modify the examples as necessary +to execute against a remote cluster. + +. Create {es_version}/mapping.html[mappings] using the following console +command: ++ +[source,js] +---- +PUT /seats +{ + "mappings": { + "seat": { + "properties": { + "theatre": { "type": "keyword" }, + "play": { "type": "text" }, + "actors": { "type": "text" }, + "row": { "type": "integer" }, + "number": { "type": "integer" }, + "cost": { "type": "double" }, + "sold": { "type": "boolean" }, + "datetime": { "type": "date" }, + "date": { "type": "keyword" }, + "time": { "type": "keyword" } + } + } + } +} +---- ++ +//CONSOLE + +. Execute the <> example. This is a +requirement to upload the seat data for use in all the examples. + +. Upload the seat data using the following console command: ++ +[source,js] +---- +curl -XPOST localhost:9200/seats/seat/_bulk?pipeline=seats -H "Content-Type: application/x-ndjson" --data-binary "@//seats.json" +---- + diff --git a/docs/painless/painless-contexts/painless-ingest-processor-context.asciidoc b/docs/painless/painless-contexts/painless-ingest-processor-context.asciidoc index ba3be0739631f..9350c252f940e 100644 --- a/docs/painless/painless-contexts/painless-ingest-processor-context.asciidoc +++ b/docs/painless/painless-contexts/painless-ingest-processor-context.asciidoc @@ -27,7 +27,7 @@ to modify documents upon insertion. {es_version}/mapping-type-field.html[`ctx['_type']`]:: Modify this to change the type for the current document. -`ctx` (`Map`, read-only):: +`ctx` (`Map`):: Modify the values in the `Map/List` structure to add, modify, or delete the fields of a document. @@ -38,4 +38,145 @@ void:: *API* -The standard <> is available. \ No newline at end of file +The standard <> is available. + +*Example* + +To use this example first follow the steps outlined in +<>. + +The original seat data gives a date `String` with the format `YYYY-MM-DD` where +the second digit of each the month and the day is optional and gives a time +`String` with the format `HH:MM*` where the second digit of each the hours and +the minutes is optional and the star represents a `String` of either `AM` or +`PM`. The following ingest script processor converts the given date and time +`Strings` into a useful format for storage into a date field. Upon completion of +the script each document will have its `datetime` field value filled in. + +The following script is used as the ingest script processor: + +[source,Painless] +---- +<1> String[] split(String s, char d) { + int count = 0; + +<2> for (char c : s.toCharArray()) { + if (c == d) { + ++count; + } + } + +<3> if (count == 0) { + return new String[] {s}; + } + +<4> String[] r = new String[count + 1]; + int i0 = 0, i1 = 0; + count = 0; + +<5> for (char c : s.toCharArray()) { + if (c == d) { + r[count++] = s.substring(i0, i1); + i0 = i1 + 1; + } + + ++i1; + } + +<6> r[count] = s.substring(i0, i1); + + return r; + } + +<7> String[] dateSplit = split(ctx.date, (char)"-"); + String year = dateSplit[0].trim(); + String month = dateSplit[1].trim(); + +<8> if (month.length() == 1) { + month = "0" + month; + } + + String day = dateSplit[2].trim(); + +<9> if (day.length() == 1) { + day = "0" + day; + } + +<10> boolean pm = ctx.time.substring(ctx.time.length() - 2).equals("PM"); +<11> String[] timeSplit = split( + ctx.time.substring(0, ctx.time.length() - 2), (char)":"); + int hours = Integer.parseInt(timeSplit[0].trim()); + int minutes = Integer.parseInt(timeSplit[1].trim()); + +<12> if (pm) { + hours += 12; + } + +<13> String dts = year + "-" + month + "-" + day + "T" + + (hours < 10 ? "0" + hours : "" + hours) + ":" + + (minutes < 10 ? "0" + minutes : "" + minutes) + + ":00+08:00"; + +<14> ZonedDateTime dt = ZonedDateTime.parse( + dts, DateTimeFormatter.ISO_OFFSET_DATE_TIME); +<15> ctx.datetime = dt.getLong(ChronoField.INSTANT_SECONDS)*1000L; +---- +<1> Creates a `split` <> to split a + <> type value using a <> + type value as the delimiter. This is useful for handling the necessity of + pulling out the individual pieces of the date and time `Strings` from the + original seat data since . +<2> The first pass through each `char` in the `String` collects how many new + `Strings` the original is split into. +<3> Returns the original `String` if there are no instances of the delimiting + `char`. +<4> Creates an <> value to collect the split `Strings` + into based on the number of `char` delimiters found in the first pass. +<5> The second pass through each `char` in the `String` collects each split + substring into an array type value of `Strings`. +<6> Collects the last substring into the array type value of `Strings`. +<7> Uses the `split` function to separate the date `String` from the seat data + into year, month, and day `Strings`. Note the use of a `String` type value + to `char` type value <> as part of the + second argument since character literals do not exist. +<8> Appends the <> `"0"` value to a single + digit month since the format of the seat data allows for this case. +<9> Appends the <> `"0"` value to a single + digit day since the format of the seat data allows for this case. +<10> Sets the <> + <> to `true` if the time `String` is a time + in the afternoon or evening. +<11> Uses the `split` 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`. Also note the use of + a `String` type value to `char` type value + <> as part of the second argument since + character literals do not exist. +<12> If the time `String` is an afternoon or evening value adds the + <> `12` to the existing hours to move to + a 24-hour based time. +<13> Builds a new time `String` that is parsable using existing API methods. +<14> Creates a `ZonedDateTime` <> value by using + the API method `parse` to parse the new time `String`. +<15> Sets the datetime field `datetime` to the number of milliseconds retrieved + from the API method `getLong`. Note the use of the `ctx` ingest processor + context variable to set the field `datetime`. Manipulate each document's + fields with the `ctx` variable as each document is indexed. + +Use the following curl command to create the ingest script processor: + +[source,js] +---- +PUT /_ingest/pipeline/seats +{ + "description": "update datetime for seats", + "processors": [ + { + "script": { + "source": "String[] split(String s, char d) { int count = 0; for (char c : s.toCharArray()) { if (c == d) { ++count; } } if (count == 0) { return new String[] {s}; } String[] r = new String[count + 1]; int i0 = 0, i1 = 0; count = 0; for (char c : s.toCharArray()) { if (c == d) { r[count++] = s.substring(i0, i1); i0 = i1 + 1; } ++i1; } r[count] = s.substring(i0, i1); return r; } String[] dateSplit = split(ctx.date, (char)\"-\"); 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 = split(ctx.time.substring(0, ctx.time.length() - 2), (char)\":\"); 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;" + } + } + ] +} +---- +// CONSOLE \ No newline at end of file diff --git a/docs/painless/painless-keywords.asciidoc b/docs/painless/painless-keywords.asciidoc index 9463902c8d346..24371d3713c0b 100644 --- a/docs/painless/painless-keywords.asciidoc +++ b/docs/painless/painless-keywords.asciidoc @@ -5,7 +5,7 @@ Keywords are reserved tokens for built-in language features. *Errors* -If a keyword is used as an <>. +* If a keyword is used as an <>. *Keywords* diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/TutorialTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/ContextExampleTests.java similarity index 98% rename from modules/lang-painless/src/test/java/org/elasticsearch/painless/TutorialTests.java rename to modules/lang-painless/src/test/java/org/elasticsearch/painless/ContextExampleTests.java index ba794e06a31c6..15eed75bcb8df 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/TutorialTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/ContextExampleTests.java @@ -19,7 +19,12 @@ package org.elasticsearch.painless; -public class TutorialTests extends ScriptTestCase { +/** + * These tests run the Painless scripts used in the context docs against + * slightly modified data designed around unit tests rather than a fully- + * running Elasticsearch server. + */ +public class ContextExampleTests extends ScriptTestCase { // **** Docs Generator Code **** @@ -223,6 +228,7 @@ public static void main(String args[]) throws IOException { } } ' + */ // Create Ingest to Modify Dates: @@ -240,8 +246,9 @@ public static void main(String args[]) throws IOException { } ] } + ' - '*/ + */ public void testIngestProcessorScript() { assertEquals(1535785200000L, From e133c85471096c716121f648ffcf6092a48b6f44 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Tue, 24 Jul 2018 08:27:55 -0700 Subject: [PATCH 05/15] Fix noconsole issue. --- .../painless-contexts/painless-context-examples.asciidoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/painless/painless-contexts/painless-context-examples.asciidoc b/docs/painless/painless-contexts/painless-context-examples.asciidoc index 16e775b1b672c..9207864f13268 100644 --- a/docs/painless/painless-contexts/painless-context-examples.asciidoc +++ b/docs/painless/painless-contexts/painless-context-examples.asciidoc @@ -40,7 +40,7 @@ to execute against a remote cluster. . Create {es_version}/mapping.html[mappings] using the following console command: -+ + [source,js] ---- PUT /seats @@ -63,8 +63,7 @@ PUT /seats } } ---- -+ -//CONSOLE +// CONSOLE . Execute the <> example. This is a requirement to upload the seat data for use in all the examples. @@ -75,4 +74,5 @@ requirement to upload the seat data for use in all the examples. ---- curl -XPOST localhost:9200/seats/seat/_bulk?pipeline=seats -H "Content-Type: application/x-ndjson" --data-binary "@//seats.json" ---- +// NOTCONSOLE From caea6d4f67fd2a8e00cbf8e4bd273b589eb92d87 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Tue, 24 Jul 2018 09:21:59 -0700 Subject: [PATCH 06/15] Add download link. --- .../painless-contexts/painless-context-examples.asciidoc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/painless/painless-contexts/painless-context-examples.asciidoc b/docs/painless/painless-contexts/painless-context-examples.asciidoc index 9207864f13268..71124749c4133 100644 --- a/docs/painless/painless-contexts/painless-context-examples.asciidoc +++ b/docs/painless/painless-contexts/painless-context-examples.asciidoc @@ -7,9 +7,11 @@ executed in the order of the table in the <> to work correctly. -. Download the seat data for use in the examples. The data is a fictional set of -plays and their locations and times where each individual document represents a -single seat in a theater for a single play. +. Download the +https://download.elastic.co/demos/painless/contexts/seats.json[seat data] +for use in the examples. The data is a fictional set of plays and their +locations and times where each individual document represents a single seat in +a theater for a single play. + Each document contains the following values: + From ea9f050d459b7f568c8cca96c9d96e4ed360f599 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Tue, 24 Jul 2018 10:05:17 -0700 Subject: [PATCH 07/15] Checkstyle fix. --- buildSrc/src/main/resources/checkstyle_suppressions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/resources/checkstyle_suppressions.xml b/buildSrc/src/main/resources/checkstyle_suppressions.xml index 16a2c383d6b23..420ed3b10b4c9 100644 --- a/buildSrc/src/main/resources/checkstyle_suppressions.xml +++ b/buildSrc/src/main/resources/checkstyle_suppressions.xml @@ -686,7 +686,7 @@ - + From 3e306f3d473f113a4d9791aef6268e333144db92 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Wed, 25 Jul 2018 11:05:43 -0700 Subject: [PATCH 08/15] Ref fixes. --- docs/painless/painless-contexts.asciidoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/painless/painless-contexts.asciidoc b/docs/painless/painless-contexts.asciidoc index 4f12e24b21052..cc7bc752ec6d9 100644 --- a/docs/painless/painless-contexts.asciidoc +++ b/docs/painless/painless-contexts.asciidoc @@ -15,7 +15,7 @@ specialized code may define new ways to use a Painless script. | Name | Painless Documentation | Elasticsearch Documentation | Ingest processor | <> - | {es_version}/script-processor.html[Elasticsearch Documentation] + | {ref}/script-processor.html[Elasticsearch Documentation] | Update | <> | {ref}/docs-update.html[Elasticsearch Documentation] | Update by query | <> @@ -25,9 +25,9 @@ specialized code may define new ways to use a Painless script. | Sort | <> | {ref}/search-request-sort.html[Elasticsearch Documentation] | Similarity | <> - | {es_version}/index-modules-similarity.html[Elasticsearch Documentation] + | {ref}/index-modules-similarity.html[Elasticsearch Documentation] | Weight | <> - | {es_version}/index-modules-similarity.html[Elasticsearch Documentation] + | {ref}/index-modules-similarity.html[Elasticsearch Documentation] | Score | <> | {ref}/query-dsl-function-score-query.html[Elasticsearch Documentation] | Field | <> @@ -45,7 +45,7 @@ specialized code may define new ways to use a Painless script. | Metric aggregation reduce | <> | {ref}/search-aggregations-metrics-scripted-metric-aggregation.html[Elasticsearch Documentation] | Bucket aggregation | <> - | {es_version}/search-aggregations-pipeline-bucket-script-aggregation.html[Elasticsearch Documentation] + | {ref}/search-aggregations-pipeline-bucket-script-aggregation.html[Elasticsearch Documentation] | Watcher condition | <> | {xpack-ref}/condition-script.html[Elasticsearch Documentation] | Watcher transform | <> From 494a936f0c8df73ea9c98b7e481ae44594fd9a3b Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Mon, 6 Aug 2018 10:57:38 -0700 Subject: [PATCH 09/15] Response to PR feedback. --- .../painless-context-examples.asciidoc | 56 +++++++++---------- ...painless-ingest-processor-context.asciidoc | 55 +++++++++++------- 2 files changed, 62 insertions(+), 49 deletions(-) diff --git a/docs/painless/painless-contexts/painless-context-examples.asciidoc b/docs/painless/painless-contexts/painless-context-examples.asciidoc index 71124749c4133..3550506d10aae 100644 --- a/docs/painless/painless-contexts/painless-context-examples.asciidoc +++ b/docs/painless/painless-contexts/painless-context-examples.asciidoc @@ -1,48 +1,47 @@ [[painless-context-examples]] === Context examples -Use the commands below to setup an Elasticsearch cluster to execute the example -scripts for each context where an example is provided. Each example must be -executed in the order of the table in the -<> to work correctly. - +Each example must be run in the order of the table in the +<> to work correctly. To run each example, +first index the sample data into Elasticsearch: . Download the -https://download.elastic.co/demos/painless/contexts/seats.json[seat data] -for use in the examples. The data is a fictional set of plays and their -locations and times where each individual document represents a single seat in -a theater for a single play. +https://download.elastic.co/demos/painless/contexts/seats.json[seat data]. This +data set contains booking information for a collection of plays. Each document +represents a single seat for a play at a particular theater on a specific date +and time. + -Each document contains the following values: +Each document contains the following fields: + -`theatre` ({es_version}/keyword.html[`keyword`]):: +`theatre` ({ref}/keyword.html[`keyword`]):: The name of the theater the play is in. -`play` ({es_version}/text.html[`text`]):: +`play` ({ref}/text.html[`text`]):: The name of the play. -`actors` ({es_version}/text.html[`text`]):: +`actors` ({ref}/text.html[`text`]):: A list of actors in the play. -`row` ({es_version}/number.html[`integer`]):: +`row` ({ref}/number.html[`integer`]):: The row of the seat. -`number` ({es_version}/number.html[`integer`]):: +`number` ({ref}/number.html[`integer`]):: The number of the seat within a row. -`cost` ({es_version}/number.html[`double`]):: +`cost` ({ref}/number.html[`double`]):: The cost of the ticket for the seat. -`sold` ({es_version}/boolean.html[`boolean`]):: +`sold` ({ref}/boolean.html[`boolean`]):: Whether or not the seat is sold. -`datetime` ({es_version}/date.html[`date`]):: +`datetime` ({ref}/date.html[`date`]):: The date and time of the play as a date object. -`date` ({es_version}/keyword.html[`keyword`]):: +`date` ({ref}/keyword.html[`keyword`]):: The date of the play as a keyword. -`time` ({es_version}/keyword.html[`keyword`]):: +`time` ({ref}/keyword.html[`keyword`]):: The time of the play as a keyword. -. {es_version}/running-elasticsearch.html[Run] an elasticsearch cluster. The -examples assume the cluster is running locally. Modify the examples as necessary -to execute against a remote cluster. - -. Create {es_version}/mapping.html[mappings] using the following console -command: +. {ref}/running-elasticsearch.html[Start] Elasticsearch. Note these +examples assume Elasticsearch and Kibana are running locally. To use the Console +editor in a remote Kibana instance, click the settings icon and enter the +Console URL. Edit a request to submit a cURL request to a remote Elasticsearch +instance. +. Create {ref}/mapping.html[mappings] for the sample data: ++ [source,js] ---- PUT /seats @@ -65,12 +64,13 @@ PUT /seats } } ---- ++ // CONSOLE -. Execute the <> example. This is a +. Run the <> example. This is a requirement to upload the seat data for use in all the examples. -. Upload the seat data using the following console command: +. Upload the seat data: + [source,js] ---- diff --git a/docs/painless/painless-contexts/painless-ingest-processor-context.asciidoc b/docs/painless/painless-contexts/painless-ingest-processor-context.asciidoc index 5b1f9719b3f49..8c79371cace56 100644 --- a/docs/painless/painless-contexts/painless-ingest-processor-context.asciidoc +++ b/docs/painless/painless-contexts/painless-ingest-processor-context.asciidoc @@ -42,18 +42,18 @@ The standard <> is available. *Example* -To use this example first follow the steps outlined in +To run this example, first follow the steps in <>. -The original seat data gives a date `String` with the format `YYYY-MM-DD` where -the second digit of each the month and the day is optional and gives a time -`String` with the format `HH:MM*` where the second digit of each the hours and -the minutes is optional and the star represents a `String` of either `AM` or -`PM`. The following ingest script processor converts the given date and time -`Strings` into a useful format for storage into a date field. Upon completion of -the script each document will have its `datetime` field value filled in. +The seat data contains: -The following script is used as the ingest script processor: +* 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. [source,Painless] ---- @@ -136,9 +136,13 @@ The following script is used as the ingest script processor: substring into an array type value of `Strings`. <6> Collects the last substring into the array type value of `Strings`. <7> Uses the `split` function to separate the date `String` from the seat data - into year, month, and day `Strings`. Note the use of a `String` type value - to `char` type value <> as part of the - second argument since character literals do not exist. + into year, month, and day `Strings`. + Note:: + * The use of a `String` type value to `char` type value + <> as part of the second argument since + character literals do not exist. + * The use of the `ctx` ingest processor context variable to retrieve the + data from the `date` field. <8> Appends the <> `"0"` value to a single digit month since the format of the seat data allows for this case. <9> Appends the <> `"0"` value to a single @@ -146,12 +150,19 @@ The following script is used as the ingest script processor: <10> Sets the <> <> 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. <11> Uses the `split` 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`. Also note the use of - a `String` type value to `char` type value - <> as part of the second argument since - character literals do not exist. + 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 a `String` type value to `char` type value + <> as part of the second argument since + character literals do not exist. + * The use of the `ctx` ingest processor context variable to retrieve the + data from the `date` field. <12> If the time `String` is an afternoon or evening value adds the <> `12` to the existing hours to move to a 24-hour based time. @@ -159,11 +170,13 @@ The following script is used as the ingest script processor: <14> Creates a `ZonedDateTime` <> value by using the API method `parse` to parse the new time `String`. <15> Sets the datetime field `datetime` to the number of milliseconds retrieved - from the API method `getLong`. Note the use of the `ctx` ingest processor - context variable to set the field `datetime`. Manipulate each document's - fields with the `ctx` variable as each document is indexed. + from the API method `getLong`. + Note:: + * The use of the `ctx` ingest processor context variable to set the field + `datetime`. Manipulate each document's fields with the `ctx` variable as + each document is indexed. -Use the following curl command to create the ingest script processor: +Submit the following request: [source,js] ---- From 533e7144e5774b0dea2ade172f5085c06166ec5a Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Mon, 6 Aug 2018 11:17:12 -0700 Subject: [PATCH 10/15] Fix ref for guide. --- .../painless-contexts/painless-context-examples.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/painless/painless-contexts/painless-context-examples.asciidoc b/docs/painless/painless-contexts/painless-context-examples.asciidoc index 3550506d10aae..0a6496518b13d 100644 --- a/docs/painless/painless-contexts/painless-context-examples.asciidoc +++ b/docs/painless/painless-contexts/painless-context-examples.asciidoc @@ -34,7 +34,7 @@ Each document contains the following fields: `time` ({ref}/keyword.html[`keyword`]):: The time of the play as a keyword. -. {ref}/running-elasticsearch.html[Start] Elasticsearch. Note these +. {defguide}/running-elasticsearch.html[Start] Elasticsearch. Note these examples assume Elasticsearch and Kibana are running locally. To use the Console editor in a remote Kibana instance, click the settings icon and enter the Console URL. Edit a request to submit a cURL request to a remote Elasticsearch From f8934a217a7dfd44c9e365e5927e00d75d2cb4ba Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Mon, 6 Aug 2018 12:08:38 -0700 Subject: [PATCH 11/15] Add snippet fix for now. --- .../groovy/org/elasticsearch/gradle/doc/SnippetsTask.groovy | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/doc/SnippetsTask.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/doc/SnippetsTask.groovy index ec012633f0893..31085efd9bf9d 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/doc/SnippetsTask.groovy +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/doc/SnippetsTask.groovy @@ -284,6 +284,10 @@ public class SnippetsTask extends DefaultTask { contents.append(line).append('\n') return } + // Allow line extensions for console snippets within lists + if (snippet != null && line.trim() == '+') { + return + } // Just finished emit() } From d264f85083a17bb57d31bcab9f9feadabc52f29e Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Thu, 9 Aug 2018 11:40:44 -0700 Subject: [PATCH 12/15] Response to PR feedback. --- .../painless-context-examples.asciidoc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/painless/painless-contexts/painless-context-examples.asciidoc b/docs/painless/painless-contexts/painless-context-examples.asciidoc index 0a6496518b13d..469f425d1d89f 100644 --- a/docs/painless/painless-contexts/painless-context-examples.asciidoc +++ b/docs/painless/painless-contexts/painless-context-examples.asciidoc @@ -1,9 +1,8 @@ [[painless-context-examples]] === Context examples -Each example must be run in the order of the table in the -<> to work correctly. To run each example, -first index the sample data into Elasticsearch: +To run the examples, index the sample seat data into Elasticsearch. The examples +must be run sequentially to work correctly. . Download the https://download.elastic.co/demos/painless/contexts/seats.json[seat data]. This @@ -36,9 +35,9 @@ Each document contains the following fields: . {defguide}/running-elasticsearch.html[Start] Elasticsearch. Note these examples assume Elasticsearch and Kibana are running locally. To use the Console -editor in a remote Kibana instance, click the settings icon and enter the -Console URL. Edit a request to submit a cURL request to a remote Elasticsearch -instance. +editor with a remote Kibana instance, click the settings icon and enter the +Console URL. To submit a cURL request to a remote Elasticsearch instance, edit +the request URL. . Create {ref}/mapping.html[mappings] for the sample data: + @@ -67,10 +66,11 @@ PUT /seats + // CONSOLE -. Run the <> example. This is a -requirement to upload the seat data for use in all the examples. +. Run the <> +example. This sets up a script ingest processor used on each document as the +seat data is indexed. -. Upload the seat data: +. Index the seat data: + [source,js] ---- From 8cde957ec344ac23b512e352bf424b4ef7b247d8 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Thu, 9 Aug 2018 11:52:51 -0700 Subject: [PATCH 13/15] reposition callouts --- ...painless-ingest-processor-context.asciidoc | 96 +++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/docs/painless/painless-contexts/painless-ingest-processor-context.asciidoc b/docs/painless/painless-contexts/painless-ingest-processor-context.asciidoc index 8c79371cace56..2e590cae3ef4e 100644 --- a/docs/painless/painless-contexts/painless-ingest-processor-context.asciidoc +++ b/docs/painless/painless-contexts/painless-ingest-processor-context.asciidoc @@ -57,69 +57,69 @@ result in a `datetime` field. [source,Painless] ---- -<1> String[] split(String s, char d) { - int count = 0; +String[] split(String s, char d) { <1> + int count = 0; -<2> for (char c : s.toCharArray()) { - if (c == d) { - ++count; - } - } + for (char c : s.toCharArray()) { <2> + if (c == d) { + ++count; + } + } -<3> if (count == 0) { - return new String[] {s}; - } + if (count == 0) { + return new String[] {s}; <3> + } -<4> String[] r = new String[count + 1]; - int i0 = 0, i1 = 0; - count = 0; + String[] r = new String[count + 1]; <4> + int i0 = 0, i1 = 0; + count = 0; -<5> for (char c : s.toCharArray()) { - if (c == d) { - r[count++] = s.substring(i0, i1); - i0 = i1 + 1; - } + for (char c : s.toCharArray()) { <5> + if (c == d) { + r[count++] = s.substring(i0, i1); + i0 = i1 + 1; + } - ++i1; - } + ++i1; + } -<6> r[count] = s.substring(i0, i1); + r[count] = s.substring(i0, i1); <6> - return r; - } + return r; +} -<7> String[] dateSplit = split(ctx.date, (char)"-"); - String year = dateSplit[0].trim(); - String month = dateSplit[1].trim(); +String[] dateSplit = split(ctx.date, (char)"-"); <7> +String year = dateSplit[0].trim(); +String month = dateSplit[1].trim(); -<8> if (month.length() == 1) { - month = "0" + month; - } +if (month.length() == 1) { <8> + month = "0" + month; +} - String day = dateSplit[2].trim(); +String day = dateSplit[2].trim(); -<9> if (day.length() == 1) { - day = "0" + day; - } +if (day.length() == 1) { <9> + day = "0" + day; +} -<10> boolean pm = ctx.time.substring(ctx.time.length() - 2).equals("PM"); -<11> String[] timeSplit = split( - ctx.time.substring(0, ctx.time.length() - 2), (char)":"); - int hours = Integer.parseInt(timeSplit[0].trim()); - int minutes = Integer.parseInt(timeSplit[1].trim()); +boolean pm = ctx.time.substring(ctx.time.length() - 2).equals("PM"); <10> +String[] timeSplit = split( <11> + ctx.time.substring(0, ctx.time.length() - 2), (char)":"); +int hours = Integer.parseInt(timeSplit[0].trim()); +int minutes = Integer.parseInt(timeSplit[1].trim()); -<12> if (pm) { - hours += 12; - } +if (pm) { <12> + hours += 12; +} -<13> String dts = year + "-" + month + "-" + day + "T" + - (hours < 10 ? "0" + hours : "" + hours) + ":" + - (minutes < 10 ? "0" + minutes : "" + minutes) + - ":00+08:00"; +String dts = year + "-" + month + "-" + day + "T" + + (hours < 10 ? "0" + hours : "" + hours) + ":" + + (minutes < 10 ? "0" + minutes : "" + minutes) + + ":00+08:00"; <13> -<14> ZonedDateTime dt = ZonedDateTime.parse( - dts, DateTimeFormatter.ISO_OFFSET_DATE_TIME); -<15> ctx.datetime = dt.getLong(ChronoField.INSTANT_SECONDS)*1000L; +ZonedDateTime dt = ZonedDateTime.parse( + dts, DateTimeFormatter.ISO_OFFSET_DATE_TIME); <14> +ctx.datetime = dt.getLong(ChronoField.INSTANT_SECONDS)*1000L; <15> ---- <1> Creates a `split` <> to split a <> type value using a <> From a09ee39dd1d0c7d91a47f8d5dcdd8ffc11660716 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Thu, 9 Aug 2018 11:56:32 -0700 Subject: [PATCH 14/15] Correct callout 11. --- .../painless-ingest-processor-context.asciidoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/painless/painless-contexts/painless-ingest-processor-context.asciidoc b/docs/painless/painless-contexts/painless-ingest-processor-context.asciidoc index 2e590cae3ef4e..fc43531dd5fee 100644 --- a/docs/painless/painless-contexts/painless-ingest-processor-context.asciidoc +++ b/docs/painless/painless-contexts/painless-ingest-processor-context.asciidoc @@ -103,8 +103,8 @@ if (day.length() == 1) { <9> } boolean pm = ctx.time.substring(ctx.time.length() - 2).equals("PM"); <10> -String[] timeSplit = split( <11> - ctx.time.substring(0, ctx.time.length() - 2), (char)":"); +String[] timeSplit = split( + ctx.time.substring(0, ctx.time.length() - 2), (char)":"); <11> int hours = Integer.parseInt(timeSplit[0].trim()); int minutes = Integer.parseInt(timeSplit[1].trim()); From 216a5788de084e6dd6aa9e58f88eeb4e3e228a78 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Thu, 9 Aug 2018 11:57:33 -0700 Subject: [PATCH 15/15] Fix broken sentence. --- .../painless-ingest-processor-context.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/painless/painless-contexts/painless-ingest-processor-context.asciidoc b/docs/painless/painless-contexts/painless-ingest-processor-context.asciidoc index fc43531dd5fee..546057ab1a0b8 100644 --- a/docs/painless/painless-contexts/painless-ingest-processor-context.asciidoc +++ b/docs/painless/painless-contexts/painless-ingest-processor-context.asciidoc @@ -125,7 +125,7 @@ ctx.datetime = dt.getLong(ChronoField.INSTANT_SECONDS)*1000L; <15> <> type value using a <> type value as the delimiter. This is useful for handling the necessity of pulling out the individual pieces of the date and time `Strings` from the - original seat data since . + original seat data. <2> The first pass through each `char` in the `String` collects how many new `Strings` the original is split into. <3> Returns the original `String` if there are no instances of the delimiting