Browse Source

[DOCS] Focus scripting docs on Painless (#69748)

* Initial changes for scripting.

* Shorten script examples.

* Expanding types docs.

* Updating types.

* Fixing broken cross-link.

* Fixing map error.

* Incorporating review feedback.

* Fixing broken table.

* Adding more info about reference types.

* Fixing broken path.

* Adding more info an examples for def type.

* Adding more info on operators.

* Incorporating review feedback.

* Adding notconsole for example.

* Removing comments in example.

* More review feedback.

* Editorial changes.

* Incorporating more reviewer feedback.

* Rewrites based on review feedback.

* Adding new sections for storing scripts and shortening scripts.

* Adding redirect for stored scripts.

* Adding DELETE for stored script plus link.

* Adding section for updating docs with scripts.

* Incorporating final feedback from reviews.

* Tightening up a few areas.

* Minor change around other languages.

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Adam Locke 4 years ago
parent
commit
aba4422606

+ 1 - 1
docs/painless/painless-guide/painless-datetime.asciidoc

@@ -381,7 +381,7 @@ source document, or from an indexed document.
 
 ===== Datetime Input From User Parameters
 
-Use the {ref}/modules-scripting-using.html#_script_parameters[params section]
+Use the {ref}/modules-scripting-using.html[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

+ 32 - 47
docs/painless/painless-lang-spec/painless-types.asciidoc

@@ -23,53 +23,38 @@ type). Use the <<field-access-operator, field access operator>> or
 <<method-call-operator, method call operator>> on a primitive type value to
 force evaluation as its corresponding reference type value.
 
-The following primitive types are available:
-
-[horizontal]
-`byte`::
-8-bit, signed, two's complement integer
-* range: [`-128`, `127`]
-* default value: `0`
-* reference type: `Byte`
-
-`short`::
-16-bit, signed, two's complement integer
-* range: [`-32768`, `32767`]
-* default value: `0`
-* reference type: `Short`
-
-`char`::
-16-bit, unsigned, Unicode character
-* range: [`0`, `65535`]
-* default value: `0` or `\u0000`
-* reference type: `Character`
-
-`int`::
-32-bit, signed, two's complement integer
-* range: [`-2^31`, `2^31-1`]
-* default value: `0`
-* reference type: `Integer`
-
-`long`::
-64-bit, signed, two's complement integer
-* range: [`-2^63`, `2^63-1`]
-* default value: `0`
-* reference type: `Long`
-
-`float`::
-32-bit, signed, single-precision, IEEE 754 floating point number
-* default value: `0.0`
-* reference type: `Float`
-
-`double`::
-64-bit, signed, double-precision, IEEE 754 floating point number
-* default value: `0.0`
-* reference type: `Double`
-
-`boolean`::
-logical quantity with two possible values of `true` and `false`
-* default value: `false`
-* reference type: `Boolean`
+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:
+
+[[available-primitive-types]]
+.**Available primitive types**
+[%collapsible%open]
+====
+`byte` (`Byte`)::
+    8-bit, signed, two's complement integer. Range: [`-128`, `127`]. Default: `0`.
+
+`short` (`Short`)::
+    16-bit, signed, two's 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, two's complement integer. Range: [`-2^31`, `2^31-1`]. Default: `0`.
+
+`long` (`Long`)::
+    64-bit, signed, two's 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*
 

+ 2 - 2
docs/reference/analysis/tokenfilters/condition-tokenfilter.asciidoc

@@ -102,7 +102,7 @@ Predicate script used to apply token filters. If a token
 matches this script, the filters in the `filter` parameter are applied to the
 token.
 
-For valid parameters, see <<_script_parameters>>. Only inline scripts are
+For valid parameters, see <<modules-scripting-using>>. Only inline scripts are
 supported. Painless scripts are executed in the
 {painless}/painless-analysis-predicate-context.html[analysis predicate context]
 and require a `token` property.
@@ -145,4 +145,4 @@ PUT /palindrome_list
     }
   }
 }
---------------------------------------------------
+--------------------------------------------------

+ 1 - 1
docs/reference/ingest/processors/script.asciidoc

@@ -10,7 +10,7 @@ See <<modules-scripting-using, How to use scripts>> to learn more about writing
 leverages caching of compiled scripts for improved performance. Since the
 script specified within the processor is potentially re-compiled per document, it is important
 to understand how script caching works. To learn more about
-caching see <<modules-scripting-using-caching, Script Caching>>.
+caching see <<scripts-and-search-speed, Script Caching>>.
 
 [[script-options]]
 .Script Options

+ 5 - 0
docs/reference/redirects.asciidoc

@@ -3,6 +3,11 @@
 
 The following pages have moved or been deleted.
 
+[roles="exclude",id="modules-scripting-stored-scripts"]
+=== Stored scripts
+
+See <<script-stored-scripts,Store and retrieve scripts>>
+
 [role="exclude",id="node.name"]
 === Node name setting
 

+ 28 - 50
docs/reference/scripting.asciidoc

@@ -4,81 +4,59 @@
 [partintro]
 --
 With scripting, you can evaluate custom expressions in {es}. For example, you
-could use a script to return "script fields" as part of a search request or
-evaluate a custom score for a query.
+can use a script to return a computed value as a field or evaluate a custom
+score for a query.
 
-The default scripting language is <<modules-scripting-painless, `Painless`>>.
-Additional `lang` plugins enable you to run scripts written in other languages.
-Everywhere a script can be used, you can include a `lang` parameter
-to specify the language of the script.
+The default scripting language is <<modules-scripting-painless,Painless>>.
+Additional `lang` plugins are available to run scripts written in other
+languages. You can specify the language of the script anywhere that scripts run.
 
 [discrete]
-== General-purpose languages
+[[scripting-available-languages]]
+== Available scripting languages
 
-These languages can be used for any purpose in the scripting APIs,
-and give the most flexibility.
-
-[cols="<,<,<",options="header",]
-|=======================================================================
-|Language
-    |Sandboxed
-    |Required plugin
-
-|<<modules-scripting-painless, `painless`>>
-    |yes
-    |built-in
-
-|=======================================================================
-
-[discrete]
-== Special-purpose languages
-
-These languages are less flexible, but typically have higher performance for
-certain tasks.
+Painless is purpose-built for {es}, can be used for any purpose in the
+scripting APIs, and provides the most flexibility. The other languages are less
+flexible, but can be useful for specific purposes.
 
 [cols="<,<,<,<",options="header",]
-|=======================================================================
+|========
 |Language
     |Sandboxed
     |Required plugin
     |Purpose
 
+|<<modules-scripting-painless,`painless`>>
+    |{yes-icon}
+    |Built-in
+    |Purpose-built for {es}
+
 |<<modules-scripting-expression, `expression`>>
-    |yes
-    |built-in
-    |fast custom ranking and sorting
+    |{yes-icon}
+    |Built-in
+    |Fast custom ranking and sorting
 
 |<<search-template, `mustache`>>
-    |yes
-    |built-in
-    |templates
+    |{yes-icon}
+    |Built-in
+    |Templates
 
 |<<modules-scripting-engine, `java`>>
-    |n/a
-    |you write it!
-    |expert API
-
-|=======================================================================
-
-[WARNING]
-.Scripts and security
-=================================================
-
-Languages that are sandboxed are designed with security in mind. However, non-
-sandboxed languages can be a security issue, please read
-<<modules-scripting-security, Scripting and security>> for more details.
+    |{no-icon}
+    |You write it!
+    |Expert API
+|========
 
-=================================================
 --
 
+include::scripting/painless.asciidoc[]
+
 include::scripting/using.asciidoc[]
 
 include::scripting/fields.asciidoc[]
 
 include::scripting/security.asciidoc[]
 
-include::scripting/painless.asciidoc[]
-
 include::scripting/expression.asciidoc[]
 
 include::scripting/engine.asciidoc[]

+ 29 - 27
docs/reference/scripting/painless.asciidoc

@@ -1,32 +1,34 @@
 [[modules-scripting-painless]]
 == Painless scripting language
 
-_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. To get started with
-Painless, see the {painless}/painless-guide.html[Painless Guide]. For a
-detailed description of the Painless syntax and language features, see the
-{painless}/painless-lang-spec.html[Painless Language Specification].
+_Painless_ is a performant, secure scripting language designed specifically for
+{es}. You can use Painless to safely write inline and stored scripts anywhere
+scripts are supported in {es}.
 
 [[painless-features]]
-You can use Painless anywhere scripts can be used in Elasticsearch. Painless
-provides:
-
-* Fast performance: Painless scripts https://benchmarks.elastic.co/index.html#search_qps_scripts[
-run several times faster] than the alternatives.
-
-* Safety: Fine-grained allowlists with method call/field granularity. See the
-{painless}/painless-api-reference.html[Painless API Reference] 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 Java's syntax to provide additional scripting
-language features.
-
-* Optimizations: Designed specifically for Elasticsearch scripting.
-
-Ready to start scripting with Painless? See the
-{painless}/painless-guide.html[Painless Guide] for the
-{painless}/index.html[Painless Scripting Language].
+Painless provides numerous capabilities that center around the following
+core principles:
+
+* **Safety**: Ensuring the security of your cluster is of utmost importance. To
+that end, Painless uses a fine-grained allowlist with a granularity down to the
+members of a class. Anything that is not part of the allowlist results in a
+compilation error. See the
+{painless}/painless-api-reference.html[Painless API Reference]
+for a complete list of available classes, methods, and fields per script
+context.
+* **Performance**: Painless compiles directly into JVM bytecode to take
+advantage of all possible optimizations that the JVM provides. Also, Painless
+typically avoids features that require additional slower checks at runtime.
+* **Simplicity**: Painless implements a syntax with a natural familiarity to
+anyone with some basic coding experience. Painless uses a subset of Java syntax
+with some additional improvements to enhance readability and remove
+boilerplate.
+
+[discrete]
+=== Start scripting
+Ready to start scripting with Painless? Learn how to
+<<modules-scripting-using,write your first script>>.
+
+If you're already familiar with Painless, see the
+{painless}/painless-lang-spec.html[Painless Language Specification] for a
+detailed description of the Painless syntax and language features.

+ 4 - 4
docs/reference/scripting/security.asciidoc

@@ -79,12 +79,12 @@ security of the Elasticsearch deployment.
 === Allowed script types setting
 
 Elasticsearch supports two script types: `inline` and `stored` (<<modules-scripting-using>>).
-By default, {es} is configured to run both types of scripts. 
-To limit what type of scripts are run, set `script.allowed_types` to `inline` or `stored`. 
+By default, {es} is configured to run both types of scripts.
+To limit what type of scripts are run, set `script.allowed_types` to `inline` or `stored`.
 To prevent any scripts from running, set `script.allowed_types` to `none`.
 
-IMPORTANT: If you use {kib}, set `script.allowed_types` to `both` or `inline`. 
-Some {kib} features rely on inline scripts and do not function as expected 
+IMPORTANT: If you use {kib}, set `script.allowed_types` to `both` or `inline`.
+Some {kib} features rely on inline scripts and do not function as expected
 if {es} does not allow inline scripts.
 
 For example, to run `inline` scripts but not `stored` scripts, specify:

+ 331 - 193
docs/reference/scripting/using.asciidoc

@@ -1,39 +1,74 @@
 [[modules-scripting-using]]
-== How to use scripts
+== How to write scripts
 
-Wherever scripting is supported in the Elasticsearch API, the syntax follows
-the same pattern:
+Wherever scripting is supported in the {es} APIs, the syntax follows the same
+pattern; you specify the language of your script, provide the script logic (or
+source, and add parameters that are passed into the script:
 
 [source,js]
 -------------------------------------
   "script": {
-    "lang":   "...",  <1>
-    "source" | "id": "...", <2>
-    "params": { ... } <3>
+    "lang":   "...",
+    "source" | "id": "...",
+    "params": { ... }
   }
 -------------------------------------
 // NOTCONSOLE
-<1> The language the script is written in, which defaults to `painless`.
-<2> The script itself which may be specified as `source` for an inline script or `id` for a stored script.
-<3> Any named parameters that should be passed into the script.
 
-For example, the following script is used in a search request to return a
-<<script-fields, scripted field>>:
+`lang`::
+
+    Specifies the language the script is written in. Defaults to `painless`.
+
+`source`, `id`::
+
+    The script itself, which you specify as `source` for an inline script or `id` for a stored script. Use the `_scripts` endpoint to retrieve a stored script. For example, you can create or delete a <<script-stored-scripts,stored script>> by calling `POST _scripts/{id}` and `DELETE _scripts/{id}`.
+
+`params`::
+
+    Specifies any named parameters that are passed into the script as
+    variables. <<prefer-params,Use parameters>> instead of hard-coded values to decrease compile time.
+
+[discrete]
+[[hello-world-script]]
+=== Write your first script
+<<modules-scripting-painless,Painless>> is the default scripting language
+for {es}. It is secure, performant, and provides a natural syntax for anyone
+with a little coding experience.
+
+A Painless script is structured as one or more statements and optionally
+has one or more user-defined functions at the beginning. A script must always
+have at least one statement.
+
+The {painless}/painless-execute-api.html[Painless execute API] provides the ability to
+test a script with simple user-defined parameters and receive a result. Let's
+start with a complete script and review its constituent parts.
+
+First, index a document with a single field so that we have some data to work
+with:
 
 [source,console]
--------------------------------------
+----
 PUT my-index-000001/_doc/1
 {
   "my_field": 5
 }
+----
+
+We can then construct a script that operates on that field and run evaluate the
+script as part of a query. The following query uses the
+<<script-fields,`script_fields`>> parameter of the search API to retrieve a
+script valuation. There's a lot happening here, but we'll break it down the
+components to understand them individually. For now, you only need to
+understand that this script takes `my_field` and operates on it.
 
+[source,console]
+----
 GET my-index-000001/_search
 {
   "script_fields": {
     "my_doubled_field": {
-      "script": {
-        "lang":   "expression",
-        "source": "doc['my_field'] * multiplier",
+      "script": { <1>
+        "source": "doc['my_field'].value * params['multiplier']", <2>
         "params": {
           "multiplier": 2
         }
@@ -41,117 +76,141 @@ GET my-index-000001/_search
     }
   }
 }
--------------------------------------
-
-[discrete]
-=== Script parameters
-
-`lang`::
-
-    Specifies the language the script is written in.  Defaults to `painless`.
-
-
-`source`, `id`::
+----
+// TEST[continued]
+<1> `script` object
+<2> `script` source
 
-    Specifies the source of the script.  An `inline` script is specified
-    `source` as in the example above. A `stored` script is specified `id`
-    and is retrieved from the cluster state (see <<modules-scripting-stored-scripts,Stored Scripts>>).
+The `script` is a standard JSON object that defines scripts under most APIs
+in {es}. This object requires `source` to define the script itself. The
+script doesn't specify a language, so it defaults to Painless.
 
+[discrete]
+[[prefer-params]]
+=== Use parameters in your script
 
-`params`::
+The first time {es} sees a new script, it compiles the script and stores the
+compiled version in a cache. Compilation can be a heavy process. Rather than
+hard-coding values in your script, pass them as named `params` instead.
 
-    Specifies any named parameters that are passed into the script as
-    variables.
+For example, in the previous script, we could have just hard coded values and
+written a script that is seemingly less complex. We could just retrieve the
+first value for `my_field` and then multiply it by `2`:
 
-[IMPORTANT]
-[[prefer-params]]
-.Prefer parameters
-========================================
+[source,painless]
+----
+"source": "return doc['my_field'].value * 2"
+----
 
-The first time Elasticsearch sees a new script, it compiles it and stores the
-compiled version in a cache. Compilation can be a heavy process.
+Though it works, this solution is pretty inflexible. We have to modify the
+script source to change the multiplier, and {es} has to recompile the script
+every time that the multiplier changes.
 
-If you need to pass variables into the script, you should pass them in as
-named `params` instead of hard-coding values into the script itself.  For
-example, if you want to be able to multiply a field value by different
-multipliers, don't hard-code the multiplier into the script:
+Instead of hard-coding values, use named `params` to make scripts flexible, and
+also reduce compilation time when the script runs. You can now make changes to
+the `multiplier` parameter without {es} recompiling the script.
 
-[source,js]
-----------------------
-  "source": "doc['my_field'] * 2"
-----------------------
-// NOTCONSOLE
+[source,painless]
+----
+"source": "doc['my_field'].value * params['multiplier']",
+"params": {
+  "multiplier": 2
+}
+----
 
-Instead, pass it in as a named parameter:
+For most contexts, you can compile up to 75 scripts per 5 minutes by default.
+For ingest contexts, the default script compilation rate is unlimited. You
+can change these settings dynamically by setting
+`script.context.$CONTEXT.max_compilations_rate`. For example, the following
+setting limits script compilation to 100 scripts every 10 minutes for the
+{painless}/painless-field-context.html[field context]:
 
 [source,js]
-----------------------
-  "source": "doc['my_field'] * multiplier",
-  "params": {
-    "multiplier": 2
-  }
-----------------------
+----
+script.context.field.max_compilations_rate=100/10m
+----
 // NOTCONSOLE
 
-The first version has to be recompiled every time the multiplier changes.  The
-second version is only compiled once.
-
-If you compile too many unique scripts within a small amount of time,
-Elasticsearch will reject the new dynamic scripts with a
-`circuit_breaking_exception` error. For most contexts, you can compile up to 75
-scripts per 5 minutes by default. For ingest contexts, the default script
-compilation rate is unlimited. You can change these settings dynamically by
-setting `script.context.$CONTEXT.max_compilations_rate` eg.
-`script.context.field.max_compilations_rate=100/10m`.
-
-========================================
+IMPORTANT: If you compile too many unique scripts within a short time, {es}
+rejects the new dynamic scripts with a `circuit_breaking_exception` error.
 
 [discrete]
-[[modules-scripting-short-script-form]]
-=== Short script form
-A short script form can be used for brevity. In the short form, `script` is represented
-by a string instead of an object. This string contains the source of the script.
-
-Short form:
-
-[source,js]
-----------------------
-  "script": "ctx._source.my-int++"
-----------------------
-// NOTCONSOLE
+[[script-shorten-syntax]]
+=== Shorten your script
+Using syntactic abilities that are native to Painless, you can reduce verbosity
+in your scripts and make them shorter. Here's a simple script that we can make
+shorter:
 
-The same script in the normal form:
-
-[source,js]
-----------------------
-  "script": {
-    "source": "ctx._source.my-int++"
+[source,console]
+----
+GET my-index-000001/_search
+{
+  "script_fields": {
+    "my_doubled_field": {
+      "script": {
+        "lang":   "painless",
+        "source": "return doc['my_field'].value * params.get('multiplier');",
+        "params": {
+          "multiplier": 2
+        }
+      }
+    }
   }
-----------------------
-// NOTCONSOLE
-
-[discrete]
-[[modules-scripting-stored-scripts]]
-=== Stored scripts
+}
+----
+// TEST[s/^/PUT my-index-000001\n/]
 
-Scripts may be stored in and retrieved from the cluster state using the
-`_scripts` end-point.
+Let's look at a shortened version of the script to see what improvements it
+includes over the previous iteration:
 
-If the {es} {security-features} are enabled, you must have the following 
-privileges to create, retrieve, and delete stored scripts:
+[source,console]
+----
+GET my-index-000001/_search
+{
+  "script_fields": {
+    "my_doubled_field": {
+      "script": {
+        "source": "doc['my_field'].value * params['multiplier']",
+        "params": {
+          "multiplier": 2
+        }
+      }
+    }
+  }
+}
+----
+// TEST[s/^/PUT my-index-000001\n/]
 
-* cluster: `all` or `manage`
+This version of the script removes several components and simplifies the syntax
+significantly:
 
-For more information, see <<security-privileges>>.
+* The `lang` declaration. Because Painless is the default language, you don't
+need to specify the language if you're writing a Painless script.
+* The `return` keyword. Painless automatically uses the final statement in a
+script (when possible) to produce a return value in a script context that
+requires one.
+* The `get` method, which is replaced with brackets `[]`. Painless
+uses a shortcut specifically for the `Map` type that allows us to use brackets
+instead of the lengthier `get` method.
+* The semicolon at the end of the `source` statement. Painless does not
+require semicolons for the final statement of a block. However, it does require
+them in other cases to remove ambiguity.
 
+Use this abbreviated syntax anywhere that {es} supports scripts.
 
 [discrete]
-==== Request examples
+[[script-stored-scripts]]
+=== Store and retrieve scripts
+You can store and retrieve scripts from the cluster state using the `_scripts`
+endpoint. Using stored scripts can help to reduce compilation time and make
+searches faster. Use the `{id}` path element in `_scripts/{id}` to refer to a
+stored script.
 
-The following are examples of using a stored script that lives at
-`/_scripts/{id}`.
+NOTE: Unlike regular scripts, stored scripts require that you specify a script
+language using the `lang` parameter.
 
-First, create the script called `calculate-score` in the cluster state:
+For example, let's create a stored script in the cluster named
+`calculate-score`:
 
 [source,console]
 -----------------------------------
@@ -159,29 +218,13 @@ POST _scripts/calculate-score
 {
   "script": {
     "lang": "painless",
-    "source": "Math.log(_score * 2) + params.my_modifier"
-  }
-}
------------------------------------
-// TEST[setup:my_index]
-
-You may also specify a context as part of the url path to compile a
-stored script against that specific context in the form of
-`/_scripts/{id}/{context}`:
-
-[source,console]
------------------------------------
-POST _scripts/calculate-score/score
-{
-  "script": {
-    "lang": "painless",
-    "source": "Math.log(_score * 2) + params.my_modifier"
+    "source": "Math.log(_score * 2) + params['my_modifier']"
   }
 }
 -----------------------------------
 // TEST[setup:my_index]
 
-This same script can be retrieved with:
+You can retrieve that script by using the `_scripts` endpoint:
 
 [source,console]
 -----------------------------------
@@ -189,10 +232,11 @@ GET _scripts/calculate-score
 -----------------------------------
 // TEST[continued]
 
-Stored scripts can be used by specifying the `id` parameters as follows:
+To use the stored script in a query, include the script `id` in the `script`
+declaration:
 
 [source,console]
---------------------------------------------------
+----
 GET my-index-000001/_search
 {
   "query": {
@@ -203,7 +247,7 @@ GET my-index-000001/_search
         }
       },
       "script": {
-        "id": "calculate-score",
+        "id": "calculate-score", <1>
         "params": {
           "my_modifier": 2
         }
@@ -211,68 +255,182 @@ GET my-index-000001/_search
     }
   }
 }
---------------------------------------------------
+----
 // TEST[continued]
+<1> `id` of the stored script
 
-And deleted with:
+To delete a stored script, submit a delete request to the `_scripts` endpoint
+and specify the stored script `id`:
 
 [source,console]
------------------------------------
+----
 DELETE _scripts/calculate-score
------------------------------------
+----
 // TEST[continued]
 
 [discrete]
-[[modules-scripting-search-templates]]
-=== Search templates
-You can also use the `_scripts` API to store **search templates**. Search
-templates save specific <<search-search,search requests>> with placeholder
-values, called template parameters.
+[[scripts-update-scripts]]
+=== Update documents with scripts
+You can use the <<docs-update,update API>> to update documents with a specified
+script. The script can update, delete, or skip modifying the document. The
+update API also supports passing a partial document, which is merged into the
+existing document.
 
-You can use stored search templates to run searches without writing out the
-entire query. Just provide the stored template's ID and the template parameters.
-This is useful when you want to run a commonly used query quickly and without
-mistakes.
+First, let's index a simple document:
 
-Search templates use the https://mustache.github.io/mustache.5.html[mustache
-templating language]. See <<search-template>> for more information and examples.
+[source,console]
+----
+PUT my-index-000001/_doc/1
+{
+  "counter" : 1,
+  "tags" : ["red"]
+}
+----
 
-[discrete]
-[[modules-scripting-using-caching]]
-=== Script caching
+To increment the counter, you can submit an update request with the following
+script:
 
-All scripts are cached by default so that they only need to be recompiled
-when updates occur. By default, scripts do not have a time-based expiration, but
-you can change this behavior by using the `script.cache.expire` setting.
-You can configure the size of this cache by using the `script.cache.max_size` setting.
-For most contexts, the default cache size is `100`. For ingest contexts, the
-default cache size is `200`.
+[source,console]
+----
+POST my-index-000001/_update/1
+{
+  "script" : {
+    "source": "ctx._source.counter += params.count",
+    "lang": "painless",
+    "params" : {
+      "count" : 4
+    }
+  }
+}
+----
+// TEST[continued]
+
+Similarly, you can use an update script to add a tag to the list of tags.
+Because this is just a list, the tag is added even it exists:
+
+[source,console]
+----
+POST my-index-000001/_update/1
+{
+  "script": {
+    "source": "ctx._source.tags.add(params['tag'])",
+    "lang": "painless",
+    "params": {
+      "tag": "blue"
+    }
+  }
+}
+----
+// TEST[continued]
+
+You can also remove a tag from the list of tags. The `remove` method of a Java
+`List` is available in Painless. It takes the index of the element you
+want to remove. To avoid a possible runtime error, you first need to make sure
+the tag exists. If the list contains duplicates of the tag, this script just
+removes one occurrence.
+
+[source,console]
+----
+POST my-index-000001/_update/1
+{
+  "script": {
+    "source": "if (ctx._source.tags.contains(params['tag'])) { ctx._source.tags.remove(ctx._source.tags.indexOf(params['tag'])) }",
+    "lang": "painless",
+    "params": {
+      "tag": "blue"
+    }
+  }
+}
+----
+// TEST[continued]
+
+You can also add and remove fields from a document. For example, this script
+adds the field `new_field`:
+
+[source,console]
+----
+POST my-index-000001/_update/1
+{
+  "script" : "ctx._source.new_field = 'value_of_new_field'"
+}
+----
+// TEST[continued]
+
+Conversely, this script removes the field `new_field`:
+
+[source,console]
+----
+POST my-index-000001/_update/1
+{
+  "script" : "ctx._source.remove('new_field')"
+}
+----
+// TEST[continued]
 
-NOTE: The size of scripts is limited to 65,535 bytes. This can be
-changed by setting `script.max_size_in_bytes` setting to increase that soft
-limit, but if scripts are really large then a
-<<modules-scripting-engine,native script engine>> should be considered.
+Instead of updating the document, you can also change the operation that is
+executed from within the script. For example, this request deletes the document
+if the `tags` field contains `green`. Otherwise it does nothing (`noop`):
+
+[source,console]
+----
+POST my-index-000001/_update/1
+{
+  "script": {
+    "source": "if (ctx._source.tags.contains(params['tag'])) { ctx.op = 'delete' } else { ctx.op = 'none' }",
+    "lang": "painless",
+    "params": {
+      "tag": "green"
+    }
+  }
+}
+----
+// TEST[continued]
 
 [[scripts-and-search-speed]]
-=== Scripts and search speed
+=== Scripts, caching, and search speed
+{es} performs a number of optimizations to make using scripts as fast as
+possible. One important optimization is a script cache. The compiled script is
+placed in a cache so that requests that reference the script do not incur a
+compilation penalty.
+
+Cache sizing is important. Your script cache should be large enough to hold all
+of the scripts that users need to be accessed concurrently.
 
-Scripts can't make use of {es}'s index structures or related optimizations. This
-can sometimes result in slower search speeds.
+If you see a large number of script cache evictions and a rising number of
+compilations in <<cluster-nodes-stats,node stats>>, your cache might be too
+small.
 
-If you often use scripts to transform indexed data, you can speed up search by
-making these changes during ingest instead. However, that often means slower
-index speeds.
+All scripts are cached by default so that they only need to be recompiled
+when updates occur. By default, scripts do not have a time-based expiration.
+You can change this behavior by using the `script.cache.expire` setting.
+Use the `script.cache.max_size` setting to configure the size of the cache.
+
+NOTE: The size of scripts is limited to 65,535 bytes. Set the value of `script.max_size_in_bytes` to increase that soft limit. If your scripts are
+really large, then consider using a
+<<modules-scripting-engine,native script engine>>.
 
-.*Example*
-[%collapsible]
-=====
-An index, `my_test_scores`, contains two `long` fields:
+[discrete]
+==== Improving search speed
+Scripts are incredibly useful, but can't use {es}'s index structures or related
+optimizations. This relationship can sometimes result in slower search speeds.
+
+If you often use scripts to transform indexed data, you can make search faster
+by transforming data during ingest instead. However, that often means slower
+index speeds. Let's look at a practical example to illustrate how you can
+increase search speed.
+
+When running searches, it's common to sort results by the sum of two values.
+For example, consider an index named `my_test_scores` that contains test score
+data. This index includes two fields of type `long`:
 
 * `math_score`
 * `verbal_score`
 
-When running searches, users often use a script to sort results by the sum of
-these two field's values.
+You can run a query with a script that adds these values together. There's
+nothing wrong with this approach, but the query will be slower because the
+script valuation occurs as part of the request. The following request returns
+documents where `grad_year` equals `2099`, and sorts by the results by the
+valuation of the script.
 
 [source,console]
 ----
@@ -298,12 +456,12 @@ GET /my_test_scores/_search
 ----
 // TEST[s/^/PUT my_test_scores\n/]
 
-To speed up search, you can perform this calculation during ingest and index the
-sum to a field instead.
+If you're searching a small index, then including the script as part of your
+search query can be a good solution. If you want to make search faster, you can
+perform this calculation during ingest and index the sum to a field instead.
 
-First, <<indices-put-mapping,add a new field>>, `total_score`, to the index. The
-`total_score` field will contain sum of the `math_score` and `verbal_score`
-field values.
+First, we'll add a new field to the index named `total_score`, which will
+contain sum of the `math_score` and `verbal_score` field values.
 
 [source,console]
 ----
@@ -319,7 +477,7 @@ PUT /my_test_scores/_mapping
 // TEST[continued]
 
 Next, use an <<ingest,ingest pipeline>> containing the
-<<script-processor,`script`>> processor to calculate the sum of `math_score` and
+<<script-processor,script processor>> to calculate the sum of `math_score` and
 `verbal_score` and index it in the `total_score` field.
 
 [source,console]
@@ -339,7 +497,7 @@ PUT _ingest/pipeline/my_test_scores_pipeline
 // TEST[continued]
 
 To update existing data, use this pipeline to <<docs-reindex,reindex>> any
-documents from `my_test_scores` to a new index, `my_test_scores_2`.
+documents from `my_test_scores` to a new index named `my_test_scores_2`.
 
 [source,console]
 ----
@@ -364,15 +522,16 @@ POST /my_test_scores_2/_doc/?pipeline=my_test_scores_pipeline
 {
   "student": "kimchy",
   "grad_year": "2099",
-  "math_score": 800,
+  "math_score": 1200,
   "verbal_score": 800
 }
 ----
 // TEST[continued]
 
-These changes may slow indexing but allow for faster searches. Users can now
-sort searches made on `my_test_scores_2` using the `total_score` field instead
-of using a script.
+These changes slow the index process, but allow for faster searches. Instead of
+using a script, you can sort searches made on `my_test_scores_2` using the
+`total_score` field. The response is near real-time! Though this process slows
+ingest time, it greatly increases queries at search time.
 
 [source,console]
 ----
@@ -401,25 +560,4 @@ DELETE /_ingest/pipeline/my_test_scores_pipeline
 ----
 // TEST[continued]
 
-[source,console-result]
-----
-{
-"acknowledged": true
-}
-----
 ////
-=====
-
-We recommend testing and benchmarking any indexing changes before deploying them
-in production.
-
-[discrete]
-[[modules-scripting-errors]]
-=== Script errors
-Elasticsearch returns error details when there is a compliation or runtime
-exception.  The contents of this response are useful for tracking down the
-problem.
-
-experimental[]
-
-The contents of `position` are experimental and subject to change.

+ 1 - 1
x-pack/docs/en/watcher/condition/script.asciidoc

@@ -70,7 +70,7 @@ always returns `true`.
 ==== Stored scripts
 
 Stored scripts refer to scripts that were
-<<modules-scripting-stored-scripts,stored>> in Elasticsearch. The following
+<<modules-scripting-using,stored>> in Elasticsearch. The following
 snippet shows how to refer to a script by its `id`:
 
 [source,js]

+ 1 - 1
x-pack/docs/en/watcher/how-watcher-works.asciidoc

@@ -415,7 +415,7 @@ The formal object definition for a script would be:
 [[stored-templates-scripts]]
 ===== Stored templates and scripts
 
-If you <<modules-scripting-stored-scripts,store>>
+If you <<modules-scripting-using,store>>
 your templates and scripts, you can reference them by id.
 
 To reference a stored script or template, you use the formal object definition