diff --git a/output/openapi/elasticsearch-openapi.json b/output/openapi/elasticsearch-openapi.json index 946086e4a0..7811993a1b 100644 --- a/output/openapi/elasticsearch-openapi.json +++ b/output/openapi/elasticsearch-openapi.json @@ -27251,7 +27251,7 @@ "script" ], "summary": "Run a script", - "description": "Runs a script and returns a result.", + "description": "Runs a script and returns a result.\nUse this API to build and test scripts, such as when defining a script for a runtime field.\nThis API requires very few dependencies and is especially useful if you don't have permissions to write documents on a cluster.\n\nThe API uses several _contexts_, which control how scripts are run, what variables are available at runtime, and what the return type is.\n\nEach context requires a script, but additional parameters depend on the context you're using for that script.", "operationId": "scripts-painless-execute", "requestBody": { "$ref": "#/components/requestBodies/scripts_painless_execute" @@ -27268,7 +27268,7 @@ "script" ], "summary": "Run a script", - "description": "Runs a script and returns a result.", + "description": "Runs a script and returns a result.\nUse this API to build and test scripts, such as when defining a script for a runtime field.\nThis API requires very few dependencies and is especially useful if you don't have permissions to write documents on a cluster.\n\nThe API uses several _contexts_, which control how scripts are run, what variables are available at runtime, and what the return type is.\n\nEach context requires a script, but additional parameters depend on the context you're using for that script.", "operationId": "scripts-painless-execute-1", "requestBody": { "$ref": "#/components/requestBodies/scripts_painless_execute" @@ -85677,11 +85677,27 @@ "agg" ] }, + "_global.scripts_painless_execute:PainlessContext": { + "type": "string", + "enum": [ + "painless_test", + "filter", + "score", + "boolean_field", + "date_field", + "double_field", + "geo_point_field", + "ip_field", + "keyword_field", + "long_field", + "composite_field" + ] + }, "_global.scripts_painless_execute:PainlessContextSetup": { "type": "object", "properties": { "document": { - "description": "Document that’s temporarily indexed in-memory and accessible from the script.", + "description": "Document that's temporarily indexed in-memory and accessible from the script.", "type": "object" }, "index": { @@ -109312,8 +109328,7 @@ "type": "object", "properties": { "context": { - "description": "The context that the script should run in.", - "type": "string" + "$ref": "#/components/schemas/_global.scripts_painless_execute:PainlessContext" }, "context_setup": { "$ref": "#/components/schemas/_global.scripts_painless_execute:PainlessContextSetup" diff --git a/output/openapi/elasticsearch-serverless-openapi.json b/output/openapi/elasticsearch-serverless-openapi.json index 969a7ff040..3bd4bc32a6 100644 --- a/output/openapi/elasticsearch-serverless-openapi.json +++ b/output/openapi/elasticsearch-serverless-openapi.json @@ -15719,7 +15719,7 @@ "script" ], "summary": "Run a script", - "description": "Runs a script and returns a result.", + "description": "Runs a script and returns a result.\nUse this API to build and test scripts, such as when defining a script for a runtime field.\nThis API requires very few dependencies and is especially useful if you don't have permissions to write documents on a cluster.\n\nThe API uses several _contexts_, which control how scripts are run, what variables are available at runtime, and what the return type is.\n\nEach context requires a script, but additional parameters depend on the context you're using for that script.", "operationId": "scripts-painless-execute", "requestBody": { "$ref": "#/components/requestBodies/scripts_painless_execute" @@ -15736,7 +15736,7 @@ "script" ], "summary": "Run a script", - "description": "Runs a script and returns a result.", + "description": "Runs a script and returns a result.\nUse this API to build and test scripts, such as when defining a script for a runtime field.\nThis API requires very few dependencies and is especially useful if you don't have permissions to write documents on a cluster.\n\nThe API uses several _contexts_, which control how scripts are run, what variables are available at runtime, and what the return type is.\n\nEach context requires a script, but additional parameters depend on the context you're using for that script.", "operationId": "scripts-painless-execute-1", "requestBody": { "$ref": "#/components/requestBodies/scripts_painless_execute" @@ -54166,11 +54166,27 @@ "_types:Password": { "type": "string" }, + "_global.scripts_painless_execute:PainlessContext": { + "type": "string", + "enum": [ + "painless_test", + "filter", + "score", + "boolean_field", + "date_field", + "double_field", + "geo_point_field", + "ip_field", + "keyword_field", + "long_field", + "composite_field" + ] + }, "_global.scripts_painless_execute:PainlessContextSetup": { "type": "object", "properties": { "document": { - "description": "Document that’s temporarily indexed in-memory and accessible from the script.", + "description": "Document that's temporarily indexed in-memory and accessible from the script.", "type": "object" }, "index": { @@ -64290,8 +64306,7 @@ "type": "object", "properties": { "context": { - "description": "The context that the script should run in.", - "type": "string" + "$ref": "#/components/schemas/_global.scripts_painless_execute:PainlessContext" }, "context_setup": { "$ref": "#/components/schemas/_global.scripts_painless_execute:PainlessContextSetup" diff --git a/output/schema/schema.json b/output/schema/schema.json index d7fb0d13e8..f481125348 100644 --- a/output/schema/schema.json +++ b/output/schema/schema.json @@ -15277,9 +15277,10 @@ "stability": "experimental" } }, - "description": "Run a script.\nRuns a script and returns a result.", + "description": "Run a script.\n\nRuns a script and returns a result.\nUse this API to build and test scripts, such as when defining a script for a runtime field.\nThis API requires very few dependencies and is especially useful if you don't have permissions to write documents on a cluster.\n\nThe API uses several _contexts_, which control how scripts are run, what variables are available at runtime, and what the return type is.\n\nEach context requires a script, but additional parameters depend on the context you're using for that script.", + "docId": "painless-execute-api", "docTag": "script", - "docUrl": "https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html", + "docUrl": "https://www.elastic.co/guide/en/elasticsearch/painless/{branch}/painless-execute-api.html", "name": "scripts_painless_execute", "request": { "name": "Request", @@ -33641,6 +33642,60 @@ }, "specLocation": "_global/render_search_template/RenderSearchTemplateResponse.ts#L23-L25" }, + { + "kind": "enum", + "members": [ + { + "description": "The default context if no other context is specified.", + "name": "painless_test" + }, + { + "description": "Treats scripts as if they were run inside a script query.", + "name": "filter" + }, + { + "description": "Treats scripts as if they were run inside a `script_score` function in a `function_score` query.", + "name": "score" + }, + { + "description": "The context for boolean fields. The script returns a `true` or `false` response.", + "name": "boolean_field" + }, + { + "description": "The context for date fields. `emit` takes a long value and the script returns a sorted list of dates.", + "name": "date_field" + }, + { + "description": "The context for double numeric fields. The script returns a sorted list of double values.", + "name": "double_field" + }, + { + "description": "The context for geo-point fields. `emit` takes two double parameters, the latitude and longitude values, and the script returns an object in GeoJSON format containing the coordinates for the geo point.", + "name": "geo_point_field" + }, + { + "description": "The context for `ip` fields. The script returns a sorted list of IP addresses.", + "name": "ip_field" + }, + { + "description": "The context for keyword fields. The script returns a sorted list of string values.", + "name": "keyword_field" + }, + { + "description": "The context for long numeric fields. The script returns a sorted list of long values.", + "name": "long_field" + }, + { + "description": "The context for composite runtime fields. The script returns a map of values.", + "name": "composite_field" + } + ], + "name": { + "name": "PainlessContext", + "namespace": "_global.scripts_painless_execute" + }, + "specLocation": "_global/scripts_painless_execute/types.ts#L57-L80" + }, { "kind": "interface", "name": { @@ -33649,7 +33704,7 @@ }, "properties": [ { - "description": "Document that’s temporarily indexed in-memory and accessible from the script.", + "description": "Document that's temporarily indexed in-memory and accessible from the script.", "name": "document", "required": true, "type": { @@ -33657,7 +33712,7 @@ } }, { - "description": "Index containing a mapping that’s compatible with the indexed document.\nYou may specify a remote index by prefixing the index with the remote cluster alias.", + "description": "Index containing a mapping that's compatible with the indexed document.\nYou may specify a remote index by prefixing the index with the remote cluster alias.\nFor example, `remote1:my_index` indicates that you want to run the painless script against the \"my_index\" index on the \"remote1\" cluster.\nThis request will be forwarded to the \"remote1\" cluster if you have configured a connection to that remote cluster.\n\nNOTE: Wildcards are not accepted in the index expression for this endpoint.\nThe expression `*:myindex` will return the error \"No such remote cluster\" and the expression `logs*` or `remote1:logs*` will return the error \"index not found\".", "name": "index", "required": true, "type": { @@ -33681,7 +33736,7 @@ } } ], - "specLocation": "_global/scripts_painless_execute/types.ts#L25-L39" + "specLocation": "_global/scripts_painless_execute/types.ts#L27-L46" }, { "kind": "request", @@ -33692,20 +33747,20 @@ "kind": "properties", "properties": [ { - "description": "The context that the script should run in.", + "description": "The context that the script should run in.\nNOTE: Result ordering in the field contexts is not guaranteed.", "name": "context", "required": false, "serverDefault": "painless_test", "type": { "kind": "instance_of", "type": { - "name": "string", - "namespace": "_builtins" + "name": "PainlessContext", + "namespace": "_global.scripts_painless_execute" } } }, { - "description": "Additional parameters for the `context`.", + "description": "Additional parameters for the `context`.\nNOTE: This parameter is required for all contexts except `painless_test`, which is the default if no value is provided for `context`.", "name": "context_setup", "required": false, "type": { @@ -33717,7 +33772,7 @@ } }, { - "description": "The Painless script to execute.", + "description": "The Painless script to run.", "name": "script", "required": false, "type": { @@ -33730,7 +33785,7 @@ } ] }, - "description": "Run a script.\nRuns a script and returns a result.", + "description": "Run a script.\n\nRuns a script and returns a result.\nUse this API to build and test scripts, such as when defining a script for a runtime field.\nThis API requires very few dependencies and is especially useful if you don't have permissions to write documents on a cluster.\n\nThe API uses several _contexts_, which control how scripts are run, what variables are available at runtime, and what the return type is.\n\nEach context requires a script, but additional parameters depend on the context you're using for that script.", "inherits": { "type": { "name": "RequestBase", @@ -33743,7 +33798,7 @@ }, "path": [], "query": [], - "specLocation": "_global/scripts_painless_execute/ExecutePainlessScriptRequest.ts#L24-L54" + "specLocation": "_global/scripts_painless_execute/ExecutePainlessScriptRequest.ts#L24-L64" }, { "kind": "response", diff --git a/output/typescript/types.ts b/output/typescript/types.ts index 0d5271b06e..9fd7f48976 100644 --- a/output/typescript/types.ts +++ b/output/typescript/types.ts @@ -1150,6 +1150,8 @@ export interface RenderSearchTemplateResponse { template_output: Record } +export type ScriptsPainlessExecutePainlessContext = 'painless_test' | 'filter' | 'score' | 'boolean_field' | 'date_field' | 'double_field' | 'geo_point_field' | 'ip_field' | 'keyword_field' | 'long_field' | 'composite_field' + export interface ScriptsPainlessExecutePainlessContextSetup { document: any index: IndexName @@ -1158,7 +1160,7 @@ export interface ScriptsPainlessExecutePainlessContextSetup { export interface ScriptsPainlessExecuteRequest extends RequestBase { body?: { - context?: string + context?: ScriptsPainlessExecutePainlessContext context_setup?: ScriptsPainlessExecutePainlessContextSetup script?: Script | string } diff --git a/specification/_global/scripts_painless_execute/ExecutePainlessScriptRequest.ts b/specification/_global/scripts_painless_execute/ExecutePainlessScriptRequest.ts index 8f9772a45e..8c8d52005d 100644 --- a/specification/_global/scripts_painless_execute/ExecutePainlessScriptRequest.ts +++ b/specification/_global/scripts_painless_execute/ExecutePainlessScriptRequest.ts @@ -19,15 +19,23 @@ import { RequestBase } from '@_types/Base' import { Script } from '@_types/Scripting' -import { PainlessContextSetup } from './types' +import { PainlessContext, PainlessContextSetup } from './types' /** * Run a script. + * * Runs a script and returns a result. + * Use this API to build and test scripts, such as when defining a script for a runtime field. + * This API requires very few dependencies and is especially useful if you don't have permissions to write documents on a cluster. + * + * The API uses several _contexts_, which control how scripts are run, what variables are available at runtime, and what the return type is. + * + * Each context requires a script, but additional parameters depend on the context you're using for that script. * @rest_spec_name scripts_painless_execute * @availability stack since=6.3.0 stability=experimental * @availability serverless stability=experimental visibility=public * @doc_tag script + * @doc_id painless-execute-api */ export interface Request extends RequestBase { urls: [ @@ -39,15 +47,17 @@ export interface Request extends RequestBase { body: { /** * The context that the script should run in. + * NOTE: Result ordering in the field contexts is not guaranteed. * @server_default painless_test */ - context?: string + context?: PainlessContext /** * Additional parameters for the `context`. + * NOTE: This parameter is required for all contexts except `painless_test`, which is the default if no value is provided for `context`. */ context_setup?: PainlessContextSetup /** - * The Painless script to execute. + * The Painless script to run. */ script?: Script } diff --git a/specification/_global/scripts_painless_execute/examples/request/ExecutePainlessScriptRequestExample1.yaml b/specification/_global/scripts_painless_execute/examples/request/ExecutePainlessScriptRequestExample1.yaml new file mode 100644 index 0000000000..e0590f7a81 --- /dev/null +++ b/specification/_global/scripts_painless_execute/examples/request/ExecutePainlessScriptRequestExample1.yaml @@ -0,0 +1,19 @@ +summary: Test context +# method_request: POST /_scripts/painless/_execute +description: > + Run `POST /_scripts/painless/_execute`. + The `painless_test` context is the default context. + It runs scripts without additional parameters. + The only variable that is available is `params`, which can be used to access user defined values. + The result of the script is always converted to a string. +# type: request +value: |- + { + "script": { + "source": "params.count / params.total", + "params": { + "count": 100.0, + "total": 1000.0 + } + } + } diff --git a/specification/_global/scripts_painless_execute/examples/request/ExecutePainlessScriptRequestExample2.yaml b/specification/_global/scripts_painless_execute/examples/request/ExecutePainlessScriptRequestExample2.yaml new file mode 100644 index 0000000000..2d71c09c80 --- /dev/null +++ b/specification/_global/scripts_painless_execute/examples/request/ExecutePainlessScriptRequestExample2.yaml @@ -0,0 +1,24 @@ +summary: Filter context +# method_request: POST /_scripts/painless/_execute +description: > + Run `POST /_scripts/painless/_execute` with a `filter` context. + It treats scripts as if they were run inside a script query. + For testing purposes, a document must be provided so that it will be temporarily indexed in-memory and is accessible from the script. + More precisely, the `_source`, stored fields, and doc values of such a document are available to the script being tested. +# type: request +value: |- + { + "script": { + "source": "doc['field'].value.length() <= params.max_length", + "params": { + "max_length": 4 + } + }, + "context": "filter", + "context_setup": { + "index": "my-index-000001", + "document": { + "field": "four" + } + } + } diff --git a/specification/_global/scripts_painless_execute/examples/request/ExecutePainlessScriptRequestExample3.yaml b/specification/_global/scripts_painless_execute/examples/request/ExecutePainlessScriptRequestExample3.yaml new file mode 100644 index 0000000000..a6d4585164 --- /dev/null +++ b/specification/_global/scripts_painless_execute/examples/request/ExecutePainlessScriptRequestExample3.yaml @@ -0,0 +1,22 @@ +summary: Score context +# method_request: POST /_scripts/painless/_execute +description: > + Run `POST /_scripts/painless/_execute` with a `score` context. + It treats scripts as if they were run inside a `script_score` function in a `function_score` query. +# type: request +value: |- + { + "script": { + "source": "doc['rank'].value / params.max_rank", + "params": { + "max_rank": 5.0 + } + }, + "context": "score", + "context_setup": { + "index": "my-index-000001", + "document": { + "rank": 4 + } + } + } diff --git a/specification/_global/scripts_painless_execute/examples/response/ExecutePainlessScriptResponseExample1.yaml b/specification/_global/scripts_painless_execute/examples/response/ExecutePainlessScriptResponseExample1.yaml new file mode 100644 index 0000000000..a6f56a374b --- /dev/null +++ b/specification/_global/scripts_painless_execute/examples/response/ExecutePainlessScriptResponseExample1.yaml @@ -0,0 +1,8 @@ +summary: Test context +description: A successful response from `POST /_scripts/painless/_execute` with a `painless_test` context. +# type: response +# response_code: '' +value: |- + { + "result": "0.1" + } diff --git a/specification/_global/scripts_painless_execute/examples/response/ExecutePainlessScriptResponseExample2.yaml b/specification/_global/scripts_painless_execute/examples/response/ExecutePainlessScriptResponseExample2.yaml new file mode 100644 index 0000000000..963705b06f --- /dev/null +++ b/specification/_global/scripts_painless_execute/examples/response/ExecutePainlessScriptResponseExample2.yaml @@ -0,0 +1,8 @@ +summary: Filter context +description: A successful response from `POST /_scripts/painless/_execute` with a `filter` context. +# type: response +# response_code: '' +value: |- + { + "result": true + } diff --git a/specification/_global/scripts_painless_execute/examples/response/ExecutePainlessScriptResponseExample3.yaml b/specification/_global/scripts_painless_execute/examples/response/ExecutePainlessScriptResponseExample3.yaml new file mode 100644 index 0000000000..3dacb2d6cc --- /dev/null +++ b/specification/_global/scripts_painless_execute/examples/response/ExecutePainlessScriptResponseExample3.yaml @@ -0,0 +1,8 @@ +summary: Score context +description: A successful response from `POST /_scripts/painless/_execute` with a `score` context. +# type: response +# response_code: '' +value: |- + { + "result": 0.8 + } diff --git a/specification/_global/scripts_painless_execute/types.ts b/specification/_global/scripts_painless_execute/types.ts index f51d7414b4..3e5e35011c 100644 --- a/specification/_global/scripts_painless_execute/types.ts +++ b/specification/_global/scripts_painless_execute/types.ts @@ -19,17 +19,24 @@ import { UserDefinedValue } from '@spec_utils/UserDefinedValue' import { IndexName } from '@_types/common' -import { integer } from '@_types/Numeric' +import { Ip } from '@_types/Networking' +import { double, integer, long } from '@_types/Numeric' import { QueryContainer } from '@_types/query_dsl/abstractions' +import { DateTime } from '@_types/Time' export class PainlessContextSetup { /** - * Document that’s temporarily indexed in-memory and accessible from the script. + * Document that's temporarily indexed in-memory and accessible from the script. */ document: UserDefinedValue /** - * Index containing a mapping that’s compatible with the indexed document. + * Index containing a mapping that's compatible with the indexed document. * You may specify a remote index by prefixing the index with the remote cluster alias. + * For example, `remote1:my_index` indicates that you want to run the painless script against the "my_index" index on the "remote1" cluster. + * This request will be forwarded to the "remote1" cluster if you have configured a connection to that remote cluster. + * + * NOTE: Wildcards are not accepted in the index expression for this endpoint. + * The expression `*:myindex` will return the error "No such remote cluster" and the expression `logs*` or `remote1:logs*` will return the error "index not found". */ index: IndexName /** @@ -46,3 +53,49 @@ export class PainlessExecutionPosition { start: integer end: integer } + +export enum PainlessContext { + /** The default context if no other context is specified. */ + painless_test, + /** Treats scripts as if they were run inside a script query. */ + filter, + /** Treats scripts as if they were run inside a `script_score` function in a `function_score` query. */ + score, + /** The context for boolean fields. The script returns a `true` or `false` response. */ + boolean_field, + /** The context for date fields. `emit` takes a long value and the script returns a sorted list of dates. */ + date_field, + /** The context for double numeric fields. The script returns a sorted list of double values. */ + double_field, + /** The context for geo-point fields. `emit` takes two double parameters, the latitude and longitude values, and the script returns an object in GeoJSON format containing the coordinates for the geo point. */ + geo_point_field, + /** The context for `ip` fields. The script returns a sorted list of IP addresses. */ + ip_field, + /** The context for keyword fields. The script returns a sorted list of string values. */ + keyword_field, + /** The context for long numeric fields. The script returns a sorted list of long values. */ + long_field, + /** The context for composite runtime fields. The script returns a map of values.*/ + composite_field +} + +export class PainlessScript { + /** + * Accepts the values from the script valuation. + * Scripts can call the `emit` method multiple times to `emit` multiple values. + * The `emit` method applies only to scripts used in a runtime fields context. + * + * IMPORTANT: The emit method cannot accept null values. Do not call this method if the referenced fields do not have any values. + * + * The signature for`emit` depends on the type of the field. For example: + * + * * `boolean`: `emit(boolean)` + * * `date`: `emit(long)` + * * `double`: `emit(double)` + * * `geo_point`: `emit(double lat, double lon)` + * * `ip`: `emit(String)` + * * `long`: `emit(long)` + * * `keyword`: `emit(String)` + */ + emit: boolean | DateTime | double | string | Ip | long +}