From 09649ce64b4e8c00ea64209002fcd3fda8028e71 Mon Sep 17 00:00:00 2001 From: Marci W <333176+marciw@users.noreply.github.com> Date: Fri, 7 Mar 2025 00:21:27 -0500 Subject: [PATCH 01/57] fix external links (#2826) (#2827) (cherry picked from commit 9ac0b0afdf80946135581d086ee9f4603f4af99e) Co-authored-by: Colleen McGinnis --- docs/reference/client-helpers.md | 2 +- docs/reference/connecting.md | 4 ++-- docs/reference/opentelemetry.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/reference/client-helpers.md b/docs/reference/client-helpers.md index 02ab4e026..904d61815 100644 --- a/docs/reference/client-helpers.md +++ b/docs/reference/client-helpers.md @@ -5,7 +5,7 @@ mapped_pages: # Client helpers [client-helpers] -You can find here a collection of simple helper functions that abstract some specifics of the raw API. For detailed examples, refer to [this page](https://elasticsearch-py.readthedocs.io/en/stable/helpers.md). +You can find here a collection of simple helper functions that abstract some specifics of the raw API. For detailed examples, refer to [this page](https://elasticsearch-py.readthedocs.io/en/stable/helpers.html). ## Bulk helpers [bulk-helpers] diff --git a/docs/reference/connecting.md b/docs/reference/connecting.md index aefc50b1f..27f7fecbc 100644 --- a/docs/reference/connecting.md +++ b/docs/reference/connecting.md @@ -352,6 +352,6 @@ def main(request: func.HttpRequest) -> func.HttpResponse: Resources used to assess these recommendations: * [GCP Cloud Functions: Tips & Tricks](https://cloud.google.com/functions/docs/bestpractices/tips#use_global_variables_to_reuse_objects_in_future_invocations) -* [Best practices for working with AWS Lambda functions](https://docs.aws.amazon.com/lambda/latest/dg/best-practices.md) +* [Best practices for working with AWS Lambda functions](https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html) * [Azure Functions Python developer guide](https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-python?tabs=azurecli-linux%2Capplication-level#global-variables) -* [AWS Lambda: Comparing the effect of global scope](https://docs.aws.amazon.com/lambda/latest/operatorguide/global-scope.md) +* [AWS Lambda: Comparing the effect of global scope](https://docs.aws.amazon.com/lambda/latest/operatorguide/global-scope.html) diff --git a/docs/reference/opentelemetry.md b/docs/reference/opentelemetry.md index fb117d505..2b6b1eec2 100644 --- a/docs/reference/opentelemetry.md +++ b/docs/reference/opentelemetry.md @@ -41,7 +41,7 @@ When using the [manual Python OpenTelemetry instrumentation](https://opentelemet ## Comparison with community instrumentation [_comparison_with_community_instrumentation] -The [commmunity OpenTelemetry Elasticsearch instrumentation](https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/elasticsearch/elasticsearch.md) also instruments the client and sends OpenTelemetry traces, but was developed before the OpenTelemetry Semantic Conventions for {{es}}, so the traces attributes are inconsistent with other OpenTelemetry Elasticsearch client instrumentations. To avoid tracing the same requests twice, make sure to use only one instrumentation, either by uninstalling the opentelemetry-instrumentation-elasticsearch Python package or by [disabling the native instrumentation](#opentelemetry-config-enable). +The [commmunity OpenTelemetry Elasticsearch instrumentation](https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/elasticsearch/elasticsearch.html) also instruments the client and sends OpenTelemetry traces, but was developed before the OpenTelemetry Semantic Conventions for {{es}}, so the traces attributes are inconsistent with other OpenTelemetry Elasticsearch client instrumentations. To avoid tracing the same requests twice, make sure to use only one instrumentation, either by uninstalling the opentelemetry-instrumentation-elasticsearch Python package or by [disabling the native instrumentation](#opentelemetry-config-enable). ### Configuring the OpenTelemetry instrumentation [_configuring_the_opentelemetry_instrumentation] From 3910e1ad3057fafba1141a7d8023b545f11de8b0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 7 Mar 2025 10:06:09 +0400 Subject: [PATCH 02/57] Delete docs-preview.yml (#2828) (#2829) (cherry picked from commit b59f2fc926cbc0de618bfef2b53e81e7f4d135ef) Co-authored-by: Marci W <333176+marciw@users.noreply.github.com> --- .github/workflows/docs-preview.yml | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 .github/workflows/docs-preview.yml diff --git a/.github/workflows/docs-preview.yml b/.github/workflows/docs-preview.yml deleted file mode 100644 index 40d7b7208..000000000 --- a/.github/workflows/docs-preview.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: docs-preview - -on: - pull_request_target: - types: [opened] - -permissions: - pull-requests: write - -jobs: - doc-preview-pr: - runs-on: ubuntu-latest - steps: - - uses: elastic/docs/.github/actions/docs-preview@master - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - repo: ${{ github.event.repository.name }} - preview-path: 'guide/en/elasticsearch/client/python-api/index.html' - pr: ${{ github.event.pull_request.number }} From 6eb283e5625d3156dddc2c6d55819ad0e6cb8951 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 7 Mar 2025 10:59:21 +0400 Subject: [PATCH 03/57] Fix logo URL (#2825) (#2830) (cherry picked from commit 922020165c3f3e57571682cce15404ddf22c88eb) Co-authored-by: Quentin Pradet --- README.md | 2 +- docs/images/logo-elastic-glyph-color.svg | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 docs/images/logo-elastic-glyph-color.svg diff --git a/README.md b/README.md index eb242a90c..20b72407d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- Elastic logo + Elastic logo

# Elasticsearch Python Client diff --git a/docs/images/logo-elastic-glyph-color.svg b/docs/images/logo-elastic-glyph-color.svg new file mode 100644 index 000000000..bfc5bfb6a --- /dev/null +++ b/docs/images/logo-elastic-glyph-color.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + From a2cd77bf0db5a3a503516d486a9cf36dc4d8abc7 Mon Sep 17 00:00:00 2001 From: Elastic Machine Date: Mon, 10 Mar 2025 14:10:08 +0100 Subject: [PATCH 04/57] Auto-generated API code (#2838) --- elasticsearch/_async/client/__init__.py | 4 +- elasticsearch/_async/client/connector.py | 4 +- elasticsearch/_async/client/esql.py | 4 +- elasticsearch/_async/client/indices.py | 29 +- elasticsearch/_async/client/inference.py | 440 +++++++++++++++++++---- elasticsearch/_async/client/ingest.py | 6 +- elasticsearch/_async/client/ml.py | 7 +- elasticsearch/_async/client/simulate.py | 10 +- elasticsearch/_sync/client/__init__.py | 4 +- elasticsearch/_sync/client/connector.py | 4 +- elasticsearch/_sync/client/esql.py | 4 +- elasticsearch/_sync/client/indices.py | 29 +- elasticsearch/_sync/client/inference.py | 440 +++++++++++++++++++---- elasticsearch/_sync/client/ingest.py | 6 +- elasticsearch/_sync/client/ml.py | 7 +- elasticsearch/_sync/client/simulate.py | 10 +- elasticsearch/dsl/query.py | 22 ++ elasticsearch/dsl/types.py | 42 +++ 18 files changed, 856 insertions(+), 216 deletions(-) diff --git a/elasticsearch/_async/client/__init__.py b/elasticsearch/_async/client/__init__.py index 98d006405..b0992bd67 100644 --- a/elasticsearch/_async/client/__init__.py +++ b/elasticsearch/_async/client/__init__.py @@ -3114,7 +3114,7 @@ async def knn_search( - ``_ + ``_ :param index: A comma-separated list of index names to search; use `_all` or to perform the operation on all indices. @@ -4446,7 +4446,7 @@ async def scripts_painless_execute(

Each context requires a script, but additional parameters depend on the context you're using for that script.

- ``_ + ``_ :param context: The context that the script should run in. NOTE: Result ordering in the field contexts is not guaranteed. diff --git a/elasticsearch/_async/client/connector.py b/elasticsearch/_async/client/connector.py index debf9e3ce..3a55163bb 100644 --- a/elasticsearch/_async/client/connector.py +++ b/elasticsearch/_async/client/connector.py @@ -1539,7 +1539,7 @@ async def update_filtering_validation(

Update the draft filtering validation info for a connector.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param validation: @@ -1710,7 +1710,7 @@ async def update_native(

Update the connector is_native flag.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param is_native: diff --git a/elasticsearch/_async/client/esql.py b/elasticsearch/_async/client/esql.py index 0df836730..dca7ca2bb 100644 --- a/elasticsearch/_async/client/esql.py +++ b/elasticsearch/_async/client/esql.py @@ -323,7 +323,7 @@ async def async_query_stop( If the Elasticsearch security features are enabled, only the user who first submitted the ES|QL query can stop it.

- ``_ + ``_ :param id: The unique identifier of the query. A query ID is provided in the ES|QL async query API response for a query that does not complete in the @@ -408,7 +408,7 @@ async def query( Get search results for an ES|QL (Elasticsearch query language) query.

- ``_ + ``_ :param query: The ES|QL query API accepts an ES|QL query string in the query parameter, runs it, and returns the results. diff --git a/elasticsearch/_async/client/indices.py b/elasticsearch/_async/client/indices.py index 31ee76bca..ac3f93d8f 100644 --- a/elasticsearch/_async/client/indices.py +++ b/elasticsearch/_async/client/indices.py @@ -265,7 +265,7 @@ async def cancel_migrate_reindex(

Cancel a migration reindex attempt for a data stream or index.

- ``_ + ``_ :param index: The index or data stream name """ @@ -794,7 +794,7 @@ async def create_from(

Copy the mappings and settings from the source index to a destination index while allowing request settings and mappings to override the source values.

- ``_ + ``_ :param source: The source index or data stream name :param dest: The destination index or data stream name @@ -2487,6 +2487,7 @@ async def get_field_mapping( human: t.Optional[bool] = None, ignore_unavailable: t.Optional[bool] = None, include_defaults: t.Optional[bool] = None, + local: t.Optional[bool] = None, pretty: t.Optional[bool] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -2515,6 +2516,8 @@ async def get_field_mapping( :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param include_defaults: If `true`, return all default settings in the response. + :param local: If `true`, the request retrieves information from the local node + only. """ if fields in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'fields'") @@ -2542,6 +2545,8 @@ async def get_field_mapping( __query["ignore_unavailable"] = ignore_unavailable if include_defaults is not None: __query["include_defaults"] = include_defaults + if local is not None: + __query["local"] = local if pretty is not None: __query["pretty"] = pretty __headers = {"accept": "application/json"} @@ -2726,7 +2731,7 @@ async def get_migrate_reindex_status(

Get the status of a migration reindex attempt for a data stream or index.

- ``_ + ``_ :param index: The index or data stream name. """ @@ -2945,7 +2950,7 @@ async def migrate_reindex( The persistent task ID is returned immediately and the reindexing work is completed in that task.

- ``_ + ``_ :param reindex: """ @@ -3006,7 +3011,7 @@ async def migrate_to_data_stream( The write index for the alias becomes the write index for the stream.

- ``_ + ``_ :param name: Name of the index alias to convert to a data stream. :param master_timeout: Period to wait for a connection to the master node. If @@ -3062,7 +3067,7 @@ async def modify_data_stream( Performs one or more data stream modification actions in a single atomic operation.

- ``_ + ``_ :param actions: Actions to perform. """ @@ -3227,7 +3232,7 @@ async def promote_data_stream( This will affect the lifecycle management of the data stream and interfere with the data stream size and retention.

- ``_ + ``_ :param name: The name of the data stream :param master_timeout: Period to wait for a connection to the master node. If @@ -3293,7 +3298,7 @@ async def put_alias( Adds a data stream or index to an alias.

- ``_ + ``_ :param index: Comma-separated list of data streams or indices to add. Supports wildcards (`*`). Wildcard patterns that match both data streams and indices @@ -3400,7 +3405,7 @@ async def put_data_lifecycle( Update the data stream lifecycle of the specified data streams.

- ``_ + ``_ :param name: Comma-separated list of data streams used to limit the request. Supports wildcards (`*`). To target all data streams use `*` or `_all`. @@ -3528,7 +3533,7 @@ async def put_index_template( If an entry already exists with the same key, then it is overwritten by the new definition.

- ``_ + ``_ :param name: Index or template name :param allow_auto_create: This setting overrides the value of the `action.auto_create_index` @@ -5372,7 +5377,7 @@ async def update_aliases( Adds a data stream or index to an alias.

- ``_ + ``_ :param actions: Actions to perform. :param master_timeout: Period to wait for a connection to the master node. If @@ -5451,7 +5456,7 @@ async def validate_query( Validates a query without running it.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases to search. Supports wildcards (`*`). To search all data streams or indices, omit this diff --git a/elasticsearch/_async/client/inference.py b/elasticsearch/_async/client/inference.py index 54dd0d32b..e685d1c5c 100644 --- a/elasticsearch/_async/client/inference.py +++ b/elasticsearch/_async/client/inference.py @@ -25,6 +25,74 @@ class InferenceClient(NamespacedClient): + @_rewrite_parameters( + body_fields=("input", "task_settings"), + ) + async def completion( + self, + *, + inference_id: str, + input: t.Optional[t.Union[str, t.Sequence[str]]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Any] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Perform completion inference on the service

+ + + ``_ + + :param inference_id: The inference Id + :param input: Inference input. Either a string or an array of strings. + :param task_settings: Optional task settings + :param timeout: Specifies the amount of time to wait for the inference request + to complete. + """ + if inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'inference_id'") + if input is None and body is None: + raise ValueError("Empty value passed for parameter 'input'") + __path_parts: t.Dict[str, str] = {"inference_id": _quote(inference_id)} + __path = f'/_inference/completion/{__path_parts["inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout + if not __body: + if input is not None: + __body["input"] = input + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "POST", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.completion", + path_parts=__path_parts, + ) + @_rewrite_parameters() async def delete( self, @@ -33,7 +101,13 @@ async def delete( task_type: t.Optional[ t.Union[ str, - t.Literal["completion", "rerank", "sparse_embedding", "text_embedding"], + t.Literal[ + "chat_completion", + "completion", + "rerank", + "sparse_embedding", + "text_embedding", + ], ] ] = None, dry_run: t.Optional[bool] = None, @@ -102,7 +176,13 @@ async def get( task_type: t.Optional[ t.Union[ str, - t.Literal["completion", "rerank", "sparse_embedding", "text_embedding"], + t.Literal[ + "chat_completion", + "completion", + "rerank", + "sparse_embedding", + "text_embedding", + ], ] ] = None, inference_id: t.Optional[str] = None, @@ -155,24 +235,188 @@ async def get( ) @_rewrite_parameters( - body_fields=("input", "query", "task_settings"), + body_name="inference_config", ) - async def inference( + async def put( self, *, inference_id: str, - input: t.Optional[t.Union[str, t.Sequence[str]]] = None, + inference_config: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Mapping[str, t.Any]] = None, task_type: t.Optional[ t.Union[ str, - t.Literal["completion", "rerank", "sparse_embedding", "text_embedding"], + t.Literal[ + "chat_completion", + "completion", + "rerank", + "sparse_embedding", + "text_embedding", + ], ] ] = None, error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an inference endpoint. + When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+

IMPORTANT: The inference APIs enable you to use certain services, such as built-in machine learning models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Mistral, Azure OpenAI, Google AI Studio, Google Vertex AI, Anthropic, Watsonx.ai, or Hugging Face. + For built-in models and models uploaded through Eland, the inference APIs offer an alternative way to use and manage trained models. + However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.

+ + + ``_ + + :param inference_id: The inference Id + :param inference_config: + :param task_type: The task type + """ + if inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'inference_id'") + if inference_config is None and body is None: + raise ValueError( + "Empty value passed for parameters 'inference_config' and 'body', one of them should be set." + ) + elif inference_config is not None and body is not None: + raise ValueError("Cannot set both 'inference_config' and 'body'") + __path_parts: t.Dict[str, str] + if task_type not in SKIP_IN_PATH and inference_id not in SKIP_IN_PATH: + __path_parts = { + "task_type": _quote(task_type), + "inference_id": _quote(inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["inference_id"]}' + elif inference_id not in SKIP_IN_PATH: + __path_parts = {"inference_id": _quote(inference_id)} + __path = f'/_inference/{__path_parts["inference_id"]}' + else: + raise ValueError("Couldn't find a path for the given parameters") + __query: t.Dict[str, t.Any] = {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + __body = inference_config if inference_config is not None else body + __headers = {"accept": "application/json", "content-type": "application/json"} + return await self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=("service", "service_settings"), + ) + async def put_watsonx( + self, + *, + task_type: t.Union[str, t.Literal["text_embedding"]], + watsonx_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["watsonxai"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create a Watsonx inference endpoint.

+

Creates an inference endpoint to perform an inference task with the watsonxai service. + You need an IBM Cloud Databases for Elasticsearch deployment to use the watsonxai inference service. + You can provision one through the IBM catalog, the Cloud Databases CLI plug-in, the Cloud Databases API, or Terraform.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The task type. The only valid task type for the model to perform + is `text_embedding`. + :param watsonx_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `watsonxai`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `watsonxai` service. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if watsonx_inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'watsonx_inference_id'") + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "watsonx_inference_id": _quote(watsonx_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["watsonx_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_watsonx", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=("input", "query", "task_settings"), + ) + async def rerank( + self, + *, + inference_id: str, + input: t.Optional[t.Union[str, t.Sequence[str]]] = None, query: t.Optional[str] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Any] = None, timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, @@ -180,14 +424,7 @@ async def inference( """ .. raw:: html -

Perform inference on the service.

-

This API enables you to use machine learning models to perform specific tasks on data that you provide as an input. - It returns a response with the results of the tasks. - The inference endpoint you use can perform one specific task that has been defined when the endpoint was created with the create inference API.

-
-

info - The inference APIs enable you to use certain services, such as built-in machine learning models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Azure, Google AI Studio, Google Vertex AI, Anthropic, Watsonx.ai, or Hugging Face. For built-in models and models uploaded through Eland, the inference APIs offer an alternative way to use and manage trained models. However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.

-
+

Perform rereanking inference on the service

``_ @@ -196,9 +433,7 @@ async def inference( :param input: The text on which you want to perform the inference task. It can be a single string or an array. > info > Inference endpoints for the `completion` task type currently only support a single string as input. - :param task_type: The type of inference task that the model performs. - :param query: The query input, which is required only for the `rerank` task. - It is not required for other tasks. + :param query: Query input. :param task_settings: Task settings for the individual inference request. These settings are specific to the task type you specified and override the task settings specified when initializing the service. @@ -208,18 +443,10 @@ async def inference( raise ValueError("Empty value passed for parameter 'inference_id'") if input is None and body is None: raise ValueError("Empty value passed for parameter 'input'") - __path_parts: t.Dict[str, str] - if task_type not in SKIP_IN_PATH and inference_id not in SKIP_IN_PATH: - __path_parts = { - "task_type": _quote(task_type), - "inference_id": _quote(inference_id), - } - __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["inference_id"]}' - elif inference_id not in SKIP_IN_PATH: - __path_parts = {"inference_id": _quote(inference_id)} - __path = f'/_inference/{__path_parts["inference_id"]}' - else: - raise ValueError("Couldn't find a path for the given parameters") + if query is None and body is None: + raise ValueError("Empty value passed for parameter 'query'") + __path_parts: t.Dict[str, str] = {"inference_id": _quote(inference_id)} + __path = f'/_inference/rerank/{__path_parts["inference_id"]}' __query: t.Dict[str, t.Any] = {} __body: t.Dict[str, t.Any] = body if body is not None else {} if error_trace is not None: @@ -250,71 +477,48 @@ async def inference( params=__query, headers=__headers, body=__body, - endpoint_id="inference.inference", + endpoint_id="inference.rerank", path_parts=__path_parts, ) @_rewrite_parameters( - body_name="inference_config", + body_fields=("input", "task_settings"), ) - async def put( + async def sparse_embedding( self, *, inference_id: str, - inference_config: t.Optional[t.Mapping[str, t.Any]] = None, - body: t.Optional[t.Mapping[str, t.Any]] = None, - task_type: t.Optional[ - t.Union[ - str, - t.Literal["completion", "rerank", "sparse_embedding", "text_embedding"], - ] - ] = None, + input: t.Optional[t.Union[str, t.Sequence[str]]] = None, error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Any] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ .. raw:: html -

Create an inference endpoint. - When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

-

IMPORTANT: The inference APIs enable you to use certain services, such as built-in machine learning models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Mistral, Azure OpenAI, Google AI Studio, Google Vertex AI, Anthropic, Watsonx.ai, or Hugging Face. - For built-in models and models uploaded through Eland, the inference APIs offer an alternative way to use and manage trained models. - However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.

+

Perform sparse embedding inference on the service

- ``_ + ``_ :param inference_id: The inference Id - :param inference_config: - :param task_type: The task type + :param input: Inference input. Either a string or an array of strings. + :param task_settings: Optional task settings + :param timeout: Specifies the amount of time to wait for the inference request + to complete. """ if inference_id in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'inference_id'") - if inference_config is None and body is None: - raise ValueError( - "Empty value passed for parameters 'inference_config' and 'body', one of them should be set." - ) - elif inference_config is not None and body is not None: - raise ValueError("Cannot set both 'inference_config' and 'body'") - __path_parts: t.Dict[str, str] - if task_type not in SKIP_IN_PATH and inference_id not in SKIP_IN_PATH: - __path_parts = { - "task_type": _quote(task_type), - "inference_id": _quote(inference_id), - } - __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["inference_id"]}' - elif inference_id not in SKIP_IN_PATH: - __path_parts = {"inference_id": _quote(inference_id)} - __path = f'/_inference/{__path_parts["inference_id"]}' - else: - raise ValueError("Couldn't find a path for the given parameters") + if input is None and body is None: + raise ValueError("Empty value passed for parameter 'input'") + __path_parts: t.Dict[str, str] = {"inference_id": _quote(inference_id)} + __path = f'/_inference/sparse_embedding/{__path_parts["inference_id"]}' __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} if error_trace is not None: __query["error_trace"] = error_trace if filter_path is not None: @@ -323,15 +527,93 @@ async def put( __query["human"] = human if pretty is not None: __query["pretty"] = pretty - __body = inference_config if inference_config is not None else body - __headers = {"accept": "application/json", "content-type": "application/json"} + if timeout is not None: + __query["timeout"] = timeout + if not __body: + if input is not None: + __body["input"] = input + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" return await self.perform_request( # type: ignore[return-value] - "PUT", + "POST", __path, params=__query, headers=__headers, body=__body, - endpoint_id="inference.put", + endpoint_id="inference.sparse_embedding", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=("input", "task_settings"), + ) + async def text_embedding( + self, + *, + inference_id: str, + input: t.Optional[t.Union[str, t.Sequence[str]]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Any] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Perform text embedding inference on the service

+ + + ``_ + + :param inference_id: The inference Id + :param input: Inference input. Either a string or an array of strings. + :param task_settings: Optional task settings + :param timeout: Specifies the amount of time to wait for the inference request + to complete. + """ + if inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'inference_id'") + if input is None and body is None: + raise ValueError("Empty value passed for parameter 'input'") + __path_parts: t.Dict[str, str] = {"inference_id": _quote(inference_id)} + __path = f'/_inference/text_embedding/{__path_parts["inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout + if not __body: + if input is not None: + __body["input"] = input + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "POST", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.text_embedding", path_parts=__path_parts, ) @@ -347,7 +629,13 @@ async def update( task_type: t.Optional[ t.Union[ str, - t.Literal["completion", "rerank", "sparse_embedding", "text_embedding"], + t.Literal[ + "chat_completion", + "completion", + "rerank", + "sparse_embedding", + "text_embedding", + ], ] ] = None, error_trace: t.Optional[bool] = None, @@ -403,7 +691,7 @@ async def update( __body = inference_config if inference_config is not None else body __headers = {"accept": "application/json", "content-type": "application/json"} return await self.perform_request( # type: ignore[return-value] - "POST", + "PUT", __path, params=__query, headers=__headers, diff --git a/elasticsearch/_async/client/ingest.py b/elasticsearch/_async/client/ingest.py index 1cf0cfe1b..27a0f09f3 100644 --- a/elasticsearch/_async/client/ingest.py +++ b/elasticsearch/_async/client/ingest.py @@ -208,7 +208,7 @@ async def geo_ip_stats( Get download statistics for GeoIP2 databases that are used with the GeoIP processor.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_ingest/geoip/stats" @@ -412,7 +412,7 @@ async def processor_grok( A grok pattern is like a regular expression that supports aliased expressions that can be reused.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_ingest/processor/grok" @@ -620,7 +620,7 @@ async def put_pipeline( Changes made using this API take effect immediately.

- ``_ + ``_ :param id: ID of the ingest pipeline to create or update. :param deprecated: Marks this ingest pipeline as deprecated. When a deprecated diff --git a/elasticsearch/_async/client/ml.py b/elasticsearch/_async/client/ml.py index 80bc46565..6599c0923 100644 --- a/elasticsearch/_async/client/ml.py +++ b/elasticsearch/_async/client/ml.py @@ -2616,7 +2616,6 @@ async def get_trained_models( ], ] ] = None, - include_model_definition: t.Optional[bool] = None, pretty: t.Optional[bool] = None, size: t.Optional[int] = None, tags: t.Optional[t.Union[str, t.Sequence[str]]] = None, @@ -2646,8 +2645,6 @@ async def get_trained_models( :param from_: Skips the specified number of models. :param include: A comma delimited string of optional fields to include in the response body. - :param include_model_definition: parameter is deprecated! Use [include=definition] - instead :param size: Specifies the maximum number of models to obtain. :param tags: A comma delimited string of tags. A trained model can have many tags, or none. When supplied, only trained models that contain all the supplied @@ -2677,8 +2674,6 @@ async def get_trained_models( __query["human"] = human if include is not None: __query["include"] = include - if include_model_definition is not None: - __query["include_model_definition"] = include_model_definition if pretty is not None: __query["pretty"] = pretty if size is not None: @@ -5733,7 +5728,7 @@ async def validate(

Validate an anomaly detection job.

- ``_ + ``_ :param analysis_config: :param analysis_limits: diff --git a/elasticsearch/_async/client/simulate.py b/elasticsearch/_async/client/simulate.py index 3c3d33288..bb636ddb6 100644 --- a/elasticsearch/_async/client/simulate.py +++ b/elasticsearch/_async/client/simulate.py @@ -35,7 +35,7 @@ class SimulateClient(NamespacedClient): body_fields=( "docs", "component_template_substitutions", - "index_template_subtitutions", + "index_template_substitutions", "mapping_addition", "pipeline_substitutions", ), @@ -52,7 +52,7 @@ async def ingest( error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, - index_template_subtitutions: t.Optional[ + index_template_substitutions: t.Optional[ t.Mapping[str, t.Mapping[str, t.Any]] ] = None, mapping_addition: t.Optional[t.Mapping[str, t.Any]] = None, @@ -90,7 +90,7 @@ async def ingest( an index argument. :param component_template_substitutions: A map of component template names to substitute component template definition objects. - :param index_template_subtitutions: A map of index template names to substitute + :param index_template_substitutions: A map of index template names to substitute index template definition objects. :param mapping_addition: :param pipeline: The pipeline to use as the default pipeline. This value can @@ -127,8 +127,8 @@ async def ingest( __body["component_template_substitutions"] = ( component_template_substitutions ) - if index_template_subtitutions is not None: - __body["index_template_subtitutions"] = index_template_subtitutions + if index_template_substitutions is not None: + __body["index_template_substitutions"] = index_template_substitutions if mapping_addition is not None: __body["mapping_addition"] = mapping_addition if pipeline_substitutions is not None: diff --git a/elasticsearch/_sync/client/__init__.py b/elasticsearch/_sync/client/__init__.py index 6d9131995..32d736192 100644 --- a/elasticsearch/_sync/client/__init__.py +++ b/elasticsearch/_sync/client/__init__.py @@ -3112,7 +3112,7 @@ def knn_search( - ``_ + ``_ :param index: A comma-separated list of index names to search; use `_all` or to perform the operation on all indices. @@ -4444,7 +4444,7 @@ def scripts_painless_execute(

Each context requires a script, but additional parameters depend on the context you're using for that script.

- ``_ + ``_ :param context: The context that the script should run in. NOTE: Result ordering in the field contexts is not guaranteed. diff --git a/elasticsearch/_sync/client/connector.py b/elasticsearch/_sync/client/connector.py index fc9b193a1..fe2b931da 100644 --- a/elasticsearch/_sync/client/connector.py +++ b/elasticsearch/_sync/client/connector.py @@ -1539,7 +1539,7 @@ def update_filtering_validation(

Update the draft filtering validation info for a connector.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param validation: @@ -1710,7 +1710,7 @@ def update_native(

Update the connector is_native flag.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param is_native: diff --git a/elasticsearch/_sync/client/esql.py b/elasticsearch/_sync/client/esql.py index ce9a3a838..7d29224a9 100644 --- a/elasticsearch/_sync/client/esql.py +++ b/elasticsearch/_sync/client/esql.py @@ -323,7 +323,7 @@ def async_query_stop( If the Elasticsearch security features are enabled, only the user who first submitted the ES|QL query can stop it.

- ``_ + ``_ :param id: The unique identifier of the query. A query ID is provided in the ES|QL async query API response for a query that does not complete in the @@ -408,7 +408,7 @@ def query( Get search results for an ES|QL (Elasticsearch query language) query.

- ``_ + ``_ :param query: The ES|QL query API accepts an ES|QL query string in the query parameter, runs it, and returns the results. diff --git a/elasticsearch/_sync/client/indices.py b/elasticsearch/_sync/client/indices.py index 4d502f1af..939eeaf29 100644 --- a/elasticsearch/_sync/client/indices.py +++ b/elasticsearch/_sync/client/indices.py @@ -265,7 +265,7 @@ def cancel_migrate_reindex(

Cancel a migration reindex attempt for a data stream or index.

- ``_ + ``_ :param index: The index or data stream name """ @@ -794,7 +794,7 @@ def create_from(

Copy the mappings and settings from the source index to a destination index while allowing request settings and mappings to override the source values.

- ``_ + ``_ :param source: The source index or data stream name :param dest: The destination index or data stream name @@ -2487,6 +2487,7 @@ def get_field_mapping( human: t.Optional[bool] = None, ignore_unavailable: t.Optional[bool] = None, include_defaults: t.Optional[bool] = None, + local: t.Optional[bool] = None, pretty: t.Optional[bool] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -2515,6 +2516,8 @@ def get_field_mapping( :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param include_defaults: If `true`, return all default settings in the response. + :param local: If `true`, the request retrieves information from the local node + only. """ if fields in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'fields'") @@ -2542,6 +2545,8 @@ def get_field_mapping( __query["ignore_unavailable"] = ignore_unavailable if include_defaults is not None: __query["include_defaults"] = include_defaults + if local is not None: + __query["local"] = local if pretty is not None: __query["pretty"] = pretty __headers = {"accept": "application/json"} @@ -2726,7 +2731,7 @@ def get_migrate_reindex_status(

Get the status of a migration reindex attempt for a data stream or index.

- ``_ + ``_ :param index: The index or data stream name. """ @@ -2945,7 +2950,7 @@ def migrate_reindex( The persistent task ID is returned immediately and the reindexing work is completed in that task.

- ``_ + ``_ :param reindex: """ @@ -3006,7 +3011,7 @@ def migrate_to_data_stream( The write index for the alias becomes the write index for the stream.

- ``_ + ``_ :param name: Name of the index alias to convert to a data stream. :param master_timeout: Period to wait for a connection to the master node. If @@ -3062,7 +3067,7 @@ def modify_data_stream( Performs one or more data stream modification actions in a single atomic operation.

- ``_ + ``_ :param actions: Actions to perform. """ @@ -3227,7 +3232,7 @@ def promote_data_stream( This will affect the lifecycle management of the data stream and interfere with the data stream size and retention.

- ``_ + ``_ :param name: The name of the data stream :param master_timeout: Period to wait for a connection to the master node. If @@ -3293,7 +3298,7 @@ def put_alias( Adds a data stream or index to an alias.

- ``_ + ``_ :param index: Comma-separated list of data streams or indices to add. Supports wildcards (`*`). Wildcard patterns that match both data streams and indices @@ -3400,7 +3405,7 @@ def put_data_lifecycle( Update the data stream lifecycle of the specified data streams.

- ``_ + ``_ :param name: Comma-separated list of data streams used to limit the request. Supports wildcards (`*`). To target all data streams use `*` or `_all`. @@ -3528,7 +3533,7 @@ def put_index_template( If an entry already exists with the same key, then it is overwritten by the new definition.

- ``_ + ``_ :param name: Index or template name :param allow_auto_create: This setting overrides the value of the `action.auto_create_index` @@ -5372,7 +5377,7 @@ def update_aliases( Adds a data stream or index to an alias.

- ``_ + ``_ :param actions: Actions to perform. :param master_timeout: Period to wait for a connection to the master node. If @@ -5451,7 +5456,7 @@ def validate_query( Validates a query without running it.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases to search. Supports wildcards (`*`). To search all data streams or indices, omit this diff --git a/elasticsearch/_sync/client/inference.py b/elasticsearch/_sync/client/inference.py index 911a8a530..2ae2b637d 100644 --- a/elasticsearch/_sync/client/inference.py +++ b/elasticsearch/_sync/client/inference.py @@ -25,6 +25,74 @@ class InferenceClient(NamespacedClient): + @_rewrite_parameters( + body_fields=("input", "task_settings"), + ) + def completion( + self, + *, + inference_id: str, + input: t.Optional[t.Union[str, t.Sequence[str]]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Any] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Perform completion inference on the service

+ + + ``_ + + :param inference_id: The inference Id + :param input: Inference input. Either a string or an array of strings. + :param task_settings: Optional task settings + :param timeout: Specifies the amount of time to wait for the inference request + to complete. + """ + if inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'inference_id'") + if input is None and body is None: + raise ValueError("Empty value passed for parameter 'input'") + __path_parts: t.Dict[str, str] = {"inference_id": _quote(inference_id)} + __path = f'/_inference/completion/{__path_parts["inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout + if not __body: + if input is not None: + __body["input"] = input + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "POST", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.completion", + path_parts=__path_parts, + ) + @_rewrite_parameters() def delete( self, @@ -33,7 +101,13 @@ def delete( task_type: t.Optional[ t.Union[ str, - t.Literal["completion", "rerank", "sparse_embedding", "text_embedding"], + t.Literal[ + "chat_completion", + "completion", + "rerank", + "sparse_embedding", + "text_embedding", + ], ] ] = None, dry_run: t.Optional[bool] = None, @@ -102,7 +176,13 @@ def get( task_type: t.Optional[ t.Union[ str, - t.Literal["completion", "rerank", "sparse_embedding", "text_embedding"], + t.Literal[ + "chat_completion", + "completion", + "rerank", + "sparse_embedding", + "text_embedding", + ], ] ] = None, inference_id: t.Optional[str] = None, @@ -155,24 +235,188 @@ def get( ) @_rewrite_parameters( - body_fields=("input", "query", "task_settings"), + body_name="inference_config", ) - def inference( + def put( self, *, inference_id: str, - input: t.Optional[t.Union[str, t.Sequence[str]]] = None, + inference_config: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Mapping[str, t.Any]] = None, task_type: t.Optional[ t.Union[ str, - t.Literal["completion", "rerank", "sparse_embedding", "text_embedding"], + t.Literal[ + "chat_completion", + "completion", + "rerank", + "sparse_embedding", + "text_embedding", + ], ] ] = None, error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an inference endpoint. + When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+

IMPORTANT: The inference APIs enable you to use certain services, such as built-in machine learning models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Mistral, Azure OpenAI, Google AI Studio, Google Vertex AI, Anthropic, Watsonx.ai, or Hugging Face. + For built-in models and models uploaded through Eland, the inference APIs offer an alternative way to use and manage trained models. + However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.

+ + + ``_ + + :param inference_id: The inference Id + :param inference_config: + :param task_type: The task type + """ + if inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'inference_id'") + if inference_config is None and body is None: + raise ValueError( + "Empty value passed for parameters 'inference_config' and 'body', one of them should be set." + ) + elif inference_config is not None and body is not None: + raise ValueError("Cannot set both 'inference_config' and 'body'") + __path_parts: t.Dict[str, str] + if task_type not in SKIP_IN_PATH and inference_id not in SKIP_IN_PATH: + __path_parts = { + "task_type": _quote(task_type), + "inference_id": _quote(inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["inference_id"]}' + elif inference_id not in SKIP_IN_PATH: + __path_parts = {"inference_id": _quote(inference_id)} + __path = f'/_inference/{__path_parts["inference_id"]}' + else: + raise ValueError("Couldn't find a path for the given parameters") + __query: t.Dict[str, t.Any] = {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + __body = inference_config if inference_config is not None else body + __headers = {"accept": "application/json", "content-type": "application/json"} + return self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=("service", "service_settings"), + ) + def put_watsonx( + self, + *, + task_type: t.Union[str, t.Literal["text_embedding"]], + watsonx_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["watsonxai"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create a Watsonx inference endpoint.

+

Creates an inference endpoint to perform an inference task with the watsonxai service. + You need an IBM Cloud Databases for Elasticsearch deployment to use the watsonxai inference service. + You can provision one through the IBM catalog, the Cloud Databases CLI plug-in, the Cloud Databases API, or Terraform.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The task type. The only valid task type for the model to perform + is `text_embedding`. + :param watsonx_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `watsonxai`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `watsonxai` service. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if watsonx_inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'watsonx_inference_id'") + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "watsonx_inference_id": _quote(watsonx_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["watsonx_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_watsonx", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=("input", "query", "task_settings"), + ) + def rerank( + self, + *, + inference_id: str, + input: t.Optional[t.Union[str, t.Sequence[str]]] = None, query: t.Optional[str] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Any] = None, timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, @@ -180,14 +424,7 @@ def inference( """ .. raw:: html -

Perform inference on the service.

-

This API enables you to use machine learning models to perform specific tasks on data that you provide as an input. - It returns a response with the results of the tasks. - The inference endpoint you use can perform one specific task that has been defined when the endpoint was created with the create inference API.

-
-

info - The inference APIs enable you to use certain services, such as built-in machine learning models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Azure, Google AI Studio, Google Vertex AI, Anthropic, Watsonx.ai, or Hugging Face. For built-in models and models uploaded through Eland, the inference APIs offer an alternative way to use and manage trained models. However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.

-
+

Perform rereanking inference on the service

``_ @@ -196,9 +433,7 @@ def inference( :param input: The text on which you want to perform the inference task. It can be a single string or an array. > info > Inference endpoints for the `completion` task type currently only support a single string as input. - :param task_type: The type of inference task that the model performs. - :param query: The query input, which is required only for the `rerank` task. - It is not required for other tasks. + :param query: Query input. :param task_settings: Task settings for the individual inference request. These settings are specific to the task type you specified and override the task settings specified when initializing the service. @@ -208,18 +443,10 @@ def inference( raise ValueError("Empty value passed for parameter 'inference_id'") if input is None and body is None: raise ValueError("Empty value passed for parameter 'input'") - __path_parts: t.Dict[str, str] - if task_type not in SKIP_IN_PATH and inference_id not in SKIP_IN_PATH: - __path_parts = { - "task_type": _quote(task_type), - "inference_id": _quote(inference_id), - } - __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["inference_id"]}' - elif inference_id not in SKIP_IN_PATH: - __path_parts = {"inference_id": _quote(inference_id)} - __path = f'/_inference/{__path_parts["inference_id"]}' - else: - raise ValueError("Couldn't find a path for the given parameters") + if query is None and body is None: + raise ValueError("Empty value passed for parameter 'query'") + __path_parts: t.Dict[str, str] = {"inference_id": _quote(inference_id)} + __path = f'/_inference/rerank/{__path_parts["inference_id"]}' __query: t.Dict[str, t.Any] = {} __body: t.Dict[str, t.Any] = body if body is not None else {} if error_trace is not None: @@ -250,71 +477,48 @@ def inference( params=__query, headers=__headers, body=__body, - endpoint_id="inference.inference", + endpoint_id="inference.rerank", path_parts=__path_parts, ) @_rewrite_parameters( - body_name="inference_config", + body_fields=("input", "task_settings"), ) - def put( + def sparse_embedding( self, *, inference_id: str, - inference_config: t.Optional[t.Mapping[str, t.Any]] = None, - body: t.Optional[t.Mapping[str, t.Any]] = None, - task_type: t.Optional[ - t.Union[ - str, - t.Literal["completion", "rerank", "sparse_embedding", "text_embedding"], - ] - ] = None, + input: t.Optional[t.Union[str, t.Sequence[str]]] = None, error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Any] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ .. raw:: html -

Create an inference endpoint. - When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

-

IMPORTANT: The inference APIs enable you to use certain services, such as built-in machine learning models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Mistral, Azure OpenAI, Google AI Studio, Google Vertex AI, Anthropic, Watsonx.ai, or Hugging Face. - For built-in models and models uploaded through Eland, the inference APIs offer an alternative way to use and manage trained models. - However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.

+

Perform sparse embedding inference on the service

- ``_ + ``_ :param inference_id: The inference Id - :param inference_config: - :param task_type: The task type + :param input: Inference input. Either a string or an array of strings. + :param task_settings: Optional task settings + :param timeout: Specifies the amount of time to wait for the inference request + to complete. """ if inference_id in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'inference_id'") - if inference_config is None and body is None: - raise ValueError( - "Empty value passed for parameters 'inference_config' and 'body', one of them should be set." - ) - elif inference_config is not None and body is not None: - raise ValueError("Cannot set both 'inference_config' and 'body'") - __path_parts: t.Dict[str, str] - if task_type not in SKIP_IN_PATH and inference_id not in SKIP_IN_PATH: - __path_parts = { - "task_type": _quote(task_type), - "inference_id": _quote(inference_id), - } - __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["inference_id"]}' - elif inference_id not in SKIP_IN_PATH: - __path_parts = {"inference_id": _quote(inference_id)} - __path = f'/_inference/{__path_parts["inference_id"]}' - else: - raise ValueError("Couldn't find a path for the given parameters") + if input is None and body is None: + raise ValueError("Empty value passed for parameter 'input'") + __path_parts: t.Dict[str, str] = {"inference_id": _quote(inference_id)} + __path = f'/_inference/sparse_embedding/{__path_parts["inference_id"]}' __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} if error_trace is not None: __query["error_trace"] = error_trace if filter_path is not None: @@ -323,15 +527,93 @@ def put( __query["human"] = human if pretty is not None: __query["pretty"] = pretty - __body = inference_config if inference_config is not None else body - __headers = {"accept": "application/json", "content-type": "application/json"} + if timeout is not None: + __query["timeout"] = timeout + if not __body: + if input is not None: + __body["input"] = input + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" return self.perform_request( # type: ignore[return-value] - "PUT", + "POST", __path, params=__query, headers=__headers, body=__body, - endpoint_id="inference.put", + endpoint_id="inference.sparse_embedding", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=("input", "task_settings"), + ) + def text_embedding( + self, + *, + inference_id: str, + input: t.Optional[t.Union[str, t.Sequence[str]]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Any] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Perform text embedding inference on the service

+ + + ``_ + + :param inference_id: The inference Id + :param input: Inference input. Either a string or an array of strings. + :param task_settings: Optional task settings + :param timeout: Specifies the amount of time to wait for the inference request + to complete. + """ + if inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'inference_id'") + if input is None and body is None: + raise ValueError("Empty value passed for parameter 'input'") + __path_parts: t.Dict[str, str] = {"inference_id": _quote(inference_id)} + __path = f'/_inference/text_embedding/{__path_parts["inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout + if not __body: + if input is not None: + __body["input"] = input + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "POST", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.text_embedding", path_parts=__path_parts, ) @@ -347,7 +629,13 @@ def update( task_type: t.Optional[ t.Union[ str, - t.Literal["completion", "rerank", "sparse_embedding", "text_embedding"], + t.Literal[ + "chat_completion", + "completion", + "rerank", + "sparse_embedding", + "text_embedding", + ], ] ] = None, error_trace: t.Optional[bool] = None, @@ -403,7 +691,7 @@ def update( __body = inference_config if inference_config is not None else body __headers = {"accept": "application/json", "content-type": "application/json"} return self.perform_request( # type: ignore[return-value] - "POST", + "PUT", __path, params=__query, headers=__headers, diff --git a/elasticsearch/_sync/client/ingest.py b/elasticsearch/_sync/client/ingest.py index 2a1b0463d..3a66284e9 100644 --- a/elasticsearch/_sync/client/ingest.py +++ b/elasticsearch/_sync/client/ingest.py @@ -208,7 +208,7 @@ def geo_ip_stats( Get download statistics for GeoIP2 databases that are used with the GeoIP processor.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_ingest/geoip/stats" @@ -412,7 +412,7 @@ def processor_grok( A grok pattern is like a regular expression that supports aliased expressions that can be reused.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_ingest/processor/grok" @@ -620,7 +620,7 @@ def put_pipeline( Changes made using this API take effect immediately.

- ``_ + ``_ :param id: ID of the ingest pipeline to create or update. :param deprecated: Marks this ingest pipeline as deprecated. When a deprecated diff --git a/elasticsearch/_sync/client/ml.py b/elasticsearch/_sync/client/ml.py index 32c00028f..3713ff741 100644 --- a/elasticsearch/_sync/client/ml.py +++ b/elasticsearch/_sync/client/ml.py @@ -2616,7 +2616,6 @@ def get_trained_models( ], ] ] = None, - include_model_definition: t.Optional[bool] = None, pretty: t.Optional[bool] = None, size: t.Optional[int] = None, tags: t.Optional[t.Union[str, t.Sequence[str]]] = None, @@ -2646,8 +2645,6 @@ def get_trained_models( :param from_: Skips the specified number of models. :param include: A comma delimited string of optional fields to include in the response body. - :param include_model_definition: parameter is deprecated! Use [include=definition] - instead :param size: Specifies the maximum number of models to obtain. :param tags: A comma delimited string of tags. A trained model can have many tags, or none. When supplied, only trained models that contain all the supplied @@ -2677,8 +2674,6 @@ def get_trained_models( __query["human"] = human if include is not None: __query["include"] = include - if include_model_definition is not None: - __query["include_model_definition"] = include_model_definition if pretty is not None: __query["pretty"] = pretty if size is not None: @@ -5733,7 +5728,7 @@ def validate(

Validate an anomaly detection job.

- ``_ + ``_ :param analysis_config: :param analysis_limits: diff --git a/elasticsearch/_sync/client/simulate.py b/elasticsearch/_sync/client/simulate.py index ed5442d97..5f22ae433 100644 --- a/elasticsearch/_sync/client/simulate.py +++ b/elasticsearch/_sync/client/simulate.py @@ -35,7 +35,7 @@ class SimulateClient(NamespacedClient): body_fields=( "docs", "component_template_substitutions", - "index_template_subtitutions", + "index_template_substitutions", "mapping_addition", "pipeline_substitutions", ), @@ -52,7 +52,7 @@ def ingest( error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, - index_template_subtitutions: t.Optional[ + index_template_substitutions: t.Optional[ t.Mapping[str, t.Mapping[str, t.Any]] ] = None, mapping_addition: t.Optional[t.Mapping[str, t.Any]] = None, @@ -90,7 +90,7 @@ def ingest( an index argument. :param component_template_substitutions: A map of component template names to substitute component template definition objects. - :param index_template_subtitutions: A map of index template names to substitute + :param index_template_substitutions: A map of index template names to substitute index template definition objects. :param mapping_addition: :param pipeline: The pipeline to use as the default pipeline. This value can @@ -127,8 +127,8 @@ def ingest( __body["component_template_substitutions"] = ( component_template_substitutions ) - if index_template_subtitutions is not None: - __body["index_template_subtitutions"] = index_template_subtitutions + if index_template_substitutions is not None: + __body["index_template_substitutions"] = index_template_substitutions if mapping_addition is not None: __body["mapping_addition"] = mapping_addition if pipeline_substitutions is not None: diff --git a/elasticsearch/dsl/query.py b/elasticsearch/dsl/query.py index b5808959c..6e87f926c 100644 --- a/elasticsearch/dsl/query.py +++ b/elasticsearch/dsl/query.py @@ -795,6 +795,28 @@ def __init__( ) +class GeoGrid(Query): + """ + Matches `geo_point` and `geo_shape` values that intersect a grid cell + from a GeoGrid aggregation. + + :arg _field: The field to use in this query. + :arg _value: The query value for the field. + """ + + name = "geo_grid" + + def __init__( + self, + _field: Union[str, "InstrumentedField", "DefaultType"] = DEFAULT, + _value: Union["types.GeoGridQuery", Dict[str, Any], "DefaultType"] = DEFAULT, + **kwargs: Any, + ): + if _field is not DEFAULT: + kwargs[str(_field)] = _value + super().__init__(**kwargs) + + class GeoPolygon(Query): """ :arg _field: The field to use in this query. diff --git a/elasticsearch/dsl/types.py b/elasticsearch/dsl/types.py index d1c39003e..4ea6d8361 100644 --- a/elasticsearch/dsl/types.py +++ b/elasticsearch/dsl/types.py @@ -880,6 +880,48 @@ def __init__( super().__init__(kwargs) +class GeoGridQuery(AttrDict[Any]): + """ + :arg geogrid: + :arg geohash: + :arg geohex: + :arg boost: Floating point number used to decrease or increase the + relevance scores of the query. Boost values are relative to the + default value of 1.0. A boost value between 0 and 1.0 decreases + the relevance score. A value greater than 1.0 increases the + relevance score. Defaults to `1` if omitted. + :arg _name: + """ + + geogrid: Union[str, DefaultType] + geohash: Union[str, DefaultType] + geohex: Union[str, DefaultType] + boost: Union[float, DefaultType] + _name: Union[str, DefaultType] + + def __init__( + self, + *, + geogrid: Union[str, DefaultType] = DEFAULT, + geohash: Union[str, DefaultType] = DEFAULT, + geohex: Union[str, DefaultType] = DEFAULT, + boost: Union[float, DefaultType] = DEFAULT, + _name: Union[str, DefaultType] = DEFAULT, + **kwargs: Any, + ): + if geogrid is not DEFAULT: + kwargs["geogrid"] = geogrid + if geohash is not DEFAULT: + kwargs["geohash"] = geohash + if geohex is not DEFAULT: + kwargs["geohex"] = geohex + if boost is not DEFAULT: + kwargs["boost"] = boost + if _name is not DEFAULT: + kwargs["_name"] = _name + super().__init__(kwargs) + + class GeoHashLocation(AttrDict[Any]): """ :arg geohash: (required) From a35da3c566ffd025ee8bc75bc778a86caa34c3d9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 19 Mar 2025 10:38:31 +0000 Subject: [PATCH 05/57] rename DSL documentation for clarity (#2851) (#2852) (cherry picked from commit 4ef7740a977aa3d7b202c3c7c4bec2cd24d7106f) Co-authored-by: Miguel Grinberg --- .../{_configuration.md => dsl_configuration.md} | 0 docs/reference/{_examples.md => dsl_examples.md} | 0 .../{_how_to_guides.md => dsl_how_to_guides.md} | 0 docs/reference/{_tutorials.md => dsl_tutorials.md} | 0 docs/reference/toc.yml | 10 +++++----- 5 files changed, 5 insertions(+), 5 deletions(-) rename docs/reference/{_configuration.md => dsl_configuration.md} (100%) rename docs/reference/{_examples.md => dsl_examples.md} (100%) rename docs/reference/{_how_to_guides.md => dsl_how_to_guides.md} (100%) rename docs/reference/{_tutorials.md => dsl_tutorials.md} (100%) diff --git a/docs/reference/_configuration.md b/docs/reference/dsl_configuration.md similarity index 100% rename from docs/reference/_configuration.md rename to docs/reference/dsl_configuration.md diff --git a/docs/reference/_examples.md b/docs/reference/dsl_examples.md similarity index 100% rename from docs/reference/_examples.md rename to docs/reference/dsl_examples.md diff --git a/docs/reference/_how_to_guides.md b/docs/reference/dsl_how_to_guides.md similarity index 100% rename from docs/reference/_how_to_guides.md rename to docs/reference/dsl_how_to_guides.md diff --git a/docs/reference/_tutorials.md b/docs/reference/dsl_tutorials.md similarity index 100% rename from docs/reference/_tutorials.md rename to docs/reference/dsl_tutorials.md diff --git a/docs/reference/toc.yml b/docs/reference/toc.yml index 8de284050..abb74bc42 100644 --- a/docs/reference/toc.yml +++ b/docs/reference/toc.yml @@ -12,8 +12,8 @@ toc: - file: examples.md - file: elasticsearch-dsl.md children: - - file: _configuration.md - - file: _tutorials.md - - file: _how_to_guides.md - - file: _examples.md - - file: client-helpers.md \ No newline at end of file + - file: dsl_configuration.md + - file: dsl_tutorials.md + - file: dsl_how_to_guides.md + - file: dsl_examples.md + - file: client-helpers.md From c31463e456b87a302d6fcbcff40f37c78b536655 Mon Sep 17 00:00:00 2001 From: Elastic Machine Date: Mon, 24 Mar 2025 10:04:51 +0200 Subject: [PATCH 06/57] Auto-generated API code (#2848) --- elasticsearch/_async/client/__init__.py | 85 ++++++++++++++----- elasticsearch/_async/client/esql.py | 5 +- elasticsearch/_async/client/indices.py | 51 ++++++++++-- elasticsearch/_async/client/inference.py | 102 ++++++++++++++++++++++- elasticsearch/_async/client/ml.py | 8 +- elasticsearch/_async/client/security.py | 14 ++-- elasticsearch/_sync/client/__init__.py | 85 ++++++++++++++----- elasticsearch/_sync/client/esql.py | 5 +- elasticsearch/_sync/client/indices.py | 51 ++++++++++-- elasticsearch/_sync/client/inference.py | 102 ++++++++++++++++++++++- elasticsearch/_sync/client/ml.py | 8 +- elasticsearch/_sync/client/security.py | 14 ++-- elasticsearch/dsl/field.py | 68 +++++++++++---- elasticsearch/dsl/types.py | 55 ++++++++---- 14 files changed, 530 insertions(+), 123 deletions(-) diff --git a/elasticsearch/_async/client/__init__.py b/elasticsearch/_async/client/__init__.py index b0992bd67..a897f2d37 100644 --- a/elasticsearch/_async/client/__init__.py +++ b/elasticsearch/_async/client/__init__.py @@ -1121,12 +1121,17 @@ async def create( error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, + if_primary_term: t.Optional[int] = None, + if_seq_no: t.Optional[int] = None, include_source_on_error: t.Optional[bool] = None, + op_type: t.Optional[t.Union[str, t.Literal["create", "index"]]] = None, pipeline: t.Optional[str] = None, pretty: t.Optional[bool] = None, refresh: t.Optional[ t.Union[bool, str, t.Literal["false", "true", "wait_for"]] ] = None, + require_alias: t.Optional[bool] = None, + require_data_stream: t.Optional[bool] = None, routing: t.Optional[str] = None, timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, version: t.Optional[int] = None, @@ -1204,8 +1209,18 @@ async def create( :param id: A unique identifier for the document. To automatically generate a document ID, use the `POST //_doc/` request format. :param document: + :param if_primary_term: Only perform the operation if the document has this primary + term. + :param if_seq_no: Only perform the operation if the document has this sequence + number. :param include_source_on_error: True or false if to include the document source in the error message in case of parsing errors. + :param op_type: Set to `create` to only index the document if it does not already + exist (put if absent). If a document with the specified `_id` already exists, + the indexing operation will fail. The behavior is the same as using the `/_create` + endpoint. If a document ID is specified, this paramater defaults to `index`. + Otherwise, it defaults to `create`. If the request targets a data stream, + an `op_type` of `create` is required. :param pipeline: The ID of the pipeline to use to preprocess incoming documents. If the index has a default ingest pipeline specified, setting the value to `_none` turns off the default ingest pipeline for this request. If a final @@ -1214,6 +1229,9 @@ async def create( :param refresh: If `true`, Elasticsearch refreshes the affected shards to make this operation visible to search. If `wait_for`, it waits for a refresh to make this operation visible to search. If `false`, it does nothing with refreshes. + :param require_alias: If `true`, the destination must be an index alias. + :param require_data_stream: If `true`, the request's actions must target a data + stream (existing or to be created). :param routing: A custom value that is used to route operations to a specific shard. :param timeout: The period the request waits for the following operations: automatic @@ -1254,14 +1272,24 @@ async def create( __query["filter_path"] = filter_path if human is not None: __query["human"] = human + if if_primary_term is not None: + __query["if_primary_term"] = if_primary_term + if if_seq_no is not None: + __query["if_seq_no"] = if_seq_no if include_source_on_error is not None: __query["include_source_on_error"] = include_source_on_error + if op_type is not None: + __query["op_type"] = op_type if pipeline is not None: __query["pipeline"] = pipeline if pretty is not None: __query["pretty"] = pretty if refresh is not None: __query["refresh"] = refresh + if require_alias is not None: + __query["require_alias"] = require_alias + if require_data_stream is not None: + __query["require_data_stream"] = require_data_stream if routing is not None: __query["routing"] = routing if timeout is not None: @@ -5969,7 +5997,20 @@ async def terms_enum( ) @_rewrite_parameters( - body_fields=("doc", "filter", "per_field_analyzer"), + body_fields=( + "doc", + "field_statistics", + "fields", + "filter", + "offsets", + "payloads", + "per_field_analyzer", + "positions", + "routing", + "term_statistics", + "version", + "version_type", + ), ) async def termvectors( self, @@ -6046,9 +6087,9 @@ async def termvectors( (the sum of document frequencies for all terms in this field). * The sum of total term frequencies (the sum of total term frequencies of each term in this field). - :param fields: A comma-separated list or wildcard expressions of fields to include - in the statistics. It is used as the default list unless a specific field - list is provided in the `completion_fields` or `fielddata_fields` parameters. + :param fields: A list of fields to include in the statistics. It is used as the + default list unless a specific field list is provided in the `completion_fields` + or `fielddata_fields` parameters. :param filter: Filter terms based on their tf-idf scores. This could be useful in order find out a good characteristic vector of a document. This feature works in a similar manner to the second phase of the More Like This Query. @@ -6086,41 +6127,41 @@ async def termvectors( __body: t.Dict[str, t.Any] = body if body is not None else {} if error_trace is not None: __query["error_trace"] = error_trace - if field_statistics is not None: - __query["field_statistics"] = field_statistics - if fields is not None: - __query["fields"] = fields if filter_path is not None: __query["filter_path"] = filter_path if human is not None: __query["human"] = human - if offsets is not None: - __query["offsets"] = offsets - if payloads is not None: - __query["payloads"] = payloads - if positions is not None: - __query["positions"] = positions if preference is not None: __query["preference"] = preference if pretty is not None: __query["pretty"] = pretty if realtime is not None: __query["realtime"] = realtime - if routing is not None: - __query["routing"] = routing - if term_statistics is not None: - __query["term_statistics"] = term_statistics - if version is not None: - __query["version"] = version - if version_type is not None: - __query["version_type"] = version_type if not __body: if doc is not None: __body["doc"] = doc + if field_statistics is not None: + __body["field_statistics"] = field_statistics + if fields is not None: + __body["fields"] = fields if filter is not None: __body["filter"] = filter + if offsets is not None: + __body["offsets"] = offsets + if payloads is not None: + __body["payloads"] = payloads if per_field_analyzer is not None: __body["per_field_analyzer"] = per_field_analyzer + if positions is not None: + __body["positions"] = positions + if routing is not None: + __body["routing"] = routing + if term_statistics is not None: + __body["term_statistics"] = term_statistics + if version is not None: + __body["version"] = version + if version_type is not None: + __body["version_type"] = version_type if not __body: __body = None # type: ignore[assignment] __headers = {"accept": "application/json"} diff --git a/elasticsearch/_async/client/esql.py b/elasticsearch/_async/client/esql.py index dca7ca2bb..d1a83e00b 100644 --- a/elasticsearch/_async/client/esql.py +++ b/elasticsearch/_async/client/esql.py @@ -35,6 +35,7 @@ class EsqlClient(NamespacedClient): "params", "profile", "tables", + "wait_for_completion_timeout", ), ignore_deprecated_options={"params"}, ) @@ -150,8 +151,6 @@ async def async_query( __query["keep_on_completion"] = keep_on_completion if pretty is not None: __query["pretty"] = pretty - if wait_for_completion_timeout is not None: - __query["wait_for_completion_timeout"] = wait_for_completion_timeout if not __body: if query is not None: __body["query"] = query @@ -169,6 +168,8 @@ async def async_query( __body["profile"] = profile if tables is not None: __body["tables"] = tables + if wait_for_completion_timeout is not None: + __body["wait_for_completion_timeout"] = wait_for_completion_timeout __headers = {"accept": "application/json", "content-type": "application/json"} return await self.perform_request( # type: ignore[return-value] "POST", diff --git a/elasticsearch/_async/client/indices.py b/elasticsearch/_async/client/indices.py index ac3f93d8f..0c128e9d9 100644 --- a/elasticsearch/_async/client/indices.py +++ b/elasticsearch/_async/client/indices.py @@ -1622,7 +1622,9 @@ async def exists_index_template( name: str, error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + flat_settings: t.Optional[bool] = None, human: t.Optional[bool] = None, + local: t.Optional[bool] = None, master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, pretty: t.Optional[bool] = None, ) -> HeadApiResponse: @@ -1637,6 +1639,10 @@ async def exists_index_template( :param name: Comma-separated list of index template names used to limit the request. Wildcard (*) expressions are supported. + :param flat_settings: If true, returns settings in flat format. + :param local: If true, the request retrieves information from the local node + only. Defaults to false, which means information is retrieved from the master + node. :param master_timeout: Period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails and returns an error. @@ -1650,8 +1656,12 @@ async def exists_index_template( __query["error_trace"] = error_trace if filter_path is not None: __query["filter_path"] = filter_path + if flat_settings is not None: + __query["flat_settings"] = flat_settings if human is not None: __query["human"] = human + if local is not None: + __query["local"] = local if master_timeout is not None: __query["master_timeout"] = master_timeout if pretty is not None: @@ -1801,9 +1811,6 @@ async def field_usage_stats( human: t.Optional[bool] = None, ignore_unavailable: t.Optional[bool] = None, pretty: t.Optional[bool] = None, - wait_for_active_shards: t.Optional[ - t.Union[int, t.Union[str, t.Literal["all", "index-setting"]]] - ] = None, ) -> ObjectApiResponse[t.Any]: """ .. raw:: html @@ -1833,9 +1840,6 @@ async def field_usage_stats( in the statistics. :param ignore_unavailable: If `true`, missing or closed indices are not included in the response. - :param wait_for_active_shards: The number of shard copies that must be active - before proceeding with the operation. Set to all or any positive integer - up to the total number of shards in the index (`number_of_replicas+1`). """ if index in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'index'") @@ -1858,8 +1862,6 @@ async def field_usage_stats( __query["ignore_unavailable"] = ignore_unavailable if pretty is not None: __query["pretty"] = pretty - if wait_for_active_shards is not None: - __query["wait_for_active_shards"] = wait_for_active_shards __headers = {"accept": "application/json"} return await self.perform_request( # type: ignore[return-value] "GET", @@ -3840,6 +3842,7 @@ async def put_settings( master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, preserve_existing: t.Optional[bool] = None, pretty: t.Optional[bool] = None, + reopen: t.Optional[bool] = None, timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -3882,6 +3885,9 @@ async def put_settings( no response is received before the timeout expires, the request fails and returns an error. :param preserve_existing: If `true`, existing index settings remain unchanged. + :param reopen: Whether to close and reopen the index to apply non-dynamic settings. + If set to `true` the indices to which the settings are being applied will + be closed temporarily and then reopened in order to apply the changes. :param timeout: Period to wait for a response. If no response is received before the timeout expires, the request fails and returns an error. """ @@ -3919,6 +3925,8 @@ async def put_settings( __query["preserve_existing"] = preserve_existing if pretty is not None: __query["pretty"] = pretty + if reopen is not None: + __query["reopen"] = reopen if timeout is not None: __query["timeout"] = timeout __body = settings if settings is not None else body @@ -3986,7 +3994,7 @@ async def put_template( :param name: The name of the template :param aliases: Aliases for the index. - :param cause: + :param cause: User defined reason for creating/updating the index template :param create: If true, this request cannot replace or update existing index templates. :param index_patterns: Array of wildcard expressions used to match the names @@ -4224,6 +4232,7 @@ async def reload_search_analyzers( human: t.Optional[bool] = None, ignore_unavailable: t.Optional[bool] = None, pretty: t.Optional[bool] = None, + resource: t.Optional[str] = None, ) -> ObjectApiResponse[t.Any]: """ .. raw:: html @@ -4251,6 +4260,7 @@ async def reload_search_analyzers( that are open, closed or both. :param ignore_unavailable: Whether specified concrete indices should be ignored when unavailable (missing or closed) + :param resource: Changed resource to reload analyzers from if applicable """ if index in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'index'") @@ -4271,6 +4281,8 @@ async def reload_search_analyzers( __query["ignore_unavailable"] = ignore_unavailable if pretty is not None: __query["pretty"] = pretty + if resource is not None: + __query["resource"] = resource __headers = {"accept": "application/json"} return await self.perform_request( # type: ignore[return-value] "POST", @@ -4507,6 +4519,7 @@ async def rollover( error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, + lazy: t.Optional[bool] = None, mappings: t.Optional[t.Mapping[str, t.Any]] = None, master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, pretty: t.Optional[bool] = None, @@ -4563,6 +4576,9 @@ async def rollover( conditions are satisfied. :param dry_run: If `true`, checks whether the current index satisfies the specified conditions but does not perform a rollover. + :param lazy: If set to true, the rollover action will only mark a data stream + to signal that it needs to be rolled over at the next write. Only allowed + on data streams. :param mappings: Mapping for fields in the index. If specified, this mapping can include field names, field data types, and mapping paramaters. :param master_timeout: Period to wait for a connection to the master node. If @@ -4597,6 +4613,8 @@ async def rollover( __query["filter_path"] = filter_path if human is not None: __query["human"] = human + if lazy is not None: + __query["lazy"] = lazy if master_timeout is not None: __query["master_timeout"] = master_timeout if pretty is not None: @@ -4913,6 +4931,8 @@ async def simulate_index_template( self, *, name: str, + cause: t.Optional[str] = None, + create: t.Optional[bool] = None, error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, @@ -4930,6 +4950,10 @@ async def simulate_index_template( ``_ :param name: Name of the index to simulate + :param cause: User defined reason for dry-run creating the new template for simulation + purposes + :param create: Whether the index template we optionally defined in the body should + only be dry-run added if new or can also replace an existing one :param include_defaults: If true, returns all relevant default configurations for the index template. :param master_timeout: Period to wait for a connection to the master node. If @@ -4941,6 +4965,10 @@ async def simulate_index_template( __path_parts: t.Dict[str, str] = {"name": _quote(name)} __path = f'/_index_template/_simulate_index/{__path_parts["name"]}' __query: t.Dict[str, t.Any] = {} + if cause is not None: + __query["cause"] = cause + if create is not None: + __query["create"] = create if error_trace is not None: __query["error_trace"] = error_trace if filter_path is not None: @@ -4983,6 +5011,7 @@ async def simulate_template( *, name: t.Optional[str] = None, allow_auto_create: t.Optional[bool] = None, + cause: t.Optional[str] = None, composed_of: t.Optional[t.Sequence[str]] = None, create: t.Optional[bool] = None, data_stream: t.Optional[t.Mapping[str, t.Any]] = None, @@ -5019,6 +5048,8 @@ async def simulate_template( via `actions.auto_create_index`. If set to `false`, then indices or data streams matching the template must always be explicitly created, and may never be automatically created. + :param cause: User defined reason for dry-run creating the new template for simulation + purposes :param composed_of: An ordered list of component template names. Component templates are merged in the order specified, meaning that the last component template specified has the highest precedence. @@ -5063,6 +5094,8 @@ async def simulate_template( __path = "/_index_template/_simulate" __query: t.Dict[str, t.Any] = {} __body: t.Dict[str, t.Any] = body if body is not None else {} + if cause is not None: + __query["cause"] = cause if create is not None: __query["create"] = create if error_trace is not None: diff --git a/elasticsearch/_async/client/inference.py b/elasticsearch/_async/client/inference.py index e685d1c5c..ce96dba63 100644 --- a/elasticsearch/_async/client/inference.py +++ b/elasticsearch/_async/client/inference.py @@ -321,6 +321,104 @@ async def put( path_parts=__path_parts, ) + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + async def put_openai( + self, + *, + task_type: t.Union[ + str, t.Literal["chat_completion", "completion", "text_embedding"] + ], + openai_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["openai"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an OpenAI inference endpoint.

+

Create an inference endpoint to perform an inference task with the openai service.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + NOTE: The `chat_completion` task type only supports streaming and only through + the _stream API. + :param openai_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `openai`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `openai` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if openai_inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'openai_inference_id'") + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "openai_inference_id": _quote(openai_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["openai_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_openai", + path_parts=__path_parts, + ) + @_rewrite_parameters( body_fields=("service", "service_settings"), ) @@ -341,7 +439,7 @@ async def put_watsonx( .. raw:: html

Create a Watsonx inference endpoint.

-

Creates an inference endpoint to perform an inference task with the watsonxai service. +

Create an inference endpoint to perform an inference task with the watsonxai service. You need an IBM Cloud Databases for Elasticsearch deployment to use the watsonxai inference service. You can provision one through the IBM catalog, the Cloud Databases CLI plug-in, the Cloud Databases API, or Terraform.

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. @@ -351,7 +449,7 @@ async def put_watsonx( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The task type. The only valid task type for the model to perform is `text_embedding`. diff --git a/elasticsearch/_async/client/ml.py b/elasticsearch/_async/client/ml.py index 6599c0923..acee1e6ea 100644 --- a/elasticsearch/_async/client/ml.py +++ b/elasticsearch/_async/client/ml.py @@ -3599,11 +3599,11 @@ async def put_datafeed( :param ignore_unavailable: If true, unavailable indices (missing or closed) are ignored. :param indexes: An array of index names. Wildcards are supported. If any of the - indices are in remote clusters, the machine learning nodes must have the - `remote_cluster_client` role. + indices are in remote clusters, the master nodes and the machine learning + nodes must have the `remote_cluster_client` role. :param indices: An array of index names. Wildcards are supported. If any of the - indices are in remote clusters, the machine learning nodes must have the - `remote_cluster_client` role. + indices are in remote clusters, the master nodes and the machine learning + nodes must have the `remote_cluster_client` role. :param indices_options: Specifies index expansion options that are used during search :param job_id: Identifier for the anomaly detection job. diff --git a/elasticsearch/_async/client/security.py b/elasticsearch/_async/client/security.py index 0bc3084a3..840a3d249 100644 --- a/elasticsearch/_async/client/security.py +++ b/elasticsearch/_async/client/security.py @@ -2867,12 +2867,12 @@ async def oidc_authenticate( ) @_rewrite_parameters( - body_fields=("access_token", "refresh_token"), + body_fields=("token", "refresh_token"), ) async def oidc_logout( self, *, - access_token: t.Optional[str] = None, + token: t.Optional[str] = None, error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, @@ -2892,11 +2892,11 @@ async def oidc_logout( ``_ - :param access_token: The access token to be invalidated. + :param token: The access token to be invalidated. :param refresh_token: The refresh token to be invalidated. """ - if access_token is None and body is None: - raise ValueError("Empty value passed for parameter 'access_token'") + if token is None and body is None: + raise ValueError("Empty value passed for parameter 'token'") __path_parts: t.Dict[str, str] = {} __path = "/_security/oidc/logout" __query: t.Dict[str, t.Any] = {} @@ -2910,8 +2910,8 @@ async def oidc_logout( if pretty is not None: __query["pretty"] = pretty if not __body: - if access_token is not None: - __body["access_token"] = access_token + if token is not None: + __body["token"] = token if refresh_token is not None: __body["refresh_token"] = refresh_token __headers = {"accept": "application/json", "content-type": "application/json"} diff --git a/elasticsearch/_sync/client/__init__.py b/elasticsearch/_sync/client/__init__.py index 32d736192..1d80efee7 100644 --- a/elasticsearch/_sync/client/__init__.py +++ b/elasticsearch/_sync/client/__init__.py @@ -1119,12 +1119,17 @@ def create( error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, + if_primary_term: t.Optional[int] = None, + if_seq_no: t.Optional[int] = None, include_source_on_error: t.Optional[bool] = None, + op_type: t.Optional[t.Union[str, t.Literal["create", "index"]]] = None, pipeline: t.Optional[str] = None, pretty: t.Optional[bool] = None, refresh: t.Optional[ t.Union[bool, str, t.Literal["false", "true", "wait_for"]] ] = None, + require_alias: t.Optional[bool] = None, + require_data_stream: t.Optional[bool] = None, routing: t.Optional[str] = None, timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, version: t.Optional[int] = None, @@ -1202,8 +1207,18 @@ def create( :param id: A unique identifier for the document. To automatically generate a document ID, use the `POST //_doc/` request format. :param document: + :param if_primary_term: Only perform the operation if the document has this primary + term. + :param if_seq_no: Only perform the operation if the document has this sequence + number. :param include_source_on_error: True or false if to include the document source in the error message in case of parsing errors. + :param op_type: Set to `create` to only index the document if it does not already + exist (put if absent). If a document with the specified `_id` already exists, + the indexing operation will fail. The behavior is the same as using the `/_create` + endpoint. If a document ID is specified, this paramater defaults to `index`. + Otherwise, it defaults to `create`. If the request targets a data stream, + an `op_type` of `create` is required. :param pipeline: The ID of the pipeline to use to preprocess incoming documents. If the index has a default ingest pipeline specified, setting the value to `_none` turns off the default ingest pipeline for this request. If a final @@ -1212,6 +1227,9 @@ def create( :param refresh: If `true`, Elasticsearch refreshes the affected shards to make this operation visible to search. If `wait_for`, it waits for a refresh to make this operation visible to search. If `false`, it does nothing with refreshes. + :param require_alias: If `true`, the destination must be an index alias. + :param require_data_stream: If `true`, the request's actions must target a data + stream (existing or to be created). :param routing: A custom value that is used to route operations to a specific shard. :param timeout: The period the request waits for the following operations: automatic @@ -1252,14 +1270,24 @@ def create( __query["filter_path"] = filter_path if human is not None: __query["human"] = human + if if_primary_term is not None: + __query["if_primary_term"] = if_primary_term + if if_seq_no is not None: + __query["if_seq_no"] = if_seq_no if include_source_on_error is not None: __query["include_source_on_error"] = include_source_on_error + if op_type is not None: + __query["op_type"] = op_type if pipeline is not None: __query["pipeline"] = pipeline if pretty is not None: __query["pretty"] = pretty if refresh is not None: __query["refresh"] = refresh + if require_alias is not None: + __query["require_alias"] = require_alias + if require_data_stream is not None: + __query["require_data_stream"] = require_data_stream if routing is not None: __query["routing"] = routing if timeout is not None: @@ -5967,7 +5995,20 @@ def terms_enum( ) @_rewrite_parameters( - body_fields=("doc", "filter", "per_field_analyzer"), + body_fields=( + "doc", + "field_statistics", + "fields", + "filter", + "offsets", + "payloads", + "per_field_analyzer", + "positions", + "routing", + "term_statistics", + "version", + "version_type", + ), ) def termvectors( self, @@ -6044,9 +6085,9 @@ def termvectors( (the sum of document frequencies for all terms in this field). * The sum of total term frequencies (the sum of total term frequencies of each term in this field). - :param fields: A comma-separated list or wildcard expressions of fields to include - in the statistics. It is used as the default list unless a specific field - list is provided in the `completion_fields` or `fielddata_fields` parameters. + :param fields: A list of fields to include in the statistics. It is used as the + default list unless a specific field list is provided in the `completion_fields` + or `fielddata_fields` parameters. :param filter: Filter terms based on their tf-idf scores. This could be useful in order find out a good characteristic vector of a document. This feature works in a similar manner to the second phase of the More Like This Query. @@ -6084,41 +6125,41 @@ def termvectors( __body: t.Dict[str, t.Any] = body if body is not None else {} if error_trace is not None: __query["error_trace"] = error_trace - if field_statistics is not None: - __query["field_statistics"] = field_statistics - if fields is not None: - __query["fields"] = fields if filter_path is not None: __query["filter_path"] = filter_path if human is not None: __query["human"] = human - if offsets is not None: - __query["offsets"] = offsets - if payloads is not None: - __query["payloads"] = payloads - if positions is not None: - __query["positions"] = positions if preference is not None: __query["preference"] = preference if pretty is not None: __query["pretty"] = pretty if realtime is not None: __query["realtime"] = realtime - if routing is not None: - __query["routing"] = routing - if term_statistics is not None: - __query["term_statistics"] = term_statistics - if version is not None: - __query["version"] = version - if version_type is not None: - __query["version_type"] = version_type if not __body: if doc is not None: __body["doc"] = doc + if field_statistics is not None: + __body["field_statistics"] = field_statistics + if fields is not None: + __body["fields"] = fields if filter is not None: __body["filter"] = filter + if offsets is not None: + __body["offsets"] = offsets + if payloads is not None: + __body["payloads"] = payloads if per_field_analyzer is not None: __body["per_field_analyzer"] = per_field_analyzer + if positions is not None: + __body["positions"] = positions + if routing is not None: + __body["routing"] = routing + if term_statistics is not None: + __body["term_statistics"] = term_statistics + if version is not None: + __body["version"] = version + if version_type is not None: + __body["version_type"] = version_type if not __body: __body = None # type: ignore[assignment] __headers = {"accept": "application/json"} diff --git a/elasticsearch/_sync/client/esql.py b/elasticsearch/_sync/client/esql.py index 7d29224a9..7ef16cde1 100644 --- a/elasticsearch/_sync/client/esql.py +++ b/elasticsearch/_sync/client/esql.py @@ -35,6 +35,7 @@ class EsqlClient(NamespacedClient): "params", "profile", "tables", + "wait_for_completion_timeout", ), ignore_deprecated_options={"params"}, ) @@ -150,8 +151,6 @@ def async_query( __query["keep_on_completion"] = keep_on_completion if pretty is not None: __query["pretty"] = pretty - if wait_for_completion_timeout is not None: - __query["wait_for_completion_timeout"] = wait_for_completion_timeout if not __body: if query is not None: __body["query"] = query @@ -169,6 +168,8 @@ def async_query( __body["profile"] = profile if tables is not None: __body["tables"] = tables + if wait_for_completion_timeout is not None: + __body["wait_for_completion_timeout"] = wait_for_completion_timeout __headers = {"accept": "application/json", "content-type": "application/json"} return self.perform_request( # type: ignore[return-value] "POST", diff --git a/elasticsearch/_sync/client/indices.py b/elasticsearch/_sync/client/indices.py index 939eeaf29..4f697b9a1 100644 --- a/elasticsearch/_sync/client/indices.py +++ b/elasticsearch/_sync/client/indices.py @@ -1622,7 +1622,9 @@ def exists_index_template( name: str, error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + flat_settings: t.Optional[bool] = None, human: t.Optional[bool] = None, + local: t.Optional[bool] = None, master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, pretty: t.Optional[bool] = None, ) -> HeadApiResponse: @@ -1637,6 +1639,10 @@ def exists_index_template( :param name: Comma-separated list of index template names used to limit the request. Wildcard (*) expressions are supported. + :param flat_settings: If true, returns settings in flat format. + :param local: If true, the request retrieves information from the local node + only. Defaults to false, which means information is retrieved from the master + node. :param master_timeout: Period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails and returns an error. @@ -1650,8 +1656,12 @@ def exists_index_template( __query["error_trace"] = error_trace if filter_path is not None: __query["filter_path"] = filter_path + if flat_settings is not None: + __query["flat_settings"] = flat_settings if human is not None: __query["human"] = human + if local is not None: + __query["local"] = local if master_timeout is not None: __query["master_timeout"] = master_timeout if pretty is not None: @@ -1801,9 +1811,6 @@ def field_usage_stats( human: t.Optional[bool] = None, ignore_unavailable: t.Optional[bool] = None, pretty: t.Optional[bool] = None, - wait_for_active_shards: t.Optional[ - t.Union[int, t.Union[str, t.Literal["all", "index-setting"]]] - ] = None, ) -> ObjectApiResponse[t.Any]: """ .. raw:: html @@ -1833,9 +1840,6 @@ def field_usage_stats( in the statistics. :param ignore_unavailable: If `true`, missing or closed indices are not included in the response. - :param wait_for_active_shards: The number of shard copies that must be active - before proceeding with the operation. Set to all or any positive integer - up to the total number of shards in the index (`number_of_replicas+1`). """ if index in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'index'") @@ -1858,8 +1862,6 @@ def field_usage_stats( __query["ignore_unavailable"] = ignore_unavailable if pretty is not None: __query["pretty"] = pretty - if wait_for_active_shards is not None: - __query["wait_for_active_shards"] = wait_for_active_shards __headers = {"accept": "application/json"} return self.perform_request( # type: ignore[return-value] "GET", @@ -3840,6 +3842,7 @@ def put_settings( master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, preserve_existing: t.Optional[bool] = None, pretty: t.Optional[bool] = None, + reopen: t.Optional[bool] = None, timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -3882,6 +3885,9 @@ def put_settings( no response is received before the timeout expires, the request fails and returns an error. :param preserve_existing: If `true`, existing index settings remain unchanged. + :param reopen: Whether to close and reopen the index to apply non-dynamic settings. + If set to `true` the indices to which the settings are being applied will + be closed temporarily and then reopened in order to apply the changes. :param timeout: Period to wait for a response. If no response is received before the timeout expires, the request fails and returns an error. """ @@ -3919,6 +3925,8 @@ def put_settings( __query["preserve_existing"] = preserve_existing if pretty is not None: __query["pretty"] = pretty + if reopen is not None: + __query["reopen"] = reopen if timeout is not None: __query["timeout"] = timeout __body = settings if settings is not None else body @@ -3986,7 +3994,7 @@ def put_template( :param name: The name of the template :param aliases: Aliases for the index. - :param cause: + :param cause: User defined reason for creating/updating the index template :param create: If true, this request cannot replace or update existing index templates. :param index_patterns: Array of wildcard expressions used to match the names @@ -4224,6 +4232,7 @@ def reload_search_analyzers( human: t.Optional[bool] = None, ignore_unavailable: t.Optional[bool] = None, pretty: t.Optional[bool] = None, + resource: t.Optional[str] = None, ) -> ObjectApiResponse[t.Any]: """ .. raw:: html @@ -4251,6 +4260,7 @@ def reload_search_analyzers( that are open, closed or both. :param ignore_unavailable: Whether specified concrete indices should be ignored when unavailable (missing or closed) + :param resource: Changed resource to reload analyzers from if applicable """ if index in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'index'") @@ -4271,6 +4281,8 @@ def reload_search_analyzers( __query["ignore_unavailable"] = ignore_unavailable if pretty is not None: __query["pretty"] = pretty + if resource is not None: + __query["resource"] = resource __headers = {"accept": "application/json"} return self.perform_request( # type: ignore[return-value] "POST", @@ -4507,6 +4519,7 @@ def rollover( error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, + lazy: t.Optional[bool] = None, mappings: t.Optional[t.Mapping[str, t.Any]] = None, master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, pretty: t.Optional[bool] = None, @@ -4563,6 +4576,9 @@ def rollover( conditions are satisfied. :param dry_run: If `true`, checks whether the current index satisfies the specified conditions but does not perform a rollover. + :param lazy: If set to true, the rollover action will only mark a data stream + to signal that it needs to be rolled over at the next write. Only allowed + on data streams. :param mappings: Mapping for fields in the index. If specified, this mapping can include field names, field data types, and mapping paramaters. :param master_timeout: Period to wait for a connection to the master node. If @@ -4597,6 +4613,8 @@ def rollover( __query["filter_path"] = filter_path if human is not None: __query["human"] = human + if lazy is not None: + __query["lazy"] = lazy if master_timeout is not None: __query["master_timeout"] = master_timeout if pretty is not None: @@ -4913,6 +4931,8 @@ def simulate_index_template( self, *, name: str, + cause: t.Optional[str] = None, + create: t.Optional[bool] = None, error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, @@ -4930,6 +4950,10 @@ def simulate_index_template( ``_ :param name: Name of the index to simulate + :param cause: User defined reason for dry-run creating the new template for simulation + purposes + :param create: Whether the index template we optionally defined in the body should + only be dry-run added if new or can also replace an existing one :param include_defaults: If true, returns all relevant default configurations for the index template. :param master_timeout: Period to wait for a connection to the master node. If @@ -4941,6 +4965,10 @@ def simulate_index_template( __path_parts: t.Dict[str, str] = {"name": _quote(name)} __path = f'/_index_template/_simulate_index/{__path_parts["name"]}' __query: t.Dict[str, t.Any] = {} + if cause is not None: + __query["cause"] = cause + if create is not None: + __query["create"] = create if error_trace is not None: __query["error_trace"] = error_trace if filter_path is not None: @@ -4983,6 +5011,7 @@ def simulate_template( *, name: t.Optional[str] = None, allow_auto_create: t.Optional[bool] = None, + cause: t.Optional[str] = None, composed_of: t.Optional[t.Sequence[str]] = None, create: t.Optional[bool] = None, data_stream: t.Optional[t.Mapping[str, t.Any]] = None, @@ -5019,6 +5048,8 @@ def simulate_template( via `actions.auto_create_index`. If set to `false`, then indices or data streams matching the template must always be explicitly created, and may never be automatically created. + :param cause: User defined reason for dry-run creating the new template for simulation + purposes :param composed_of: An ordered list of component template names. Component templates are merged in the order specified, meaning that the last component template specified has the highest precedence. @@ -5063,6 +5094,8 @@ def simulate_template( __path = "/_index_template/_simulate" __query: t.Dict[str, t.Any] = {} __body: t.Dict[str, t.Any] = body if body is not None else {} + if cause is not None: + __query["cause"] = cause if create is not None: __query["create"] = create if error_trace is not None: diff --git a/elasticsearch/_sync/client/inference.py b/elasticsearch/_sync/client/inference.py index 2ae2b637d..6bab33aec 100644 --- a/elasticsearch/_sync/client/inference.py +++ b/elasticsearch/_sync/client/inference.py @@ -321,6 +321,104 @@ def put( path_parts=__path_parts, ) + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + def put_openai( + self, + *, + task_type: t.Union[ + str, t.Literal["chat_completion", "completion", "text_embedding"] + ], + openai_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["openai"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an OpenAI inference endpoint.

+

Create an inference endpoint to perform an inference task with the openai service.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + NOTE: The `chat_completion` task type only supports streaming and only through + the _stream API. + :param openai_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `openai`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `openai` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if openai_inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'openai_inference_id'") + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "openai_inference_id": _quote(openai_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["openai_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_openai", + path_parts=__path_parts, + ) + @_rewrite_parameters( body_fields=("service", "service_settings"), ) @@ -341,7 +439,7 @@ def put_watsonx( .. raw:: html

Create a Watsonx inference endpoint.

-

Creates an inference endpoint to perform an inference task with the watsonxai service. +

Create an inference endpoint to perform an inference task with the watsonxai service. You need an IBM Cloud Databases for Elasticsearch deployment to use the watsonxai inference service. You can provision one through the IBM catalog, the Cloud Databases CLI plug-in, the Cloud Databases API, or Terraform.

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. @@ -351,7 +449,7 @@ def put_watsonx( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The task type. The only valid task type for the model to perform is `text_embedding`. diff --git a/elasticsearch/_sync/client/ml.py b/elasticsearch/_sync/client/ml.py index 3713ff741..d162abe82 100644 --- a/elasticsearch/_sync/client/ml.py +++ b/elasticsearch/_sync/client/ml.py @@ -3599,11 +3599,11 @@ def put_datafeed( :param ignore_unavailable: If true, unavailable indices (missing or closed) are ignored. :param indexes: An array of index names. Wildcards are supported. If any of the - indices are in remote clusters, the machine learning nodes must have the - `remote_cluster_client` role. + indices are in remote clusters, the master nodes and the machine learning + nodes must have the `remote_cluster_client` role. :param indices: An array of index names. Wildcards are supported. If any of the - indices are in remote clusters, the machine learning nodes must have the - `remote_cluster_client` role. + indices are in remote clusters, the master nodes and the machine learning + nodes must have the `remote_cluster_client` role. :param indices_options: Specifies index expansion options that are used during search :param job_id: Identifier for the anomaly detection job. diff --git a/elasticsearch/_sync/client/security.py b/elasticsearch/_sync/client/security.py index 1f7c8bac2..5aac0202f 100644 --- a/elasticsearch/_sync/client/security.py +++ b/elasticsearch/_sync/client/security.py @@ -2867,12 +2867,12 @@ def oidc_authenticate( ) @_rewrite_parameters( - body_fields=("access_token", "refresh_token"), + body_fields=("token", "refresh_token"), ) def oidc_logout( self, *, - access_token: t.Optional[str] = None, + token: t.Optional[str] = None, error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, @@ -2892,11 +2892,11 @@ def oidc_logout( ``_ - :param access_token: The access token to be invalidated. + :param token: The access token to be invalidated. :param refresh_token: The refresh token to be invalidated. """ - if access_token is None and body is None: - raise ValueError("Empty value passed for parameter 'access_token'") + if token is None and body is None: + raise ValueError("Empty value passed for parameter 'token'") __path_parts: t.Dict[str, str] = {} __path = "/_security/oidc/logout" __query: t.Dict[str, t.Any] = {} @@ -2910,8 +2910,8 @@ def oidc_logout( if pretty is not None: __query["pretty"] = pretty if not __body: - if access_token is not None: - __body["access_token"] = access_token + if token is not None: + __body["token"] = token if refresh_token is not None: __body["refresh_token"] = refresh_token __headers = {"accept": "application/json", "content-type": "application/json"} diff --git a/elasticsearch/dsl/field.py b/elasticsearch/dsl/field.py index 50f30b405..7fcc9ada5 100644 --- a/elasticsearch/dsl/field.py +++ b/elasticsearch/dsl/field.py @@ -1390,11 +1390,29 @@ def __init__( class DenseVector(Field): """ - :arg element_type: - :arg dims: - :arg similarity: - :arg index: - :arg index_options: + :arg dims: Number of vector dimensions. Can't exceed `4096`. If `dims` + is not specified, it will be set to the length of the first vector + added to the field. + :arg element_type: The data type used to encode vectors. The supported + data types are `float` (default), `byte`, and `bit`. Defaults to + `float` if omitted. + :arg index: If `true`, you can search this field using the kNN search + API. Defaults to `True` if omitted. + :arg index_options: An optional section that configures the kNN + indexing algorithm. The HNSW algorithm has two internal parameters + that influence how the data structure is built. These can be + adjusted to improve the accuracy of results, at the expense of + slower indexing speed. This parameter can only be specified when + `index` is `true`. + :arg similarity: The vector similarity metric to use in kNN search. + Documents are ranked by their vector field's similarity to the + query vector. The `_score` of each document will be derived from + the similarity, in a way that ensures scores are positive and that + a larger score corresponds to a higher ranking. Defaults to + `l2_norm` when `element_type` is `bit` otherwise defaults to + `cosine`. `bit` vectors only support `l2_norm` as their + similarity metric. This parameter can only be specified when + `index` is `true`. :arg meta: Metadata about the field. :arg properties: :arg ignore_above: @@ -1413,13 +1431,16 @@ class DenseVector(Field): def __init__( self, *args: Any, - element_type: Union[str, "DefaultType"] = DEFAULT, dims: Union[int, "DefaultType"] = DEFAULT, - similarity: Union[str, "DefaultType"] = DEFAULT, + element_type: Union[Literal["bit", "byte", "float"], "DefaultType"] = DEFAULT, index: Union[bool, "DefaultType"] = DEFAULT, index_options: Union[ "types.DenseVectorIndexOptions", Dict[str, Any], "DefaultType" ] = DEFAULT, + similarity: Union[ + Literal["cosine", "dot_product", "l2_norm", "max_inner_product"], + "DefaultType", + ] = DEFAULT, meta: Union[Mapping[str, str], "DefaultType"] = DEFAULT, properties: Union[Mapping[str, Field], "DefaultType"] = DEFAULT, ignore_above: Union[int, "DefaultType"] = DEFAULT, @@ -1432,16 +1453,16 @@ def __init__( ] = DEFAULT, **kwargs: Any, ): - if element_type is not DEFAULT: - kwargs["element_type"] = element_type if dims is not DEFAULT: kwargs["dims"] = dims - if similarity is not DEFAULT: - kwargs["similarity"] = similarity + if element_type is not DEFAULT: + kwargs["element_type"] = element_type if index is not DEFAULT: kwargs["index"] = index if index_options is not DEFAULT: kwargs["index_options"] = index_options + if similarity is not DEFAULT: + kwargs["similarity"] = similarity if meta is not DEFAULT: kwargs["meta"] = meta if properties is not DEFAULT: @@ -1905,6 +1926,7 @@ class GeoShape(Field): :arg coerce: :arg ignore_malformed: :arg ignore_z_value: + :arg index: :arg orientation: :arg strategy: :arg doc_values: @@ -1930,6 +1952,7 @@ def __init__( coerce: Union[bool, "DefaultType"] = DEFAULT, ignore_malformed: Union[bool, "DefaultType"] = DEFAULT, ignore_z_value: Union[bool, "DefaultType"] = DEFAULT, + index: Union[bool, "DefaultType"] = DEFAULT, orientation: Union[Literal["right", "left"], "DefaultType"] = DEFAULT, strategy: Union[Literal["recursive", "term"], "DefaultType"] = DEFAULT, doc_values: Union[bool, "DefaultType"] = DEFAULT, @@ -1957,6 +1980,8 @@ def __init__( kwargs["ignore_malformed"] = ignore_malformed if ignore_z_value is not DEFAULT: kwargs["ignore_z_value"] = ignore_z_value + if index is not DEFAULT: + kwargs["index"] = index if orientation is not DEFAULT: kwargs["orientation"] = orientation if strategy is not DEFAULT: @@ -3497,8 +3522,18 @@ def __init__( class SemanticText(Field): """ - :arg inference_id: (required) :arg meta: + :arg inference_id: Inference endpoint that will be used to generate + embeddings for the field. This parameter cannot be updated. Use + the Create inference API to create the endpoint. If + `search_inference_id` is specified, the inference endpoint will + only be used at index time. Defaults to `.elser-2-elasticsearch` + if omitted. + :arg search_inference_id: Inference endpoint that will be used to + generate embeddings at query time. You can update this parameter + by using the Update mapping API. Use the Create inference API to + create the endpoint. If not specified, the inference endpoint + defined by inference_id will be used at both index and query time. """ name = "semantic_text" @@ -3506,14 +3541,17 @@ class SemanticText(Field): def __init__( self, *args: Any, - inference_id: Union[str, "DefaultType"] = DEFAULT, meta: Union[Mapping[str, str], "DefaultType"] = DEFAULT, + inference_id: Union[str, "DefaultType"] = DEFAULT, + search_inference_id: Union[str, "DefaultType"] = DEFAULT, **kwargs: Any, ): - if inference_id is not DEFAULT: - kwargs["inference_id"] = inference_id if meta is not DEFAULT: kwargs["meta"] = meta + if inference_id is not DEFAULT: + kwargs["inference_id"] = inference_id + if search_inference_id is not DEFAULT: + kwargs["search_inference_id"] = search_inference_id super().__init__(*args, **kwargs) diff --git a/elasticsearch/dsl/types.py b/elasticsearch/dsl/types.py index 4ea6d8361..7474769c6 100644 --- a/elasticsearch/dsl/types.py +++ b/elasticsearch/dsl/types.py @@ -364,34 +364,57 @@ def __init__( class DenseVectorIndexOptions(AttrDict[Any]): """ - :arg type: (required) - :arg m: - :arg ef_construction: - :arg confidence_interval: - """ - - type: Union[str, DefaultType] - m: Union[int, DefaultType] - ef_construction: Union[int, DefaultType] + :arg type: (required) The type of kNN algorithm to use. + :arg confidence_interval: The confidence interval to use when + quantizing the vectors. Can be any value between and including + `0.90` and `1.0` or exactly `0`. When the value is `0`, this + indicates that dynamic quantiles should be calculated for + optimized quantization. When between `0.90` and `1.0`, this value + restricts the values used when calculating the quantization + thresholds. For example, a value of `0.95` will only use the + middle `95%` of the values when calculating the quantization + thresholds (e.g. the highest and lowest `2.5%` of values will be + ignored). Defaults to `1/(dims + 1)` for `int8` quantized vectors + and `0` for `int4` for dynamic quantile calculation. Only + applicable to `int8_hnsw`, `int4_hnsw`, `int8_flat`, and + `int4_flat` index types. + :arg ef_construction: The number of candidates to track while + assembling the list of nearest neighbors for each new node. Only + applicable to `hnsw`, `int8_hnsw`, and `int4_hnsw` index types. + Defaults to `100` if omitted. + :arg m: The number of neighbors each node will be connected to in the + HNSW graph. Only applicable to `hnsw`, `int8_hnsw`, and + `int4_hnsw` index types. Defaults to `16` if omitted. + """ + + type: Union[ + Literal["flat", "hnsw", "int4_flat", "int4_hnsw", "int8_flat", "int8_hnsw"], + DefaultType, + ] confidence_interval: Union[float, DefaultType] + ef_construction: Union[int, DefaultType] + m: Union[int, DefaultType] def __init__( self, *, - type: Union[str, DefaultType] = DEFAULT, - m: Union[int, DefaultType] = DEFAULT, - ef_construction: Union[int, DefaultType] = DEFAULT, + type: Union[ + Literal["flat", "hnsw", "int4_flat", "int4_hnsw", "int8_flat", "int8_hnsw"], + DefaultType, + ] = DEFAULT, confidence_interval: Union[float, DefaultType] = DEFAULT, + ef_construction: Union[int, DefaultType] = DEFAULT, + m: Union[int, DefaultType] = DEFAULT, **kwargs: Any, ): if type is not DEFAULT: kwargs["type"] = type - if m is not DEFAULT: - kwargs["m"] = m - if ef_construction is not DEFAULT: - kwargs["ef_construction"] = ef_construction if confidence_interval is not DEFAULT: kwargs["confidence_interval"] = confidence_interval + if ef_construction is not DEFAULT: + kwargs["ef_construction"] = ef_construction + if m is not DEFAULT: + kwargs["m"] = m super().__init__(kwargs) From cb1c14f794ad3f48941688f26956bd0aa1c0a8a2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 28 Mar 2025 15:23:22 +0000 Subject: [PATCH 07/57] Use class-based queries and type-hinted documents in DSL documentation examples (#2857) (#2862) * Use class-based queries and type-hinted documents in DSL documentation examples * DSL migrating section (cherry picked from commit d49252487daab1e3e5fd8667714c2a369e7de4e5) Co-authored-by: Miguel Grinberg --- docs/reference/dsl_how_to_guides.md | 208 +++++++++++++++------------- docs/reference/dsl_migrating.md | 35 +++++ docs/reference/dsl_tutorials.md | 43 +++--- docs/reference/elasticsearch-dsl.md | 14 +- docs/reference/toc.yml | 1 + elasticsearch/dsl/search_base.py | 19 ++- 6 files changed, 189 insertions(+), 131 deletions(-) create mode 100644 docs/reference/dsl_migrating.md diff --git a/docs/reference/dsl_how_to_guides.md b/docs/reference/dsl_how_to_guides.md index 08e16b28c..93dc8d9a1 100644 --- a/docs/reference/dsl_how_to_guides.md +++ b/docs/reference/dsl_how_to_guides.md @@ -23,7 +23,7 @@ The `Search` object represents the entire search request: * additional parameters * associated client -The API is designed to be chainable. With the exception of the aggregations functionality this means that the `Search` object is immutable -all changes to the object will result in a shallow copy being created which contains the changes. This means you can safely pass the `Search` object to foreign code without fear of it modifying your objects as long as it sticks to the `Search` object APIs. +The API is designed to be chainable. With the exception of the aggregations functionality this means that the `Search` object is immutable -all changes to the object will result in a shallow copy being created which contains the changes. You can safely pass the `Search` object to foreign code without fear of it modifying your objects as long as it sticks to the `Search` object APIs. You can pass an instance of the [elasticsearch client](https://elasticsearch-py.readthedocs.io/) when instantiating the `Search` object: @@ -51,7 +51,7 @@ All methods return a *copy* of the object, making it safe to pass to outside cod The API is chainable, allowing you to combine multiple method calls in one statement: ```python -s = Search().using(client).query("match", title="python") +s = Search().using(client).query(Match("title", "python")) ``` To send the request to Elasticsearch: @@ -67,9 +67,9 @@ for hit in s: print(hit.title) ``` -Search results will be cached. Subsequent calls to `execute` or trying to iterate over an already executed `Search` object will not trigger additional requests being sent to Elasticsearch. To force a request specify `ignore_cache=True` when calling `execute`. +Search results will be cached. Subsequent calls to `execute` or trying to iterate over an already executed `Search` object will not trigger additional requests being sent to Elasticsearch. To force a new request to be issued specify `ignore_cache=True` when calling `execute`. -For debugging purposes you can serialize the `Search` object to a `dict` explicitly: +For debugging purposes you can serialize the `Search` object to a `dict` with the raw Elasticsearch request: ```python print(s.to_dict()) @@ -80,32 +80,28 @@ print(s.to_dict()) You can delete the documents matching a search by calling `delete` on the `Search` object instead of `execute` like this: ```python -s = Search(index='i').query("match", title="python") +s = Search(index='i').query(Match("title", "python")) response = s.delete() ``` #### Queries [_queries] -The library provides classes for all Elasticsearch query types. Pass all the parameters as keyword arguments. The classes accept any keyword arguments, the dsl then takes all arguments passed to the constructor and serializes them as top-level keys in the resulting dictionary (and thus the resulting json being sent to elasticsearch). This means that there is a clear one-to-one mapping between the raw query and its equivalent in the DSL: +The `elasticsearch.dsl.query` module provides classes for all Elasticsearch query types. These classes accept keyword arguments in their constructors, which are serialized to the appropriate format to be sent to Elasticsearch. There is a clear one-to-one mapping between the raw query and its equivalent class-based version: ```python -from elasticsearch.dsl.query import MultiMatch, Match +>>> from elasticsearch.dsl.query import MultiMatch, Match -# {"multi_match": {"query": "python django", "fields": ["title", "body"]}} -MultiMatch(query='python django', fields=['title', 'body']) +>>> q = MultiMatch(query='python django', fields=['title', 'body']) +>>> q.to_dict() +{'multi_match': {'query': 'python django', 'fields': ['title', 'body']}} -# {"match": {"title": {"query": "web framework", "type": "phrase"}}} -Match(title={"query": "web framework", "type": "phrase"}) +>>> q = Match("title", {"query": "web framework", "type": "phrase"}) +>>> q.to_dict() +{'match': {'title': {'query': 'web framework', 'type': 'phrase'}}} ``` -::::{note} -In some cases this approach is not possible due to python’s restriction on identifiers - for example if your field is called `@timestamp`. In that case you have to fall back to unpacking a dictionary: `Range(*+ {'@timestamp': {'lt': 'now'}})` - -:::: - - -You can use the `Q` shortcut to construct the instance using a name with parameters or the raw `dict`: +An alternative to the class-based queries is to use the `Q` shortcut, passing a query name followed by its parameters, or the raw query as a `dict`: ```python from elasticsearch.dsl import Q @@ -114,20 +110,20 @@ Q("multi_match", query='python django', fields=['title', 'body']) Q({"multi_match": {"query": "python django", "fields": ["title", "body"]}}) ``` -To add the query to the `Search` object, use the `.query()` method: +To add a query to the `Search` object, use the `.query()` method. This works with class-based or `Q` queries: ```python q = Q("multi_match", query='python django', fields=['title', 'body']) s = s.query(q) ``` -The method also accepts all the parameters as the `Q` shortcut: +As a shortcut the `query()` method also accepts all the parameters of the `Q` shortcut directly: ```python s = s.query("multi_match", query='python django', fields=['title', 'body']) ``` -If you already have a query object, or a `dict` representing one, you can just override the query used in the `Search` object: +If you already have a query object, or a `dict` representing one, you can assign it to the `query` attribute of a `Search` object to add it to it, replacing any previously configured queries: ```python s.query = Q('bool', must=[Q('match', title='python'), Q('match', body='best')]) @@ -136,7 +132,7 @@ s.query = Q('bool', must=[Q('match', title='python'), Q('match', body='best')]) #### Dotted fields [_dotted_fields] -Sometimes you want to refer to a field within another field, either as a multi-field (`title.keyword`) or in a structured `json` document like `address.city`. To make it easier, the `Q` shortcut (as well as the `query`, `filter`, and `exclude` methods on `Search` class) allows you to use `_+` (double underscore) in place of a dot in a keyword argument: +Sometimes you want to refer to a field within another field, either as a multi-field (`title.keyword`) or in a structured `json` document like `address.city`. This is not a problem when using class-based queries, but when working without classes it is often required to pass field names as keyword arguments. To make this easier, you can use `__` (double underscore) in place of a dot in a keyword argument: ```python s = Search() @@ -144,7 +140,7 @@ s = s.filter('term', category__keyword='Python') s = s.query('match', address__city='prague') ``` -Alternatively you can always fall back to python’s kwarg unpacking if you prefer: +Alternatively you can use Python’s keyword argument unpacking: ```python s = Search() @@ -155,20 +151,23 @@ s = s.query('match', **{'address.city': 'prague'}) #### Query combination [_query_combination] -Query objects can be combined using logical operators: +Query objects can be combined using logical operators `|`, `&` and `~`: ```python -Q("match", title='python') | Q("match", title='django') -# {"bool": {"should": [...]}} +>>> q = Match("title", "python") | Match("title", "django") +>>> q.to_dict() +{'bool': {'should': [{'match': {'title': 'python'}}, {'match': {'title': 'django'}}]}} -Q("match", title='python') & Q("match", title='django') -# {"bool": {"must": [...]}} +>>> q = Match("title", "python") & Match("title", "django") +>>> q.to_dict() +{'bool': {'must': [{'match': {'title': 'python'}}, {'match': {'title': 'django'}}]}} -~Q("match", title="python") -# {"bool": {"must_not": [...]}} +>>> q = ~Match("title", "python") +>>> q.to_dict() +{'bool': {'must_not': [{'match': {'title': 'python'}}]}} ``` -When you call the `.query()` method multiple times, the `&` operator will be used internally: +When you call the `.query()` method multiple times, the `&` operator will be used internally to combine all the queries: ```python s = s.query().query() @@ -193,48 +192,64 @@ s = Search().query(q) If you want to add a query in a [filter context](docs-content://explore-analyze/query-filter/languages/querydsl.md) you can use the `filter()` method to make things easier: ```python +from elasticsearch.dsl.query import Terms + s = Search() -s = s.filter('terms', tags=['search', 'python']) +s = s.filter(Terms("tags", ['search', 'python'])) ``` Behind the scenes this will produce a `Bool` query and place the specified `terms` query into its `filter` branch, making it equivalent to: ```python +from elasticsearch.dsl.query import Terms, Bool + s = Search() -s = s.query('bool', filter=[Q('terms', tags=['search', 'python'])]) +s = s.query(Bool(filter=[Terms("tags", ["search", "python"])])) ``` -If you want to use the post_filter element for faceted navigation, use the `.post_filter()` method. +If you want to use the `post_filter` element for faceted navigation, use the `.post_filter()` method. -You can also `exclude()` items from your query like this: +The `exclude()` method works like `filter()`, but it applies the query as negated: ```python s = Search() -s = s.exclude('terms', tags=['search', 'python']) +s = s.exclude(Terms("tags", ['search', 'python'])) ``` -which is shorthand for: `s = s.query('bool', filter=[~Q('terms', tags=['search', 'python'])])` +which is shorthand for: + +```python +s = s.query(Bool(filter=[~Terms("tags", ["search", "python"])])) +``` #### Aggregations [_aggregations] -To define an aggregation, you can use the `A` shortcut: +As with queries, there are classes that represent each aggregation type, all accessible through the `elasticsearch.dsl.aggs` module: + +```python +from elasticsearch.dsl import aggs + +a = aggs.Terms(field="tags") +# {"terms": {"field": "tags"}} +``` + +It is also possible to define an aggregation using the `A` shortcut: ```python from elasticsearch.dsl import A A('terms', field='tags') -# {"terms": {"field": "tags"}} ``` To nest aggregations, you can use the `.bucket()`, `.metric()` and `.pipeline()` methods: ```python -a = A('terms', field='category') +a = aggs.Terms(field="category") # {'terms': {'field': 'category'}} -a.metric('clicks_per_category', 'sum', field='clicks')\ - .bucket('tags_per_category', 'terms', field='tags') +a.metric("clicks_per_category", aggs.Sum(field="clicks")) \ + .bucket("tags_per_category", aggs.Terms(field="tags")) # { # 'terms': {'field': 'category'}, # 'aggs': { @@ -248,8 +263,8 @@ To add aggregations to the `Search` object, use the `.aggs` property, which acts ```python s = Search() -a = A('terms', field='category') -s.aggs.bucket('category_terms', a) +a = aggs.Terms(field="category") +s.aggs.bucket("category_terms", a) # { # 'aggs': { # 'category_terms': { @@ -265,10 +280,10 @@ or ```python s = Search() -s.aggs.bucket('articles_per_day', 'date_histogram', field='publish_date', interval='day')\ - .metric('clicks_per_day', 'sum', field='clicks')\ - .pipeline('moving_click_average', 'moving_avg', buckets_path='clicks_per_day')\ - .bucket('tags_per_day', 'terms', field='tags') +s.aggs.bucket("articles_per_day", aggs.DateHistogram(field="publish_date", interval="day")) \ + .metric("clicks_per_day", aggs.Sum(field="clicks")) \ + .pipeline("moving_click_average", aggs.MovingAvg(buckets_path="clicks_per_day")) \ + .bucket("tags_per_day", aggs.Terms(field="tags")) s.to_dict() # { @@ -290,9 +305,9 @@ You can access an existing bucket by its name: ```python s = Search() -s.aggs.bucket('per_category', 'terms', field='category') -s.aggs['per_category'].metric('clicks_per_category', 'sum', field='clicks') -s.aggs['per_category'].bucket('tags_per_category', 'terms', field='tags') +s.aggs.bucket("per_category", aggs.Terms(field="category")) +s.aggs["per_category"].metric("clicks_per_category", aggs.Sum(field="clicks")) +s.aggs["per_category"].bucket("tags_per_category", aggs.Terms(field="tags")) ``` ::::{note} @@ -301,7 +316,7 @@ When chaining multiple aggregations, there is a difference between what `.bucket :::: -As opposed to other methods on the `Search` objects, defining aggregations is done in-place (does not return a copy). +As opposed to other methods on the `Search` objects, aggregations are defined in-place, without returning a new copy. #### K-Nearest Neighbor Searches [_k_nearest_neighbor_searches] @@ -348,7 +363,7 @@ s = s.sort() #### Pagination [_pagination] -To specify the from/size parameters, use the Python slicing API: +To specify the from/size parameters, apply the standard Python slicing operator on the `Search` instance: ```python s = s[10:20] @@ -417,7 +432,7 @@ The first argument is the name of the suggestions (name under which it will be r To collapse search results use the `collapse` method on your `Search` object: ```python -s = Search().query("match", message="GET /search") +s = Search().query(Match("message", "GET /search")) # collapse results by user_id s = s.collapse("user_id") ``` @@ -526,11 +541,11 @@ If you want to inspect the contents of the `response` objects, just use its `to_ #### Hits [_hits] -To access to the hits returned by the search, access the `hits` property or just iterate over the `Response` object: +To access the hits returned by the search, use the `hits` property or just iterate over the `Response` object: ```python response = s.execute() -print('Total %d hits found.' % response.hits.total) +print(f"Total {response.hits.total} hits found.") for h in response: print(h.title, h.body) ``` @@ -549,8 +564,7 @@ The individual hits is wrapped in a convenience class that allows attribute acce ```python response = s.execute() h = response.hits[0] -print('/%s/%s/%s returned with score %f' % ( - h.meta.index, h.meta.doc_type, h.meta.id, h.meta.score)) +print(f"/{h.meta.index}/{h.meta.doc_type}/{h.meta.id} returned with score {h.meta.score}") ``` ::::{note} @@ -577,11 +591,12 @@ If you need to execute multiple searches at the same time you can use the `Multi ```python from elasticsearch.dsl import MultiSearch, Search +from elasticsearch.dsl.query import Term ms = MultiSearch(index='blogs') -ms = ms.add(Search().filter('term', tags='python')) -ms = ms.add(Search().filter('term', tags='elasticsearch')) +ms = ms.add(Search().filter(Term("tags", "python"))) +ms = ms.add(Search().filter(Term("tags", 'elasticsearch'))) responses = ms.execute() @@ -653,9 +668,9 @@ class Post(Document): #### Data types [_data_types] -The `Document` instances use native python types like `str` and `datetime`. In case of `Object` or `Nested` fields an instance of the `InnerDoc` subclass is used, as in the `add_comment` method in the above example where we are creating an instance of the `Comment` class. +The `Document` instances use native python types such as `str` and `datetime` for its attributes. In case of `Object` or `Nested` fields an instance of the `InnerDoc` subclass is used, as in the `add_comment` method in the above example, where we are creating an instance of the `Comment` class. -There are some specific types that were created as part of this library to make working with some field types easier, for example the `Range` object used in any of the [range fields](elasticsearch://reference/elasticsearch/mapping-reference/range.md): +There are some specific types that were created to make working with some field types easier, for example the `Range` object used in any of the [range fields](elasticsearch://reference/elasticsearch/mapping-reference/range.md): ```python from elasticsearch.dsl import Document, DateRange, Keyword, Range @@ -664,7 +679,6 @@ class RoomBooking(Document): room = Keyword() dates = DateRange() - rb = RoomBooking( room='Conference Room II', dates=Range( @@ -700,7 +714,7 @@ class Post(Document): It is important to note that when using `Field` subclasses such as `Text`, `Date` and `Boolean`, they must be given in the right-side of an assignment, as shown in examples above. Using these classes as type hints will result in errors. -Python types are mapped to their corresponding field type according to the following table: +Python types are mapped to their corresponding field types according to the following table: | Python type | DSL field | | --- | --- | @@ -740,18 +754,18 @@ class Post(Document): comments: List[Comment] # same as comments = Nested(Comment, required=True) ``` -Unfortunately it is impossible to have Python type hints that uniquely identify every possible Elasticsearch field type. To choose a field type that is different than the ones in the table above, the field instance can be added explicitly as a right-side assignment in the field declaration. The next example creates a field that is typed as `Optional[str]`, but is mapped to `Keyword` instead of `Text`: +Unfortunately it is impossible to have Python type hints that uniquely identify every possible Elasticsearch field type. To choose a field type that is different than the one that is assigned according to the table above, the desired field instance can be added explicitly as a right-side assignment in the field declaration. The next example creates a field that is typed as `Optional[str]`, but is mapped to `Keyword` instead of `Text`: ```python class MyDocument(Document): category: Optional[str] = Keyword() ``` -This form can also be used when additional options need to be given to initialize the field, such as when using custom analyzer settings or changing the `required` default: +This form can also be used when additional options need to be given to initialize the field, such as when using custom analyzer settings: ```python class Comment(InnerDoc): - content: str = Text(analyzer='snowball', required=True) + content: str = Text(analyzer='snowball') ``` When using type hints as above, subclasses of `Document` and `InnerDoc` inherit some of the behaviors associated with Python dataclasses, as defined by [PEP 681](https://peps.python.org/pep-0681/) and the [dataclass_transform decorator](https://typing.readthedocs.io/en/latest/spec/dataclasses.html#dataclass-transform). To add per-field dataclass options such as `default` or `default_factory`, the `mapped_field()` wrapper can be used on the right side of a typed field declaration: @@ -761,12 +775,12 @@ class MyDocument(Document): title: str = mapped_field(default="no title") created_at: datetime = mapped_field(default_factory=datetime.now) published: bool = mapped_field(default=False) - category: str = mapped_field(Keyword(required=True), default="general") + category: str = mapped_field(Keyword(), default="general") ``` When using the `mapped_field()` wrapper function, an explicit field type instance can be passed as a first positional argument, as the `category` field does in the example above. -Static type checkers such as [mypy](https://mypy-lang.org/) and [pyright](https://github.com/microsoft/pyright) can use the type hints and the dataclass-specific options added to the `mapped_field()` function to improve type inference and provide better real-time suggestions in IDEs. +Static type checkers such as [mypy](https://mypy-lang.org/) and [pyright](https://github.com/microsoft/pyright) can use the type hints and the dataclass-specific options added to the `mapped_field()` function to improve type inference and provide better real-time code completion and suggestions in IDEs. One situation in which type checkers can’t infer the correct type is when using fields as class attributes. Consider the following example: @@ -804,7 +818,7 @@ The `InstrumentedField` objects returned when fields are accessed as class attri s = MyDocument.search().sort(-MyDocument.created_at, MyDocument.title) ``` -When specifying sorting order, the `{{plus}}` and `-` unary operators can be used on the class field attributes to indicate ascending and descending order. +When specifying sorting order, the `+` and `-` unary operators can be used on the class field attributes to indicate ascending and descending order. Finally, the `ClassVar` annotation can be used to define a regular class attribute that should not be mapped to the Elasticsearch index: @@ -812,9 +826,8 @@ Finally, the `ClassVar` annotation can be used to define a regular class attribu from typing import ClassVar class MyDoc(Document): - title: M[str] created_at: M[datetime] = - mapped_field(default_factory=datetime.now) my_var: - ClassVar[str] # regular class variable, ignored by Elasticsearch + title: M[str] created_at: M[datetime] = mapped_field(default_factory=datetime.now) + my_var: ClassVar[str] # regular class variable, ignored by Elasticsearch ``` @@ -1050,13 +1063,13 @@ You can use standard Python inheritance to extend models, this can be useful in ```python class User(InnerDoc): - username = Text(fields={'keyword': Keyword()}) - email = Text() + username: str = mapped_field(Text(fields={'keyword': Keyword()})) + email: str class BaseDocument(Document): - created_by = Object(User) - created_date = Date() - last_updated = Date() + created_by: User + created_date: datetime + last_updated: datetime def save(**kwargs): if not self.created_date: @@ -1101,7 +1114,7 @@ blogs.document(Post) # can also be used as class decorator when defining the Document @blogs.document class Post(Document): - title = Text() + title: str # You can attach custom analyzers to the index @@ -1138,9 +1151,15 @@ dev_blogs.setting(number_of_shards=1) #### IndexTemplate [index-template] -The DSL module also exposes an option to manage [index templates](docs-content://manage-data/data-store/templates.md) in elasticsearch using the `IndexTemplate` class which has very similar API to `Index`. +The DSL module also exposes an option to manage [index templates](docs-content://manage-data/data-store/templates.md) in elasticsearch using the `ComposableIndexTemplate` and `IndexTemplate` classes, which have very similar API to `Index`. + +::::{note} +Composable index templates should be always be preferred over the legacy index templates, since the latter are deprecated. -Once an index template is saved in elasticsearch it’s contents will be automatically applied to new indices (existing indices are completely unaffected by templates) that match the template pattern (any index starting with `blogs-` in our example), even if the index is created automatically upon indexing a document into that index. +:::: + + +Once an index template is saved in Elasticsearch its contents will be automatically applied to new indices (existing indices are completely unaffected by templates) that match the template pattern (any index starting with `blogs-` in our example), even if the index is created automatically upon indexing a document into that index. Potential workflow for a set of time based indices governed by a single template: @@ -1151,14 +1170,11 @@ from elasticsearch.dsl import Document, Date, Text class Log(Document): - content = Text() - timestamp = Date() + content: str + timestamp: datetime class Index: name = "logs-*" - settings = { - "number_of_shards": 2 - } def save(self, **kwargs): # assign now if no timestamp given @@ -1170,7 +1186,7 @@ class Log(Document): return super().save(**kwargs) # once, as part of application setup, during deploy/migrations: -logs = Log._index.as_template('logs', order=0) +logs = Log._index.as_composable_template('logs', priority=100) logs.save() # to perform search across all logs: @@ -1184,12 +1200,6 @@ search = Log.search() The library comes with a simple abstraction aimed at helping you develop faceted navigation for your data. -::::{note} -This API is experimental and will be subject to change. Any feedback is welcome. - -:::: - - ### Configuration [_configuration_2] You can provide several configuration options (as class attributes) when declaring a `FacetedSearch` subclass: @@ -1316,7 +1326,7 @@ All methods return a *copy* of the object, making it safe to pass to outside cod The API is chainable, allowing you to combine multiple method calls in one statement: ```python -ubq = UpdateByQuery().using(client).query("match", title="python") +ubq = UpdateByQuery().using(client).query(Match("title", python")) ``` To send the request to Elasticsearch: @@ -1444,8 +1454,9 @@ Use the `AsyncSearch` class to perform asynchronous searches. ```python from elasticsearch.dsl import AsyncSearch +from elasticsearch.dsl.query import Match -s = AsyncSearch().query("match", title="python") +s = AsyncSearch().query(Match("title", "python")) async for hit in s: print(hit.title) ``` @@ -1453,7 +1464,7 @@ async for hit in s: Instead of using the `AsyncSearch` object as an asynchronous iterator, you can explicitly call the `execute()` method to get a `Response` object. ```python -s = AsyncSearch().query("match", title="python") +s = AsyncSearch().query(Match("title", "python")) response = await s.execute() for hit in response: print(hit.title) @@ -1463,11 +1474,12 @@ An `AsyncMultiSearch` is available as well. ```python from elasticsearch.dsl import AsyncMultiSearch +from elasticsearch.dsl.query import Term ms = AsyncMultiSearch(index='blogs') -ms = ms.add(AsyncSearch().filter('term', tags='python')) -ms = ms.add(AsyncSearch().filter('term', tags='elasticsearch')) +ms = ms.add(AsyncSearch().filter(Term("tags", "python"))) +ms = ms.add(AsyncSearch().filter(Term("tags", "elasticsearch"))) responses = await ms.execute() diff --git a/docs/reference/dsl_migrating.md b/docs/reference/dsl_migrating.md new file mode 100644 index 000000000..ef4bd9f23 --- /dev/null +++ b/docs/reference/dsl_migrating.md @@ -0,0 +1,35 @@ +# Migrating from the `elasticsearch-dsl` package [_migrating_from_elasticsearch_dsl_package] + +In the past the Elasticsearch Python DSL module was distributed as a standalone package called `elasticsearch-dsl`. This package is now deprecated, since all its functionality has been integrated into the main Python client. We recommend all developers to migrate their applications and eliminate their dependency on the `elasticsearch-dsl` package. + +To migrate your application, all references to `elasticsearch_dsl` as a top-level package must be changed to `elasticsearch.dsl`. In other words, the underscore from the package name should be replaced by a period. + +Here are a few examples: + +```python +# from: +from elasticsearch_dsl import Date, Document, InnerDoc, Text, connections +# to: +from elasticsearch.dsl import Date, Document, InnerDoc, Text, connections + +# from: +from elasticsearch_dsl.query import MultiMatch +# to: +from elasticsearch.dsl.query import MultiMatch + +# from: +import elasticsearch_dsl as dsl +# to: +from elasticsearch import dsl + +# from: +import elasticsearch_dsl +# to: +from elasticsearch import dsl as elasticsearch_dsl + +# from: +import elasticsearch_dsl +# to: +from elasticsearch import dsl +# and replace all references to "elasticsearch_dsl" in the code with "dsl" +``` diff --git a/docs/reference/dsl_tutorials.md b/docs/reference/dsl_tutorials.md index 7b72bc04e..77992587b 100644 --- a/docs/reference/dsl_tutorials.md +++ b/docs/reference/dsl_tutorials.md @@ -47,17 +47,17 @@ Let’s rewrite the example using the DSL module: ```python from elasticsearch import Elasticsearch -from elasticsearch.dsl import Search +from elasticsearch.dsl import Search, query, aggs client = Elasticsearch("https://localhost:9200") s = Search(using=client, index="my-index") \ - .filter("term", category="search") \ - .query("match", title="python") \ - .exclude("match", description="beta") + .query(query.Match("title", "python")) \ + .filter(query.Term("category", "search")) \ + .exclude(query.Match("description", "beta")) -s.aggs.bucket('per_tag', 'terms', field='tags') \ - .metric('max_lines', 'max', field='lines') +s.aggs.bucket('per_tag', aggs.Terms(field="tags")) \ + .metric('max_lines', aggs.Max(field='lines')) response = s.execute() @@ -68,9 +68,9 @@ for tag in response.aggregations.per_tag.buckets: print(tag.key, tag.max_lines.value) ``` -As you see, the library took care of: +As you see, the DSL module took care of: -* creating appropriate `Query` objects by name (eq. "match") +* creating appropriate `Query` objects from classes * composing queries into a compound `bool` query * putting the `term` query in a filter context of the `bool` query * providing a convenient access to response data @@ -89,11 +89,11 @@ from elasticsearch.dsl import Document, Date, Integer, Keyword, Text, connection connections.create_connection(hosts="https://localhost:9200") class Article(Document): - title = Text(analyzer='snowball', fields={'raw': Keyword()}) - body = Text(analyzer='snowball') - tags = Keyword() - published_from = Date() - lines = Integer() + title: str = mapped_field(Text(analyzer='snowball', fields={'raw': Keyword()})) + body: str = mapped_field(Text(analyzer='snowball')) + tags: str = mapped_field(Keyword()) + published_from: datetime + lines: int class Index: name = 'blog' @@ -101,7 +101,7 @@ class Article(Document): "number_of_shards": 2, } - def save(self, ** kwargs): + def save(self, **kwargs): self.lines = len(self.body.split()) return super(Article, self).save(** kwargs) @@ -127,7 +127,7 @@ print(connections.get_connection().cluster.health()) In this example you can see: * providing a default connection -* defining fields with mapping configuration +* defining fields with Python type hints and additional mapping configuration when necessary * setting index name * defining custom methods * overriding the built-in `.save()` method to hook into the persistence life cycle @@ -141,12 +141,6 @@ You can see more in the `persistence` chapter. If you have your `Document`s defined you can very easily create a faceted search class to simplify searching and filtering. -::::{note} -This feature is experimental and may be subject to change. - -:::: - - ```python from elasticsearch.dsl import FacetedSearch, TermsFacet, DateHistogramFacet @@ -208,11 +202,12 @@ Using the DSL, we can now express this query as such: ```python from elasticsearch import Elasticsearch from elasticsearch.dsl import Search, UpdateByQuery +from elasticsearch.dsl.query import Match client = Elasticsearch() ubq = UpdateByQuery(using=client, index="my-index") \ - .query("match", title="python") \ - .exclude("match", description="beta") \ + .query(Match("title", "python")) \ + .exclude(Match("description", "beta")) \ .script(source="ctx._source.likes++", lang="painless") response = ubq.execute() @@ -232,7 +227,7 @@ body = {...} # insert complicated query here s = Search.from_dict(body) # Add some filters, aggregations, queries, ... -s.filter("term", tags="python") +s.filter(query.Term("tags", "python")) # Convert back to dict to plug back into existing code body = s.to_dict() diff --git a/docs/reference/elasticsearch-dsl.md b/docs/reference/elasticsearch-dsl.md index 4030e232d..ad72cb1fe 100644 --- a/docs/reference/elasticsearch-dsl.md +++ b/docs/reference/elasticsearch-dsl.md @@ -9,11 +9,12 @@ Elasticsearch DSL is a module of the official Python client that aims to help wi ```python from elasticsearch.dsl import Search +from elasticsearch.dsl.query import Match, Term s = Search(index="my-index") \ - .filter("term", category="search") \ - .query("match", title="python") \ - .exclude("match", description="beta") + .query(Match("title", "python")) \ + .filter(Term("category", "search")) \ + .exclude(Match("description", "beta")) for hit in s: print(hit.title) ``` @@ -22,12 +23,13 @@ Or with asynchronous Python: ```python from elasticsearch.dsl import AsyncSearch +from elasticsearch.dsl.query import Match, Term async def run_query(): s = AsyncSearch(index="my-index") \ - .filter("term", category="search") \ - .query("match", title="python") \ - .exclude("match", description="beta") + .query(Match("title", "python")) \ + .filter(Term("category", "search")) \ + .exclude(Match("description", "beta")) async for hit in s: print(hit.title) ``` diff --git a/docs/reference/toc.yml b/docs/reference/toc.yml index abb74bc42..0ff68225e 100644 --- a/docs/reference/toc.yml +++ b/docs/reference/toc.yml @@ -16,4 +16,5 @@ toc: - file: dsl_tutorials.md - file: dsl_how_to_guides.md - file: dsl_examples.md + - file: dsl_migrating.md - file: client-helpers.md diff --git a/elasticsearch/dsl/search_base.py b/elasticsearch/dsl/search_base.py index c513fc78d..cd690ddae 100644 --- a/elasticsearch/dsl/search_base.py +++ b/elasticsearch/dsl/search_base.py @@ -72,6 +72,9 @@ def __nonzero__(self) -> bool: __bool__ = __nonzero__ def __call__(self, *args: Any, **kwargs: Any) -> _S: + """ + Add a query. + """ s = self._search._clone() # we cannot use self._proxied since we just cloned self._search and @@ -354,18 +357,22 @@ class SearchBase(Request[_R]): post_filter = ProxyDescriptor[Self]("post_filter") _response: Response[_R] - def __init__(self, **kwargs: Any): + def __init__( + self, + using: AnyUsingType = "default", + index: Optional[Union[str, List[str]]] = None, + **kwargs: Any, + ): """ Search request to elasticsearch. :arg using: `Elasticsearch` instance to use :arg index: limit the search to index - :arg doc_type: only query this type. All the parameters supplied (or omitted) at creation type can be later overridden by methods (`using`, `index` and `doc_type` respectively). """ - super().__init__(**kwargs) + super().__init__(using=using, index=index, **kwargs) self.aggs = AggsProxy[_R](self) self._sort: List[Union[str, Dict[str, Dict[str, str]]]] = [] @@ -383,9 +390,15 @@ def __init__(self, **kwargs: Any): self._post_filter_proxy = QueryProxy(self, "post_filter") def filter(self, *args: Any, **kwargs: Any) -> Self: + """ + Add a query in filter context. + """ return self.query(Bool(filter=[Q(*args, **kwargs)])) def exclude(self, *args: Any, **kwargs: Any) -> Self: + """ + Add a negative query in filter context. + """ return self.query(Bool(filter=[~Q(*args, **kwargs)])) def __getitem__(self, n: Union[int, slice]) -> Self: From 5702bde0348f732f43ad6a70ebc99dceb1667ff4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 31 Mar 2025 16:32:15 +0100 Subject: [PATCH 08/57] Remove unneded nonlocal and global declarations (#2866) (#2868) (cherry picked from commit 83025a601ce112e6045abe1b5d84cfbaed722b3f) Co-authored-by: Miguel Grinberg --- elasticsearch/_async/client/_base.py | 1 - elasticsearch/_async/helpers.py | 1 - elasticsearch/_sync/client/_base.py | 1 - elasticsearch/_sync/client/utils.py | 3 --- test_elasticsearch/test_server/test_rest_api_spec.py | 4 +--- utils/build-dists.py | 1 - 6 files changed, 1 insertion(+), 10 deletions(-) diff --git a/elasticsearch/_async/client/_base.py b/elasticsearch/_async/client/_base.py index dd0b0f44e..cc090671c 100644 --- a/elasticsearch/_async/client/_base.py +++ b/elasticsearch/_async/client/_base.py @@ -298,7 +298,6 @@ async def _perform_request( def mimetype_header_to_compat(header: str) -> None: # Converts all parts of a Accept/Content-Type headers # from application/X -> application/vnd.elasticsearch+X - nonlocal request_headers mimetype = request_headers.get(header, None) if mimetype: request_headers[header] = _COMPAT_MIMETYPE_RE.sub( diff --git a/elasticsearch/_async/helpers.py b/elasticsearch/_async/helpers.py index 4c53f0bbe..e4d5e6bc5 100644 --- a/elasticsearch/_async/helpers.py +++ b/elasticsearch/_async/helpers.py @@ -136,7 +136,6 @@ def aiter(x: Union[Iterable[T], AsyncIterable[T]]) -> AsyncIterator[T]: return x.__aiter__() async def f() -> AsyncIterable[T]: - nonlocal x ix: Iterable[T] = x for item in ix: yield item diff --git a/elasticsearch/_sync/client/_base.py b/elasticsearch/_sync/client/_base.py index 8929b1db7..868b71073 100644 --- a/elasticsearch/_sync/client/_base.py +++ b/elasticsearch/_sync/client/_base.py @@ -298,7 +298,6 @@ def _perform_request( def mimetype_header_to_compat(header: str) -> None: # Converts all parts of a Accept/Content-Type headers # from application/X -> application/vnd.elasticsearch+X - nonlocal request_headers mimetype = request_headers.get(header, None) if mimetype: request_headers[header] = _COMPAT_MIMETYPE_RE.sub( diff --git a/elasticsearch/_sync/client/utils.py b/elasticsearch/_sync/client/utils.py index 45f33fc6e..48ebcb217 100644 --- a/elasticsearch/_sync/client/utils.py +++ b/elasticsearch/_sync/client/utils.py @@ -134,7 +134,6 @@ def client_node_configs( def apply_node_options(node_config: NodeConfig) -> NodeConfig: """Needs special handling of headers since .replace() wipes out existing headers""" - nonlocal node_options headers = node_config.headers.copy() # type: ignore[attr-defined] headers_to_add = node_options.pop("headers", ()) @@ -306,8 +305,6 @@ def _rewrite_parameters( def wrapper(api: F) -> F: @wraps(api) def wrapped(*args: Any, **kwargs: Any) -> Any: - nonlocal api, body_name, body_fields - # Let's give a nicer error message when users pass positional arguments. if len(args) >= 2: raise TypeError( diff --git a/test_elasticsearch/test_server/test_rest_api_spec.py b/test_elasticsearch/test_server/test_rest_api_spec.py index 0b602684a..a84f0822a 100644 --- a/test_elasticsearch/test_server/test_rest_api_spec.py +++ b/test_elasticsearch/test_server/test_rest_api_spec.py @@ -280,8 +280,6 @@ def run_catch(self, catch, exception): self.last_response = exception.body def run_skip(self, skip): - global IMPLEMENTED_FEATURES - if "features" in skip: features = skip["features"] if not isinstance(features, (tuple, list)): @@ -437,7 +435,7 @@ def _lookup(self, path): return value def _feature_enabled(self, name): - global XPACK_FEATURES, IMPLEMENTED_FEATURES + global XPACK_FEATURES if XPACK_FEATURES is None: try: xinfo = self.client.xpack.info() diff --git a/utils/build-dists.py b/utils/build-dists.py index ec8083103..d67d6053a 100644 --- a/utils/build-dists.py +++ b/utils/build-dists.py @@ -42,7 +42,6 @@ def set_tmp_dir(): def run(*argv, expect_exit_code=0): - global tmp_dir try: prev_dir = os.getcwd() if tmp_dir is None: From 01893c88ed6440d0ad10b53a3ded8c04d063833e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 1 Apr 2025 09:59:41 +0100 Subject: [PATCH 09/57] [docs] Add param notes to DSL search.delete documentation, fix broken links (#2861) (#2869) * Add param notes to DSL search.delete documentation, fix broken links The preferred way of passing parameters to the DSL `Search.delete` appears to be calling `Search.params` first, but this is only ever discussed in GitHub issues like elastic/elasticsearch-dsl-py#1115 and elastic/elasticsearch-dsl-py#1395. To help anyone else who has stumbled across this, I added a note about this to the documentation. I also went ahead and updated the links for the `Search.scan` and `FacetedSearch.params` methods to the most recent versions since they were 404ing. * make sync and async changes the same --------- Co-authored-by: Luna Lucadou Co-authored-by: Miguel Grinberg (cherry picked from commit b6d1211cfb04825eb00f9d756738af3258eba199) Co-authored-by: Luna Lucadou <22415965+lunalucadou@users.noreply.github.com> --- docs/reference/dsl_how_to_guides.md | 9 +++++++++ elasticsearch/dsl/_async/search.py | 10 +++++++--- elasticsearch/dsl/_sync/search.py | 10 +++++++--- elasticsearch/dsl/faceted_search_base.py | 2 +- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/docs/reference/dsl_how_to_guides.md b/docs/reference/dsl_how_to_guides.md index 93dc8d9a1..ce128528a 100644 --- a/docs/reference/dsl_how_to_guides.md +++ b/docs/reference/dsl_how_to_guides.md @@ -84,6 +84,15 @@ s = Search(index='i').query(Match("title", "python")) response = s.delete() ``` +To pass [deletion parameters](https://elasticsearch-py.readthedocs.io/en/latest/api/elasticsearch.html#elasticsearch.Elasticsearch.delete_by_query) +in your query, you can add them by calling ``params`` on the ``Search`` object before ``delete`` like this: + +```python +s = Search(index='i').query("match", title="python") +s = s.params(ignore_unavailable=False, wait_for_completion=True) +response = s.delete() +``` + #### Queries [_queries] diff --git a/elasticsearch/dsl/_async/search.py b/elasticsearch/dsl/_async/search.py index 42eb142fd..2ea277a07 100644 --- a/elasticsearch/dsl/_async/search.py +++ b/elasticsearch/dsl/_async/search.py @@ -107,9 +107,9 @@ async def scan(self) -> AsyncIterator[_R]: Turn the search into a scan search and return a generator that will iterate over all the documents matching the query. - Use ``params`` method to specify any additional arguments you with to + Use the ``params`` method to specify any additional arguments you wish to pass to the underlying ``scan`` helper from ``elasticsearch-py`` - - https://elasticsearch-py.readthedocs.io/en/master/helpers.html#elasticsearch.helpers.scan + https://elasticsearch-py.readthedocs.io/en/latest/helpers.html#scan The ``iterate()`` method should be preferred, as it provides similar functionality using an Elasticsearch point in time. @@ -123,7 +123,11 @@ async def scan(self) -> AsyncIterator[_R]: async def delete(self) -> AttrDict[Any]: """ - delete() executes the query by delegating to delete_by_query() + ``delete()`` executes the query by delegating to ``delete_by_query()``. + + Use the ``params`` method to specify any additional arguments you wish to + pass to the underlying ``delete_by_query`` helper from ``elasticsearch-py`` - + https://elasticsearch-py.readthedocs.io/en/latest/api/elasticsearch.html#elasticsearch.Elasticsearch.delete_by_query """ es = get_connection(self._using) diff --git a/elasticsearch/dsl/_sync/search.py b/elasticsearch/dsl/_sync/search.py index ae826a12f..4dfbdb92b 100644 --- a/elasticsearch/dsl/_sync/search.py +++ b/elasticsearch/dsl/_sync/search.py @@ -104,9 +104,9 @@ def scan(self) -> Iterator[_R]: Turn the search into a scan search and return a generator that will iterate over all the documents matching the query. - Use ``params`` method to specify any additional arguments you with to + Use the ``params`` method to specify any additional arguments you wish to pass to the underlying ``scan`` helper from ``elasticsearch-py`` - - https://elasticsearch-py.readthedocs.io/en/master/helpers.html#elasticsearch.helpers.scan + https://elasticsearch-py.readthedocs.io/en/latest/helpers.html#scan The ``iterate()`` method should be preferred, as it provides similar functionality using an Elasticsearch point in time. @@ -118,7 +118,11 @@ def scan(self) -> Iterator[_R]: def delete(self) -> AttrDict[Any]: """ - delete() executes the query by delegating to delete_by_query() + ``delete()`` executes the query by delegating to ``delete_by_query()``. + + Use the ``params`` method to specify any additional arguments you wish to + pass to the underlying ``delete_by_query`` helper from ``elasticsearch-py`` - + https://elasticsearch-py.readthedocs.io/en/latest/api/elasticsearch.html#elasticsearch.Elasticsearch.delete_by_query """ es = get_connection(self._using) diff --git a/elasticsearch/dsl/faceted_search_base.py b/elasticsearch/dsl/faceted_search_base.py index 5caa041bf..b58f23dca 100644 --- a/elasticsearch/dsl/faceted_search_base.py +++ b/elasticsearch/dsl/faceted_search_base.py @@ -469,7 +469,7 @@ def params(self, **kwargs: Any) -> None: """ Specify query params to be used when executing the search. All the keyword arguments will override the current values. See - https://elasticsearch-py.readthedocs.io/en/master/api.html#elasticsearch.Elasticsearch.search + https://elasticsearch-py.readthedocs.io/en/latest/api/elasticsearch.html#elasticsearch.Elasticsearch.search for all available parameters. """ self._s = self._s.params(**kwargs) From 43ce0dc4e1edf4b150ca27d04d4f412dbf71ea89 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 1 Apr 2025 10:32:39 +0100 Subject: [PATCH 10/57] Handle new aggregation range types Pythoncally (#2860) (#2865) (cherry picked from commit a224f49cef40e55ea847c4831083ce6648e618d3) Co-authored-by: Miguel Grinberg --- elasticsearch/dsl/aggs.py | 13 +- elasticsearch/dsl/faceted_search_base.py | 6 +- elasticsearch/dsl/field.py | 157 ++++++++++++++++++++++- elasticsearch/dsl/query.py | 8 +- elasticsearch/dsl/types.py | 120 ++++++----------- elasticsearch/dsl/wrappers.py | 25 ++++ utils/dsl-generator.py | 35 +++-- utils/templates/aggs.py.tpl | 1 + 8 files changed, 269 insertions(+), 96 deletions(-) diff --git a/elasticsearch/dsl/aggs.py b/elasticsearch/dsl/aggs.py index ba5150803..a20373163 100644 --- a/elasticsearch/dsl/aggs.py +++ b/elasticsearch/dsl/aggs.py @@ -35,6 +35,7 @@ from elastic_transport.client_utils import DEFAULT +from . import wrappers from .query import Query from .response.aggs import AggResponse, BucketData, FieldBucketData, TopHitsData from .utils import _R, AttrDict, DslBase @@ -761,7 +762,7 @@ def __init__( *, after: Union[ Mapping[ - Union[str, "InstrumentedField"], Union[int, float, str, bool, None, Any] + Union[str, "InstrumentedField"], Union[int, float, str, bool, None] ], "DefaultType", ] = DEFAULT, @@ -958,7 +959,7 @@ def __init__( format: Union[str, "DefaultType"] = DEFAULT, missing: Union[str, int, float, bool, "DefaultType"] = DEFAULT, ranges: Union[ - Sequence["types.DateRangeExpression"], + Sequence["wrappers.AggregationRange"], Sequence[Dict[str, Any]], "DefaultType", ] = DEFAULT, @@ -1347,7 +1348,9 @@ def __init__( "DefaultType", ] = DEFAULT, ranges: Union[ - Sequence["types.AggregationRange"], Sequence[Dict[str, Any]], "DefaultType" + Sequence["wrappers.AggregationRange"], + Sequence[Dict[str, Any]], + "DefaultType", ] = DEFAULT, unit: Union[ Literal["in", "ft", "yd", "mi", "nmi", "km", "m", "cm", "mm"], "DefaultType" @@ -2657,7 +2660,9 @@ def __init__( field: Union[str, "InstrumentedField", "DefaultType"] = DEFAULT, missing: Union[int, "DefaultType"] = DEFAULT, ranges: Union[ - Sequence["types.AggregationRange"], Sequence[Dict[str, Any]], "DefaultType" + Sequence["wrappers.AggregationRange"], + Sequence[Dict[str, Any]], + "DefaultType", ] = DEFAULT, script: Union["types.Script", Dict[str, Any], "DefaultType"] = DEFAULT, keyed: Union[bool, "DefaultType"] = DEFAULT, diff --git a/elasticsearch/dsl/faceted_search_base.py b/elasticsearch/dsl/faceted_search_base.py index b58f23dca..c70a5db0e 100644 --- a/elasticsearch/dsl/faceted_search_base.py +++ b/elasticsearch/dsl/faceted_search_base.py @@ -42,7 +42,7 @@ from .response.aggs import BucketData from .search_base import SearchBase -FilterValueType = Union[str, datetime, Sequence[str]] +FilterValueType = Union[str, int, float, bool] __all__ = [ "FacetedSearchBase", @@ -396,10 +396,10 @@ def add_filter( ] # remember the filter values for use in FacetedResponse - self.filter_values[name] = filter_values # type: ignore[assignment] + self.filter_values[name] = filter_values # get the filter from the facet - f = self.facets[name].add_filter(filter_values) # type: ignore[arg-type] + f = self.facets[name].add_filter(filter_values) if f is None: return diff --git a/elasticsearch/dsl/field.py b/elasticsearch/dsl/field.py index 7fcc9ada5..726fbe358 100644 --- a/elasticsearch/dsl/field.py +++ b/elasticsearch/dsl/field.py @@ -437,7 +437,9 @@ def __init__( doc_class: Union[Type["InnerDoc"], "DefaultType"] = DEFAULT, *args: Any, enabled: Union[bool, "DefaultType"] = DEFAULT, - subobjects: Union[bool, "DefaultType"] = DEFAULT, + subobjects: Union[ + Literal["true", "false", "auto"], bool, "DefaultType" + ] = DEFAULT, copy_to: Union[ Union[str, "InstrumentedField"], Sequence[Union[str, "InstrumentedField"]], @@ -762,6 +764,11 @@ class Boolean(Field): :arg fielddata: :arg index: :arg null_value: + :arg ignore_malformed: + :arg script: + :arg on_script_error: + :arg time_series_dimension: For internal use by Elastic only. Marks + the field as a time series dimension. Defaults to false. :arg doc_values: :arg copy_to: :arg store: @@ -789,6 +796,10 @@ def __init__( ] = DEFAULT, index: Union[bool, "DefaultType"] = DEFAULT, null_value: Union[bool, "DefaultType"] = DEFAULT, + ignore_malformed: Union[bool, "DefaultType"] = DEFAULT, + script: Union["types.Script", Dict[str, Any], "DefaultType"] = DEFAULT, + on_script_error: Union[Literal["fail", "continue"], "DefaultType"] = DEFAULT, + time_series_dimension: Union[bool, "DefaultType"] = DEFAULT, doc_values: Union[bool, "DefaultType"] = DEFAULT, copy_to: Union[ Union[str, "InstrumentedField"], @@ -816,6 +827,14 @@ def __init__( kwargs["index"] = index if null_value is not DEFAULT: kwargs["null_value"] = null_value + if ignore_malformed is not DEFAULT: + kwargs["ignore_malformed"] = ignore_malformed + if script is not DEFAULT: + kwargs["script"] = script + if on_script_error is not DEFAULT: + kwargs["on_script_error"] = on_script_error + if time_series_dimension is not DEFAULT: + kwargs["time_series_dimension"] = time_series_dimension if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: @@ -1092,6 +1111,56 @@ def __init__( super().__init__(*args, **kwargs) +class CountedKeyword(Field): + """ + :arg index: + :arg meta: Metadata about the field. + :arg properties: + :arg ignore_above: + :arg dynamic: + :arg fields: + :arg synthetic_source_keep: + """ + + name = "counted_keyword" + _param_defs = { + "properties": {"type": "field", "hash": True}, + "fields": {"type": "field", "hash": True}, + } + + def __init__( + self, + *args: Any, + index: Union[bool, "DefaultType"] = DEFAULT, + meta: Union[Mapping[str, str], "DefaultType"] = DEFAULT, + properties: Union[Mapping[str, Field], "DefaultType"] = DEFAULT, + ignore_above: Union[int, "DefaultType"] = DEFAULT, + dynamic: Union[ + Literal["strict", "runtime", "true", "false"], bool, "DefaultType" + ] = DEFAULT, + fields: Union[Mapping[str, Field], "DefaultType"] = DEFAULT, + synthetic_source_keep: Union[ + Literal["none", "arrays", "all"], "DefaultType" + ] = DEFAULT, + **kwargs: Any, + ): + if index is not DEFAULT: + kwargs["index"] = index + if meta is not DEFAULT: + kwargs["meta"] = meta + if properties is not DEFAULT: + kwargs["properties"] = properties + if ignore_above is not DEFAULT: + kwargs["ignore_above"] = ignore_above + if dynamic is not DEFAULT: + kwargs["dynamic"] = dynamic + if fields is not DEFAULT: + kwargs["fields"] = fields + if synthetic_source_keep is not DEFAULT: + kwargs["synthetic_source_keep"] = synthetic_source_keep + super().__init__(*args, **kwargs) + + class Date(Field): """ :arg default_timezone: timezone that will be automatically used for tz-naive values @@ -1101,6 +1170,8 @@ class Date(Field): :arg format: :arg ignore_malformed: :arg index: + :arg script: + :arg on_script_error: :arg null_value: :arg precision_step: :arg locale: @@ -1133,6 +1204,8 @@ def __init__( format: Union[str, "DefaultType"] = DEFAULT, ignore_malformed: Union[bool, "DefaultType"] = DEFAULT, index: Union[bool, "DefaultType"] = DEFAULT, + script: Union["types.Script", Dict[str, Any], "DefaultType"] = DEFAULT, + on_script_error: Union[Literal["fail", "continue"], "DefaultType"] = DEFAULT, null_value: Any = DEFAULT, precision_step: Union[int, "DefaultType"] = DEFAULT, locale: Union[str, "DefaultType"] = DEFAULT, @@ -1165,6 +1238,10 @@ def __init__( kwargs["ignore_malformed"] = ignore_malformed if index is not DEFAULT: kwargs["index"] = index + if script is not DEFAULT: + kwargs["script"] = script + if on_script_error is not DEFAULT: + kwargs["on_script_error"] = on_script_error if null_value is not DEFAULT: kwargs["null_value"] = null_value if precision_step is not DEFAULT: @@ -1229,6 +1306,8 @@ class DateNanos(Field): :arg format: :arg ignore_malformed: :arg index: + :arg script: + :arg on_script_error: :arg null_value: :arg precision_step: :arg doc_values: @@ -1255,6 +1334,8 @@ def __init__( format: Union[str, "DefaultType"] = DEFAULT, ignore_malformed: Union[bool, "DefaultType"] = DEFAULT, index: Union[bool, "DefaultType"] = DEFAULT, + script: Union["types.Script", Dict[str, Any], "DefaultType"] = DEFAULT, + on_script_error: Union[Literal["fail", "continue"], "DefaultType"] = DEFAULT, null_value: Any = DEFAULT, precision_step: Union[int, "DefaultType"] = DEFAULT, doc_values: Union[bool, "DefaultType"] = DEFAULT, @@ -1284,6 +1365,10 @@ def __init__( kwargs["ignore_malformed"] = ignore_malformed if index is not DEFAULT: kwargs["index"] = index + if script is not DEFAULT: + kwargs["script"] = script + if on_script_error is not DEFAULT: + kwargs["on_script_error"] = on_script_error if null_value is not DEFAULT: kwargs["null_value"] = null_value if precision_step is not DEFAULT: @@ -3068,6 +3153,76 @@ def __init__( super().__init__(*args, **kwargs) +class Passthrough(Field): + """ + :arg enabled: + :arg priority: + :arg time_series_dimension: + :arg copy_to: + :arg store: + :arg meta: Metadata about the field. + :arg properties: + :arg ignore_above: + :arg dynamic: + :arg fields: + :arg synthetic_source_keep: + """ + + name = "passthrough" + _param_defs = { + "properties": {"type": "field", "hash": True}, + "fields": {"type": "field", "hash": True}, + } + + def __init__( + self, + *args: Any, + enabled: Union[bool, "DefaultType"] = DEFAULT, + priority: Union[int, "DefaultType"] = DEFAULT, + time_series_dimension: Union[bool, "DefaultType"] = DEFAULT, + copy_to: Union[ + Union[str, "InstrumentedField"], + Sequence[Union[str, "InstrumentedField"]], + "DefaultType", + ] = DEFAULT, + store: Union[bool, "DefaultType"] = DEFAULT, + meta: Union[Mapping[str, str], "DefaultType"] = DEFAULT, + properties: Union[Mapping[str, Field], "DefaultType"] = DEFAULT, + ignore_above: Union[int, "DefaultType"] = DEFAULT, + dynamic: Union[ + Literal["strict", "runtime", "true", "false"], bool, "DefaultType" + ] = DEFAULT, + fields: Union[Mapping[str, Field], "DefaultType"] = DEFAULT, + synthetic_source_keep: Union[ + Literal["none", "arrays", "all"], "DefaultType" + ] = DEFAULT, + **kwargs: Any, + ): + if enabled is not DEFAULT: + kwargs["enabled"] = enabled + if priority is not DEFAULT: + kwargs["priority"] = priority + if time_series_dimension is not DEFAULT: + kwargs["time_series_dimension"] = time_series_dimension + if copy_to is not DEFAULT: + kwargs["copy_to"] = str(copy_to) + if store is not DEFAULT: + kwargs["store"] = store + if meta is not DEFAULT: + kwargs["meta"] = meta + if properties is not DEFAULT: + kwargs["properties"] = properties + if ignore_above is not DEFAULT: + kwargs["ignore_above"] = ignore_above + if dynamic is not DEFAULT: + kwargs["dynamic"] = dynamic + if fields is not DEFAULT: + kwargs["fields"] = fields + if synthetic_source_keep is not DEFAULT: + kwargs["synthetic_source_keep"] = synthetic_source_keep + super().__init__(*args, **kwargs) + + class Percolator(Field): """ :arg meta: Metadata about the field. diff --git a/elasticsearch/dsl/query.py b/elasticsearch/dsl/query.py index 6e87f926c..1282d3b02 100644 --- a/elasticsearch/dsl/query.py +++ b/elasticsearch/dsl/query.py @@ -1083,6 +1083,8 @@ class Knn(Query): :arg filter: Filters for the kNN search query :arg similarity: The minimum similarity for a vector to be considered a match + :arg rescore_vector: Apply oversampling and rescoring to quantized + vectors * :arg boost: Floating point number used to decrease or increase the relevance scores of the query. Boost values are relative to the default value of 1.0. A boost value between 0 and 1.0 decreases @@ -1108,6 +1110,9 @@ def __init__( k: Union[int, "DefaultType"] = DEFAULT, filter: Union[Query, Sequence[Query], "DefaultType"] = DEFAULT, similarity: Union[float, "DefaultType"] = DEFAULT, + rescore_vector: Union[ + "types.RescoreVector", Dict[str, Any], "DefaultType" + ] = DEFAULT, boost: Union[float, "DefaultType"] = DEFAULT, _name: Union[str, "DefaultType"] = DEFAULT, **kwargs: Any, @@ -1120,6 +1125,7 @@ def __init__( k=k, filter=filter, similarity=similarity, + rescore_vector=rescore_vector, boost=boost, _name=_name, **kwargs, @@ -2650,7 +2656,7 @@ def __init__( self, _field: Union[str, "InstrumentedField", "DefaultType"] = DEFAULT, _value: Union[ - Sequence[Union[int, float, str, bool, None, Any]], + Sequence[Union[int, float, str, bool, None]], "types.TermsLookup", Dict[str, Any], "DefaultType", diff --git a/elasticsearch/dsl/types.py b/elasticsearch/dsl/types.py index 7474769c6..772e596cd 100644 --- a/elasticsearch/dsl/types.py +++ b/elasticsearch/dsl/types.py @@ -26,34 +26,6 @@ PipeSeparatedFlags = str -class AggregationRange(AttrDict[Any]): - """ - :arg from: Start of the range (inclusive). - :arg key: Custom key to return the range with. - :arg to: End of the range (exclusive). - """ - - from_: Union[float, None, DefaultType] - key: Union[str, DefaultType] - to: Union[float, None, DefaultType] - - def __init__( - self, - *, - from_: Union[float, None, DefaultType] = DEFAULT, - key: Union[str, DefaultType] = DEFAULT, - to: Union[float, None, DefaultType] = DEFAULT, - **kwargs: Any, - ): - if from_ is not DEFAULT: - kwargs["from_"] = from_ - if key is not DEFAULT: - kwargs["key"] = key - if to is not DEFAULT: - kwargs["to"] = to - super().__init__(kwargs) - - class BucketCorrelationFunction(AttrDict[Any]): """ :arg count_correlation: (required) The configuration to calculate a @@ -334,34 +306,6 @@ def __init__( super().__init__(kwargs) -class DateRangeExpression(AttrDict[Any]): - """ - :arg from: Start of the range (inclusive). - :arg key: Custom key to return the range with. - :arg to: End of the range (exclusive). - """ - - from_: Union[str, float, DefaultType] - key: Union[str, DefaultType] - to: Union[str, float, DefaultType] - - def __init__( - self, - *, - from_: Union[str, float, DefaultType] = DEFAULT, - key: Union[str, DefaultType] = DEFAULT, - to: Union[str, float, DefaultType] = DEFAULT, - **kwargs: Any, - ): - if from_ is not DEFAULT: - kwargs["from_"] = from_ - if key is not DEFAULT: - kwargs["key"] = key - if to is not DEFAULT: - kwargs["to"] = to - super().__init__(kwargs) - - class DenseVectorIndexOptions(AttrDict[Any]): """ :arg type: (required) The type of kNN algorithm to use. @@ -591,6 +535,7 @@ class FieldSort(AttrDict[Any]): "completion", "nested", "object", + "passthrough", "version", "murmur3", "token_count", @@ -617,6 +562,7 @@ class FieldSort(AttrDict[Any]): "shape", "histogram", "constant_keyword", + "counted_keyword", "aggregate_metric_double", "dense_vector", "semantic_text", @@ -654,6 +600,7 @@ def __init__( "completion", "nested", "object", + "passthrough", "version", "murmur3", "token_count", @@ -680,6 +627,7 @@ def __init__( "shape", "histogram", "constant_keyword", + "counted_keyword", "aggregate_metric_double", "dense_vector", "semantic_text", @@ -2625,7 +2573,7 @@ class PercentageScoreHeuristic(AttrDict[Any]): class PinnedDoc(AttrDict[Any]): """ :arg _id: (required) The unique document ID. - :arg _index: (required) The index that contains the document. + :arg _index: The index that contains the document. """ _id: Union[str, DefaultType] @@ -2850,6 +2798,22 @@ def __init__( super().__init__(kwargs) +class RescoreVector(AttrDict[Any]): + """ + :arg oversample: (required) Applies the specified oversample factor to + k on the approximate kNN search + """ + + oversample: Union[float, DefaultType] + + def __init__( + self, *, oversample: Union[float, DefaultType] = DEFAULT, **kwargs: Any + ): + if oversample is not DEFAULT: + kwargs["oversample"] = oversample + super().__init__(kwargs) + + class ScoreSort(AttrDict[Any]): """ :arg order: @@ -2880,7 +2844,7 @@ class Script(AttrDict[Any]): :arg options: """ - source: Union[str, DefaultType] + source: Union[str, Dict[str, Any], DefaultType] id: Union[str, DefaultType] params: Union[Mapping[str, Any], DefaultType] lang: Union[Literal["painless", "expression", "mustache", "java"], DefaultType] @@ -2889,7 +2853,7 @@ class Script(AttrDict[Any]): def __init__( self, *, - source: Union[str, DefaultType] = DEFAULT, + source: Union[str, Dict[str, Any], DefaultType] = DEFAULT, id: Union[str, DefaultType] = DEFAULT, params: Union[Mapping[str, Any], DefaultType] = DEFAULT, lang: Union[ @@ -3488,14 +3452,14 @@ class SpanTermQuery(AttrDict[Any]): :arg _name: """ - value: Union[str, DefaultType] + value: Union[int, float, str, bool, None, DefaultType] boost: Union[float, DefaultType] _name: Union[str, DefaultType] def __init__( self, *, - value: Union[str, DefaultType] = DEFAULT, + value: Union[int, float, str, bool, None, DefaultType] = DEFAULT, boost: Union[float, DefaultType] = DEFAULT, _name: Union[str, DefaultType] = DEFAULT, **kwargs: Any, @@ -3613,7 +3577,7 @@ class TermQuery(AttrDict[Any]): :arg _name: """ - value: Union[int, float, str, bool, None, Any, DefaultType] + value: Union[int, float, str, bool, None, DefaultType] case_insensitive: Union[bool, DefaultType] boost: Union[float, DefaultType] _name: Union[str, DefaultType] @@ -3621,7 +3585,7 @@ class TermQuery(AttrDict[Any]): def __init__( self, *, - value: Union[int, float, str, bool, None, Any, DefaultType] = DEFAULT, + value: Union[int, float, str, bool, None, DefaultType] = DEFAULT, case_insensitive: Union[bool, DefaultType] = DEFAULT, boost: Union[float, DefaultType] = DEFAULT, _name: Union[str, DefaultType] = DEFAULT, @@ -3712,7 +3676,7 @@ class TermsSetQuery(AttrDict[Any]): :arg _name: """ - terms: Union[Sequence[str], DefaultType] + terms: Union[Sequence[Union[int, float, str, bool, None]], DefaultType] minimum_should_match: Union[int, str, DefaultType] minimum_should_match_field: Union[str, InstrumentedField, DefaultType] minimum_should_match_script: Union["Script", Dict[str, Any], DefaultType] @@ -3722,7 +3686,9 @@ class TermsSetQuery(AttrDict[Any]): def __init__( self, *, - terms: Union[Sequence[str], DefaultType] = DEFAULT, + terms: Union[ + Sequence[Union[int, float, str, bool, None]], DefaultType + ] = DEFAULT, minimum_should_match: Union[int, str, DefaultType] = DEFAULT, minimum_should_match_field: Union[ str, InstrumentedField, DefaultType @@ -4544,7 +4510,7 @@ class CompositeAggregate(AttrDict[Any]): :arg meta: """ - after_key: Mapping[str, Union[int, float, str, bool, None, Any]] + after_key: Mapping[str, Union[int, float, str, bool, None]] buckets: Sequence["CompositeBucket"] meta: Mapping[str, Any] @@ -4559,7 +4525,7 @@ class CompositeBucket(AttrDict[Any]): :arg doc_count: (required) """ - key: Mapping[str, Union[int, float, str, bool, None, Any]] + key: Mapping[str, Union[int, float, str, bool, None]] doc_count: int @@ -5235,9 +5201,7 @@ class Hit(AttrDict[Any]): matched_queries: Union[Sequence[str], Mapping[str, float]] nested: "NestedIdentity" ignored: Sequence[str] - ignored_field_values: Mapping[ - str, Sequence[Union[int, float, str, bool, None, Any]] - ] + ignored_field_values: Mapping[str, Sequence[Any]] shard: str node: str routing: str @@ -5246,7 +5210,7 @@ class Hit(AttrDict[Any]): seq_no: int primary_term: int version: int - sort: Sequence[Union[int, float, str, bool, None, Any]] + sort: Sequence[Union[int, float, str, bool, None]] class HitsMetadata(AttrDict[Any]): @@ -5271,7 +5235,7 @@ class InferenceAggregate(AttrDict[Any]): :arg meta: """ - value: Union[int, float, str, bool, None, Any] + value: Union[int, float, str, bool, None] feature_importance: Sequence["InferenceFeatureImportance"] top_classes: Sequence["InferenceTopClassEntry"] warning: str @@ -5307,7 +5271,7 @@ class InferenceTopClassEntry(AttrDict[Any]): :arg class_score: (required) """ - class_name: Union[int, float, str, bool, None, Any] + class_name: Union[int, float, str, bool, None] class_probability: float class_score: float @@ -5636,7 +5600,7 @@ class MultiTermsBucket(AttrDict[Any]): :arg doc_count_error_upper_bound: """ - key: Sequence[Union[int, float, str, bool, None, Any]] + key: Sequence[Union[int, float, str, bool, None]] doc_count: int key_as_string: str doc_count_error_upper_bound: int @@ -6187,7 +6151,7 @@ class StringTermsBucket(AttrDict[Any]): :arg doc_count_error_upper_bound: """ - key: Union[int, float, str, bool, None, Any] + key: Union[int, float, str, bool, None] doc_count: int doc_count_error_upper_bound: int @@ -6291,7 +6255,7 @@ class TimeSeriesBucket(AttrDict[Any]): :arg doc_count: (required) """ - key: Mapping[str, Union[int, float, str, bool, None, Any]] + key: Mapping[str, Union[int, float, str, bool, None]] doc_count: int @@ -6311,8 +6275,8 @@ class TopMetrics(AttrDict[Any]): :arg metrics: (required) """ - sort: Sequence[Union[Union[int, float, str, bool, None, Any], None]] - metrics: Mapping[str, Union[Union[int, float, str, bool, None, Any], None]] + sort: Sequence[Union[Union[int, float, str, bool, None], None]] + metrics: Mapping[str, Union[Union[int, float, str, bool, None], None]] class TopMetricsAggregate(AttrDict[Any]): diff --git a/elasticsearch/dsl/wrappers.py b/elasticsearch/dsl/wrappers.py index ecd2e1363..52e7af257 100644 --- a/elasticsearch/dsl/wrappers.py +++ b/elasticsearch/dsl/wrappers.py @@ -18,6 +18,7 @@ import operator from typing import ( TYPE_CHECKING, + Any, Callable, ClassVar, Dict, @@ -117,3 +118,27 @@ def lower(self) -> Union[Tuple[RangeValT, bool], Tuple[None, Literal[False]]]: if "gte" in self._d_: return self._d_["gte"], True return None, False + + +class AggregationRange(AttrDict[Any]): + """ + :arg from: Start of the range (inclusive). + :arg key: Custom key to return the range with. + :arg to: End of the range (exclusive). + """ + + def __init__( + self, + *, + from_: Any = None, + key: Optional[str] = None, + to: Any = None, + **kwargs: Any, + ): + if from_ is not None: + kwargs["from_"] = from_ + if key is not None: + kwargs["key"] = key + if to is not None: + kwargs["to"] = to + super().__init__(kwargs) diff --git a/utils/dsl-generator.py b/utils/dsl-generator.py index 3841967e7..2aa12c53d 100644 --- a/utils/dsl-generator.py +++ b/utils/dsl-generator.py @@ -17,14 +17,13 @@ import json import re +import subprocess import textwrap from urllib.error import HTTPError from urllib.request import urlopen from jinja2 import Environment, PackageLoader, select_autoescape -from elasticsearch import VERSION - jinja_env = Environment( loader=PackageLoader("utils"), autoescape=select_autoescape(), @@ -38,7 +37,7 @@ types_py = jinja_env.get_template("types.py.tpl") # map with name replacements for Elasticsearch attributes -PROP_REPLACEMENTS = {"from": "from_"} +PROP_REPLACEMENTS = {"from": "from_", "global": "global_"} # map with Elasticsearch type replacements # keys and values are in given in "{namespace}:{name}" format @@ -115,9 +114,9 @@ def type_for_types_py(type_): class ElasticsearchSchema: """Operations related to the Elasticsearch schema.""" - def __init__(self): + def __init__(self, version="main"): response = None - for branch in [f"{VERSION[0]}.{VERSION[1]}", "main"]: + for branch in [version, "main"]: url = f"https://raw.githubusercontent.com/elastic/elasticsearch-specification/{branch}/output/schema/schema.json" try: response = urlopen(url) @@ -201,6 +200,12 @@ def get_python_type(self, schema_type, for_response=False): ): # QueryContainer maps to the DSL's Query class return "Query", {"type": "query"} + elif ( + type_name["namespace"] == "_global.search._types" + and type_name["name"] == "SearchRequestBody" + ): + # we currently do not provide specific typing for this one + return "Dict[str, Any]", None elif ( type_name["namespace"] == "_types.query_dsl" and type_name["name"] == "FunctionScoreContainer" @@ -219,7 +224,7 @@ def get_python_type(self, schema_type, for_response=False): type_name["namespace"] == "_types.aggregations" and type_name["name"] == "CompositeAggregationSource" ): - # QueryContainer maps to the DSL's Query class + # CompositeAggreagationSource maps to the DSL's Agg class return "Agg[_R]", None else: # for any other instances we get the type and recurse @@ -300,6 +305,8 @@ def get_python_type(self, schema_type, for_response=False): ] ) ) + if len(types) == 1: + return types[0] return "Union[" + ", ".join([type_ for type_, _ in types]) + "]", None elif schema_type["kind"] == "enum": @@ -338,6 +345,12 @@ def get_python_type(self, schema_type, for_response=False): ]["name"].endswith("Analyzer"): # not expanding analyzers at this time, maybe in the future return "str, Dict[str, Any]", None + elif ( + schema_type["name"]["namespace"] == "_types.aggregations" + and schema_type["name"]["name"].endswith("AggregationRange") + and schema_type["name"]["name"] != "IpRangeAggregationRange" + ): + return '"wrappers.AggregationRange"', None # to handle other interfaces we generate a type of the same name # and add the interface to the interfaces.py module @@ -380,9 +393,12 @@ def add_attribute(self, k, arg, for_types_py=False, for_response=False): param = None if not for_response: if type_ != "Any": - if 'Sequence["types.' in type_: + if ( + 'Sequence["types.' in type_ + or 'Sequence["wrappers.AggregationRange' in type_ + ): type_ = add_seq_dict_type(type_) # interfaces can be given as dicts - elif "types." in type_: + elif "types." in type_ or "wrappers.AggregationRange" in type_: type_ = add_dict_type(type_) # interfaces can be given as dicts type_ = add_not_set(type_) if for_types_py: @@ -999,7 +1015,8 @@ def generate_types_py(schema, filename): if __name__ == "__main__": - schema = ElasticsearchSchema() + v = subprocess.check_output(["git", "branch", "--show-current"]).strip().decode() + schema = ElasticsearchSchema(v) generate_field_py(schema, "elasticsearch/dsl/field.py") generate_query_py(schema, "elasticsearch/dsl/query.py") generate_aggs_py(schema, "elasticsearch/dsl/aggs.py") diff --git a/utils/templates/aggs.py.tpl b/utils/templates/aggs.py.tpl index d4ba4f4cd..68d46e63d 100644 --- a/utils/templates/aggs.py.tpl +++ b/utils/templates/aggs.py.tpl @@ -38,6 +38,7 @@ from elastic_transport.client_utils import DEFAULT from .query import Query from .response.aggs import AggResponse, BucketData, FieldBucketData, TopHitsData from .utils import _R, AttrDict, DslBase +from . import wrappers if TYPE_CHECKING: from elastic_transport.client_utils import DefaultType From ea46777916d3db58910410f9e6a09fb40b7b54bd Mon Sep 17 00:00:00 2001 From: Elastic Machine Date: Tue, 1 Apr 2025 12:32:02 +0100 Subject: [PATCH 11/57] Auto-generated API code (#2863) Co-authored-by: Quentin Pradet --- elasticsearch/_async/client/__init__.py | 16 +- elasticsearch/_async/client/inference.py | 1513 +++++++++++++++++++++- elasticsearch/_sync/client/__init__.py | 16 +- elasticsearch/_sync/client/inference.py | 1513 +++++++++++++++++++++- 4 files changed, 3014 insertions(+), 44 deletions(-) diff --git a/elasticsearch/_async/client/__init__.py b/elasticsearch/_async/client/__init__.py index a897f2d37..4eab35bb0 100644 --- a/elasticsearch/_async/client/__init__.py +++ b/elasticsearch/_async/client/__init__.py @@ -1581,7 +1581,7 @@ async def delete_by_query( If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. It supports comma-separated values, such as `open,hidden`. - :param from_: Starting offset (default: 0) + :param from_: Skips the specified number of documents. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param lenient: If `true`, format-based query failures (such as providing text @@ -3420,7 +3420,8 @@ async def msearch( computationally expensive named queries on a large number of hits may add significant overhead. :param max_concurrent_searches: Maximum number of concurrent searches the multi - search API can execute. + search API can execute. Defaults to `max(1, (# of data nodes * min(search + thread pool size, 10)))`. :param max_concurrent_shard_requests: Maximum number of concurrent shard requests that each sub-search request executes per node. :param pre_filter_shard_size: Defines a threshold that enforces a pre-filter @@ -3748,6 +3749,7 @@ async def open_point_in_time( human: t.Optional[bool] = None, ignore_unavailable: t.Optional[bool] = None, index_filter: t.Optional[t.Mapping[str, t.Any]] = None, + max_concurrent_shard_requests: t.Optional[int] = None, preference: t.Optional[str] = None, pretty: t.Optional[bool] = None, routing: t.Optional[str] = None, @@ -3803,6 +3805,8 @@ async def open_point_in_time( a missing or closed index. :param index_filter: Filter indices if the provided query rewrites to `match_none` on every shard. + :param max_concurrent_shard_requests: Maximum number of concurrent shard requests + that each sub-search request executes per node. :param preference: The node or shard the operation should be performed on. By default, it is random. :param routing: A custom value that is used to route operations to a specific @@ -3830,6 +3834,8 @@ async def open_point_in_time( __query["human"] = human if ignore_unavailable is not None: __query["ignore_unavailable"] = ignore_unavailable + if max_concurrent_shard_requests is not None: + __query["max_concurrent_shard_requests"] = max_concurrent_shard_requests if preference is not None: __query["preference"] = preference if pretty is not None: @@ -4370,7 +4376,7 @@ async def render_search_template( human: t.Optional[bool] = None, params: t.Optional[t.Mapping[str, t.Any]] = None, pretty: t.Optional[bool] = None, - source: t.Optional[str] = None, + source: t.Optional[t.Union[str, t.Mapping[str, t.Any]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -5774,7 +5780,7 @@ async def search_template( search_type: t.Optional[ t.Union[str, t.Literal["dfs_query_then_fetch", "query_then_fetch"]] ] = None, - source: t.Optional[str] = None, + source: t.Optional[t.Union[str, t.Mapping[str, t.Any]]] = None, typed_keys: t.Optional[bool] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: @@ -6512,7 +6518,7 @@ async def update_by_query( wildcard expressions match hidden data streams. It supports comma-separated values, such as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. - :param from_: Starting offset (default: 0) + :param from_: Skips the specified number of documents. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param lenient: If `true`, format-based query failures (such as providing text diff --git a/elasticsearch/_async/client/inference.py b/elasticsearch/_async/client/inference.py index ce96dba63..73983f07a 100644 --- a/elasticsearch/_async/client/inference.py +++ b/elasticsearch/_async/client/inference.py @@ -234,6 +234,67 @@ async def get( path_parts=__path_parts, ) + @_rewrite_parameters( + body_name="chat_completion_request", + ) + async def post_eis_chat_completion( + self, + *, + eis_inference_id: str, + chat_completion_request: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Perform a chat completion task through the Elastic Inference Service (EIS).

+

Perform a chat completion inference task with the elastic service.

+ + + ``_ + + :param eis_inference_id: The unique identifier of the inference endpoint. + :param chat_completion_request: + """ + if eis_inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'eis_inference_id'") + if chat_completion_request is None and body is None: + raise ValueError( + "Empty value passed for parameters 'chat_completion_request' and 'body', one of them should be set." + ) + elif chat_completion_request is not None and body is not None: + raise ValueError("Cannot set both 'chat_completion_request' and 'body'") + __path_parts: t.Dict[str, str] = {"eis_inference_id": _quote(eis_inference_id)} + __path = ( + f'/_inference/chat_completion/{__path_parts["eis_inference_id"]}/_stream' + ) + __query: t.Dict[str, t.Any] = {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + __body = ( + chat_completion_request if chat_completion_request is not None else body + ) + __headers = {"accept": "application/json", "content-type": "application/json"} + return await self.perform_request( # type: ignore[return-value] + "POST", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.post_eis_chat_completion", + path_parts=__path_parts, + ) + @_rewrite_parameters( body_name="inference_config", ) @@ -329,14 +390,14 @@ async def put( "task_settings", ), ) - async def put_openai( + async def put_alibabacloud( self, *, task_type: t.Union[ - str, t.Literal["chat_completion", "completion", "text_embedding"] + str, t.Literal["completion", "rerank", "space_embedding", "text_embedding"] ], - openai_inference_id: str, - service: t.Optional[t.Union[str, t.Literal["openai"]]] = None, + alibabacloud_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["alibabacloud-ai-search"]]] = None, service_settings: t.Optional[t.Mapping[str, t.Any]] = None, chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, error_trace: t.Optional[bool] = None, @@ -349,8 +410,8 @@ async def put_openai( """ .. raw:: html -

Create an OpenAI inference endpoint.

-

Create an inference endpoint to perform an inference task with the openai service.

+

Create an AlibabaCloud AI Search inference endpoint.

+

Create an inference endpoint to perform an inference task with the alibabacloud-ai-search service.

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. After creating the endpoint, wait for the model deployment to complete before using it. To verify the deployment status, use the get trained model statistics API. @@ -358,33 +419,33 @@ async def put_openai( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. - NOTE: The `chat_completion` task type only supports streaming and only through - the _stream API. - :param openai_inference_id: The unique identifier of the inference endpoint. + :param alibabacloud_inference_id: The unique identifier of the inference endpoint. :param service: The type of service supported for the specified task type. In - this case, `openai`. + this case, `alibabacloud-ai-search`. :param service_settings: Settings used to install the inference model. These - settings are specific to the `openai` service. + settings are specific to the `alibabacloud-ai-search` service. :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") - if openai_inference_id in SKIP_IN_PATH: - raise ValueError("Empty value passed for parameter 'openai_inference_id'") + if alibabacloud_inference_id in SKIP_IN_PATH: + raise ValueError( + "Empty value passed for parameter 'alibabacloud_inference_id'" + ) if service is None and body is None: raise ValueError("Empty value passed for parameter 'service'") if service_settings is None and body is None: raise ValueError("Empty value passed for parameter 'service_settings'") __path_parts: t.Dict[str, str] = { "task_type": _quote(task_type), - "openai_inference_id": _quote(openai_inference_id), + "alibabacloud_inference_id": _quote(alibabacloud_inference_id), } - __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["openai_inference_id"]}' + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["alibabacloud_inference_id"]}' __query: t.Dict[str, t.Any] = {} __body: t.Dict[str, t.Any] = body if body is not None else {} if error_trace is not None: @@ -415,7 +476,1425 @@ async def put_openai( params=__query, headers=__headers, body=__body, - endpoint_id="inference.put_openai", + endpoint_id="inference.put_alibabacloud", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + async def put_amazonbedrock( + self, + *, + task_type: t.Union[str, t.Literal["completion", "text_embedding"]], + amazonbedrock_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["amazonbedrock"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an Amazon Bedrock inference endpoint.

+

Creates an inference endpoint to perform an inference task with the amazonbedrock service.

+
+

info + You need to provide the access and secret keys only once, during the inference model creation. The get inference API does not retrieve your access or secret keys. After creating the inference model, you cannot change the associated key pairs. If you want to use a different access and secret key pair, delete the inference model and recreate it with the same name and the updated keys.

+
+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + :param amazonbedrock_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `amazonbedrock`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `amazonbedrock` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if amazonbedrock_inference_id in SKIP_IN_PATH: + raise ValueError( + "Empty value passed for parameter 'amazonbedrock_inference_id'" + ) + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "amazonbedrock_inference_id": _quote(amazonbedrock_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["amazonbedrock_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_amazonbedrock", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + async def put_anthropic( + self, + *, + task_type: t.Union[str, t.Literal["completion"]], + anthropic_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["anthropic"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an Anthropic inference endpoint.

+

Create an inference endpoint to perform an inference task with the anthropic service.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The task type. The only valid task type for the model to perform + is `completion`. + :param anthropic_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `anthropic`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `watsonxai` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if anthropic_inference_id in SKIP_IN_PATH: + raise ValueError( + "Empty value passed for parameter 'anthropic_inference_id'" + ) + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "anthropic_inference_id": _quote(anthropic_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["anthropic_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_anthropic", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + async def put_azureaistudio( + self, + *, + task_type: t.Union[str, t.Literal["completion", "text_embedding"]], + azureaistudio_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["azureaistudio"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an Azure AI studio inference endpoint.

+

Create an inference endpoint to perform an inference task with the azureaistudio service.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + :param azureaistudio_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `azureaistudio`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `openai` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if azureaistudio_inference_id in SKIP_IN_PATH: + raise ValueError( + "Empty value passed for parameter 'azureaistudio_inference_id'" + ) + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "azureaistudio_inference_id": _quote(azureaistudio_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["azureaistudio_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_azureaistudio", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + async def put_azureopenai( + self, + *, + task_type: t.Union[str, t.Literal["completion", "text_embedding"]], + azureopenai_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["azureopenai"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an Azure OpenAI inference endpoint.

+

Create an inference endpoint to perform an inference task with the azureopenai service.

+

The list of chat completion models that you can choose from in your Azure OpenAI deployment include:

+ +

The list of embeddings models that you can choose from in your deployment can be found in the Azure models documentation.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + NOTE: The `chat_completion` task type only supports streaming and only through + the _stream API. + :param azureopenai_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `azureopenai`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `azureopenai` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if azureopenai_inference_id in SKIP_IN_PATH: + raise ValueError( + "Empty value passed for parameter 'azureopenai_inference_id'" + ) + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "azureopenai_inference_id": _quote(azureopenai_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["azureopenai_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_azureopenai", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + async def put_cohere( + self, + *, + task_type: t.Union[str, t.Literal["completion", "rerank", "text_embedding"]], + cohere_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["cohere"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create a Cohere inference endpoint.

+

Create an inference endpoint to perform an inference task with the cohere service.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + :param cohere_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `cohere`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `cohere` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if cohere_inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'cohere_inference_id'") + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "cohere_inference_id": _quote(cohere_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["cohere_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_cohere", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=("service", "service_settings"), + ) + async def put_eis( + self, + *, + task_type: t.Union[str, t.Literal["chat_completion"]], + eis_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["elastic"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an Elastic Inference Service (EIS) inference endpoint.

+

Create an inference endpoint to perform an inference task through the Elastic Inference Service (EIS).

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + NOTE: The `chat_completion` task type only supports streaming and only through + the _stream API. + :param eis_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `elastic`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `elastic` service. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if eis_inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'eis_inference_id'") + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "eis_inference_id": _quote(eis_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["eis_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_eis", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + async def put_elasticsearch( + self, + *, + task_type: t.Union[ + str, t.Literal["rerank", "sparse_embedding", "text_embedding"] + ], + elasticsearch_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["elasticsearch"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an Elasticsearch inference endpoint.

+

Create an inference endpoint to perform an inference task with the elasticsearch service.

+
+

info + Your Elasticsearch deployment contains preconfigured ELSER and E5 inference endpoints, you only need to create the enpoints using the API if you want to customize the settings.

+
+

If you use the ELSER or the E5 model through the elasticsearch service, the API request will automatically download and deploy the model if it isn't downloaded yet.

+
+

info + You might see a 502 bad gateway error in the response when using the Kibana Console. This error usually just reflects a timeout, while the model downloads in the background. You can check the download progress in the Machine Learning UI. If using the Python client, you can set the timeout parameter to a higher value.

+
+

After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + :param elasticsearch_inference_id: The unique identifier of the inference endpoint. + The must not match the `model_id`. + :param service: The type of service supported for the specified task type. In + this case, `elasticsearch`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `elasticsearch` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if elasticsearch_inference_id in SKIP_IN_PATH: + raise ValueError( + "Empty value passed for parameter 'elasticsearch_inference_id'" + ) + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "elasticsearch_inference_id": _quote(elasticsearch_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["elasticsearch_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_elasticsearch", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=("service", "service_settings", "chunking_settings"), + ) + async def put_elser( + self, + *, + task_type: t.Union[str, t.Literal["sparse_embedding"]], + elser_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["elser"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an ELSER inference endpoint.

+

Create an inference endpoint to perform an inference task with the elser service. + You can also deploy ELSER by using the Elasticsearch inference integration.

+
+

info + Your Elasticsearch deployment contains a preconfigured ELSER inference endpoint, you only need to create the enpoint using the API if you want to customize the settings.

+
+

The API request will automatically download and deploy the ELSER model if it isn't already downloaded.

+
+

info + You might see a 502 bad gateway error in the response when using the Kibana Console. This error usually just reflects a timeout, while the model downloads in the background. You can check the download progress in the Machine Learning UI. If using the Python client, you can set the timeout parameter to a higher value.

+
+

After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + :param elser_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `elser`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `elser` service. + :param chunking_settings: The chunking configuration object. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if elser_inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'elser_inference_id'") + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "elser_inference_id": _quote(elser_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["elser_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_elser", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=("service", "service_settings", "chunking_settings"), + ) + async def put_googleaistudio( + self, + *, + task_type: t.Union[str, t.Literal["completion", "text_embedding"]], + googleaistudio_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["googleaistudio"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an Google AI Studio inference endpoint.

+

Create an inference endpoint to perform an inference task with the googleaistudio service.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + :param googleaistudio_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `googleaistudio`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `googleaistudio` service. + :param chunking_settings: The chunking configuration object. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if googleaistudio_inference_id in SKIP_IN_PATH: + raise ValueError( + "Empty value passed for parameter 'googleaistudio_inference_id'" + ) + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "googleaistudio_inference_id": _quote(googleaistudio_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["googleaistudio_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_googleaistudio", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + async def put_googlevertexai( + self, + *, + task_type: t.Union[str, t.Literal["rerank", "text_embedding"]], + googlevertexai_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["googlevertexai"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create a Google Vertex AI inference endpoint.

+

Create an inference endpoint to perform an inference task with the googlevertexai service.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + :param googlevertexai_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `googlevertexai`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `googlevertexai` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if googlevertexai_inference_id in SKIP_IN_PATH: + raise ValueError( + "Empty value passed for parameter 'googlevertexai_inference_id'" + ) + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "googlevertexai_inference_id": _quote(googlevertexai_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["googlevertexai_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_googlevertexai", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=("service", "service_settings", "chunking_settings"), + ) + async def put_hugging_face( + self, + *, + task_type: t.Union[str, t.Literal["text_embedding"]], + huggingface_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["hugging_face"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create a Hugging Face inference endpoint.

+

Create an inference endpoint to perform an inference task with the hugging_face service.

+

You must first create an inference endpoint on the Hugging Face endpoint page to get an endpoint URL. + Select the model you want to use on the new endpoint creation page (for example intfloat/e5-small-v2), then select the sentence embeddings task under the advanced configuration section. + Create the endpoint and copy the URL after the endpoint initialization has been finished.

+

The following models are recommended for the Hugging Face service:

+
    +
  • all-MiniLM-L6-v2
  • +
  • all-MiniLM-L12-v2
  • +
  • all-mpnet-base-v2
  • +
  • e5-base-v2
  • +
  • e5-small-v2
  • +
  • multilingual-e5-base
  • +
  • multilingual-e5-small
  • +
+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + :param huggingface_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `hugging_face`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `hugging_face` service. + :param chunking_settings: The chunking configuration object. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if huggingface_inference_id in SKIP_IN_PATH: + raise ValueError( + "Empty value passed for parameter 'huggingface_inference_id'" + ) + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "huggingface_inference_id": _quote(huggingface_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["huggingface_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_hugging_face", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + async def put_jinaai( + self, + *, + task_type: t.Union[str, t.Literal["rerank", "text_embedding"]], + jinaai_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["jinaai"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an JinaAI inference endpoint.

+

Create an inference endpoint to perform an inference task with the jinaai service.

+

To review the available rerank models, refer to https://jina.ai/reranker. + To review the available text_embedding models, refer to the https://jina.ai/embeddings/.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + :param jinaai_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `jinaai`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `jinaai` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if jinaai_inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'jinaai_inference_id'") + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "jinaai_inference_id": _quote(jinaai_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["jinaai_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_jinaai", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=("service", "service_settings", "chunking_settings"), + ) + async def put_mistral( + self, + *, + task_type: t.Union[str, t.Literal["text_embedding"]], + mistral_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["mistral"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create a Mistral inference endpoint.

+

Creates an inference endpoint to perform an inference task with the mistral service.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The task type. The only valid task type for the model to perform + is `text_embedding`. + :param mistral_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `mistral`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `mistral` service. + :param chunking_settings: The chunking configuration object. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if mistral_inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'mistral_inference_id'") + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "mistral_inference_id": _quote(mistral_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["mistral_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_mistral", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + async def put_openai( + self, + *, + task_type: t.Union[ + str, t.Literal["chat_completion", "completion", "text_embedding"] + ], + openai_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["openai"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an OpenAI inference endpoint.

+

Create an inference endpoint to perform an inference task with the openai service.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + NOTE: The `chat_completion` task type only supports streaming and only through + the _stream API. + :param openai_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `openai`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `openai` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if openai_inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'openai_inference_id'") + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "openai_inference_id": _quote(openai_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["openai_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_openai", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + async def put_voyageai( + self, + *, + task_type: t.Union[str, t.Literal["rerank", "text_embedding"]], + voyageai_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["voyageai"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create a VoyageAI inference endpoint.

+

Create an inference endpoint to perform an inference task with the voyageai service.

+

Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + :param voyageai_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `voyageai`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `voyageai` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if voyageai_inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'voyageai_inference_id'") + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "voyageai_inference_id": _quote(voyageai_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["voyageai_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_voyageai", path_parts=__path_parts, ) diff --git a/elasticsearch/_sync/client/__init__.py b/elasticsearch/_sync/client/__init__.py index 1d80efee7..d4082ceb1 100644 --- a/elasticsearch/_sync/client/__init__.py +++ b/elasticsearch/_sync/client/__init__.py @@ -1579,7 +1579,7 @@ def delete_by_query( If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. It supports comma-separated values, such as `open,hidden`. - :param from_: Starting offset (default: 0) + :param from_: Skips the specified number of documents. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param lenient: If `true`, format-based query failures (such as providing text @@ -3418,7 +3418,8 @@ def msearch( computationally expensive named queries on a large number of hits may add significant overhead. :param max_concurrent_searches: Maximum number of concurrent searches the multi - search API can execute. + search API can execute. Defaults to `max(1, (# of data nodes * min(search + thread pool size, 10)))`. :param max_concurrent_shard_requests: Maximum number of concurrent shard requests that each sub-search request executes per node. :param pre_filter_shard_size: Defines a threshold that enforces a pre-filter @@ -3746,6 +3747,7 @@ def open_point_in_time( human: t.Optional[bool] = None, ignore_unavailable: t.Optional[bool] = None, index_filter: t.Optional[t.Mapping[str, t.Any]] = None, + max_concurrent_shard_requests: t.Optional[int] = None, preference: t.Optional[str] = None, pretty: t.Optional[bool] = None, routing: t.Optional[str] = None, @@ -3801,6 +3803,8 @@ def open_point_in_time( a missing or closed index. :param index_filter: Filter indices if the provided query rewrites to `match_none` on every shard. + :param max_concurrent_shard_requests: Maximum number of concurrent shard requests + that each sub-search request executes per node. :param preference: The node or shard the operation should be performed on. By default, it is random. :param routing: A custom value that is used to route operations to a specific @@ -3828,6 +3832,8 @@ def open_point_in_time( __query["human"] = human if ignore_unavailable is not None: __query["ignore_unavailable"] = ignore_unavailable + if max_concurrent_shard_requests is not None: + __query["max_concurrent_shard_requests"] = max_concurrent_shard_requests if preference is not None: __query["preference"] = preference if pretty is not None: @@ -4368,7 +4374,7 @@ def render_search_template( human: t.Optional[bool] = None, params: t.Optional[t.Mapping[str, t.Any]] = None, pretty: t.Optional[bool] = None, - source: t.Optional[str] = None, + source: t.Optional[t.Union[str, t.Mapping[str, t.Any]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -5772,7 +5778,7 @@ def search_template( search_type: t.Optional[ t.Union[str, t.Literal["dfs_query_then_fetch", "query_then_fetch"]] ] = None, - source: t.Optional[str] = None, + source: t.Optional[t.Union[str, t.Mapping[str, t.Any]]] = None, typed_keys: t.Optional[bool] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: @@ -6510,7 +6516,7 @@ def update_by_query( wildcard expressions match hidden data streams. It supports comma-separated values, such as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. - :param from_: Starting offset (default: 0) + :param from_: Skips the specified number of documents. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param lenient: If `true`, format-based query failures (such as providing text diff --git a/elasticsearch/_sync/client/inference.py b/elasticsearch/_sync/client/inference.py index 6bab33aec..279528a96 100644 --- a/elasticsearch/_sync/client/inference.py +++ b/elasticsearch/_sync/client/inference.py @@ -234,6 +234,67 @@ def get( path_parts=__path_parts, ) + @_rewrite_parameters( + body_name="chat_completion_request", + ) + def post_eis_chat_completion( + self, + *, + eis_inference_id: str, + chat_completion_request: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Perform a chat completion task through the Elastic Inference Service (EIS).

+

Perform a chat completion inference task with the elastic service.

+ + + ``_ + + :param eis_inference_id: The unique identifier of the inference endpoint. + :param chat_completion_request: + """ + if eis_inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'eis_inference_id'") + if chat_completion_request is None and body is None: + raise ValueError( + "Empty value passed for parameters 'chat_completion_request' and 'body', one of them should be set." + ) + elif chat_completion_request is not None and body is not None: + raise ValueError("Cannot set both 'chat_completion_request' and 'body'") + __path_parts: t.Dict[str, str] = {"eis_inference_id": _quote(eis_inference_id)} + __path = ( + f'/_inference/chat_completion/{__path_parts["eis_inference_id"]}/_stream' + ) + __query: t.Dict[str, t.Any] = {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + __body = ( + chat_completion_request if chat_completion_request is not None else body + ) + __headers = {"accept": "application/json", "content-type": "application/json"} + return self.perform_request( # type: ignore[return-value] + "POST", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.post_eis_chat_completion", + path_parts=__path_parts, + ) + @_rewrite_parameters( body_name="inference_config", ) @@ -329,14 +390,14 @@ def put( "task_settings", ), ) - def put_openai( + def put_alibabacloud( self, *, task_type: t.Union[ - str, t.Literal["chat_completion", "completion", "text_embedding"] + str, t.Literal["completion", "rerank", "space_embedding", "text_embedding"] ], - openai_inference_id: str, - service: t.Optional[t.Union[str, t.Literal["openai"]]] = None, + alibabacloud_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["alibabacloud-ai-search"]]] = None, service_settings: t.Optional[t.Mapping[str, t.Any]] = None, chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, error_trace: t.Optional[bool] = None, @@ -349,8 +410,8 @@ def put_openai( """ .. raw:: html -

Create an OpenAI inference endpoint.

-

Create an inference endpoint to perform an inference task with the openai service.

+

Create an AlibabaCloud AI Search inference endpoint.

+

Create an inference endpoint to perform an inference task with the alibabacloud-ai-search service.

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. After creating the endpoint, wait for the model deployment to complete before using it. To verify the deployment status, use the get trained model statistics API. @@ -358,33 +419,33 @@ def put_openai( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. - NOTE: The `chat_completion` task type only supports streaming and only through - the _stream API. - :param openai_inference_id: The unique identifier of the inference endpoint. + :param alibabacloud_inference_id: The unique identifier of the inference endpoint. :param service: The type of service supported for the specified task type. In - this case, `openai`. + this case, `alibabacloud-ai-search`. :param service_settings: Settings used to install the inference model. These - settings are specific to the `openai` service. + settings are specific to the `alibabacloud-ai-search` service. :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") - if openai_inference_id in SKIP_IN_PATH: - raise ValueError("Empty value passed for parameter 'openai_inference_id'") + if alibabacloud_inference_id in SKIP_IN_PATH: + raise ValueError( + "Empty value passed for parameter 'alibabacloud_inference_id'" + ) if service is None and body is None: raise ValueError("Empty value passed for parameter 'service'") if service_settings is None and body is None: raise ValueError("Empty value passed for parameter 'service_settings'") __path_parts: t.Dict[str, str] = { "task_type": _quote(task_type), - "openai_inference_id": _quote(openai_inference_id), + "alibabacloud_inference_id": _quote(alibabacloud_inference_id), } - __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["openai_inference_id"]}' + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["alibabacloud_inference_id"]}' __query: t.Dict[str, t.Any] = {} __body: t.Dict[str, t.Any] = body if body is not None else {} if error_trace is not None: @@ -415,7 +476,1425 @@ def put_openai( params=__query, headers=__headers, body=__body, - endpoint_id="inference.put_openai", + endpoint_id="inference.put_alibabacloud", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + def put_amazonbedrock( + self, + *, + task_type: t.Union[str, t.Literal["completion", "text_embedding"]], + amazonbedrock_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["amazonbedrock"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an Amazon Bedrock inference endpoint.

+

Creates an inference endpoint to perform an inference task with the amazonbedrock service.

+
+

info + You need to provide the access and secret keys only once, during the inference model creation. The get inference API does not retrieve your access or secret keys. After creating the inference model, you cannot change the associated key pairs. If you want to use a different access and secret key pair, delete the inference model and recreate it with the same name and the updated keys.

+
+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + :param amazonbedrock_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `amazonbedrock`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `amazonbedrock` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if amazonbedrock_inference_id in SKIP_IN_PATH: + raise ValueError( + "Empty value passed for parameter 'amazonbedrock_inference_id'" + ) + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "amazonbedrock_inference_id": _quote(amazonbedrock_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["amazonbedrock_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_amazonbedrock", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + def put_anthropic( + self, + *, + task_type: t.Union[str, t.Literal["completion"]], + anthropic_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["anthropic"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an Anthropic inference endpoint.

+

Create an inference endpoint to perform an inference task with the anthropic service.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The task type. The only valid task type for the model to perform + is `completion`. + :param anthropic_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `anthropic`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `watsonxai` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if anthropic_inference_id in SKIP_IN_PATH: + raise ValueError( + "Empty value passed for parameter 'anthropic_inference_id'" + ) + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "anthropic_inference_id": _quote(anthropic_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["anthropic_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_anthropic", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + def put_azureaistudio( + self, + *, + task_type: t.Union[str, t.Literal["completion", "text_embedding"]], + azureaistudio_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["azureaistudio"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an Azure AI studio inference endpoint.

+

Create an inference endpoint to perform an inference task with the azureaistudio service.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + :param azureaistudio_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `azureaistudio`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `openai` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if azureaistudio_inference_id in SKIP_IN_PATH: + raise ValueError( + "Empty value passed for parameter 'azureaistudio_inference_id'" + ) + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "azureaistudio_inference_id": _quote(azureaistudio_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["azureaistudio_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_azureaistudio", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + def put_azureopenai( + self, + *, + task_type: t.Union[str, t.Literal["completion", "text_embedding"]], + azureopenai_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["azureopenai"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an Azure OpenAI inference endpoint.

+

Create an inference endpoint to perform an inference task with the azureopenai service.

+

The list of chat completion models that you can choose from in your Azure OpenAI deployment include:

+ +

The list of embeddings models that you can choose from in your deployment can be found in the Azure models documentation.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + NOTE: The `chat_completion` task type only supports streaming and only through + the _stream API. + :param azureopenai_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `azureopenai`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `azureopenai` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if azureopenai_inference_id in SKIP_IN_PATH: + raise ValueError( + "Empty value passed for parameter 'azureopenai_inference_id'" + ) + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "azureopenai_inference_id": _quote(azureopenai_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["azureopenai_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_azureopenai", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + def put_cohere( + self, + *, + task_type: t.Union[str, t.Literal["completion", "rerank", "text_embedding"]], + cohere_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["cohere"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create a Cohere inference endpoint.

+

Create an inference endpoint to perform an inference task with the cohere service.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + :param cohere_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `cohere`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `cohere` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if cohere_inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'cohere_inference_id'") + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "cohere_inference_id": _quote(cohere_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["cohere_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_cohere", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=("service", "service_settings"), + ) + def put_eis( + self, + *, + task_type: t.Union[str, t.Literal["chat_completion"]], + eis_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["elastic"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an Elastic Inference Service (EIS) inference endpoint.

+

Create an inference endpoint to perform an inference task through the Elastic Inference Service (EIS).

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + NOTE: The `chat_completion` task type only supports streaming and only through + the _stream API. + :param eis_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `elastic`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `elastic` service. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if eis_inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'eis_inference_id'") + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "eis_inference_id": _quote(eis_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["eis_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_eis", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + def put_elasticsearch( + self, + *, + task_type: t.Union[ + str, t.Literal["rerank", "sparse_embedding", "text_embedding"] + ], + elasticsearch_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["elasticsearch"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an Elasticsearch inference endpoint.

+

Create an inference endpoint to perform an inference task with the elasticsearch service.

+
+

info + Your Elasticsearch deployment contains preconfigured ELSER and E5 inference endpoints, you only need to create the enpoints using the API if you want to customize the settings.

+
+

If you use the ELSER or the E5 model through the elasticsearch service, the API request will automatically download and deploy the model if it isn't downloaded yet.

+
+

info + You might see a 502 bad gateway error in the response when using the Kibana Console. This error usually just reflects a timeout, while the model downloads in the background. You can check the download progress in the Machine Learning UI. If using the Python client, you can set the timeout parameter to a higher value.

+
+

After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + :param elasticsearch_inference_id: The unique identifier of the inference endpoint. + The must not match the `model_id`. + :param service: The type of service supported for the specified task type. In + this case, `elasticsearch`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `elasticsearch` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if elasticsearch_inference_id in SKIP_IN_PATH: + raise ValueError( + "Empty value passed for parameter 'elasticsearch_inference_id'" + ) + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "elasticsearch_inference_id": _quote(elasticsearch_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["elasticsearch_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_elasticsearch", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=("service", "service_settings", "chunking_settings"), + ) + def put_elser( + self, + *, + task_type: t.Union[str, t.Literal["sparse_embedding"]], + elser_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["elser"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an ELSER inference endpoint.

+

Create an inference endpoint to perform an inference task with the elser service. + You can also deploy ELSER by using the Elasticsearch inference integration.

+
+

info + Your Elasticsearch deployment contains a preconfigured ELSER inference endpoint, you only need to create the enpoint using the API if you want to customize the settings.

+
+

The API request will automatically download and deploy the ELSER model if it isn't already downloaded.

+
+

info + You might see a 502 bad gateway error in the response when using the Kibana Console. This error usually just reflects a timeout, while the model downloads in the background. You can check the download progress in the Machine Learning UI. If using the Python client, you can set the timeout parameter to a higher value.

+
+

After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + :param elser_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `elser`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `elser` service. + :param chunking_settings: The chunking configuration object. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if elser_inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'elser_inference_id'") + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "elser_inference_id": _quote(elser_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["elser_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_elser", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=("service", "service_settings", "chunking_settings"), + ) + def put_googleaistudio( + self, + *, + task_type: t.Union[str, t.Literal["completion", "text_embedding"]], + googleaistudio_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["googleaistudio"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an Google AI Studio inference endpoint.

+

Create an inference endpoint to perform an inference task with the googleaistudio service.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + :param googleaistudio_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `googleaistudio`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `googleaistudio` service. + :param chunking_settings: The chunking configuration object. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if googleaistudio_inference_id in SKIP_IN_PATH: + raise ValueError( + "Empty value passed for parameter 'googleaistudio_inference_id'" + ) + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "googleaistudio_inference_id": _quote(googleaistudio_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["googleaistudio_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_googleaistudio", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + def put_googlevertexai( + self, + *, + task_type: t.Union[str, t.Literal["rerank", "text_embedding"]], + googlevertexai_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["googlevertexai"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create a Google Vertex AI inference endpoint.

+

Create an inference endpoint to perform an inference task with the googlevertexai service.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + :param googlevertexai_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `googlevertexai`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `googlevertexai` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if googlevertexai_inference_id in SKIP_IN_PATH: + raise ValueError( + "Empty value passed for parameter 'googlevertexai_inference_id'" + ) + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "googlevertexai_inference_id": _quote(googlevertexai_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["googlevertexai_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_googlevertexai", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=("service", "service_settings", "chunking_settings"), + ) + def put_hugging_face( + self, + *, + task_type: t.Union[str, t.Literal["text_embedding"]], + huggingface_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["hugging_face"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create a Hugging Face inference endpoint.

+

Create an inference endpoint to perform an inference task with the hugging_face service.

+

You must first create an inference endpoint on the Hugging Face endpoint page to get an endpoint URL. + Select the model you want to use on the new endpoint creation page (for example intfloat/e5-small-v2), then select the sentence embeddings task under the advanced configuration section. + Create the endpoint and copy the URL after the endpoint initialization has been finished.

+

The following models are recommended for the Hugging Face service:

+
    +
  • all-MiniLM-L6-v2
  • +
  • all-MiniLM-L12-v2
  • +
  • all-mpnet-base-v2
  • +
  • e5-base-v2
  • +
  • e5-small-v2
  • +
  • multilingual-e5-base
  • +
  • multilingual-e5-small
  • +
+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + :param huggingface_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `hugging_face`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `hugging_face` service. + :param chunking_settings: The chunking configuration object. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if huggingface_inference_id in SKIP_IN_PATH: + raise ValueError( + "Empty value passed for parameter 'huggingface_inference_id'" + ) + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "huggingface_inference_id": _quote(huggingface_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["huggingface_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_hugging_face", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + def put_jinaai( + self, + *, + task_type: t.Union[str, t.Literal["rerank", "text_embedding"]], + jinaai_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["jinaai"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an JinaAI inference endpoint.

+

Create an inference endpoint to perform an inference task with the jinaai service.

+

To review the available rerank models, refer to https://jina.ai/reranker. + To review the available text_embedding models, refer to the https://jina.ai/embeddings/.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + :param jinaai_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `jinaai`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `jinaai` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if jinaai_inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'jinaai_inference_id'") + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "jinaai_inference_id": _quote(jinaai_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["jinaai_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_jinaai", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=("service", "service_settings", "chunking_settings"), + ) + def put_mistral( + self, + *, + task_type: t.Union[str, t.Literal["text_embedding"]], + mistral_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["mistral"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create a Mistral inference endpoint.

+

Creates an inference endpoint to perform an inference task with the mistral service.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The task type. The only valid task type for the model to perform + is `text_embedding`. + :param mistral_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `mistral`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `mistral` service. + :param chunking_settings: The chunking configuration object. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if mistral_inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'mistral_inference_id'") + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "mistral_inference_id": _quote(mistral_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["mistral_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_mistral", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + def put_openai( + self, + *, + task_type: t.Union[ + str, t.Literal["chat_completion", "completion", "text_embedding"] + ], + openai_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["openai"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create an OpenAI inference endpoint.

+

Create an inference endpoint to perform an inference task with the openai service.

+

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. + After creating the endpoint, wait for the model deployment to complete before using it. + To verify the deployment status, use the get trained model statistics API. + Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". + Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + NOTE: The `chat_completion` task type only supports streaming and only through + the _stream API. + :param openai_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `openai`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `openai` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if openai_inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'openai_inference_id'") + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "openai_inference_id": _quote(openai_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["openai_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_openai", + path_parts=__path_parts, + ) + + @_rewrite_parameters( + body_fields=( + "service", + "service_settings", + "chunking_settings", + "task_settings", + ), + ) + def put_voyageai( + self, + *, + task_type: t.Union[str, t.Literal["rerank", "text_embedding"]], + voyageai_inference_id: str, + service: t.Optional[t.Union[str, t.Literal["voyageai"]]] = None, + service_settings: t.Optional[t.Mapping[str, t.Any]] = None, + chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Create a VoyageAI inference endpoint.

+

Create an inference endpoint to perform an inference task with the voyageai service.

+

Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+ + + ``_ + + :param task_type: The type of the inference task that the model will perform. + :param voyageai_inference_id: The unique identifier of the inference endpoint. + :param service: The type of service supported for the specified task type. In + this case, `voyageai`. + :param service_settings: Settings used to install the inference model. These + settings are specific to the `voyageai` service. + :param chunking_settings: The chunking configuration object. + :param task_settings: Settings to configure the inference task. These settings + are specific to the task type you specified. + """ + if task_type in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'task_type'") + if voyageai_inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'voyageai_inference_id'") + if service is None and body is None: + raise ValueError("Empty value passed for parameter 'service'") + if service_settings is None and body is None: + raise ValueError("Empty value passed for parameter 'service_settings'") + __path_parts: t.Dict[str, str] = { + "task_type": _quote(task_type), + "voyageai_inference_id": _quote(voyageai_inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["voyageai_inference_id"]}' + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if not __body: + if service is not None: + __body["service"] = service + if service_settings is not None: + __body["service_settings"] = service_settings + if chunking_settings is not None: + __body["chunking_settings"] = chunking_settings + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "PUT", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.put_voyageai", path_parts=__path_parts, ) From 59deef20c7e7f1d2d19dd94dc5b5d94ce5be58a4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 2 Apr 2025 14:43:01 +0100 Subject: [PATCH 12/57] Remove deprecated http_auth parameter (#2839) (#2875) (cherry picked from commit 74387d0a3f42517e2a5805c9bb0aec57511b6e15) Co-authored-by: Quentin Pradet --- elasticsearch/_async/client/__init__.py | 21 ----- elasticsearch/_async/client/_base.py | 26 ------ elasticsearch/_async/client/utils.py | 4 - elasticsearch/_async/helpers.py | 7 +- elasticsearch/_sync/client/__init__.py | 21 ----- elasticsearch/_sync/client/_base.py | 26 ------ elasticsearch/_sync/client/utils.py | 35 -------- elasticsearch/helpers/actions.py | 6 +- .../test_async/test_server/test_helpers.py | 6 +- .../test_client/test_deprecated_options.py | 26 ------ .../test_client/test_requests_auth.py | 84 ------------------- .../test_client/test_rewrite_parameters.py | 4 +- .../test_server/test_helpers.py | 7 +- 13 files changed, 8 insertions(+), 265 deletions(-) delete mode 100644 test_elasticsearch/test_client/test_requests_auth.py diff --git a/elasticsearch/_async/client/__init__.py b/elasticsearch/_async/client/__init__.py index 4eab35bb0..14ada0e22 100644 --- a/elasticsearch/_async/client/__init__.py +++ b/elasticsearch/_async/client/__init__.py @@ -88,8 +88,6 @@ _rewrite_parameters, _stability_warning, client_node_configs, - is_requests_http_auth, - is_requests_node_class, ) from .watcher import WatcherClient from .xpack import XPackClient @@ -191,7 +189,6 @@ def __init__( ] = None, sniffer_timeout: t.Union[DefaultType, None, float] = DEFAULT, sniff_on_connection_fail: t.Union[DefaultType, bool] = DEFAULT, - http_auth: t.Union[DefaultType, t.Any] = DEFAULT, maxsize: t.Union[DefaultType, int] = DEFAULT, # Internal use only _transport: t.Optional[AsyncTransport] = None, @@ -320,26 +317,9 @@ def __init__( sniff_callback = default_sniff_callback if _transport is None: - requests_session_auth = None - if http_auth is not None and http_auth is not DEFAULT: - if is_requests_http_auth(http_auth): - # If we're using custom requests authentication - # then we need to alert the user that they also - # need to use 'node_class=requests'. - if not is_requests_node_class(node_class): - raise ValueError( - "Using a custom 'requests.auth.AuthBase' class for " - "'http_auth' must be used with node_class='requests'" - ) - - # Reset 'http_auth' to DEFAULT so it's not consumed below. - requests_session_auth = http_auth - http_auth = DEFAULT - node_configs = client_node_configs( hosts, cloud_id=cloud_id, - requests_session_auth=requests_session_auth, connections_per_node=connections_per_node, http_compress=http_compress, verify_certs=verify_certs, @@ -426,7 +406,6 @@ def __init__( self._headers["x-opaque-id"] = opaque_id self._headers = resolve_auth_headers( self._headers, - http_auth=http_auth, api_key=api_key, basic_auth=basic_auth, bearer_auth=bearer_auth, diff --git a/elasticsearch/_async/client/_base.py b/elasticsearch/_async/client/_base.py index cc090671c..3907cfd84 100644 --- a/elasticsearch/_async/client/_base.py +++ b/elasticsearch/_async/client/_base.py @@ -68,7 +68,6 @@ def resolve_auth_headers( headers: Optional[Mapping[str, str]], - http_auth: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT, api_key: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT, basic_auth: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT, bearer_auth: Union[DefaultType, None, str] = DEFAULT, @@ -78,32 +77,7 @@ def resolve_auth_headers( elif not isinstance(headers, HttpHeaders): headers = HttpHeaders(headers) - resolved_http_auth = http_auth if http_auth is not DEFAULT else None resolved_basic_auth = basic_auth if basic_auth is not DEFAULT else None - if resolved_http_auth is not None: - if resolved_basic_auth is not None: - raise ValueError( - "Can't specify both 'http_auth' and 'basic_auth', " - "instead only specify 'basic_auth'" - ) - if isinstance(http_auth, str) or ( - isinstance(resolved_http_auth, (list, tuple)) - and all(isinstance(x, str) for x in resolved_http_auth) - ): - resolved_basic_auth = resolved_http_auth - else: - raise TypeError( - "The deprecated 'http_auth' parameter must be either 'Tuple[str, str]' or 'str'. " - "Use either the 'basic_auth' parameter instead" - ) - - warnings.warn( - "The 'http_auth' parameter is deprecated. " - "Use 'basic_auth' or 'bearer_auth' parameters instead", - category=DeprecationWarning, - stacklevel=warn_stacklevel(), - ) - resolved_api_key = api_key if api_key is not DEFAULT else None resolved_bearer_auth = bearer_auth if bearer_auth is not DEFAULT else None if resolved_api_key or resolved_basic_auth or resolved_bearer_auth: diff --git a/elasticsearch/_async/client/utils.py b/elasticsearch/_async/client/utils.py index 97918d9e4..ac7a35062 100644 --- a/elasticsearch/_async/client/utils.py +++ b/elasticsearch/_async/client/utils.py @@ -27,8 +27,6 @@ _rewrite_parameters, _stability_warning, client_node_configs, - is_requests_http_auth, - is_requests_node_class, ) __all__ = [ @@ -43,6 +41,4 @@ "client_node_configs", "_rewrite_parameters", "_stability_warning", - "is_requests_http_auth", - "is_requests_node_class", ] diff --git a/elasticsearch/_async/helpers.py b/elasticsearch/_async/helpers.py index e4d5e6bc5..8b5d3d0d2 100644 --- a/elasticsearch/_async/helpers.py +++ b/elasticsearch/_async/helpers.py @@ -418,12 +418,9 @@ def pop_transport_kwargs(kw: MutableMapping[str, Any]) -> MutableMapping[str, An # Grab options that should be propagated to every # API call within this helper instead of just 'search()' transport_kwargs = {} - for key in ("headers", "api_key", "http_auth", "basic_auth", "bearer_auth"): + for key in ("headers", "api_key", "basic_auth", "bearer_auth"): try: - value = kw.pop(key) - if key == "http_auth": - key = "basic_auth" - transport_kwargs[key] = value + transport_kwargs[key] = kw.pop(key) except KeyError: pass return transport_kwargs diff --git a/elasticsearch/_sync/client/__init__.py b/elasticsearch/_sync/client/__init__.py index d4082ceb1..46484630a 100644 --- a/elasticsearch/_sync/client/__init__.py +++ b/elasticsearch/_sync/client/__init__.py @@ -88,8 +88,6 @@ _rewrite_parameters, _stability_warning, client_node_configs, - is_requests_http_auth, - is_requests_node_class, ) from .watcher import WatcherClient from .xpack import XPackClient @@ -191,7 +189,6 @@ def __init__( ] = None, sniffer_timeout: t.Union[DefaultType, None, float] = DEFAULT, sniff_on_connection_fail: t.Union[DefaultType, bool] = DEFAULT, - http_auth: t.Union[DefaultType, t.Any] = DEFAULT, maxsize: t.Union[DefaultType, int] = DEFAULT, # Internal use only _transport: t.Optional[Transport] = None, @@ -320,26 +317,9 @@ def __init__( sniff_callback = default_sniff_callback if _transport is None: - requests_session_auth = None - if http_auth is not None and http_auth is not DEFAULT: - if is_requests_http_auth(http_auth): - # If we're using custom requests authentication - # then we need to alert the user that they also - # need to use 'node_class=requests'. - if not is_requests_node_class(node_class): - raise ValueError( - "Using a custom 'requests.auth.AuthBase' class for " - "'http_auth' must be used with node_class='requests'" - ) - - # Reset 'http_auth' to DEFAULT so it's not consumed below. - requests_session_auth = http_auth - http_auth = DEFAULT - node_configs = client_node_configs( hosts, cloud_id=cloud_id, - requests_session_auth=requests_session_auth, connections_per_node=connections_per_node, http_compress=http_compress, verify_certs=verify_certs, @@ -426,7 +406,6 @@ def __init__( self._headers["x-opaque-id"] = opaque_id self._headers = resolve_auth_headers( self._headers, - http_auth=http_auth, api_key=api_key, basic_auth=basic_auth, bearer_auth=bearer_auth, diff --git a/elasticsearch/_sync/client/_base.py b/elasticsearch/_sync/client/_base.py index 868b71073..64abdc250 100644 --- a/elasticsearch/_sync/client/_base.py +++ b/elasticsearch/_sync/client/_base.py @@ -68,7 +68,6 @@ def resolve_auth_headers( headers: Optional[Mapping[str, str]], - http_auth: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT, api_key: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT, basic_auth: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT, bearer_auth: Union[DefaultType, None, str] = DEFAULT, @@ -78,32 +77,7 @@ def resolve_auth_headers( elif not isinstance(headers, HttpHeaders): headers = HttpHeaders(headers) - resolved_http_auth = http_auth if http_auth is not DEFAULT else None resolved_basic_auth = basic_auth if basic_auth is not DEFAULT else None - if resolved_http_auth is not None: - if resolved_basic_auth is not None: - raise ValueError( - "Can't specify both 'http_auth' and 'basic_auth', " - "instead only specify 'basic_auth'" - ) - if isinstance(http_auth, str) or ( - isinstance(resolved_http_auth, (list, tuple)) - and all(isinstance(x, str) for x in resolved_http_auth) - ): - resolved_basic_auth = resolved_http_auth - else: - raise TypeError( - "The deprecated 'http_auth' parameter must be either 'Tuple[str, str]' or 'str'. " - "Use either the 'basic_auth' parameter instead" - ) - - warnings.warn( - "The 'http_auth' parameter is deprecated. " - "Use 'basic_auth' or 'bearer_auth' parameters instead", - category=DeprecationWarning, - stacklevel=warn_stacklevel(), - ) - resolved_api_key = api_key if api_key is not DEFAULT else None resolved_bearer_auth = bearer_auth if bearer_auth is not DEFAULT else None if resolved_api_key or resolved_basic_auth or resolved_bearer_auth: diff --git a/elasticsearch/_sync/client/utils.py b/elasticsearch/_sync/client/utils.py index 48ebcb217..3293e356e 100644 --- a/elasticsearch/_sync/client/utils.py +++ b/elasticsearch/_sync/client/utils.py @@ -16,7 +16,6 @@ # under the License. import base64 -import inspect import urllib.parse import warnings from datetime import date, datetime @@ -44,7 +43,6 @@ AsyncTransport, HttpHeaders, NodeConfig, - RequestsHttpNode, SniffOptions, Transport, ) @@ -92,7 +90,6 @@ class Stability(Enum): _TRANSPORT_OPTIONS = { "api_key", - "http_auth", "request_timeout", "opaque_id", "headers", @@ -105,7 +102,6 @@ class Stability(Enum): def client_node_configs( hosts: Optional[_TYPE_HOSTS], cloud_id: Optional[str], - requests_session_auth: Optional[Any] = None, **kwargs: Any, ) -> List[NodeConfig]: if cloud_id is not None: @@ -126,12 +122,6 @@ def client_node_configs( headers.setdefault("user-agent", USER_AGENT) node_options["headers"] = headers - # If a custom Requests AuthBase is passed we set that via '_extras'. - if requests_session_auth is not None: - node_options.setdefault("_extras", {})[ - "requests.session.auth" - ] = requests_session_auth - def apply_node_options(node_config: NodeConfig) -> NodeConfig: """Needs special handling of headers since .replace() wipes out existing headers""" headers = node_config.headers.copy() # type: ignore[attr-defined] @@ -448,28 +438,3 @@ def wrapped(*args: Any, **kwargs: Any) -> Any: return wrapped # type: ignore[return-value] return wrapper - - -def is_requests_http_auth(http_auth: Any) -> bool: - """Detect if an http_auth value is a custom Requests auth object""" - try: - from requests.auth import AuthBase - - return isinstance(http_auth, AuthBase) - except ImportError: - pass - return False - - -def is_requests_node_class(node_class: Any) -> bool: - """Detect if 'RequestsHttpNode' would be used given the setting of 'node_class'""" - return ( - node_class is not None - and node_class is not DEFAULT - and ( - node_class == "requests" - or ( - inspect.isclass(node_class) and issubclass(node_class, RequestsHttpNode) - ) - ) - ) diff --git a/elasticsearch/helpers/actions.py b/elasticsearch/helpers/actions.py index d1a43a8dc..25c21cdd4 100644 --- a/elasticsearch/helpers/actions.py +++ b/elasticsearch/helpers/actions.py @@ -698,16 +698,12 @@ def pop_transport_kwargs(kw: MutableMapping[str, Any]) -> Dict[str, Any]: for key in ( "headers", "api_key", - "http_auth", "basic_auth", "bearer_auth", "opaque_id", ): try: - value = kw.pop(key) - if key == "http_auth": - key = "basic_auth" - transport_kwargs[key] = value + transport_kwargs[key] = kw.pop(key) except KeyError: pass return transport_kwargs diff --git a/test_elasticsearch/test_async/test_server/test_helpers.py b/test_elasticsearch/test_async/test_server/test_helpers.py index 0bb781304..86439b487 100644 --- a/test_elasticsearch/test_async/test_server/test_helpers.py +++ b/test_elasticsearch/test_async/test_server/test_helpers.py @@ -741,7 +741,8 @@ async def test_clear_scroll(self, async_client, scan_teardown): "kwargs", [ {"api_key": ("name", "value")}, - {"http_auth": ("username", "password")}, + {"basic_auth": ("username", "password")}, + {"bearer_auth": "token"}, {"headers": {"custom", "header"}}, ], ) @@ -790,9 +791,6 @@ async def test_scan_auth_kwargs_forwarded( assert data == [{"search_data": 1}] - if "http_auth" in kwargs: - kwargs = {"basic_auth": kwargs.pop("http_auth")} - assert options.call_args_list == [ call(request_timeout=None, **kwargs), call(ignore_status=404), diff --git a/test_elasticsearch/test_client/test_deprecated_options.py b/test_elasticsearch/test_client/test_deprecated_options.py index 3b4e0b9ed..a4db1fbb7 100644 --- a/test_elasticsearch/test_client/test_deprecated_options.py +++ b/test_elasticsearch/test_client/test_deprecated_options.py @@ -100,32 +100,6 @@ def test_randomize_hosts(): ) -def test_http_auth(): - with warnings.catch_warnings(record=True) as w: - client = Elasticsearch( - "http://localhost:9200", http_auth=("username", "password") - ) - - assert len(w) == 1 - assert w[0].category == DeprecationWarning - assert ( - str(w[0].message) - == "The 'http_auth' parameter is deprecated. Use 'basic_auth' or 'bearer_auth' parameters instead" - ) - assert client._headers["Authorization"] == "Basic dXNlcm5hbWU6cGFzc3dvcmQ=" - - with pytest.raises(ValueError) as e: - Elasticsearch( - "http://localhost:9200", - http_auth=("username", "password"), - basic_auth=("username", "password"), - ) - assert ( - str(e.value) - == "Can't specify both 'http_auth' and 'basic_auth', instead only specify 'basic_auth'" - ) - - def test_serializer_and_serializers(): with pytest.raises(ValueError) as e: Elasticsearch( diff --git a/test_elasticsearch/test_client/test_requests_auth.py b/test_elasticsearch/test_client/test_requests_auth.py deleted file mode 100644 index 2eb656f5d..000000000 --- a/test_elasticsearch/test_client/test_requests_auth.py +++ /dev/null @@ -1,84 +0,0 @@ -# Licensed to Elasticsearch B.V. under one or more contributor -# license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright -# ownership. Elasticsearch B.V. 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. - -import warnings - -import pytest -import requests -from elastic_transport import RequestsHttpNode, Urllib3HttpNode -from elastic_transport.client_utils import DEFAULT -from requests.auth import HTTPBasicAuth - -from elasticsearch import AsyncElasticsearch, Elasticsearch - - -class CustomRequestHttpNode(RequestsHttpNode): - pass - - -class CustomUrllib3HttpNode(Urllib3HttpNode): - pass - - -@pytest.mark.parametrize( - "node_class", ["requests", RequestsHttpNode, CustomRequestHttpNode] -) -def test_requests_auth(node_class): - http_auth = HTTPBasicAuth("username", "password") - - with warnings.catch_warnings(record=True) as w: - client = Elasticsearch( - "http://localhost:9200", http_auth=http_auth, node_class=node_class - ) - - # http_auth is deprecated for all other cases except this one. - assert len(w) == 0 - - # Instance should be forwarded directly to requests.Session.auth. - node = client.transport.node_pool.get() - assert isinstance(node, RequestsHttpNode) - assert isinstance(node.session, requests.Session) - assert node.session.auth is http_auth - - -@pytest.mark.parametrize("client_class", [Elasticsearch, AsyncElasticsearch]) -@pytest.mark.parametrize( - "node_class", ["urllib3", "aiohttp", None, DEFAULT, CustomUrllib3HttpNode] -) -def test_error_for_requests_auth_node_class(client_class, node_class): - http_auth = HTTPBasicAuth("username", "password") - - with pytest.raises(ValueError) as e: - client_class( - "http://localhost:9200", http_auth=http_auth, node_class=node_class - ) - assert str(e.value) == ( - "Using a custom 'requests.auth.AuthBase' class for " - "'http_auth' must be used with node_class='requests'" - ) - - -def test_error_for_requests_auth_async(): - http_auth = HTTPBasicAuth("username", "password") - - with pytest.raises(ValueError) as e: - AsyncElasticsearch( - "http://localhost:9200", http_auth=http_auth, node_class="requests" - ) - assert str(e.value) == ( - "Specified 'node_class' is not async, should be async instead" - ) diff --git a/test_elasticsearch/test_client/test_rewrite_parameters.py b/test_elasticsearch/test_client/test_rewrite_parameters.py index 50a232563..f933cfd51 100644 --- a/test_elasticsearch/test_client/test_rewrite_parameters.py +++ b/test_elasticsearch/test_client/test_rewrite_parameters.py @@ -208,7 +208,7 @@ def test_ignore_deprecated_options(self): body={"query": {"match_all": {}}}, params={"key": "value"}, param=1, - http_auth=("key", "value"), + request_timeout=10, ) assert len(w) == 1 @@ -219,7 +219,7 @@ def test_ignore_deprecated_options(self): ) assert self.calls == [ - ((), {"http_auth": ("key", "value")}), + ((), {"request_timeout": 10}), ( (), { diff --git a/test_elasticsearch/test_server/test_helpers.py b/test_elasticsearch/test_server/test_helpers.py index 6ed43e2af..361a98ae2 100644 --- a/test_elasticsearch/test_server/test_helpers.py +++ b/test_elasticsearch/test_server/test_helpers.py @@ -626,7 +626,6 @@ def test_no_scroll_id_fast_route(sync_client): "kwargs", [ {"api_key": ("name", "value")}, - {"http_auth": ("username", "password")}, {"basic_auth": ("username", "password")}, {"bearer_auth": "token"}, {"headers": {"custom", "header"}}, @@ -634,8 +633,6 @@ def test_no_scroll_id_fast_route(sync_client): ) @pytest.mark.usefixtures("scan_teardown") def test_scan_auth_kwargs_forwarded(sync_client, kwargs): - ((key, val),) = kwargs.items() - with patch.object( sync_client, "options", return_value=sync_client ) as options, patch.object( @@ -668,9 +665,7 @@ def test_scan_auth_kwargs_forwarded(sync_client, kwargs): assert data == [{"search_data": 1}] assert options.call_args_list == [ - call( - request_timeout=None, **{key if key != "http_auth" else "basic_auth": val} - ), + call(request_timeout=None, **kwargs), call(ignore_status=404), ] From 961dd2b60156ef83cdb3261e369545dd78f83e3b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 2 Apr 2025 15:45:02 +0100 Subject: [PATCH 13/57] Remove deprecated Elasticsearch() options (#2840) (#2876) (cherry picked from commit 20e09c303f14319a6fb085823fe72b9aa21905ac) Co-authored-by: Quentin Pradet --- elasticsearch/_async/client/__init__.py | 94 +----------- elasticsearch/_sync/client/__init__.py | 94 +----------- .../test_async/test_transport.py | 40 +---- .../test_client/test_deprecated_options.py | 137 ------------------ .../test_client/test_options.py | 56 ++++++- test_elasticsearch/test_transport.py | 39 +---- .../test_types/aliased_types.py | 4 - test_elasticsearch/test_types/async_types.py | 2 - test_elasticsearch/test_types/sync_types.py | 2 - 9 files changed, 59 insertions(+), 409 deletions(-) delete mode 100644 test_elasticsearch/test_client/test_deprecated_options.py diff --git a/elasticsearch/_async/client/__init__.py b/elasticsearch/_async/client/__init__.py index 14ada0e22..243a71401 100644 --- a/elasticsearch/_async/client/__init__.py +++ b/elasticsearch/_async/client/__init__.py @@ -18,7 +18,6 @@ import logging import typing as t -import warnings from elastic_transport import ( AsyncTransport, @@ -179,36 +178,12 @@ def __init__( t.Callable[[t.Dict[str, t.Any], NodeConfig], t.Optional[NodeConfig]] ] = None, meta_header: t.Union[DefaultType, bool] = DEFAULT, - timeout: t.Union[DefaultType, None, float] = DEFAULT, - randomize_hosts: t.Union[DefaultType, bool] = DEFAULT, - host_info_callback: t.Optional[ - t.Callable[ - [t.Dict[str, t.Any], t.Dict[str, t.Union[str, int]]], - t.Optional[t.Dict[str, t.Union[str, int]]], - ] - ] = None, - sniffer_timeout: t.Union[DefaultType, None, float] = DEFAULT, - sniff_on_connection_fail: t.Union[DefaultType, bool] = DEFAULT, - maxsize: t.Union[DefaultType, int] = DEFAULT, # Internal use only _transport: t.Optional[AsyncTransport] = None, ) -> None: if hosts is None and cloud_id is None and _transport is None: raise ValueError("Either 'hosts' or 'cloud_id' must be specified") - if timeout is not DEFAULT: - if request_timeout is not DEFAULT: - raise ValueError( - "Can't specify both 'timeout' and 'request_timeout', " - "instead only specify 'request_timeout'" - ) - warnings.warn( - "The 'timeout' parameter is deprecated in favor of 'request_timeout'", - category=DeprecationWarning, - stacklevel=2, - ) - request_timeout = timeout - if serializer is not None: if serializers is not DEFAULT: raise ValueError( @@ -217,58 +192,6 @@ def __init__( ) serializers = {default_mimetype: serializer} - if randomize_hosts is not DEFAULT: - if randomize_nodes_in_pool is not DEFAULT: - raise ValueError( - "Can't specify both 'randomize_hosts' and 'randomize_nodes_in_pool', " - "instead only specify 'randomize_nodes_in_pool'" - ) - warnings.warn( - "The 'randomize_hosts' parameter is deprecated in favor of 'randomize_nodes_in_pool'", - category=DeprecationWarning, - stacklevel=2, - ) - randomize_nodes_in_pool = randomize_hosts - - if sniffer_timeout is not DEFAULT: - if min_delay_between_sniffing is not DEFAULT: - raise ValueError( - "Can't specify both 'sniffer_timeout' and 'min_delay_between_sniffing', " - "instead only specify 'min_delay_between_sniffing'" - ) - warnings.warn( - "The 'sniffer_timeout' parameter is deprecated in favor of 'min_delay_between_sniffing'", - category=DeprecationWarning, - stacklevel=2, - ) - min_delay_between_sniffing = sniffer_timeout - - if sniff_on_connection_fail is not DEFAULT: - if sniff_on_node_failure is not DEFAULT: - raise ValueError( - "Can't specify both 'sniff_on_connection_fail' and 'sniff_on_node_failure', " - "instead only specify 'sniff_on_node_failure'" - ) - warnings.warn( - "The 'sniff_on_connection_fail' parameter is deprecated in favor of 'sniff_on_node_failure'", - category=DeprecationWarning, - stacklevel=2, - ) - sniff_on_node_failure = sniff_on_connection_fail - - if maxsize is not DEFAULT: - if connections_per_node is not DEFAULT: - raise ValueError( - "Can't specify both 'maxsize' and 'connections_per_node', " - "instead only specify 'connections_per_node'" - ) - warnings.warn( - "The 'maxsize' parameter is deprecated in favor of 'connections_per_node'", - category=DeprecationWarning, - stacklevel=2, - ) - connections_per_node = maxsize - # Setting min_delay_between_sniffing=True implies sniff_before_requests=True if min_delay_between_sniffing is not DEFAULT: sniff_before_requests = True @@ -290,22 +213,7 @@ def __init__( ) sniff_callback = None - if host_info_callback is not None: - if sniffed_node_callback is not None: - raise ValueError( - "Can't specify both 'host_info_callback' and 'sniffed_node_callback', " - "instead only specify 'sniffed_node_callback'" - ) - warnings.warn( - "The 'host_info_callback' parameter is deprecated in favor of 'sniffed_node_callback'", - category=DeprecationWarning, - stacklevel=2, - ) - - sniff_callback = create_sniff_callback( - host_info_callback=host_info_callback - ) - elif sniffed_node_callback is not None: + if sniffed_node_callback is not None: sniff_callback = create_sniff_callback( sniffed_node_callback=sniffed_node_callback ) diff --git a/elasticsearch/_sync/client/__init__.py b/elasticsearch/_sync/client/__init__.py index 46484630a..3a4435ce9 100644 --- a/elasticsearch/_sync/client/__init__.py +++ b/elasticsearch/_sync/client/__init__.py @@ -18,7 +18,6 @@ import logging import typing as t -import warnings from elastic_transport import ( BaseNode, @@ -179,36 +178,12 @@ def __init__( t.Callable[[t.Dict[str, t.Any], NodeConfig], t.Optional[NodeConfig]] ] = None, meta_header: t.Union[DefaultType, bool] = DEFAULT, - timeout: t.Union[DefaultType, None, float] = DEFAULT, - randomize_hosts: t.Union[DefaultType, bool] = DEFAULT, - host_info_callback: t.Optional[ - t.Callable[ - [t.Dict[str, t.Any], t.Dict[str, t.Union[str, int]]], - t.Optional[t.Dict[str, t.Union[str, int]]], - ] - ] = None, - sniffer_timeout: t.Union[DefaultType, None, float] = DEFAULT, - sniff_on_connection_fail: t.Union[DefaultType, bool] = DEFAULT, - maxsize: t.Union[DefaultType, int] = DEFAULT, # Internal use only _transport: t.Optional[Transport] = None, ) -> None: if hosts is None and cloud_id is None and _transport is None: raise ValueError("Either 'hosts' or 'cloud_id' must be specified") - if timeout is not DEFAULT: - if request_timeout is not DEFAULT: - raise ValueError( - "Can't specify both 'timeout' and 'request_timeout', " - "instead only specify 'request_timeout'" - ) - warnings.warn( - "The 'timeout' parameter is deprecated in favor of 'request_timeout'", - category=DeprecationWarning, - stacklevel=2, - ) - request_timeout = timeout - if serializer is not None: if serializers is not DEFAULT: raise ValueError( @@ -217,58 +192,6 @@ def __init__( ) serializers = {default_mimetype: serializer} - if randomize_hosts is not DEFAULT: - if randomize_nodes_in_pool is not DEFAULT: - raise ValueError( - "Can't specify both 'randomize_hosts' and 'randomize_nodes_in_pool', " - "instead only specify 'randomize_nodes_in_pool'" - ) - warnings.warn( - "The 'randomize_hosts' parameter is deprecated in favor of 'randomize_nodes_in_pool'", - category=DeprecationWarning, - stacklevel=2, - ) - randomize_nodes_in_pool = randomize_hosts - - if sniffer_timeout is not DEFAULT: - if min_delay_between_sniffing is not DEFAULT: - raise ValueError( - "Can't specify both 'sniffer_timeout' and 'min_delay_between_sniffing', " - "instead only specify 'min_delay_between_sniffing'" - ) - warnings.warn( - "The 'sniffer_timeout' parameter is deprecated in favor of 'min_delay_between_sniffing'", - category=DeprecationWarning, - stacklevel=2, - ) - min_delay_between_sniffing = sniffer_timeout - - if sniff_on_connection_fail is not DEFAULT: - if sniff_on_node_failure is not DEFAULT: - raise ValueError( - "Can't specify both 'sniff_on_connection_fail' and 'sniff_on_node_failure', " - "instead only specify 'sniff_on_node_failure'" - ) - warnings.warn( - "The 'sniff_on_connection_fail' parameter is deprecated in favor of 'sniff_on_node_failure'", - category=DeprecationWarning, - stacklevel=2, - ) - sniff_on_node_failure = sniff_on_connection_fail - - if maxsize is not DEFAULT: - if connections_per_node is not DEFAULT: - raise ValueError( - "Can't specify both 'maxsize' and 'connections_per_node', " - "instead only specify 'connections_per_node'" - ) - warnings.warn( - "The 'maxsize' parameter is deprecated in favor of 'connections_per_node'", - category=DeprecationWarning, - stacklevel=2, - ) - connections_per_node = maxsize - # Setting min_delay_between_sniffing=True implies sniff_before_requests=True if min_delay_between_sniffing is not DEFAULT: sniff_before_requests = True @@ -290,22 +213,7 @@ def __init__( ) sniff_callback = None - if host_info_callback is not None: - if sniffed_node_callback is not None: - raise ValueError( - "Can't specify both 'host_info_callback' and 'sniffed_node_callback', " - "instead only specify 'sniffed_node_callback'" - ) - warnings.warn( - "The 'host_info_callback' parameter is deprecated in favor of 'sniffed_node_callback'", - category=DeprecationWarning, - stacklevel=2, - ) - - sniff_callback = create_sniff_callback( - host_info_callback=host_info_callback - ) - elif sniffed_node_callback is not None: + if sniffed_node_callback is not None: sniff_callback = create_sniff_callback( sniffed_node_callback=sniffed_node_callback ) diff --git a/test_elasticsearch/test_async/test_transport.py b/test_elasticsearch/test_async/test_transport.py index 76a71f50b..baebc0671 100644 --- a/test_elasticsearch/test_async/test_transport.py +++ b/test_elasticsearch/test_async/test_transport.py @@ -19,7 +19,7 @@ import asyncio import re import warnings -from typing import Any, Dict, Optional, Union +from typing import Any, Dict, Optional import pytest from elastic_transport import ( @@ -562,10 +562,8 @@ async def test_sniff_after_n_seconds(self, event_loop): "kwargs", [ {"sniff_on_start": True}, - {"sniff_on_connection_fail": True}, {"sniff_on_node_failure": True}, {"sniff_before_requests": True}, - {"sniffer_timeout": 1}, {"sniff_timeout": 1}, ], ) @@ -660,42 +658,6 @@ def sniffed_node_callback( ports = {node.config.port for node in client.transport.node_pool.all()} assert ports == {9200, 124} - async def test_sniffing_deprecated_host_info_callback(self): - def host_info_callback( - node_info: Dict[str, Any], host: Dict[str, Union[int, str]] - ) -> Dict[str, Any]: - return ( - host if node_info["http"]["publish_address"].endswith(":124") else None - ) - - with warnings.catch_warnings(record=True) as w: - client = AsyncElasticsearch( # noqa: F821 - [ - NodeConfig( - "http", - "localhost", - 9200, - _extras={"data": CLUSTER_NODES_MASTER_ONLY}, - ) - ], - node_class=DummyNode, - sniff_on_start=True, - host_info_callback=host_info_callback, - ) - await client.transport._async_call() - - assert len(w) == 1 - assert w[0].category == DeprecationWarning - assert ( - str(w[0].message) - == "The 'host_info_callback' parameter is deprecated in favor of 'sniffed_node_callback'" - ) - - assert len(client.transport.node_pool) == 2 - - ports = {node.config.port for node in client.transport.node_pool.all()} - assert ports == {9200, 124} - @pytest.mark.parametrize("headers", [{}, {"X-elastic-product": "BAD HEADER"}]) async def test_unsupported_product_error(headers): diff --git a/test_elasticsearch/test_client/test_deprecated_options.py b/test_elasticsearch/test_client/test_deprecated_options.py deleted file mode 100644 index a4db1fbb7..000000000 --- a/test_elasticsearch/test_client/test_deprecated_options.py +++ /dev/null @@ -1,137 +0,0 @@ -# Licensed to Elasticsearch B.V. under one or more contributor -# license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright -# ownership. Elasticsearch B.V. 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. - -import warnings - -import pytest - -from elasticsearch import Elasticsearch, JsonSerializer - -EXPECTED_SERIALIZERS = { - "application/vnd.mapbox-vector-tile", - "application/x-ndjson", - "application/json", - "text/*", - "application/vnd.elasticsearch+json", - "application/vnd.elasticsearch+x-ndjson", -} - - -try: - import pyarrow as pa - - EXPECTED_SERIALIZERS.add("application/vnd.apache.arrow.stream") -except ImportError: - pa = None - - -def test_sniff_on_connection_fail(): - with warnings.catch_warnings(record=True) as w: - client = Elasticsearch("http://localhost:9200", sniff_on_connection_fail=True) - assert client.transport._sniff_on_node_failure is True - assert len(w) == 1 - assert w[0].category == DeprecationWarning - assert str(w[0].message) == ( - "The 'sniff_on_connection_fail' parameter is deprecated in favor of 'sniff_on_node_failure'" - ) - - with pytest.raises(ValueError) as e: - Elasticsearch( - "http://localhost:9200", - sniff_on_connection_fail=True, - sniff_on_node_failure=True, - ) - assert ( - str(e.value) - == "Can't specify both 'sniff_on_connection_fail' and 'sniff_on_node_failure', instead only specify 'sniff_on_node_failure'" - ) - - -def test_sniffer_timeout(): - with warnings.catch_warnings(record=True) as w: - client = Elasticsearch("http://localhost:9200", sniffer_timeout=1) - assert client.transport._min_delay_between_sniffing == 1 - assert len(w) == 1 - assert w[0].category == DeprecationWarning - assert str(w[0].message) == ( - "The 'sniffer_timeout' parameter is deprecated in favor of 'min_delay_between_sniffing'" - ) - - with pytest.raises(ValueError) as e: - Elasticsearch( - "http://localhost:9200", sniffer_timeout=1, min_delay_between_sniffing=1 - ) - assert ( - str(e.value) - == "Can't specify both 'sniffer_timeout' and 'min_delay_between_sniffing', instead only specify 'min_delay_between_sniffing'" - ) - - -def test_randomize_hosts(): - with warnings.catch_warnings(record=True) as w: - Elasticsearch("http://localhost:9200", randomize_hosts=True) - assert len(w) == 1 - assert w[0].category == DeprecationWarning - assert str(w[0].message) == ( - "The 'randomize_hosts' parameter is deprecated in favor of 'randomize_nodes_in_pool'" - ) - - with pytest.raises(ValueError) as e: - Elasticsearch( - "http://localhost:9200", randomize_hosts=True, randomize_nodes_in_pool=True - ) - assert ( - str(e.value) - == "Can't specify both 'randomize_hosts' and 'randomize_nodes_in_pool', instead only specify 'randomize_nodes_in_pool'" - ) - - -def test_serializer_and_serializers(): - with pytest.raises(ValueError) as e: - Elasticsearch( - "http://localhost:9200", - serializer=JsonSerializer(), - serializers={"application/json": JsonSerializer()}, - ) - assert str(e.value) == ( - "Can't specify both 'serializer' and 'serializers' parameters together. " - "Instead only specify one of the other." - ) - - class CustomSerializer(JsonSerializer): - pass - - client = Elasticsearch("http://localhost:9200", serializer=CustomSerializer()) - assert isinstance( - client.transport.serializers.get_serializer("application/json"), - CustomSerializer, - ) - assert set(client.transport.serializers.serializers.keys()) == EXPECTED_SERIALIZERS - - client = Elasticsearch( - "http://localhost:9200", - serializers={ - "application/json": CustomSerializer(), - "application/cbor": CustomSerializer(), - }, - ) - assert isinstance( - client.transport.serializers.get_serializer("application/json"), - CustomSerializer, - ) - expected = EXPECTED_SERIALIZERS | {"application/cbor"} - assert set(client.transport.serializers.serializers.keys()) == expected diff --git a/test_elasticsearch/test_client/test_options.py b/test_elasticsearch/test_client/test_options.py index b7fa3cfda..c2050d186 100644 --- a/test_elasticsearch/test_client/test_options.py +++ b/test_elasticsearch/test_client/test_options.py @@ -19,7 +19,7 @@ from elastic_transport import OpenTelemetrySpan from elastic_transport.client_utils import DEFAULT -from elasticsearch import AsyncElasticsearch, Elasticsearch +from elasticsearch import AsyncElasticsearch, Elasticsearch, JsonSerializer from elasticsearch._sync.client.utils import USER_AGENT from test_elasticsearch.test_cases import ( DummyAsyncTransport, @@ -27,6 +27,22 @@ DummyTransportTestCase, ) +EXPECTED_SERIALIZERS = { + "application/vnd.mapbox-vector-tile", + "application/x-ndjson", + "application/json", + "text/*", + "application/vnd.elasticsearch+json", + "application/vnd.elasticsearch+x-ndjson", +} + +try: + import pyarrow as pa + + EXPECTED_SERIALIZERS.add("application/vnd.apache.arrow.stream") +except ImportError: + pa = None + class TestOptions(DummyTransportTestCase): def assert_called_with_headers(self, client, method, target, headers): @@ -479,3 +495,41 @@ def test_options_timeout_parameters(self): "retry_on_status": (404,), "retry_on_timeout": True, } + + def test_serializer_and_serializers(self): + with pytest.raises(ValueError) as e: + Elasticsearch( + "http://localhost:9200", + serializer=JsonSerializer(), + serializers={"application/json": JsonSerializer()}, + ) + assert str(e.value) == ( + "Can't specify both 'serializer' and 'serializers' parameters together. " + "Instead only specify one of the other." + ) + + class CustomSerializer(JsonSerializer): + pass + + client = Elasticsearch("http://localhost:9200", serializer=CustomSerializer()) + assert isinstance( + client.transport.serializers.get_serializer("application/json"), + CustomSerializer, + ) + assert ( + set(client.transport.serializers.serializers.keys()) == EXPECTED_SERIALIZERS + ) + + client = Elasticsearch( + "http://localhost:9200", + serializers={ + "application/json": CustomSerializer(), + "application/cbor": CustomSerializer(), + }, + ) + assert isinstance( + client.transport.serializers.get_serializer("application/json"), + CustomSerializer, + ) + expected = EXPECTED_SERIALIZERS | {"application/cbor"} + assert set(client.transport.serializers.serializers.keys()) == expected diff --git a/test_elasticsearch/test_transport.py b/test_elasticsearch/test_transport.py index 5161cd8e1..6fb72f98b 100644 --- a/test_elasticsearch/test_transport.py +++ b/test_elasticsearch/test_transport.py @@ -18,7 +18,7 @@ import re import time import warnings -from typing import Any, Dict, Optional, Union +from typing import Any, Dict, Optional import pytest from elastic_transport import ( @@ -525,10 +525,8 @@ def test_sniff_after_n_seconds(self): "kwargs", [ {"sniff_on_start": True}, - {"sniff_on_connection_fail": True}, {"sniff_on_node_failure": True}, {"sniff_before_requests": True}, - {"sniffer_timeout": 1}, {"sniff_timeout": 1}, ], ) @@ -589,41 +587,6 @@ def sniffed_node_callback( ports = {node.config.port for node in client.transport.node_pool.all()} assert ports == {9200, 124} - def test_sniffing_deprecated_host_info_callback(self): - def host_info_callback( - node_info: Dict[str, Any], host: Dict[str, Union[int, str]] - ) -> Dict[str, Any]: - return ( - host if node_info["http"]["publish_address"].endswith(":124") else None - ) - - with warnings.catch_warnings(record=True) as w: - client = Elasticsearch( # noqa: F821 - [ - NodeConfig( - "http", - "localhost", - 9200, - _extras={"data": CLUSTER_NODES_MASTER_ONLY}, - ) - ], - node_class=DummyNode, - sniff_on_start=True, - host_info_callback=host_info_callback, - ) - - assert len(w) == 1 - assert w[0].category == DeprecationWarning - assert ( - str(w[0].message) - == "The 'host_info_callback' parameter is deprecated in favor of 'sniffed_node_callback'" - ) - - assert len(client.transport.node_pool) == 2 - - ports = {node.config.port for node in client.transport.node_pool.all()} - assert ports == {9200, 124} - @pytest.mark.parametrize("headers", [{}, {"X-elastic-product": "BAD HEADER"}]) def test_unsupported_product_error(headers): diff --git a/test_elasticsearch/test_types/aliased_types.py b/test_elasticsearch/test_types/aliased_types.py index 0b5c97f98..ff0aa994a 100644 --- a/test_elasticsearch/test_types/aliased_types.py +++ b/test_elasticsearch/test_types/aliased_types.py @@ -34,9 +34,7 @@ [{"host": "localhost", "port": 9443}], transport_class=Transport, sniff_on_start=True, - sniffer_timeout=0.1, sniff_timeout=1, - sniff_on_connection_fail=False, max_retries=1, retry_on_status={100, 400, 503}, retry_on_timeout=True, @@ -103,9 +101,7 @@ def reindex_types() -> None: es2 = AsyncElasticsearch( [{"host": "localhost", "port": 9443}], sniff_on_start=True, - sniffer_timeout=0.1, sniff_timeout=1, - sniff_on_connection_fail=False, max_retries=1, retry_on_status={100, 400, 503}, retry_on_timeout=True, diff --git a/test_elasticsearch/test_types/async_types.py b/test_elasticsearch/test_types/async_types.py index ac7eed19a..1743fde2d 100644 --- a/test_elasticsearch/test_types/async_types.py +++ b/test_elasticsearch/test_types/async_types.py @@ -28,9 +28,7 @@ es = AsyncElasticsearch( [{"host": "localhost", "port": 9443}], sniff_on_start=True, - sniffer_timeout=0.1, sniff_timeout=1, - sniff_on_connection_fail=False, max_retries=1, retry_on_status={100, 400, 503}, retry_on_timeout=True, diff --git a/test_elasticsearch/test_types/sync_types.py b/test_elasticsearch/test_types/sync_types.py index f4582ddba..8166e50ee 100644 --- a/test_elasticsearch/test_types/sync_types.py +++ b/test_elasticsearch/test_types/sync_types.py @@ -23,9 +23,7 @@ es = Elasticsearch( [{"host": "localhost", "port": 9443}], sniff_on_start=True, - sniffer_timeout=0.1, sniff_timeout=1, - sniff_on_connection_fail=False, max_retries=1, retry_on_status={100, 400, 503}, retry_on_timeout=True, From b243ae161ca17c890f8f974433e799a8587ef968 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 2 Apr 2025 16:09:44 +0100 Subject: [PATCH 14/57] Revert "Remove deprecated http_auth parameter (#2839)" (#2872) (#2877) This reverts commit 74387d0a3f42517e2a5805c9bb0aec57511b6e15. (cherry picked from commit d480a2f8d14ae5c91bef1ba4975e7fb0196556a6) Co-authored-by: Miguel Grinberg --- elasticsearch/_async/client/__init__.py | 21 +++++ elasticsearch/_async/client/_base.py | 26 ++++++ elasticsearch/_async/client/utils.py | 4 + elasticsearch/_async/helpers.py | 7 +- elasticsearch/_sync/client/__init__.py | 21 +++++ elasticsearch/_sync/client/_base.py | 26 ++++++ elasticsearch/_sync/client/utils.py | 35 ++++++++ elasticsearch/helpers/actions.py | 6 +- .../test_async/test_server/test_helpers.py | 6 +- .../test_client/test_deprecated_options.py | 48 +++++++++++ .../test_client/test_requests_auth.py | 84 +++++++++++++++++++ .../test_client/test_rewrite_parameters.py | 4 +- .../test_server/test_helpers.py | 7 +- 13 files changed, 287 insertions(+), 8 deletions(-) create mode 100644 test_elasticsearch/test_client/test_deprecated_options.py create mode 100644 test_elasticsearch/test_client/test_requests_auth.py diff --git a/elasticsearch/_async/client/__init__.py b/elasticsearch/_async/client/__init__.py index 243a71401..d05ce7a1a 100644 --- a/elasticsearch/_async/client/__init__.py +++ b/elasticsearch/_async/client/__init__.py @@ -87,6 +87,8 @@ _rewrite_parameters, _stability_warning, client_node_configs, + is_requests_http_auth, + is_requests_node_class, ) from .watcher import WatcherClient from .xpack import XPackClient @@ -178,6 +180,7 @@ def __init__( t.Callable[[t.Dict[str, t.Any], NodeConfig], t.Optional[NodeConfig]] ] = None, meta_header: t.Union[DefaultType, bool] = DEFAULT, + http_auth: t.Union[DefaultType, t.Any] = DEFAULT, # Internal use only _transport: t.Optional[AsyncTransport] = None, ) -> None: @@ -225,9 +228,26 @@ def __init__( sniff_callback = default_sniff_callback if _transport is None: + requests_session_auth = None + if http_auth is not None and http_auth is not DEFAULT: + if is_requests_http_auth(http_auth): + # If we're using custom requests authentication + # then we need to alert the user that they also + # need to use 'node_class=requests'. + if not is_requests_node_class(node_class): + raise ValueError( + "Using a custom 'requests.auth.AuthBase' class for " + "'http_auth' must be used with node_class='requests'" + ) + + # Reset 'http_auth' to DEFAULT so it's not consumed below. + requests_session_auth = http_auth + http_auth = DEFAULT + node_configs = client_node_configs( hosts, cloud_id=cloud_id, + requests_session_auth=requests_session_auth, connections_per_node=connections_per_node, http_compress=http_compress, verify_certs=verify_certs, @@ -314,6 +334,7 @@ def __init__( self._headers["x-opaque-id"] = opaque_id self._headers = resolve_auth_headers( self._headers, + http_auth=http_auth, api_key=api_key, basic_auth=basic_auth, bearer_auth=bearer_auth, diff --git a/elasticsearch/_async/client/_base.py b/elasticsearch/_async/client/_base.py index 3907cfd84..cc090671c 100644 --- a/elasticsearch/_async/client/_base.py +++ b/elasticsearch/_async/client/_base.py @@ -68,6 +68,7 @@ def resolve_auth_headers( headers: Optional[Mapping[str, str]], + http_auth: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT, api_key: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT, basic_auth: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT, bearer_auth: Union[DefaultType, None, str] = DEFAULT, @@ -77,7 +78,32 @@ def resolve_auth_headers( elif not isinstance(headers, HttpHeaders): headers = HttpHeaders(headers) + resolved_http_auth = http_auth if http_auth is not DEFAULT else None resolved_basic_auth = basic_auth if basic_auth is not DEFAULT else None + if resolved_http_auth is not None: + if resolved_basic_auth is not None: + raise ValueError( + "Can't specify both 'http_auth' and 'basic_auth', " + "instead only specify 'basic_auth'" + ) + if isinstance(http_auth, str) or ( + isinstance(resolved_http_auth, (list, tuple)) + and all(isinstance(x, str) for x in resolved_http_auth) + ): + resolved_basic_auth = resolved_http_auth + else: + raise TypeError( + "The deprecated 'http_auth' parameter must be either 'Tuple[str, str]' or 'str'. " + "Use either the 'basic_auth' parameter instead" + ) + + warnings.warn( + "The 'http_auth' parameter is deprecated. " + "Use 'basic_auth' or 'bearer_auth' parameters instead", + category=DeprecationWarning, + stacklevel=warn_stacklevel(), + ) + resolved_api_key = api_key if api_key is not DEFAULT else None resolved_bearer_auth = bearer_auth if bearer_auth is not DEFAULT else None if resolved_api_key or resolved_basic_auth or resolved_bearer_auth: diff --git a/elasticsearch/_async/client/utils.py b/elasticsearch/_async/client/utils.py index ac7a35062..97918d9e4 100644 --- a/elasticsearch/_async/client/utils.py +++ b/elasticsearch/_async/client/utils.py @@ -27,6 +27,8 @@ _rewrite_parameters, _stability_warning, client_node_configs, + is_requests_http_auth, + is_requests_node_class, ) __all__ = [ @@ -41,4 +43,6 @@ "client_node_configs", "_rewrite_parameters", "_stability_warning", + "is_requests_http_auth", + "is_requests_node_class", ] diff --git a/elasticsearch/_async/helpers.py b/elasticsearch/_async/helpers.py index 8b5d3d0d2..e4d5e6bc5 100644 --- a/elasticsearch/_async/helpers.py +++ b/elasticsearch/_async/helpers.py @@ -418,9 +418,12 @@ def pop_transport_kwargs(kw: MutableMapping[str, Any]) -> MutableMapping[str, An # Grab options that should be propagated to every # API call within this helper instead of just 'search()' transport_kwargs = {} - for key in ("headers", "api_key", "basic_auth", "bearer_auth"): + for key in ("headers", "api_key", "http_auth", "basic_auth", "bearer_auth"): try: - transport_kwargs[key] = kw.pop(key) + value = kw.pop(key) + if key == "http_auth": + key = "basic_auth" + transport_kwargs[key] = value except KeyError: pass return transport_kwargs diff --git a/elasticsearch/_sync/client/__init__.py b/elasticsearch/_sync/client/__init__.py index 3a4435ce9..115a27a9a 100644 --- a/elasticsearch/_sync/client/__init__.py +++ b/elasticsearch/_sync/client/__init__.py @@ -87,6 +87,8 @@ _rewrite_parameters, _stability_warning, client_node_configs, + is_requests_http_auth, + is_requests_node_class, ) from .watcher import WatcherClient from .xpack import XPackClient @@ -178,6 +180,7 @@ def __init__( t.Callable[[t.Dict[str, t.Any], NodeConfig], t.Optional[NodeConfig]] ] = None, meta_header: t.Union[DefaultType, bool] = DEFAULT, + http_auth: t.Union[DefaultType, t.Any] = DEFAULT, # Internal use only _transport: t.Optional[Transport] = None, ) -> None: @@ -225,9 +228,26 @@ def __init__( sniff_callback = default_sniff_callback if _transport is None: + requests_session_auth = None + if http_auth is not None and http_auth is not DEFAULT: + if is_requests_http_auth(http_auth): + # If we're using custom requests authentication + # then we need to alert the user that they also + # need to use 'node_class=requests'. + if not is_requests_node_class(node_class): + raise ValueError( + "Using a custom 'requests.auth.AuthBase' class for " + "'http_auth' must be used with node_class='requests'" + ) + + # Reset 'http_auth' to DEFAULT so it's not consumed below. + requests_session_auth = http_auth + http_auth = DEFAULT + node_configs = client_node_configs( hosts, cloud_id=cloud_id, + requests_session_auth=requests_session_auth, connections_per_node=connections_per_node, http_compress=http_compress, verify_certs=verify_certs, @@ -314,6 +334,7 @@ def __init__( self._headers["x-opaque-id"] = opaque_id self._headers = resolve_auth_headers( self._headers, + http_auth=http_auth, api_key=api_key, basic_auth=basic_auth, bearer_auth=bearer_auth, diff --git a/elasticsearch/_sync/client/_base.py b/elasticsearch/_sync/client/_base.py index 64abdc250..868b71073 100644 --- a/elasticsearch/_sync/client/_base.py +++ b/elasticsearch/_sync/client/_base.py @@ -68,6 +68,7 @@ def resolve_auth_headers( headers: Optional[Mapping[str, str]], + http_auth: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT, api_key: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT, basic_auth: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT, bearer_auth: Union[DefaultType, None, str] = DEFAULT, @@ -77,7 +78,32 @@ def resolve_auth_headers( elif not isinstance(headers, HttpHeaders): headers = HttpHeaders(headers) + resolved_http_auth = http_auth if http_auth is not DEFAULT else None resolved_basic_auth = basic_auth if basic_auth is not DEFAULT else None + if resolved_http_auth is not None: + if resolved_basic_auth is not None: + raise ValueError( + "Can't specify both 'http_auth' and 'basic_auth', " + "instead only specify 'basic_auth'" + ) + if isinstance(http_auth, str) or ( + isinstance(resolved_http_auth, (list, tuple)) + and all(isinstance(x, str) for x in resolved_http_auth) + ): + resolved_basic_auth = resolved_http_auth + else: + raise TypeError( + "The deprecated 'http_auth' parameter must be either 'Tuple[str, str]' or 'str'. " + "Use either the 'basic_auth' parameter instead" + ) + + warnings.warn( + "The 'http_auth' parameter is deprecated. " + "Use 'basic_auth' or 'bearer_auth' parameters instead", + category=DeprecationWarning, + stacklevel=warn_stacklevel(), + ) + resolved_api_key = api_key if api_key is not DEFAULT else None resolved_bearer_auth = bearer_auth if bearer_auth is not DEFAULT else None if resolved_api_key or resolved_basic_auth or resolved_bearer_auth: diff --git a/elasticsearch/_sync/client/utils.py b/elasticsearch/_sync/client/utils.py index 3293e356e..48ebcb217 100644 --- a/elasticsearch/_sync/client/utils.py +++ b/elasticsearch/_sync/client/utils.py @@ -16,6 +16,7 @@ # under the License. import base64 +import inspect import urllib.parse import warnings from datetime import date, datetime @@ -43,6 +44,7 @@ AsyncTransport, HttpHeaders, NodeConfig, + RequestsHttpNode, SniffOptions, Transport, ) @@ -90,6 +92,7 @@ class Stability(Enum): _TRANSPORT_OPTIONS = { "api_key", + "http_auth", "request_timeout", "opaque_id", "headers", @@ -102,6 +105,7 @@ class Stability(Enum): def client_node_configs( hosts: Optional[_TYPE_HOSTS], cloud_id: Optional[str], + requests_session_auth: Optional[Any] = None, **kwargs: Any, ) -> List[NodeConfig]: if cloud_id is not None: @@ -122,6 +126,12 @@ def client_node_configs( headers.setdefault("user-agent", USER_AGENT) node_options["headers"] = headers + # If a custom Requests AuthBase is passed we set that via '_extras'. + if requests_session_auth is not None: + node_options.setdefault("_extras", {})[ + "requests.session.auth" + ] = requests_session_auth + def apply_node_options(node_config: NodeConfig) -> NodeConfig: """Needs special handling of headers since .replace() wipes out existing headers""" headers = node_config.headers.copy() # type: ignore[attr-defined] @@ -438,3 +448,28 @@ def wrapped(*args: Any, **kwargs: Any) -> Any: return wrapped # type: ignore[return-value] return wrapper + + +def is_requests_http_auth(http_auth: Any) -> bool: + """Detect if an http_auth value is a custom Requests auth object""" + try: + from requests.auth import AuthBase + + return isinstance(http_auth, AuthBase) + except ImportError: + pass + return False + + +def is_requests_node_class(node_class: Any) -> bool: + """Detect if 'RequestsHttpNode' would be used given the setting of 'node_class'""" + return ( + node_class is not None + and node_class is not DEFAULT + and ( + node_class == "requests" + or ( + inspect.isclass(node_class) and issubclass(node_class, RequestsHttpNode) + ) + ) + ) diff --git a/elasticsearch/helpers/actions.py b/elasticsearch/helpers/actions.py index 25c21cdd4..d1a43a8dc 100644 --- a/elasticsearch/helpers/actions.py +++ b/elasticsearch/helpers/actions.py @@ -698,12 +698,16 @@ def pop_transport_kwargs(kw: MutableMapping[str, Any]) -> Dict[str, Any]: for key in ( "headers", "api_key", + "http_auth", "basic_auth", "bearer_auth", "opaque_id", ): try: - transport_kwargs[key] = kw.pop(key) + value = kw.pop(key) + if key == "http_auth": + key = "basic_auth" + transport_kwargs[key] = value except KeyError: pass return transport_kwargs diff --git a/test_elasticsearch/test_async/test_server/test_helpers.py b/test_elasticsearch/test_async/test_server/test_helpers.py index 86439b487..0bb781304 100644 --- a/test_elasticsearch/test_async/test_server/test_helpers.py +++ b/test_elasticsearch/test_async/test_server/test_helpers.py @@ -741,8 +741,7 @@ async def test_clear_scroll(self, async_client, scan_teardown): "kwargs", [ {"api_key": ("name", "value")}, - {"basic_auth": ("username", "password")}, - {"bearer_auth": "token"}, + {"http_auth": ("username", "password")}, {"headers": {"custom", "header"}}, ], ) @@ -791,6 +790,9 @@ async def test_scan_auth_kwargs_forwarded( assert data == [{"search_data": 1}] + if "http_auth" in kwargs: + kwargs = {"basic_auth": kwargs.pop("http_auth")} + assert options.call_args_list == [ call(request_timeout=None, **kwargs), call(ignore_status=404), diff --git a/test_elasticsearch/test_client/test_deprecated_options.py b/test_elasticsearch/test_client/test_deprecated_options.py new file mode 100644 index 000000000..bbde2e90b --- /dev/null +++ b/test_elasticsearch/test_client/test_deprecated_options.py @@ -0,0 +1,48 @@ +# Licensed to Elasticsearch B.V. under one or more contributor +# license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright +# ownership. Elasticsearch B.V. 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. + +import warnings + +import pytest + +from elasticsearch import Elasticsearch + + +def test_http_auth(): + with warnings.catch_warnings(record=True) as w: + client = Elasticsearch( + "http://localhost:9200", http_auth=("username", "password") + ) + + assert len(w) == 1 + assert w[0].category == DeprecationWarning + assert ( + str(w[0].message) + == "The 'http_auth' parameter is deprecated. Use 'basic_auth' or 'bearer_auth' parameters instead" + ) + assert client._headers["Authorization"] == "Basic dXNlcm5hbWU6cGFzc3dvcmQ=" + + with pytest.raises(ValueError) as e: + Elasticsearch( + "http://localhost:9200", + http_auth=("username", "password"), + basic_auth=("username", "password"), + ) + assert ( + str(e.value) + == "Can't specify both 'http_auth' and 'basic_auth', instead only specify 'basic_auth'" + ) diff --git a/test_elasticsearch/test_client/test_requests_auth.py b/test_elasticsearch/test_client/test_requests_auth.py new file mode 100644 index 000000000..2eb656f5d --- /dev/null +++ b/test_elasticsearch/test_client/test_requests_auth.py @@ -0,0 +1,84 @@ +# Licensed to Elasticsearch B.V. under one or more contributor +# license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright +# ownership. Elasticsearch B.V. 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. + +import warnings + +import pytest +import requests +from elastic_transport import RequestsHttpNode, Urllib3HttpNode +from elastic_transport.client_utils import DEFAULT +from requests.auth import HTTPBasicAuth + +from elasticsearch import AsyncElasticsearch, Elasticsearch + + +class CustomRequestHttpNode(RequestsHttpNode): + pass + + +class CustomUrllib3HttpNode(Urllib3HttpNode): + pass + + +@pytest.mark.parametrize( + "node_class", ["requests", RequestsHttpNode, CustomRequestHttpNode] +) +def test_requests_auth(node_class): + http_auth = HTTPBasicAuth("username", "password") + + with warnings.catch_warnings(record=True) as w: + client = Elasticsearch( + "http://localhost:9200", http_auth=http_auth, node_class=node_class + ) + + # http_auth is deprecated for all other cases except this one. + assert len(w) == 0 + + # Instance should be forwarded directly to requests.Session.auth. + node = client.transport.node_pool.get() + assert isinstance(node, RequestsHttpNode) + assert isinstance(node.session, requests.Session) + assert node.session.auth is http_auth + + +@pytest.mark.parametrize("client_class", [Elasticsearch, AsyncElasticsearch]) +@pytest.mark.parametrize( + "node_class", ["urllib3", "aiohttp", None, DEFAULT, CustomUrllib3HttpNode] +) +def test_error_for_requests_auth_node_class(client_class, node_class): + http_auth = HTTPBasicAuth("username", "password") + + with pytest.raises(ValueError) as e: + client_class( + "http://localhost:9200", http_auth=http_auth, node_class=node_class + ) + assert str(e.value) == ( + "Using a custom 'requests.auth.AuthBase' class for " + "'http_auth' must be used with node_class='requests'" + ) + + +def test_error_for_requests_auth_async(): + http_auth = HTTPBasicAuth("username", "password") + + with pytest.raises(ValueError) as e: + AsyncElasticsearch( + "http://localhost:9200", http_auth=http_auth, node_class="requests" + ) + assert str(e.value) == ( + "Specified 'node_class' is not async, should be async instead" + ) diff --git a/test_elasticsearch/test_client/test_rewrite_parameters.py b/test_elasticsearch/test_client/test_rewrite_parameters.py index f933cfd51..50a232563 100644 --- a/test_elasticsearch/test_client/test_rewrite_parameters.py +++ b/test_elasticsearch/test_client/test_rewrite_parameters.py @@ -208,7 +208,7 @@ def test_ignore_deprecated_options(self): body={"query": {"match_all": {}}}, params={"key": "value"}, param=1, - request_timeout=10, + http_auth=("key", "value"), ) assert len(w) == 1 @@ -219,7 +219,7 @@ def test_ignore_deprecated_options(self): ) assert self.calls == [ - ((), {"request_timeout": 10}), + ((), {"http_auth": ("key", "value")}), ( (), { diff --git a/test_elasticsearch/test_server/test_helpers.py b/test_elasticsearch/test_server/test_helpers.py index 361a98ae2..6ed43e2af 100644 --- a/test_elasticsearch/test_server/test_helpers.py +++ b/test_elasticsearch/test_server/test_helpers.py @@ -626,6 +626,7 @@ def test_no_scroll_id_fast_route(sync_client): "kwargs", [ {"api_key": ("name", "value")}, + {"http_auth": ("username", "password")}, {"basic_auth": ("username", "password")}, {"bearer_auth": "token"}, {"headers": {"custom", "header"}}, @@ -633,6 +634,8 @@ def test_no_scroll_id_fast_route(sync_client): ) @pytest.mark.usefixtures("scan_teardown") def test_scan_auth_kwargs_forwarded(sync_client, kwargs): + ((key, val),) = kwargs.items() + with patch.object( sync_client, "options", return_value=sync_client ) as options, patch.object( @@ -665,7 +668,9 @@ def test_scan_auth_kwargs_forwarded(sync_client, kwargs): assert data == [{"search_data": 1}] assert options.call_args_list == [ - call(request_timeout=None, **kwargs), + call( + request_timeout=None, **{key if key != "http_auth" else "basic_auth": val} + ), call(ignore_status=404), ] From 1edb8fc8728fa83497d3565d16c913ed9c1dabd1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 2 Apr 2025 20:17:25 +0400 Subject: [PATCH 15/57] Add back inference.inference API (#2873) (#2881) * Add back inference.inference API This function was removed from the specification in favor of one API per provider and task type, but the existing function was stable and widely used in Python. Still, we mark it as deprecated to encourage users to migrate to the new APIs. * Fix lint (cherry picked from commit eac539dcc301b6062716f1540dc0d1efe888671c) Co-authored-by: Quentin Pradet --- elasticsearch/_async/client/inference.py | 119 ++++++++++++++++++++++- elasticsearch/_sync/client/inference.py | 119 ++++++++++++++++++++++- elasticsearch/_sync/client/utils.py | 7 ++ 3 files changed, 243 insertions(+), 2 deletions(-) diff --git a/elasticsearch/_async/client/inference.py b/elasticsearch/_async/client/inference.py index 73983f07a..31b371948 100644 --- a/elasticsearch/_async/client/inference.py +++ b/elasticsearch/_async/client/inference.py @@ -20,7 +20,13 @@ from elastic_transport import ObjectApiResponse from ._base import NamespacedClient -from .utils import SKIP_IN_PATH, _quote, _rewrite_parameters +from .utils import ( + SKIP_IN_PATH, + Stability, + _quote, + _rewrite_parameters, + _stability_warning, +) class InferenceClient(NamespacedClient): @@ -234,6 +240,117 @@ async def get( path_parts=__path_parts, ) + @_rewrite_parameters( + body_fields=("input", "query", "task_settings"), + ) + @_stability_warning( + Stability.DEPRECATED, + version="8.18.0", + message="inference.inference() is deprecated in favor of provider-specific APIs such as inference.put_elasticsearch() or inference.put_hugging_face()", + ) + async def inference( + self, + *, + inference_id: str, + input: t.Optional[t.Union[str, t.Sequence[str]]] = None, + task_type: t.Optional[ + t.Union[ + str, + t.Literal[ + "chat_completion", + "completion", + "rerank", + "sparse_embedding", + "text_embedding", + ], + ] + ] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + query: t.Optional[str] = None, + task_settings: t.Optional[t.Any] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Perform inference on the service.

+

This API enables you to use machine learning models to perform specific tasks on data that you provide as an input. + It returns a response with the results of the tasks. + The inference endpoint you use can perform one specific task that has been defined when the endpoint was created with the create inference API.

+
+

info + The inference APIs enable you to use certain services, such as built-in machine learning models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Azure, Google AI Studio, Google Vertex AI, Anthropic, Watsonx.ai, or Hugging Face. For built-in models and models uploaded through Eland, the inference APIs offer an alternative way to use and manage trained models. However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.

+
+ + + ``_ + + :param inference_id: The unique identifier for the inference endpoint. + :param input: The text on which you want to perform the inference task. It can + be a single string or an array. > info > Inference endpoints for the `completion` + task type currently only support a single string as input. + :param task_type: The type of inference task that the model performs. + :param query: The query input, which is required only for the `rerank` task. + It is not required for other tasks. + :param task_settings: Task settings for the individual inference request. These + settings are specific to the task type you specified and override the task + settings specified when initializing the service. + :param timeout: The amount of time to wait for the inference request to complete. + """ + if inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'inference_id'") + if input is None and body is None: + raise ValueError("Empty value passed for parameter 'input'") + __path_parts: t.Dict[str, str] + if task_type not in SKIP_IN_PATH and inference_id not in SKIP_IN_PATH: + __path_parts = { + "task_type": _quote(task_type), + "inference_id": _quote(inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["inference_id"]}' + elif inference_id not in SKIP_IN_PATH: + __path_parts = {"inference_id": _quote(inference_id)} + __path = f'/_inference/{__path_parts["inference_id"]}' + else: + raise ValueError("Couldn't find a path for the given parameters") + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout + if not __body: + if input is not None: + __body["input"] = input + if query is not None: + __body["query"] = query + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "POST", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.inference", + path_parts=__path_parts, + ) + @_rewrite_parameters( body_name="chat_completion_request", ) diff --git a/elasticsearch/_sync/client/inference.py b/elasticsearch/_sync/client/inference.py index 279528a96..aa2ebde2e 100644 --- a/elasticsearch/_sync/client/inference.py +++ b/elasticsearch/_sync/client/inference.py @@ -20,7 +20,13 @@ from elastic_transport import ObjectApiResponse from ._base import NamespacedClient -from .utils import SKIP_IN_PATH, _quote, _rewrite_parameters +from .utils import ( + SKIP_IN_PATH, + Stability, + _quote, + _rewrite_parameters, + _stability_warning, +) class InferenceClient(NamespacedClient): @@ -234,6 +240,117 @@ def get( path_parts=__path_parts, ) + @_rewrite_parameters( + body_fields=("input", "query", "task_settings"), + ) + @_stability_warning( + Stability.DEPRECATED, + version="8.18.0", + message="inference.inference() is deprecated in favor of provider-specific APIs such as inference.put_elasticsearch() or inference.put_hugging_face()", + ) + def inference( + self, + *, + inference_id: str, + input: t.Optional[t.Union[str, t.Sequence[str]]] = None, + task_type: t.Optional[ + t.Union[ + str, + t.Literal[ + "chat_completion", + "completion", + "rerank", + "sparse_embedding", + "text_embedding", + ], + ] + ] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + query: t.Optional[str] = None, + task_settings: t.Optional[t.Any] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Perform inference on the service.

+

This API enables you to use machine learning models to perform specific tasks on data that you provide as an input. + It returns a response with the results of the tasks. + The inference endpoint you use can perform one specific task that has been defined when the endpoint was created with the create inference API.

+
+

info + The inference APIs enable you to use certain services, such as built-in machine learning models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Azure, Google AI Studio, Google Vertex AI, Anthropic, Watsonx.ai, or Hugging Face. For built-in models and models uploaded through Eland, the inference APIs offer an alternative way to use and manage trained models. However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.

+
+ + + ``_ + + :param inference_id: The unique identifier for the inference endpoint. + :param input: The text on which you want to perform the inference task. It can + be a single string or an array. > info > Inference endpoints for the `completion` + task type currently only support a single string as input. + :param task_type: The type of inference task that the model performs. + :param query: The query input, which is required only for the `rerank` task. + It is not required for other tasks. + :param task_settings: Task settings for the individual inference request. These + settings are specific to the task type you specified and override the task + settings specified when initializing the service. + :param timeout: The amount of time to wait for the inference request to complete. + """ + if inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'inference_id'") + if input is None and body is None: + raise ValueError("Empty value passed for parameter 'input'") + __path_parts: t.Dict[str, str] + if task_type not in SKIP_IN_PATH and inference_id not in SKIP_IN_PATH: + __path_parts = { + "task_type": _quote(task_type), + "inference_id": _quote(inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["inference_id"]}' + elif inference_id not in SKIP_IN_PATH: + __path_parts = {"inference_id": _quote(inference_id)} + __path = f'/_inference/{__path_parts["inference_id"]}' + else: + raise ValueError("Couldn't find a path for the given parameters") + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout + if not __body: + if input is not None: + __body["input"] = input + if query is not None: + __body["query"] = query + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "POST", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.inference", + path_parts=__path_parts, + ) + @_rewrite_parameters( body_name="chat_completion_request", ) diff --git a/elasticsearch/_sync/client/utils.py b/elasticsearch/_sync/client/utils.py index 48ebcb217..0708329ba 100644 --- a/elasticsearch/_sync/client/utils.py +++ b/elasticsearch/_sync/client/utils.py @@ -77,6 +77,7 @@ class Stability(Enum): STABLE = auto() BETA = auto() EXPERIMENTAL = auto() + DEPRECATED = auto() _TYPE_HOSTS = Union[ @@ -442,6 +443,12 @@ def wrapped(*args: Any, **kwargs: Any) -> Any: category=GeneralAvailabilityWarning, stacklevel=warn_stacklevel(), ) + elif stability == Stability.DEPRECATED and message and version: + warnings.warn( + f"In elasticsearch-py {version}, {message}.", + category=DeprecationWarning, + stacklevel=warn_stacklevel(), + ) return api(*args, **kwargs) From 901dbc30323f024574460de76fdb8fea03ab16f0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 2 Apr 2025 20:24:30 +0400 Subject: [PATCH 16/57] Add querying docs (#2843) (#2878) * Add querying docs It's not always obvious to go from an API to a function call, and this page contains the details. * Apply suggestions from code review Co-authored-by: Miguel Grinberg * Address more comments * Rename to Querying for consistency * Clarify that examples in guide depend on version --------- Co-authored-by: Miguel Grinberg (cherry picked from commit 3fcb7193cd7e46bef6edd4ed85934f505fbe5c89) Co-authored-by: Quentin Pradet --- docs/images/python-example.png | Bin 0 -> 109584 bytes docs/reference/querying.md | 106 +++++++++++++++++++++++++++++++++ docs/reference/toc.yml | 1 + 3 files changed, 107 insertions(+) create mode 100644 docs/images/python-example.png create mode 100644 docs/reference/querying.md diff --git a/docs/images/python-example.png b/docs/images/python-example.png new file mode 100644 index 0000000000000000000000000000000000000000..3eaee6d0224f549152ed9fc0b7063f67822b462e GIT binary patch literal 109584 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/_doc/<_id>` and related endpoints). + * Then there are all the other namespaces, such as: + * Indices with APIs like the Create index API (`PUT /my-index`), + * ES|QL with the Run an ES|QL query API (`POST /_async`), + * and so on. + +As a result, when you know which namespace and function you need, you can call the function. Assuming that `client` is an Elasticsearch instance, here is how you would call the examples from above: + +* Global namespace: `client.search(...)` and `client.index(...)` +* Other namespaces: + * Indices: `client.indices.create(...)` + * ES|QL: `client.esql.query(...)` + +How can you figure out the namespace? + +* The [Elasticsearch API docs](https://www.elastic.co/docs/api/doc/elasticsearch/) can help, even though the tags it uses do not fully map to namespaces. +* You can also use the client documentation, by: + * browsing the [Elasticsearch API Reference](https://elasticsearch-py.readthedocs.io/en/stable/api.html) page, or + * searching for your endpoint using [Read the Docs](https://elasticsearch-py.readthedocs.io/) search, which is powered by Elasticsearch! +* Finally, for Elasticsearch 8.x, most examples in the [Elasticsearch guide](https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html) are also available in Python. (This is still a work in progress for Elasticsearch 9.x.) In the example below, `client.ingest.put_pipeline(...)` is the function that calls the "Create or update a pipeline" API. + + +:::{image} ../images/python-example.png +:alt: Python code example in the Elasticsearch guide +::: + +## Parameters + +Now that you know which functions to call, the next step is parameters. To avoid ambiguity, the Python Elasticsearch client mandates keyword arguments. To give an example, let's look at the ["Create an index" API](https://elasticsearch-py.readthedocs.io/en/stable/api/indices.html#elasticsearch.client.IndicesClient.create). There's only one required parameter, `index`, so the minimal form looks like this: + +```python +from elasticsearch import Elasticsearch + +client = Elasticsearch("http://localhost:9200", api_key="...") + +client.indices.create(index="my-index") +``` + +You can also use other parameters, including the first level of body parameters, such as: + +```python +resp = client.indices.create( + index="logs", + aliases={"logs-alias": {}}, + mappings={"name": {"type": "text"}}, +) +print(resp) +``` + +In this case, the client will send to Elasticsearch the following JSON body: + +```console +PUT /logs +{ + "aliases": {"logs-alias": {}}, + "mappings": {"name": {"type": "text"}} +} +``` + +## Unknown parameters or APIs + +Like other clients, the Python Elasticsearch client is generated from the [Elasticsearch specification](https://github.com/elastic/elasticsearch-specification). While we strive to keep it up to date, it is not (yet!) perfect, and sometimes body parameters are missing. In this case, you can specify the body directly, as follows: + +```python +resp = client.indices.create( + index="logs", + body={ + "aliases": {"logs-alias": {}}, + "mappings": {"name": {"type": "text"}}, + "missing_parameter": "foo", + } +) +print(resp) +``` + +In the event where an API is missing, you need to use the low-level `perform_request` function: + +```python +resp = client.perform_request( + "PUT", + "/logs" + index="logs", + headers={"content-type": "application/json", "accept": "application/json"}, + body={ + "aliases": {"logs-alias": {}}, + "mappings": {"name": {"type": "text"}}, + "missing_parameter": "foo", + } +) +print(resp) +``` + +One benefit of this function is that it lets you use arbitrary headers, such as the `es-security-runas-user` header used to [impersonate users](https://www.elastic.co/guide/en/elasticsearch/reference/current/run-as-privilege.html). + + +## Options + +You can specify options such as request timeouts or retries using the `.options()` API, see the [Configuration](./configuration.md) page for details. \ No newline at end of file diff --git a/docs/reference/toc.yml b/docs/reference/toc.yml index 0ff68225e..015027e4d 100644 --- a/docs/reference/toc.yml +++ b/docs/reference/toc.yml @@ -4,6 +4,7 @@ toc: - file: installation.md - file: connecting.md - file: configuration.md + - file: querying.md - file: async.md - file: integrations.md children: From ad5c821d9e62c61103652f195cff7eee6299e9a1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 4 Apr 2025 17:51:00 +0400 Subject: [PATCH 17/57] [docs] Miscellaneous docs clean up (#2853) (#2884) * remove unused substitutions * move images (cherry picked from commit 5d7db5614b3e5187e14186e48d29ece45ee9ddb7) Co-authored-by: Colleen McGinnis --- docs/docset.yml | 478 ------------------ docs/reference/getting-started.md | 4 +- .../{ => reference}/images/create-api-key.png | Bin docs/{ => reference}/images/es-endpoint.jpg | Bin .../images/otel-waterfall-retry.png | Bin .../images/otel-waterfall-with-http.png | Bin .../images/otel-waterfall-without-http.png | Bin docs/reference/opentelemetry.md | 6 +- 8 files changed, 5 insertions(+), 483 deletions(-) rename docs/{ => reference}/images/create-api-key.png (100%) rename docs/{ => reference}/images/es-endpoint.jpg (100%) rename docs/{ => reference}/images/otel-waterfall-retry.png (100%) rename docs/{ => reference}/images/otel-waterfall-with-http.png (100%) rename docs/{ => reference}/images/otel-waterfall-without-http.png (100%) diff --git a/docs/docset.yml b/docs/docset.yml index 882aea405..b4185d296 100644 --- a/docs/docset.yml +++ b/docs/docset.yml @@ -7,482 +7,4 @@ toc: - toc: reference - toc: release-notes subs: - ref: "https://www.elastic.co/guide/en/elasticsearch/reference/current" - ref-bare: "https://www.elastic.co/guide/en/elasticsearch/reference" - ref-8x: "https://www.elastic.co/guide/en/elasticsearch/reference/8.1" - ref-80: "https://www.elastic.co/guide/en/elasticsearch/reference/8.0" - ref-7x: "https://www.elastic.co/guide/en/elasticsearch/reference/7.17" - ref-70: "https://www.elastic.co/guide/en/elasticsearch/reference/7.0" - ref-60: "https://www.elastic.co/guide/en/elasticsearch/reference/6.0" - ref-64: "https://www.elastic.co/guide/en/elasticsearch/reference/6.4" - xpack-ref: "https://www.elastic.co/guide/en/x-pack/6.2" - logstash-ref: "https://www.elastic.co/guide/en/logstash/current" - kibana-ref: "https://www.elastic.co/guide/en/kibana/current" - kibana-ref-all: "https://www.elastic.co/guide/en/kibana" - beats-ref-root: "https://www.elastic.co/guide/en/beats" - beats-ref: "https://www.elastic.co/guide/en/beats/libbeat/current" - beats-ref-60: "https://www.elastic.co/guide/en/beats/libbeat/6.0" - beats-ref-63: "https://www.elastic.co/guide/en/beats/libbeat/6.3" - beats-devguide: "https://www.elastic.co/guide/en/beats/devguide/current" - auditbeat-ref: "https://www.elastic.co/guide/en/beats/auditbeat/current" - packetbeat-ref: "https://www.elastic.co/guide/en/beats/packetbeat/current" - metricbeat-ref: "https://www.elastic.co/guide/en/beats/metricbeat/current" - filebeat-ref: "https://www.elastic.co/guide/en/beats/filebeat/current" - functionbeat-ref: "https://www.elastic.co/guide/en/beats/functionbeat/current" - winlogbeat-ref: "https://www.elastic.co/guide/en/beats/winlogbeat/current" - heartbeat-ref: "https://www.elastic.co/guide/en/beats/heartbeat/current" - journalbeat-ref: "https://www.elastic.co/guide/en/beats/journalbeat/current" - ingest-guide: "https://www.elastic.co/guide/en/ingest/current" - fleet-guide: "https://www.elastic.co/guide/en/fleet/current" - apm-guide-ref: "https://www.elastic.co/guide/en/apm/guide/current" - apm-guide-7x: "https://www.elastic.co/guide/en/apm/guide/7.17" - apm-app-ref: "https://www.elastic.co/guide/en/kibana/current" - apm-agents-ref: "https://www.elastic.co/guide/en/apm/agent" - apm-android-ref: "https://www.elastic.co/guide/en/apm/agent/android/current" - apm-py-ref: "https://www.elastic.co/guide/en/apm/agent/python/current" - apm-py-ref-3x: "https://www.elastic.co/guide/en/apm/agent/python/3.x" - apm-node-ref-index: "https://www.elastic.co/guide/en/apm/agent/nodejs" - apm-node-ref: "https://www.elastic.co/guide/en/apm/agent/nodejs/current" - apm-node-ref-1x: "https://www.elastic.co/guide/en/apm/agent/nodejs/1.x" - apm-rum-ref: "https://www.elastic.co/guide/en/apm/agent/rum-js/current" - apm-ruby-ref: "https://www.elastic.co/guide/en/apm/agent/ruby/current" - apm-java-ref: "https://www.elastic.co/guide/en/apm/agent/java/current" - apm-go-ref: "https://www.elastic.co/guide/en/apm/agent/go/current" - apm-dotnet-ref: "https://www.elastic.co/guide/en/apm/agent/dotnet/current" - apm-php-ref: "https://www.elastic.co/guide/en/apm/agent/php/current" - apm-ios-ref: "https://www.elastic.co/guide/en/apm/agent/swift/current" - apm-lambda-ref: "https://www.elastic.co/guide/en/apm/lambda/current" - apm-attacher-ref: "https://www.elastic.co/guide/en/apm/attacher/current" - docker-logging-ref: "https://www.elastic.co/guide/en/beats/loggingplugin/current" - esf-ref: "https://www.elastic.co/guide/en/esf/current" - kinesis-firehose-ref: "https://www.elastic.co/guide/en/kinesis/{{kinesis_version}}" - estc-welcome-current: "https://www.elastic.co/guide/en/starting-with-the-elasticsearch-platform-and-its-solutions/current" - estc-welcome: "https://www.elastic.co/guide/en/starting-with-the-elasticsearch-platform-and-its-solutions/current" - estc-welcome-all: "https://www.elastic.co/guide/en/starting-with-the-elasticsearch-platform-and-its-solutions" - hadoop-ref: "https://www.elastic.co/guide/en/elasticsearch/hadoop/current" - stack-ref: "https://www.elastic.co/guide/en/elastic-stack/current" - stack-ref-67: "https://www.elastic.co/guide/en/elastic-stack/6.7" - stack-ref-68: "https://www.elastic.co/guide/en/elastic-stack/6.8" - stack-ref-70: "https://www.elastic.co/guide/en/elastic-stack/7.0" - stack-ref-80: "https://www.elastic.co/guide/en/elastic-stack/8.0" - stack-ov: "https://www.elastic.co/guide/en/elastic-stack-overview/current" - stack-gs: "https://www.elastic.co/guide/en/elastic-stack-get-started/current" - stack-gs-current: "https://www.elastic.co/guide/en/elastic-stack-get-started/current" - javaclient: "https://www.elastic.co/guide/en/elasticsearch/client/java-api/current" - java-api-client: "https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current" - java-rest: "https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current" - jsclient: "https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current" - jsclient-current: "https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current" - es-ruby-client: "https://www.elastic.co/guide/en/elasticsearch/client/ruby-api/current" - es-dotnet-client: "https://www.elastic.co/guide/en/elasticsearch/client/net-api/current" - es-php-client: "https://www.elastic.co/guide/en/elasticsearch/client/php-api/current" - es-python-client: "https://www.elastic.co/guide/en/elasticsearch/client/python-api/current" - defguide: "https://www.elastic.co/guide/en/elasticsearch/guide/2.x" - painless: "https://www.elastic.co/guide/en/elasticsearch/painless/current" - plugins: "https://www.elastic.co/guide/en/elasticsearch/plugins/current" - plugins-8x: "https://www.elastic.co/guide/en/elasticsearch/plugins/8.1" - plugins-7x: "https://www.elastic.co/guide/en/elasticsearch/plugins/7.17" - plugins-6x: "https://www.elastic.co/guide/en/elasticsearch/plugins/6.8" - glossary: "https://www.elastic.co/guide/en/elastic-stack-glossary/current" - upgrade_guide: "https://www.elastic.co/products/upgrade_guide" - blog-ref: "https://www.elastic.co/blog/" - curator-ref: "https://www.elastic.co/guide/en/elasticsearch/client/curator/current" - curator-ref-current: "https://www.elastic.co/guide/en/elasticsearch/client/curator/current" - metrics-ref: "https://www.elastic.co/guide/en/metrics/current" - metrics-guide: "https://www.elastic.co/guide/en/metrics/guide/current" - logs-ref: "https://www.elastic.co/guide/en/logs/current" - logs-guide: "https://www.elastic.co/guide/en/logs/guide/current" - uptime-guide: "https://www.elastic.co/guide/en/uptime/current" - observability-guide: "https://www.elastic.co/guide/en/observability/current" - observability-guide-all: "https://www.elastic.co/guide/en/observability" - siem-guide: "https://www.elastic.co/guide/en/siem/guide/current" - security-guide: "https://www.elastic.co/guide/en/security/current" - security-guide-all: "https://www.elastic.co/guide/en/security" - endpoint-guide: "https://www.elastic.co/guide/en/endpoint/current" - sql-odbc: "https://www.elastic.co/guide/en/elasticsearch/sql-odbc/current" - ecs-ref: "https://www.elastic.co/guide/en/ecs/current" - ecs-logging-ref: "https://www.elastic.co/guide/en/ecs-logging/overview/current" - ecs-logging-go-logrus-ref: "https://www.elastic.co/guide/en/ecs-logging/go-logrus/current" - ecs-logging-go-zap-ref: "https://www.elastic.co/guide/en/ecs-logging/go-zap/current" - ecs-logging-go-zerolog-ref: "https://www.elastic.co/guide/en/ecs-logging/go-zap/current" - ecs-logging-java-ref: "https://www.elastic.co/guide/en/ecs-logging/java/current" - ecs-logging-dotnet-ref: "https://www.elastic.co/guide/en/ecs-logging/dotnet/current" - ecs-logging-nodejs-ref: "https://www.elastic.co/guide/en/ecs-logging/nodejs/current" - ecs-logging-php-ref: "https://www.elastic.co/guide/en/ecs-logging/php/current" - ecs-logging-python-ref: "https://www.elastic.co/guide/en/ecs-logging/python/current" - ecs-logging-ruby-ref: "https://www.elastic.co/guide/en/ecs-logging/ruby/current" - ml-docs: "https://www.elastic.co/guide/en/machine-learning/current" - eland-docs: "https://www.elastic.co/guide/en/elasticsearch/client/eland/current" - eql-ref: "https://eql.readthedocs.io/en/latest/query-guide" - extendtrial: "https://www.elastic.co/trialextension" - wikipedia: "https://en.wikipedia.org/wiki" - forum: "https://discuss.elastic.co/" - xpack-forum: "https://discuss.elastic.co/c/50-x-pack" - security-forum: "https://discuss.elastic.co/c/x-pack/shield" - watcher-forum: "https://discuss.elastic.co/c/x-pack/watcher" - monitoring-forum: "https://discuss.elastic.co/c/x-pack/marvel" - graph-forum: "https://discuss.elastic.co/c/x-pack/graph" - apm-forum: "https://discuss.elastic.co/c/apm" - enterprise-search-ref: "https://www.elastic.co/guide/en/enterprise-search/current" - app-search-ref: "https://www.elastic.co/guide/en/app-search/current" - workplace-search-ref: "https://www.elastic.co/guide/en/workplace-search/current" - enterprise-search-node-ref: "https://www.elastic.co/guide/en/enterprise-search-clients/enterprise-search-node/current" - enterprise-search-php-ref: "https://www.elastic.co/guide/en/enterprise-search-clients/php/current" - enterprise-search-python-ref: "https://www.elastic.co/guide/en/enterprise-search-clients/python/current" - enterprise-search-ruby-ref: "https://www.elastic.co/guide/en/enterprise-search-clients/ruby/current" - elastic-maps-service: "https://maps.elastic.co" - integrations-docs: "https://docs.elastic.co/en/integrations" - integrations-devguide: "https://www.elastic.co/guide/en/integrations-developer/current" - time-units: "https://www.elastic.co/guide/en/elasticsearch/reference/current/api-conventions.html#time-units" - byte-units: "https://www.elastic.co/guide/en/elasticsearch/reference/current/api-conventions.html#byte-units" - apm-py-ref-v: "https://www.elastic.co/guide/en/apm/agent/python/current" - apm-node-ref-v: "https://www.elastic.co/guide/en/apm/agent/nodejs/current" - apm-rum-ref-v: "https://www.elastic.co/guide/en/apm/agent/rum-js/current" - apm-ruby-ref-v: "https://www.elastic.co/guide/en/apm/agent/ruby/current" - apm-java-ref-v: "https://www.elastic.co/guide/en/apm/agent/java/current" - apm-go-ref-v: "https://www.elastic.co/guide/en/apm/agent/go/current" - apm-ios-ref-v: "https://www.elastic.co/guide/en/apm/agent/swift/current" - apm-dotnet-ref-v: "https://www.elastic.co/guide/en/apm/agent/dotnet/current" - apm-php-ref-v: "https://www.elastic.co/guide/en/apm/agent/php/current" - ecloud: "Elastic Cloud" - esf: "Elastic Serverless Forwarder" - ess: "Elasticsearch Service" - ece: "Elastic Cloud Enterprise" - eck: "Elastic Cloud on Kubernetes" - serverless-full: "Elastic Cloud Serverless" - serverless-short: "Serverless" - es-serverless: "Elasticsearch Serverless" - es3: "Elasticsearch Serverless" - obs-serverless: "Elastic Observability Serverless" - sec-serverless: "Elastic Security Serverless" - serverless-docs: "https://docs.elastic.co/serverless" - cloud: "https://www.elastic.co/guide/en/cloud/current" - ess-utm-params: "?page=docs&placement=docs-body" - ess-baymax: "?page=docs&placement=docs-body" - ess-trial: "https://cloud.elastic.co/registration?page=docs&placement=docs-body" - ess-product: "https://www.elastic.co/cloud/elasticsearch-service?page=docs&placement=docs-body" - ess-console: "https://cloud.elastic.co?page=docs&placement=docs-body" - ess-console-name: "Elasticsearch Service Console" - ess-deployments: "https://cloud.elastic.co/deployments?page=docs&placement=docs-body" - ece-ref: "https://www.elastic.co/guide/en/cloud-enterprise/current" - eck-ref: "https://www.elastic.co/guide/en/cloud-on-k8s/current" - ess-leadin: "You can run Elasticsearch on your own hardware or use our hosted Elasticsearch Service that is available on AWS, GCP, and Azure. https://cloud.elastic.co/registration{ess-utm-params}[Try the Elasticsearch Service for free]." - ess-leadin-short: "Our hosted Elasticsearch Service is available on AWS, GCP, and Azure, and you can https://cloud.elastic.co/registration{ess-utm-params}[try it for free]." - ess-icon: "image:https://doc-icons.s3.us-east-2.amazonaws.com/logo_cloud.svg[link=\"https://cloud.elastic.co/registration{ess-utm-params}\", title=\"Supported on Elasticsearch Service\"]" - ece-icon: "image:https://doc-icons.s3.us-east-2.amazonaws.com/logo_cloud_ece.svg[link=\"https://cloud.elastic.co/registration{ess-utm-params}\", title=\"Supported on Elastic Cloud Enterprise\"]" - cloud-only: "This feature is designed for indirect use by https://cloud.elastic.co/registration{ess-utm-params}[Elasticsearch Service], https://www.elastic.co/guide/en/cloud-enterprise/{ece-version-link}[Elastic Cloud Enterprise], and https://www.elastic.co/guide/en/cloud-on-k8s/current[Elastic Cloud on Kubernetes]. Direct use is not supported." - ess-setting-change: "image:https://doc-icons.s3.us-east-2.amazonaws.com/logo_cloud.svg[link=\"{ess-trial}\", title=\"Supported on {ess}\"] indicates a change to a supported https://www.elastic.co/guide/en/cloud/current/ec-add-user-settings.html[user setting] for Elasticsearch Service." - ess-skip-section: "If you use Elasticsearch Service, skip this section. Elasticsearch Service handles these changes for you." - api-cloud: "https://www.elastic.co/docs/api/doc/cloud" - api-ece: "https://www.elastic.co/docs/api/doc/cloud-enterprise" - api-kibana-serverless: "https://www.elastic.co/docs/api/doc/serverless" - es-feature-flag: "This feature is in development and not yet available for use. This documentation is provided for informational purposes only." - es-ref-dir: "'{{elasticsearch-root}}/docs/reference'" - apm-app: "APM app" - uptime-app: "Uptime app" - synthetics-app: "Synthetics app" - logs-app: "Logs app" - metrics-app: "Metrics app" - infrastructure-app: "Infrastructure app" - siem-app: "SIEM app" - security-app: "Elastic Security app" - ml-app: "Machine Learning" - dev-tools-app: "Dev Tools" - ingest-manager-app: "Ingest Manager" - stack-manage-app: "Stack Management" - stack-monitor-app: "Stack Monitoring" - alerts-ui: "Alerts and Actions" - rules-ui: "Rules" - rac-ui: "Rules and Connectors" - connectors-ui: "Connectors" - connectors-feature: "Actions and Connectors" - stack-rules-feature: "Stack Rules" - user-experience: "User Experience" - ems: "Elastic Maps Service" - ems-init: "EMS" - hosted-ems: "Elastic Maps Server" - ipm-app: "Index Pattern Management" - ingest-pipelines: "ingest pipelines" - ingest-pipelines-app: "Ingest Pipelines" - ingest-pipelines-cap: "Ingest pipelines" - ls-pipelines: "Logstash pipelines" - ls-pipelines-app: "Logstash Pipelines" - maint-windows: "maintenance windows" - maint-windows-app: "Maintenance Windows" - maint-windows-cap: "Maintenance windows" - custom-roles-app: "Custom Roles" - data-source: "data view" - data-sources: "data views" - data-source-caps: "Data View" - data-sources-caps: "Data Views" - data-source-cap: "Data view" - data-sources-cap: "Data views" - project-settings: "Project settings" - manage-app: "Management" - index-manage-app: "Index Management" - data-views-app: "Data Views" - rules-app: "Rules" - saved-objects-app: "Saved Objects" - tags-app: "Tags" - api-keys-app: "API keys" - transforms-app: "Transforms" - connectors-app: "Connectors" - files-app: "Files" - reports-app: "Reports" - maps-app: "Maps" - alerts-app: "Alerts" - crawler: "Enterprise Search web crawler" - ents: "Enterprise Search" - app-search-crawler: "App Search web crawler" - agent: "Elastic Agent" - agents: "Elastic Agents" - fleet: "Fleet" - fleet-server: "Fleet Server" - integrations-server: "Integrations Server" - ingest-manager: "Ingest Manager" - ingest-management: "ingest management" - package-manager: "Elastic Package Manager" - integrations: "Integrations" - package-registry: "Elastic Package Registry" - artifact-registry: "Elastic Artifact Registry" - aws: "AWS" - stack: "Elastic Stack" - xpack: "X-Pack" es: "Elasticsearch" - kib: "Kibana" - esms: "Elastic Stack Monitoring Service" - esms-init: "ESMS" - ls: "Logstash" - beats: "Beats" - auditbeat: "Auditbeat" - filebeat: "Filebeat" - heartbeat: "Heartbeat" - metricbeat: "Metricbeat" - packetbeat: "Packetbeat" - winlogbeat: "Winlogbeat" - functionbeat: "Functionbeat" - journalbeat: "Journalbeat" - es-sql: "Elasticsearch SQL" - esql: "ES|QL" - elastic-agent: "Elastic Agent" - k8s: "Kubernetes" - log-driver-long: "Elastic Logging Plugin for Docker" - security: "X-Pack security" - security-features: "security features" - operator-feature: "operator privileges feature" - es-security-features: "Elasticsearch security features" - stack-security-features: "Elastic Stack security features" - endpoint-sec: "Endpoint Security" - endpoint-cloud-sec: "Endpoint and Cloud Security" - elastic-defend: "Elastic Defend" - elastic-sec: "Elastic Security" - elastic-endpoint: "Elastic Endpoint" - swimlane: "Swimlane" - sn: "ServiceNow" - sn-itsm: "ServiceNow ITSM" - sn-itom: "ServiceNow ITOM" - sn-sir: "ServiceNow SecOps" - jira: "Jira" - ibm-r: "IBM Resilient" - webhook: "Webhook" - webhook-cm: "Webhook - Case Management" - opsgenie: "Opsgenie" - bedrock: "Amazon Bedrock" - gemini: "Google Gemini" - hive: "TheHive" - monitoring: "X-Pack monitoring" - monitor-features: "monitoring features" - stack-monitor-features: "Elastic Stack monitoring features" - watcher: "Watcher" - alert-features: "alerting features" - reporting: "X-Pack reporting" - report-features: "reporting features" - graph: "X-Pack graph" - graph-features: "graph analytics features" - searchprofiler: "Search Profiler" - xpackml: "X-Pack machine learning" - ml: "machine learning" - ml-cap: "Machine learning" - ml-init: "ML" - ml-features: "machine learning features" - stack-ml-features: "Elastic Stack machine learning features" - ccr: "cross-cluster replication" - ccr-cap: "Cross-cluster replication" - ccr-init: "CCR" - ccs: "cross-cluster search" - ccs-cap: "Cross-cluster search" - ccs-init: "CCS" - ilm: "index lifecycle management" - ilm-cap: "Index lifecycle management" - ilm-init: "ILM" - dlm: "data lifecycle management" - dlm-cap: "Data lifecycle management" - dlm-init: "DLM" - search-snap: "searchable snapshot" - search-snaps: "searchable snapshots" - search-snaps-cap: "Searchable snapshots" - slm: "snapshot lifecycle management" - slm-cap: "Snapshot lifecycle management" - slm-init: "SLM" - rollup-features: "data rollup features" - ipm: "index pattern management" - ipm-cap: "Index pattern" - rollup: "rollup" - rollup-cap: "Rollup" - rollups: "rollups" - rollups-cap: "Rollups" - rollup-job: "rollup job" - rollup-jobs: "rollup jobs" - rollup-jobs-cap: "Rollup jobs" - dfeed: "datafeed" - dfeeds: "datafeeds" - dfeed-cap: "Datafeed" - dfeeds-cap: "Datafeeds" - ml-jobs: "machine learning jobs" - ml-jobs-cap: "Machine learning jobs" - anomaly-detect: "anomaly detection" - anomaly-detect-cap: "Anomaly detection" - anomaly-job: "anomaly detection job" - anomaly-jobs: "anomaly detection jobs" - anomaly-jobs-cap: "Anomaly detection jobs" - dataframe: "data frame" - dataframes: "data frames" - dataframe-cap: "Data frame" - dataframes-cap: "Data frames" - watcher-transform: "payload transform" - watcher-transforms: "payload transforms" - watcher-transform-cap: "Payload transform" - watcher-transforms-cap: "Payload transforms" - transform: "transform" - transforms: "transforms" - transform-cap: "Transform" - transforms-cap: "Transforms" - dataframe-transform: "transform" - dataframe-transform-cap: "Transform" - dataframe-transforms: "transforms" - dataframe-transforms-cap: "Transforms" - dfanalytics-cap: "Data frame analytics" - dfanalytics: "data frame analytics" - dataframe-analytics-config: "'{dataframe} analytics config'" - dfanalytics-job: "'{dataframe} analytics job'" - dfanalytics-jobs: "'{dataframe} analytics jobs'" - dfanalytics-jobs-cap: "'{dataframe-cap} analytics jobs'" - cdataframe: "continuous data frame" - cdataframes: "continuous data frames" - cdataframe-cap: "Continuous data frame" - cdataframes-cap: "Continuous data frames" - cdataframe-transform: "continuous transform" - cdataframe-transforms: "continuous transforms" - cdataframe-transforms-cap: "Continuous transforms" - ctransform: "continuous transform" - ctransform-cap: "Continuous transform" - ctransforms: "continuous transforms" - ctransforms-cap: "Continuous transforms" - oldetection: "outlier detection" - oldetection-cap: "Outlier detection" - olscore: "outlier score" - olscores: "outlier scores" - fiscore: "feature influence score" - evaluatedf-api: "evaluate {dataframe} analytics API" - evaluatedf-api-cap: "Evaluate {dataframe} analytics API" - binarysc: "binary soft classification" - binarysc-cap: "Binary soft classification" - regression: "regression" - regression-cap: "Regression" - reganalysis: "regression analysis" - reganalysis-cap: "Regression analysis" - depvar: "dependent variable" - feature-var: "feature variable" - feature-vars: "feature variables" - feature-vars-cap: "Feature variables" - classification: "classification" - classification-cap: "Classification" - classanalysis: "classification analysis" - classanalysis-cap: "Classification analysis" - infer-cap: "Inference" - infer: "inference" - lang-ident-cap: "Language identification" - lang-ident: "language identification" - data-viz: "Data Visualizer" - file-data-viz: "File Data Visualizer" - feat-imp: "feature importance" - feat-imp-cap: "Feature importance" - nlp: "natural language processing" - nlp-cap: "Natural language processing" - apm-agent: "APM agent" - apm-go-agent: "Elastic APM Go agent" - apm-go-agents: "Elastic APM Go agents" - apm-ios-agent: "Elastic APM iOS agent" - apm-ios-agents: "Elastic APM iOS agents" - apm-java-agent: "Elastic APM Java agent" - apm-java-agents: "Elastic APM Java agents" - apm-dotnet-agent: "Elastic APM .NET agent" - apm-dotnet-agents: "Elastic APM .NET agents" - apm-node-agent: "Elastic APM Node.js agent" - apm-node-agents: "Elastic APM Node.js agents" - apm-php-agent: "Elastic APM PHP agent" - apm-php-agents: "Elastic APM PHP agents" - apm-py-agent: "Elastic APM Python agent" - apm-py-agents: "Elastic APM Python agents" - apm-ruby-agent: "Elastic APM Ruby agent" - apm-ruby-agents: "Elastic APM Ruby agents" - apm-rum-agent: "Elastic APM Real User Monitoring (RUM) JavaScript agent" - apm-rum-agents: "Elastic APM RUM JavaScript agents" - apm-lambda-ext: "Elastic APM AWS Lambda extension" - project-monitors: "project monitors" - project-monitors-cap: "Project monitors" - private-location: "Private Location" - private-locations: "Private Locations" - pwd: "YOUR_PASSWORD" - esh: "ES-Hadoop" - default-dist: "default distribution" - oss-dist: "OSS-only distribution" - observability: "Observability" - api-request-title: "Request" - api-prereq-title: "Prerequisites" - api-description-title: "Description" - api-path-parms-title: "Path parameters" - api-query-parms-title: "Query parameters" - api-request-body-title: "Request body" - api-response-codes-title: "Response codes" - api-response-body-title: "Response body" - api-example-title: "Example" - api-examples-title: "Examples" - api-definitions-title: "Properties" - multi-arg: "†footnoteref:[multi-arg,This parameter accepts multiple arguments.]" - multi-arg-ref: "†footnoteref:[multi-arg]" - yes-icon: "image:https://doc-icons.s3.us-east-2.amazonaws.com/icon-yes.png[Yes,20,15]" - no-icon: "image:https://doc-icons.s3.us-east-2.amazonaws.com/icon-no.png[No,20,15]" - es-repo: "https://github.com/elastic/elasticsearch/" - es-issue: "https://github.com/elastic/elasticsearch/issues/" - es-pull: "https://github.com/elastic/elasticsearch/pull/" - es-commit: "https://github.com/elastic/elasticsearch/commit/" - kib-repo: "https://github.com/elastic/kibana/" - kib-issue: "https://github.com/elastic/kibana/issues/" - kibana-issue: "'{kib-repo}issues/'" - kib-pull: "https://github.com/elastic/kibana/pull/" - kibana-pull: "'{kib-repo}pull/'" - kib-commit: "https://github.com/elastic/kibana/commit/" - ml-repo: "https://github.com/elastic/ml-cpp/" - ml-issue: "https://github.com/elastic/ml-cpp/issues/" - ml-pull: "https://github.com/elastic/ml-cpp/pull/" - ml-commit: "https://github.com/elastic/ml-cpp/commit/" - apm-repo: "https://github.com/elastic/apm-server/" - apm-issue: "https://github.com/elastic/apm-server/issues/" - apm-pull: "https://github.com/elastic/apm-server/pull/" - kibana-blob: "https://github.com/elastic/kibana/blob/current/" - apm-get-started-ref: "https://www.elastic.co/guide/en/apm/get-started/current" - apm-server-ref: "https://www.elastic.co/guide/en/apm/server/current" - apm-server-ref-v: "https://www.elastic.co/guide/en/apm/server/current" - apm-server-ref-m: "https://www.elastic.co/guide/en/apm/server/master" - apm-server-ref-62: "https://www.elastic.co/guide/en/apm/server/6.2" - apm-server-ref-64: "https://www.elastic.co/guide/en/apm/server/6.4" - apm-server-ref-70: "https://www.elastic.co/guide/en/apm/server/7.0" - apm-overview-ref-v: "https://www.elastic.co/guide/en/apm/get-started/current" - apm-overview-ref-70: "https://www.elastic.co/guide/en/apm/get-started/7.0" - apm-overview-ref-m: "https://www.elastic.co/guide/en/apm/get-started/master" - infra-guide: "https://www.elastic.co/guide/en/infrastructure/guide/current" - a-data-source: "a data view" - icon-bug: "pass:[]" - icon-checkInCircleFilled: "pass:[]" - icon-warningFilled: "pass:[]" diff --git a/docs/reference/getting-started.md b/docs/reference/getting-started.md index df413e836..5ded3f138 100644 --- a/docs/reference/getting-started.md +++ b/docs/reference/getting-started.md @@ -41,13 +41,13 @@ client = Elasticsearch( Your Elasticsearch endpoint can be found on the **My deployment** page of your deployment: -:::{image} ../images/es-endpoint.jpg +:::{image} images/es-endpoint.jpg :alt: Finding Elasticsearch endpoint ::: You can generate an API key on the **Management** page under Security. -:::{image} ../images/create-api-key.png +:::{image} images/create-api-key.png :alt: Create API key ::: diff --git a/docs/images/create-api-key.png b/docs/reference/images/create-api-key.png similarity index 100% rename from docs/images/create-api-key.png rename to docs/reference/images/create-api-key.png diff --git a/docs/images/es-endpoint.jpg b/docs/reference/images/es-endpoint.jpg similarity index 100% rename from docs/images/es-endpoint.jpg rename to docs/reference/images/es-endpoint.jpg diff --git a/docs/images/otel-waterfall-retry.png b/docs/reference/images/otel-waterfall-retry.png similarity index 100% rename from docs/images/otel-waterfall-retry.png rename to docs/reference/images/otel-waterfall-retry.png diff --git a/docs/images/otel-waterfall-with-http.png b/docs/reference/images/otel-waterfall-with-http.png similarity index 100% rename from docs/images/otel-waterfall-with-http.png rename to docs/reference/images/otel-waterfall-with-http.png diff --git a/docs/images/otel-waterfall-without-http.png b/docs/reference/images/otel-waterfall-without-http.png similarity index 100% rename from docs/images/otel-waterfall-without-http.png rename to docs/reference/images/otel-waterfall-without-http.png diff --git a/docs/reference/opentelemetry.md b/docs/reference/opentelemetry.md index 2b6b1eec2..0521665f3 100644 --- a/docs/reference/opentelemetry.md +++ b/docs/reference/opentelemetry.md @@ -9,21 +9,21 @@ You can use [OpenTelemetry](https://opentelemetry.io/) to monitor the performanc The native instrumentation in the Python client follows the [OpenTelemetry Semantic Conventions for {{es}}](https://opentelemetry.io/docs/specs/semconv/database/elasticsearch/). In particular, the instrumentation in the client covers the logical layer of {{es}} requests. A single span per request is created that is processed by the service through the Python client. The following image shows a trace that records the handling of two different {{es}} requests: an `info` request and a `search` request. -:::{image} ../images/otel-waterfall-without-http.png +:::{image} images/otel-waterfall-without-http.png :alt: Distributed trace with Elasticsearch spans :class: screenshot ::: Usually, OpenTelemetry auto-instrumentation modules come with instrumentation support for HTTP-level communication. In this case, in addition to the logical {{es}} client requests, spans will be captured for the physical HTTP requests emitted by the client. The following image shows a trace with both, {{es}} spans (in blue) and the corresponding HTTP-level spans (in red) after having installed the ``opentelemetry-instrumentation-urllib3`` package: -:::{image} ../images/otel-waterfall-with-http.png +:::{image} images/otel-waterfall-with-http.png :alt: Distributed trace with Elasticsearch spans :class: screenshot ::: Advanced Python client behavior such as nodes round-robin and request retries are revealed through the combination of logical {{es}} spans and the physical HTTP spans. The following example shows a `search` request in a scenario with two nodes: -:::{image} ../images/otel-waterfall-retry.png +:::{image} images/otel-waterfall-retry.png :alt: Distributed trace with Elasticsearch spans :class: screenshot ::: From 5d5b33993bbbd1409e12cdc991eca918e97a6dc4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 4 Apr 2025 17:53:38 +0400 Subject: [PATCH 18/57] Updates navigation titles and descriptions for release notes (#2854) (#2885) (cherry picked from commit c3653b034b510d24caf7b9c4dc14eea3ca5489ad) Co-authored-by: Kaarina Tungseth --- docs/release-notes/breaking-changes.md | 8 ++------ docs/release-notes/deprecations.md | 8 +++----- docs/release-notes/index.md | 2 -- docs/release-notes/known-issues.md | 2 +- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/docs/release-notes/breaking-changes.md b/docs/release-notes/breaking-changes.md index b79d3cb96..1d90c89dc 100644 --- a/docs/release-notes/breaking-changes.md +++ b/docs/release-notes/breaking-changes.md @@ -1,14 +1,11 @@ --- -navigation_title: "Elasticsearch Python Client" +navigation_title: "Breaking changes" --- # Elasticsearch Python Client breaking changes [elasticsearch-python-client-breaking-changes] -Before you upgrade, carefully review the Elasticsearch Python Client breaking changes and take the necessary steps to mitigate any issues. - -To learn how to upgrade, check out . +Breaking changes can impact your Elastic applications, potentially disrupting normal operations. Before you upgrade, carefully review the Elasticsearch Python Client breaking changes and take the necessary steps to mitigate any issues. To learn how to upgrade, check [Upgrade](docs-content://deploy-manage/upgrade.md). % ## Next version [elasticsearch-python-client-nextversion-breaking-changes] -% **Release date:** Month day, year % ::::{dropdown} Title of breaking change % Description of the breaking change. @@ -18,7 +15,6 @@ To learn how to upgrade, check out . % :::: % ## 9.0.0 [elasticsearch-python-client-900-breaking-changes] -% **Release date:** March 25, 2025 % ::::{dropdown} Title of breaking change % Description of the breaking change. diff --git a/docs/release-notes/deprecations.md b/docs/release-notes/deprecations.md index 1b9bfbb74..3f3fa82a6 100644 --- a/docs/release-notes/deprecations.md +++ b/docs/release-notes/deprecations.md @@ -1,14 +1,13 @@ --- -navigation_title: "Elasticsearch Python Client" +navigation_title: "Deprecations" --- # Elasticsearch Python Client deprecations [elasticsearch-python-client-deprecations] -Review the deprecated functionality for your Elasticsearch Python Client version. While deprecations have no immediate impact, we strongly encourage you update your implementation after you upgrade. +Over time, certain Elastic functionality becomes outdated and is replaced or removed. To help with the transition, Elastic deprecates functionality for a period before removal, giving you time to update your applications. -To learn how to upgrade, check out . +Review the deprecated functionality for Elasticsearch Python Client. While deprecations have no immediate impact, we strongly encourage you update your implementation after you upgrade. To learn how to upgrade, check out [Upgrade](docs-content://deploy-manage/upgrade.md). % ## Next version [elasticsearch-python-client-versionnext-deprecations] -% **Release date:** Month day, year % ::::{dropdown} Deprecation title % Description of the deprecation. @@ -18,7 +17,6 @@ To learn how to upgrade, check out . % :::: % ## 9.0.0 [elasticsearch-python-client-900-deprecations] -% **Release date:** March 25, 2025 % ::::{dropdown} Deprecation title % Description of the deprecation. diff --git a/docs/release-notes/index.md b/docs/release-notes/index.md index 156625560..81a35eb10 100644 --- a/docs/release-notes/index.md +++ b/docs/release-notes/index.md @@ -11,7 +11,6 @@ To check for security updates, go to [Security announcements for the Elastic sta % Release notes include only features, enhancements, and fixes. Add breaking changes, deprecations, and known issues to the applicable release notes sections. % ## version.next [felasticsearch-python-client-next-release-notes] -% **Release date:** Month day, year % ### Features and enhancements [elasticsearch-python-client-next-features-enhancements] % * @@ -20,7 +19,6 @@ To check for security updates, go to [Security announcements for the Elastic sta % * ## 9.0.0 [elasticsearch-python-client-900-release-notes] -**Release date:** March 25, 2025 ### Features and enhancements [elasticsearch-python-client-900-features-enhancements] diff --git a/docs/release-notes/known-issues.md b/docs/release-notes/known-issues.md index da93abb27..465030552 100644 --- a/docs/release-notes/known-issues.md +++ b/docs/release-notes/known-issues.md @@ -1,5 +1,5 @@ --- -navigation_title: "Elasticsearch Python Client" +navigation_title: "Known issues" --- From aab90fb84c0c562f75eb555b628cd61c6d2a7fbb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 4 Apr 2025 17:55:37 +0400 Subject: [PATCH 19/57] Remove deprecated transport module (#2841) (#2886) (cherry picked from commit e3e9f9f02078112393d32886962a198121821a2e) Co-authored-by: Quentin Pradet --- elasticsearch/transport.py | 57 ---------------------------- test_elasticsearch/test_transport.py | 18 --------- 2 files changed, 75 deletions(-) delete mode 100644 elasticsearch/transport.py diff --git a/elasticsearch/transport.py b/elasticsearch/transport.py deleted file mode 100644 index 5d84866aa..000000000 --- a/elasticsearch/transport.py +++ /dev/null @@ -1,57 +0,0 @@ -# Licensed to Elasticsearch B.V. under one or more contributor -# license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright -# ownership. Elasticsearch B.V. 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. - -import warnings -from typing import Any, Dict, Optional, Union - -from elastic_transport import AsyncTransport, Transport # noqa: F401 - -# This file exists for backwards compatibility. -warnings.warn( - "Importing from the 'elasticsearch.transport' module is deprecated. " - "Instead import from 'elastic_transport'", - category=DeprecationWarning, - stacklevel=2, -) - - -def get_host_info( - node_info: Dict[str, Any], host: Dict[str, Union[int, str]] -) -> Optional[Dict[str, Union[int, str]]]: - """ - Simple callback that takes the node info from `/_cluster/nodes` and a - parsed connection information and return the connection information. If - `None` is returned this node will be skipped. - Useful for filtering nodes (by proximity for example) or if additional - information needs to be provided for the :class:`~elasticsearch.Connection` - class. By default master only nodes are filtered out since they shouldn't - typically be used for API operations. - :arg node_info: node information from `/_cluster/nodes` - :arg host: connection information (host, port) extracted from the node info - """ - - warnings.warn( - "The 'get_host_info' function is deprecated. Instead " - "use the 'sniff_node_callback' parameter on the client", - category=DeprecationWarning, - stacklevel=2, - ) - - # ignore master only nodes - if node_info.get("roles", []) == ["master"]: - return None - return host diff --git a/test_elasticsearch/test_transport.py b/test_elasticsearch/test_transport.py index 6fb72f98b..4978d52fc 100644 --- a/test_elasticsearch/test_transport.py +++ b/test_elasticsearch/test_transport.py @@ -38,7 +38,6 @@ ElasticsearchWarning, UnsupportedProductError, ) -from elasticsearch.transport import get_host_info class DummyNode(BaseNode): @@ -167,23 +166,6 @@ def mark_live(self, connection): }""" -class TestHostsInfoCallback: - def test_master_only_nodes_are_ignored(self): - nodes = [ - {"roles": ["master"]}, - {"roles": ["master", "data", "ingest"]}, - {"roles": ["data", "ingest"]}, - {"roles": []}, - {}, - ] - chosen = [ - i - for i, node_info in enumerate(nodes) - if get_host_info(node_info, i) is not None - ] - assert [1, 2, 3, 4] == chosen - - class TestTransport: def test_request_timeout_extracted_from_params_and_passed(self): client = Elasticsearch( From 123a6fafe6e27d393f3e50d45adf44e685a2afb8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 4 Apr 2025 17:55:57 +0400 Subject: [PATCH 20/57] add missing mapped pages (#2859) (#2887) (cherry picked from commit e834c3d7f9f08756e57de377ea82b4761e6476fe) Co-authored-by: Colleen McGinnis --- docs/release-notes/index.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/release-notes/index.md b/docs/release-notes/index.md index 81a35eb10..d2dccfd8a 100644 --- a/docs/release-notes/index.md +++ b/docs/release-notes/index.md @@ -1,22 +1,24 @@ --- navigation_title: "Elasticsearch Python Client" +mapped_pages: + - https://www.elastic.co/guide/en/elasticsearch/client/python-api/current/release-notes.html --- # Elasticsearch Python Client release notes [elasticsearch-python-client-release-notes] -Review the changes, fixes, and more in each version of Elasticsearch Python Client. +Review the changes, fixes, and more in each version of Elasticsearch Python Client. To check for security updates, go to [Security announcements for the Elastic stack](https://discuss.elastic.co/c/announcements/security-announcements/31). -% Release notes include only features, enhancements, and fixes. Add breaking changes, deprecations, and known issues to the applicable release notes sections. +% Release notes include only features, enhancements, and fixes. Add breaking changes, deprecations, and known issues to the applicable release notes sections. % ## version.next [felasticsearch-python-client-next-release-notes] % ### Features and enhancements [elasticsearch-python-client-next-features-enhancements] -% * +% * % ### Fixes [elasticsearch-python-client-next-fixes] -% * +% * ## 9.0.0 [elasticsearch-python-client-900-release-notes] From 3b2276708543305a979032b33eceaeb5621a0dbf Mon Sep 17 00:00:00 2001 From: Elastic Machine Date: Tue, 8 Apr 2025 09:56:52 +0200 Subject: [PATCH 21/57] Auto-generated API code (#2891) --- elasticsearch/_async/client/__init__.py | 3 ++- elasticsearch/_async/client/async_search.py | 2 +- elasticsearch/_async/client/fleet.py | 2 +- elasticsearch/_async/client/watcher.py | 5 +++- elasticsearch/_sync/client/__init__.py | 3 ++- elasticsearch/_sync/client/async_search.py | 2 +- elasticsearch/_sync/client/fleet.py | 2 +- elasticsearch/_sync/client/watcher.py | 5 +++- elasticsearch/dsl/types.py | 30 ++++++++++++++++----- 9 files changed, 40 insertions(+), 14 deletions(-) diff --git a/elasticsearch/_async/client/__init__.py b/elasticsearch/_async/client/__init__.py index d05ce7a1a..1e594cac7 100644 --- a/elasticsearch/_async/client/__init__.py +++ b/elasticsearch/_async/client/__init__.py @@ -4745,7 +4745,8 @@ async def search( limit the impact of the search on the cluster in order to limit the number of concurrent shard requests. :param min_score: The minimum `_score` for matching documents. Documents with - a lower `_score` are not included in the search results. + a lower `_score` are not included in search results and results collected + by aggregations. :param pit: Limit the search to a point in time (PIT). If you provide a PIT, you cannot specify an `` in the request path. :param post_filter: Use the `post_filter` parameter to filter search results. diff --git a/elasticsearch/_async/client/async_search.py b/elasticsearch/_async/client/async_search.py index b667d9463..4d1c32974 100644 --- a/elasticsearch/_async/client/async_search.py +++ b/elasticsearch/_async/client/async_search.py @@ -401,7 +401,7 @@ async def submit( limit the impact of the search on the cluster in order to limit the number of concurrent shard requests :param min_score: Minimum _score for matching documents. Documents with a lower - _score are not included in the search results. + _score are not included in search results and results collected by aggregations. :param pit: Limits the search to a point in time (PIT). If you provide a PIT, you cannot specify an in the request path. :param post_filter: diff --git a/elasticsearch/_async/client/fleet.py b/elasticsearch/_async/client/fleet.py index 896ba78b6..9778bb1d5 100644 --- a/elasticsearch/_async/client/fleet.py +++ b/elasticsearch/_async/client/fleet.py @@ -430,7 +430,7 @@ async def search( :param lenient: :param max_concurrent_shard_requests: :param min_score: Minimum _score for matching documents. Documents with a lower - _score are not included in the search results. + _score are not included in search results and results collected by aggregations. :param pit: Limits the search to a point in time (PIT). If you provide a PIT, you cannot specify an in the request path. :param post_filter: diff --git a/elasticsearch/_async/client/watcher.py b/elasticsearch/_async/client/watcher.py index d51776c45..30f69d0e7 100644 --- a/elasticsearch/_async/client/watcher.py +++ b/elasticsearch/_async/client/watcher.py @@ -845,7 +845,10 @@ async def update_settings(

Update Watcher index settings. Update settings for the Watcher internal index (.watches). Only a subset of settings can be modified. - This includes index.auto_expand_replicas and index.number_of_replicas.

+ This includes index.auto_expand_replicas, index.number_of_replicas, index.routing.allocation.exclude.*, + index.routing.allocation.include.* and index.routing.allocation.require.*. + Modification of index.routing.allocation.include._tier_preference is an exception and is not allowed as the + Watcher shards must always be in the data_content tier.

``_ diff --git a/elasticsearch/_sync/client/__init__.py b/elasticsearch/_sync/client/__init__.py index 115a27a9a..7b70b1b13 100644 --- a/elasticsearch/_sync/client/__init__.py +++ b/elasticsearch/_sync/client/__init__.py @@ -4743,7 +4743,8 @@ def search( limit the impact of the search on the cluster in order to limit the number of concurrent shard requests. :param min_score: The minimum `_score` for matching documents. Documents with - a lower `_score` are not included in the search results. + a lower `_score` are not included in search results and results collected + by aggregations. :param pit: Limit the search to a point in time (PIT). If you provide a PIT, you cannot specify an `` in the request path. :param post_filter: Use the `post_filter` parameter to filter search results. diff --git a/elasticsearch/_sync/client/async_search.py b/elasticsearch/_sync/client/async_search.py index 7ee7f4404..3042ae07a 100644 --- a/elasticsearch/_sync/client/async_search.py +++ b/elasticsearch/_sync/client/async_search.py @@ -401,7 +401,7 @@ def submit( limit the impact of the search on the cluster in order to limit the number of concurrent shard requests :param min_score: Minimum _score for matching documents. Documents with a lower - _score are not included in the search results. + _score are not included in search results and results collected by aggregations. :param pit: Limits the search to a point in time (PIT). If you provide a PIT, you cannot specify an in the request path. :param post_filter: diff --git a/elasticsearch/_sync/client/fleet.py b/elasticsearch/_sync/client/fleet.py index adb4665d9..820e661cb 100644 --- a/elasticsearch/_sync/client/fleet.py +++ b/elasticsearch/_sync/client/fleet.py @@ -430,7 +430,7 @@ def search( :param lenient: :param max_concurrent_shard_requests: :param min_score: Minimum _score for matching documents. Documents with a lower - _score are not included in the search results. + _score are not included in search results and results collected by aggregations. :param pit: Limits the search to a point in time (PIT). If you provide a PIT, you cannot specify an in the request path. :param post_filter: diff --git a/elasticsearch/_sync/client/watcher.py b/elasticsearch/_sync/client/watcher.py index a266f54c4..92c70da27 100644 --- a/elasticsearch/_sync/client/watcher.py +++ b/elasticsearch/_sync/client/watcher.py @@ -845,7 +845,10 @@ def update_settings(

Update Watcher index settings. Update settings for the Watcher internal index (.watches). Only a subset of settings can be modified. - This includes index.auto_expand_replicas and index.number_of_replicas.

+ This includes index.auto_expand_replicas, index.number_of_replicas, index.routing.allocation.exclude.*, + index.routing.allocation.include.* and index.routing.allocation.require.*. + Modification of index.routing.allocation.include._tier_preference is an exception and is not allowed as the + Watcher shards must always be in the data_content tier.

``_ diff --git a/elasticsearch/dsl/types.py b/elasticsearch/dsl/types.py index 772e596cd..6dc9f09df 100644 --- a/elasticsearch/dsl/types.py +++ b/elasticsearch/dsl/types.py @@ -324,15 +324,24 @@ class DenseVectorIndexOptions(AttrDict[Any]): `int4_flat` index types. :arg ef_construction: The number of candidates to track while assembling the list of nearest neighbors for each new node. Only - applicable to `hnsw`, `int8_hnsw`, and `int4_hnsw` index types. - Defaults to `100` if omitted. + applicable to `hnsw`, `int8_hnsw`, `bbq_hnsw`, and `int4_hnsw` + index types. Defaults to `100` if omitted. :arg m: The number of neighbors each node will be connected to in the - HNSW graph. Only applicable to `hnsw`, `int8_hnsw`, and - `int4_hnsw` index types. Defaults to `16` if omitted. + HNSW graph. Only applicable to `hnsw`, `int8_hnsw`, `bbq_hnsw`, + and `int4_hnsw` index types. Defaults to `16` if omitted. """ type: Union[ - Literal["flat", "hnsw", "int4_flat", "int4_hnsw", "int8_flat", "int8_hnsw"], + Literal[ + "bbq_flat", + "bbq_hnsw", + "flat", + "hnsw", + "int4_flat", + "int4_hnsw", + "int8_flat", + "int8_hnsw", + ], DefaultType, ] confidence_interval: Union[float, DefaultType] @@ -343,7 +352,16 @@ def __init__( self, *, type: Union[ - Literal["flat", "hnsw", "int4_flat", "int4_hnsw", "int8_flat", "int8_hnsw"], + Literal[ + "bbq_flat", + "bbq_hnsw", + "flat", + "hnsw", + "int4_flat", + "int4_hnsw", + "int8_flat", + "int8_hnsw", + ], DefaultType, ] = DEFAULT, confidence_interval: Union[float, DefaultType] = DEFAULT, From 13f891e0a8b2f4ce4f0766ee74fe58fe36700967 Mon Sep 17 00:00:00 2001 From: Elastic Machine Date: Thu, 10 Apr 2025 13:33:47 +0200 Subject: [PATCH 22/57] Auto-generated API code (#2894) --- elasticsearch/_async/client/inference.py | 138 ----------------------- elasticsearch/_sync/client/inference.py | 138 ----------------------- 2 files changed, 276 deletions(-) diff --git a/elasticsearch/_async/client/inference.py b/elasticsearch/_async/client/inference.py index 31b371948..22f25ab8b 100644 --- a/elasticsearch/_async/client/inference.py +++ b/elasticsearch/_async/client/inference.py @@ -351,67 +351,6 @@ async def inference( path_parts=__path_parts, ) - @_rewrite_parameters( - body_name="chat_completion_request", - ) - async def post_eis_chat_completion( - self, - *, - eis_inference_id: str, - chat_completion_request: t.Optional[t.Mapping[str, t.Any]] = None, - body: t.Optional[t.Mapping[str, t.Any]] = None, - error_trace: t.Optional[bool] = None, - filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, - human: t.Optional[bool] = None, - pretty: t.Optional[bool] = None, - ) -> ObjectApiResponse[t.Any]: - """ - .. raw:: html - -

Perform a chat completion task through the Elastic Inference Service (EIS).

-

Perform a chat completion inference task with the elastic service.

- - - ``_ - - :param eis_inference_id: The unique identifier of the inference endpoint. - :param chat_completion_request: - """ - if eis_inference_id in SKIP_IN_PATH: - raise ValueError("Empty value passed for parameter 'eis_inference_id'") - if chat_completion_request is None and body is None: - raise ValueError( - "Empty value passed for parameters 'chat_completion_request' and 'body', one of them should be set." - ) - elif chat_completion_request is not None and body is not None: - raise ValueError("Cannot set both 'chat_completion_request' and 'body'") - __path_parts: t.Dict[str, str] = {"eis_inference_id": _quote(eis_inference_id)} - __path = ( - f'/_inference/chat_completion/{__path_parts["eis_inference_id"]}/_stream' - ) - __query: t.Dict[str, t.Any] = {} - if error_trace is not None: - __query["error_trace"] = error_trace - if filter_path is not None: - __query["filter_path"] = filter_path - if human is not None: - __query["human"] = human - if pretty is not None: - __query["pretty"] = pretty - __body = ( - chat_completion_request if chat_completion_request is not None else body - ) - __headers = {"accept": "application/json", "content-type": "application/json"} - return await self.perform_request( # type: ignore[return-value] - "POST", - __path, - params=__query, - headers=__headers, - body=__body, - endpoint_id="inference.post_eis_chat_completion", - path_parts=__path_parts, - ) - @_rewrite_parameters( body_name="inference_config", ) @@ -1088,83 +1027,6 @@ async def put_cohere( path_parts=__path_parts, ) - @_rewrite_parameters( - body_fields=("service", "service_settings"), - ) - async def put_eis( - self, - *, - task_type: t.Union[str, t.Literal["chat_completion"]], - eis_inference_id: str, - service: t.Optional[t.Union[str, t.Literal["elastic"]]] = None, - service_settings: t.Optional[t.Mapping[str, t.Any]] = None, - error_trace: t.Optional[bool] = None, - filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, - human: t.Optional[bool] = None, - pretty: t.Optional[bool] = None, - body: t.Optional[t.Dict[str, t.Any]] = None, - ) -> ObjectApiResponse[t.Any]: - """ - .. raw:: html - -

Create an Elastic Inference Service (EIS) inference endpoint.

-

Create an inference endpoint to perform an inference task through the Elastic Inference Service (EIS).

- - - ``_ - - :param task_type: The type of the inference task that the model will perform. - NOTE: The `chat_completion` task type only supports streaming and only through - the _stream API. - :param eis_inference_id: The unique identifier of the inference endpoint. - :param service: The type of service supported for the specified task type. In - this case, `elastic`. - :param service_settings: Settings used to install the inference model. These - settings are specific to the `elastic` service. - """ - if task_type in SKIP_IN_PATH: - raise ValueError("Empty value passed for parameter 'task_type'") - if eis_inference_id in SKIP_IN_PATH: - raise ValueError("Empty value passed for parameter 'eis_inference_id'") - if service is None and body is None: - raise ValueError("Empty value passed for parameter 'service'") - if service_settings is None and body is None: - raise ValueError("Empty value passed for parameter 'service_settings'") - __path_parts: t.Dict[str, str] = { - "task_type": _quote(task_type), - "eis_inference_id": _quote(eis_inference_id), - } - __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["eis_inference_id"]}' - __query: t.Dict[str, t.Any] = {} - __body: t.Dict[str, t.Any] = body if body is not None else {} - if error_trace is not None: - __query["error_trace"] = error_trace - if filter_path is not None: - __query["filter_path"] = filter_path - if human is not None: - __query["human"] = human - if pretty is not None: - __query["pretty"] = pretty - if not __body: - if service is not None: - __body["service"] = service - if service_settings is not None: - __body["service_settings"] = service_settings - if not __body: - __body = None # type: ignore[assignment] - __headers = {"accept": "application/json"} - if __body is not None: - __headers["content-type"] = "application/json" - return await self.perform_request( # type: ignore[return-value] - "PUT", - __path, - params=__query, - headers=__headers, - body=__body, - endpoint_id="inference.put_eis", - path_parts=__path_parts, - ) - @_rewrite_parameters( body_fields=( "service", diff --git a/elasticsearch/_sync/client/inference.py b/elasticsearch/_sync/client/inference.py index aa2ebde2e..04a7c0bc9 100644 --- a/elasticsearch/_sync/client/inference.py +++ b/elasticsearch/_sync/client/inference.py @@ -351,67 +351,6 @@ def inference( path_parts=__path_parts, ) - @_rewrite_parameters( - body_name="chat_completion_request", - ) - def post_eis_chat_completion( - self, - *, - eis_inference_id: str, - chat_completion_request: t.Optional[t.Mapping[str, t.Any]] = None, - body: t.Optional[t.Mapping[str, t.Any]] = None, - error_trace: t.Optional[bool] = None, - filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, - human: t.Optional[bool] = None, - pretty: t.Optional[bool] = None, - ) -> ObjectApiResponse[t.Any]: - """ - .. raw:: html - -

Perform a chat completion task through the Elastic Inference Service (EIS).

-

Perform a chat completion inference task with the elastic service.

- - - ``_ - - :param eis_inference_id: The unique identifier of the inference endpoint. - :param chat_completion_request: - """ - if eis_inference_id in SKIP_IN_PATH: - raise ValueError("Empty value passed for parameter 'eis_inference_id'") - if chat_completion_request is None and body is None: - raise ValueError( - "Empty value passed for parameters 'chat_completion_request' and 'body', one of them should be set." - ) - elif chat_completion_request is not None and body is not None: - raise ValueError("Cannot set both 'chat_completion_request' and 'body'") - __path_parts: t.Dict[str, str] = {"eis_inference_id": _quote(eis_inference_id)} - __path = ( - f'/_inference/chat_completion/{__path_parts["eis_inference_id"]}/_stream' - ) - __query: t.Dict[str, t.Any] = {} - if error_trace is not None: - __query["error_trace"] = error_trace - if filter_path is not None: - __query["filter_path"] = filter_path - if human is not None: - __query["human"] = human - if pretty is not None: - __query["pretty"] = pretty - __body = ( - chat_completion_request if chat_completion_request is not None else body - ) - __headers = {"accept": "application/json", "content-type": "application/json"} - return self.perform_request( # type: ignore[return-value] - "POST", - __path, - params=__query, - headers=__headers, - body=__body, - endpoint_id="inference.post_eis_chat_completion", - path_parts=__path_parts, - ) - @_rewrite_parameters( body_name="inference_config", ) @@ -1088,83 +1027,6 @@ def put_cohere( path_parts=__path_parts, ) - @_rewrite_parameters( - body_fields=("service", "service_settings"), - ) - def put_eis( - self, - *, - task_type: t.Union[str, t.Literal["chat_completion"]], - eis_inference_id: str, - service: t.Optional[t.Union[str, t.Literal["elastic"]]] = None, - service_settings: t.Optional[t.Mapping[str, t.Any]] = None, - error_trace: t.Optional[bool] = None, - filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, - human: t.Optional[bool] = None, - pretty: t.Optional[bool] = None, - body: t.Optional[t.Dict[str, t.Any]] = None, - ) -> ObjectApiResponse[t.Any]: - """ - .. raw:: html - -

Create an Elastic Inference Service (EIS) inference endpoint.

-

Create an inference endpoint to perform an inference task through the Elastic Inference Service (EIS).

- - - ``_ - - :param task_type: The type of the inference task that the model will perform. - NOTE: The `chat_completion` task type only supports streaming and only through - the _stream API. - :param eis_inference_id: The unique identifier of the inference endpoint. - :param service: The type of service supported for the specified task type. In - this case, `elastic`. - :param service_settings: Settings used to install the inference model. These - settings are specific to the `elastic` service. - """ - if task_type in SKIP_IN_PATH: - raise ValueError("Empty value passed for parameter 'task_type'") - if eis_inference_id in SKIP_IN_PATH: - raise ValueError("Empty value passed for parameter 'eis_inference_id'") - if service is None and body is None: - raise ValueError("Empty value passed for parameter 'service'") - if service_settings is None and body is None: - raise ValueError("Empty value passed for parameter 'service_settings'") - __path_parts: t.Dict[str, str] = { - "task_type": _quote(task_type), - "eis_inference_id": _quote(eis_inference_id), - } - __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["eis_inference_id"]}' - __query: t.Dict[str, t.Any] = {} - __body: t.Dict[str, t.Any] = body if body is not None else {} - if error_trace is not None: - __query["error_trace"] = error_trace - if filter_path is not None: - __query["filter_path"] = filter_path - if human is not None: - __query["human"] = human - if pretty is not None: - __query["pretty"] = pretty - if not __body: - if service is not None: - __body["service"] = service - if service_settings is not None: - __body["service_settings"] = service_settings - if not __body: - __body = None # type: ignore[assignment] - __headers = {"accept": "application/json"} - if __body is not None: - __headers["content-type"] = "application/json" - return self.perform_request( # type: ignore[return-value] - "PUT", - __path, - params=__query, - headers=__headers, - body=__body, - endpoint_id="inference.put_eis", - path_parts=__path_parts, - ) - @_rewrite_parameters( body_fields=( "service", From 81ff50cf230bcd89b78ac0cdbc8994d1cc376218 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 10 Apr 2025 14:04:42 +0100 Subject: [PATCH 23/57] use internal aggregation range class for date aggregation ranges (#2897) (#2898) (cherry picked from commit 0d23e6b5dd44b322b65938e504ebb27ca54bcf89) Co-authored-by: Miguel Grinberg --- utils/dsl-generator.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/utils/dsl-generator.py b/utils/dsl-generator.py index 2aa12c53d..f18991dfc 100644 --- a/utils/dsl-generator.py +++ b/utils/dsl-generator.py @@ -345,12 +345,12 @@ def get_python_type(self, schema_type, for_response=False): ]["name"].endswith("Analyzer"): # not expanding analyzers at this time, maybe in the future return "str, Dict[str, Any]", None - elif ( - schema_type["name"]["namespace"] == "_types.aggregations" - and schema_type["name"]["name"].endswith("AggregationRange") - and schema_type["name"]["name"] != "IpRangeAggregationRange" - ): - return '"wrappers.AggregationRange"', None + elif schema_type["name"]["namespace"] == "_types.aggregations": + if ( + schema_type["name"]["name"].endswith("AggregationRange") + or schema_type["name"]["name"] == "DateRangeExpression" + ) and schema_type["name"]["name"] != "IpRangeAggregationRange": + return '"wrappers.AggregationRange"', None # to handle other interfaces we generate a type of the same name # and add the interface to the interfaces.py module From 6705ea64c6f5935fdf81d57f766ee2241df9fad7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 11 Apr 2025 16:56:14 +0400 Subject: [PATCH 24/57] Revert "Add back inference.inference API (#2873)" (#2899) (#2903) This reverts commit eac539dcc301b6062716f1540dc0d1efe888671c. This API will be added back through the specification and isn't deprecated anymore. (cherry picked from commit 0f845eaa78427c37231fdd43e0cb549c2acc72f1) Co-authored-by: Quentin Pradet --- elasticsearch/_async/client/inference.py | 119 +---------------------- elasticsearch/_sync/client/inference.py | 119 +---------------------- elasticsearch/_sync/client/utils.py | 7 -- 3 files changed, 2 insertions(+), 243 deletions(-) diff --git a/elasticsearch/_async/client/inference.py b/elasticsearch/_async/client/inference.py index 22f25ab8b..b0c0a5d33 100644 --- a/elasticsearch/_async/client/inference.py +++ b/elasticsearch/_async/client/inference.py @@ -20,13 +20,7 @@ from elastic_transport import ObjectApiResponse from ._base import NamespacedClient -from .utils import ( - SKIP_IN_PATH, - Stability, - _quote, - _rewrite_parameters, - _stability_warning, -) +from .utils import SKIP_IN_PATH, _quote, _rewrite_parameters class InferenceClient(NamespacedClient): @@ -240,117 +234,6 @@ async def get( path_parts=__path_parts, ) - @_rewrite_parameters( - body_fields=("input", "query", "task_settings"), - ) - @_stability_warning( - Stability.DEPRECATED, - version="8.18.0", - message="inference.inference() is deprecated in favor of provider-specific APIs such as inference.put_elasticsearch() or inference.put_hugging_face()", - ) - async def inference( - self, - *, - inference_id: str, - input: t.Optional[t.Union[str, t.Sequence[str]]] = None, - task_type: t.Optional[ - t.Union[ - str, - t.Literal[ - "chat_completion", - "completion", - "rerank", - "sparse_embedding", - "text_embedding", - ], - ] - ] = None, - error_trace: t.Optional[bool] = None, - filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, - human: t.Optional[bool] = None, - pretty: t.Optional[bool] = None, - query: t.Optional[str] = None, - task_settings: t.Optional[t.Any] = None, - timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, - body: t.Optional[t.Dict[str, t.Any]] = None, - ) -> ObjectApiResponse[t.Any]: - """ - .. raw:: html - -

Perform inference on the service.

-

This API enables you to use machine learning models to perform specific tasks on data that you provide as an input. - It returns a response with the results of the tasks. - The inference endpoint you use can perform one specific task that has been defined when the endpoint was created with the create inference API.

-
-

info - The inference APIs enable you to use certain services, such as built-in machine learning models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Azure, Google AI Studio, Google Vertex AI, Anthropic, Watsonx.ai, or Hugging Face. For built-in models and models uploaded through Eland, the inference APIs offer an alternative way to use and manage trained models. However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.

-
- - - ``_ - - :param inference_id: The unique identifier for the inference endpoint. - :param input: The text on which you want to perform the inference task. It can - be a single string or an array. > info > Inference endpoints for the `completion` - task type currently only support a single string as input. - :param task_type: The type of inference task that the model performs. - :param query: The query input, which is required only for the `rerank` task. - It is not required for other tasks. - :param task_settings: Task settings for the individual inference request. These - settings are specific to the task type you specified and override the task - settings specified when initializing the service. - :param timeout: The amount of time to wait for the inference request to complete. - """ - if inference_id in SKIP_IN_PATH: - raise ValueError("Empty value passed for parameter 'inference_id'") - if input is None and body is None: - raise ValueError("Empty value passed for parameter 'input'") - __path_parts: t.Dict[str, str] - if task_type not in SKIP_IN_PATH and inference_id not in SKIP_IN_PATH: - __path_parts = { - "task_type": _quote(task_type), - "inference_id": _quote(inference_id), - } - __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["inference_id"]}' - elif inference_id not in SKIP_IN_PATH: - __path_parts = {"inference_id": _quote(inference_id)} - __path = f'/_inference/{__path_parts["inference_id"]}' - else: - raise ValueError("Couldn't find a path for the given parameters") - __query: t.Dict[str, t.Any] = {} - __body: t.Dict[str, t.Any] = body if body is not None else {} - if error_trace is not None: - __query["error_trace"] = error_trace - if filter_path is not None: - __query["filter_path"] = filter_path - if human is not None: - __query["human"] = human - if pretty is not None: - __query["pretty"] = pretty - if timeout is not None: - __query["timeout"] = timeout - if not __body: - if input is not None: - __body["input"] = input - if query is not None: - __body["query"] = query - if task_settings is not None: - __body["task_settings"] = task_settings - if not __body: - __body = None # type: ignore[assignment] - __headers = {"accept": "application/json"} - if __body is not None: - __headers["content-type"] = "application/json" - return await self.perform_request( # type: ignore[return-value] - "POST", - __path, - params=__query, - headers=__headers, - body=__body, - endpoint_id="inference.inference", - path_parts=__path_parts, - ) - @_rewrite_parameters( body_name="inference_config", ) diff --git a/elasticsearch/_sync/client/inference.py b/elasticsearch/_sync/client/inference.py index 04a7c0bc9..bcea34db5 100644 --- a/elasticsearch/_sync/client/inference.py +++ b/elasticsearch/_sync/client/inference.py @@ -20,13 +20,7 @@ from elastic_transport import ObjectApiResponse from ._base import NamespacedClient -from .utils import ( - SKIP_IN_PATH, - Stability, - _quote, - _rewrite_parameters, - _stability_warning, -) +from .utils import SKIP_IN_PATH, _quote, _rewrite_parameters class InferenceClient(NamespacedClient): @@ -240,117 +234,6 @@ def get( path_parts=__path_parts, ) - @_rewrite_parameters( - body_fields=("input", "query", "task_settings"), - ) - @_stability_warning( - Stability.DEPRECATED, - version="8.18.0", - message="inference.inference() is deprecated in favor of provider-specific APIs such as inference.put_elasticsearch() or inference.put_hugging_face()", - ) - def inference( - self, - *, - inference_id: str, - input: t.Optional[t.Union[str, t.Sequence[str]]] = None, - task_type: t.Optional[ - t.Union[ - str, - t.Literal[ - "chat_completion", - "completion", - "rerank", - "sparse_embedding", - "text_embedding", - ], - ] - ] = None, - error_trace: t.Optional[bool] = None, - filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, - human: t.Optional[bool] = None, - pretty: t.Optional[bool] = None, - query: t.Optional[str] = None, - task_settings: t.Optional[t.Any] = None, - timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, - body: t.Optional[t.Dict[str, t.Any]] = None, - ) -> ObjectApiResponse[t.Any]: - """ - .. raw:: html - -

Perform inference on the service.

-

This API enables you to use machine learning models to perform specific tasks on data that you provide as an input. - It returns a response with the results of the tasks. - The inference endpoint you use can perform one specific task that has been defined when the endpoint was created with the create inference API.

-
-

info - The inference APIs enable you to use certain services, such as built-in machine learning models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Azure, Google AI Studio, Google Vertex AI, Anthropic, Watsonx.ai, or Hugging Face. For built-in models and models uploaded through Eland, the inference APIs offer an alternative way to use and manage trained models. However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.

-
- - - ``_ - - :param inference_id: The unique identifier for the inference endpoint. - :param input: The text on which you want to perform the inference task. It can - be a single string or an array. > info > Inference endpoints for the `completion` - task type currently only support a single string as input. - :param task_type: The type of inference task that the model performs. - :param query: The query input, which is required only for the `rerank` task. - It is not required for other tasks. - :param task_settings: Task settings for the individual inference request. These - settings are specific to the task type you specified and override the task - settings specified when initializing the service. - :param timeout: The amount of time to wait for the inference request to complete. - """ - if inference_id in SKIP_IN_PATH: - raise ValueError("Empty value passed for parameter 'inference_id'") - if input is None and body is None: - raise ValueError("Empty value passed for parameter 'input'") - __path_parts: t.Dict[str, str] - if task_type not in SKIP_IN_PATH and inference_id not in SKIP_IN_PATH: - __path_parts = { - "task_type": _quote(task_type), - "inference_id": _quote(inference_id), - } - __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["inference_id"]}' - elif inference_id not in SKIP_IN_PATH: - __path_parts = {"inference_id": _quote(inference_id)} - __path = f'/_inference/{__path_parts["inference_id"]}' - else: - raise ValueError("Couldn't find a path for the given parameters") - __query: t.Dict[str, t.Any] = {} - __body: t.Dict[str, t.Any] = body if body is not None else {} - if error_trace is not None: - __query["error_trace"] = error_trace - if filter_path is not None: - __query["filter_path"] = filter_path - if human is not None: - __query["human"] = human - if pretty is not None: - __query["pretty"] = pretty - if timeout is not None: - __query["timeout"] = timeout - if not __body: - if input is not None: - __body["input"] = input - if query is not None: - __body["query"] = query - if task_settings is not None: - __body["task_settings"] = task_settings - if not __body: - __body = None # type: ignore[assignment] - __headers = {"accept": "application/json"} - if __body is not None: - __headers["content-type"] = "application/json" - return self.perform_request( # type: ignore[return-value] - "POST", - __path, - params=__query, - headers=__headers, - body=__body, - endpoint_id="inference.inference", - path_parts=__path_parts, - ) - @_rewrite_parameters( body_name="inference_config", ) diff --git a/elasticsearch/_sync/client/utils.py b/elasticsearch/_sync/client/utils.py index 0708329ba..48ebcb217 100644 --- a/elasticsearch/_sync/client/utils.py +++ b/elasticsearch/_sync/client/utils.py @@ -77,7 +77,6 @@ class Stability(Enum): STABLE = auto() BETA = auto() EXPERIMENTAL = auto() - DEPRECATED = auto() _TYPE_HOSTS = Union[ @@ -443,12 +442,6 @@ def wrapped(*args: Any, **kwargs: Any) -> Any: category=GeneralAvailabilityWarning, stacklevel=warn_stacklevel(), ) - elif stability == Stability.DEPRECATED and message and version: - warnings.warn( - f"In elasticsearch-py {version}, {message}.", - category=DeprecationWarning, - stacklevel=warn_stacklevel(), - ) return api(*args, **kwargs) From 6a074c717a85961c4621070bfdbbc6a2c90b9519 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 11 Apr 2025 16:41:14 +0100 Subject: [PATCH 25/57] Only wipe user content between tests (#2871) (#2908) * Only wipe user content between tests * wipe data streams * do not wipe component templates * remove all references to unused is_xpack variable * remove dead code * remove unused imports (cherry picked from commit b45f50e19302c9bfeaacf374de6e90f1ddd67924) Co-authored-by: Miguel Grinberg --- test_elasticsearch/utils.py | 294 +----------------------------------- 1 file changed, 3 insertions(+), 291 deletions(-) diff --git a/test_elasticsearch/utils.py b/test_elasticsearch/utils.py index 8a13ff62f..021deb76e 100644 --- a/test_elasticsearch/utils.py +++ b/test_elasticsearch/utils.py @@ -22,10 +22,8 @@ from typing import Optional, Tuple from elasticsearch import ( - AuthorizationException, ConnectionError, Elasticsearch, - NotFoundError, ) SOURCE_DIR = Path(__file__).absolute().parent.parent @@ -118,40 +116,15 @@ def wipe_cluster(client): except ImportError: pass - is_xpack = True - if is_xpack: - wipe_rollup_jobs(client) - wait_for_pending_tasks(client, filter="xpack/rollup/job") - wipe_slm_policies(client) - - # Searchable snapshot indices start in 7.8+ - if es_version(client) >= (7, 8): - wipe_searchable_snapshot_indices(client) - wipe_snapshots(client) - if is_xpack: - wipe_data_streams(client) + wipe_data_streams(client) wipe_indices(client) - if is_xpack: - wipe_xpack_templates(client) - else: - client.indices.delete_template(name="*") - client.indices.delete_index_template(name="*") - client.cluster.delete_component_template(name="*") + client.indices.delete_template(name="*") + client.indices.delete_index_template(name="*") wipe_cluster_settings(client) - if is_xpack: - wipe_ilm_policies(client) - wipe_auto_follow_patterns(client) - wipe_tasks(client) - wipe_node_shutdown_metadata(client) - wait_for_pending_datafeeds_and_jobs(client) - wipe_calendars(client) - wipe_filters(client) - wipe_transforms(client) - wait_for_cluster_state_updates_to_finish(client) if close_after_wipe: client.close() @@ -169,16 +142,6 @@ def wipe_cluster_settings(client): client.cluster.put_settings(body=new_settings) -def wipe_rollup_jobs(client): - rollup_jobs = client.rollup.get_jobs(id="_all").get("jobs", ()) - for job in rollup_jobs: - job_id = job["config"]["id"] - client.options(ignore_status=404).rollup.stop_job( - id=job_id, wait_for_completion=True - ) - client.options(ignore_status=404).rollup.delete_job(id=job_id) - - def wipe_snapshots(client): """Deletes all the snapshots and repositories from the cluster""" in_progress_snapshots = [] @@ -223,259 +186,8 @@ def wipe_indices(client): ) -def wipe_searchable_snapshot_indices(client): - cluster_metadata = client.cluster.state( - metric="metadata", - filter_path="metadata.indices.*.settings.index.store.snapshot", - ) - if cluster_metadata: - for index in cluster_metadata["metadata"]["indices"].keys(): - client.indices.delete(index=index) - - -def wipe_xpack_templates(client): - # Delete index templates (including legacy) - templates = [ - x.strip() for x in client.cat.templates(h="name").split("\n") if x.strip() - ] - for template in templates: - if is_xpack_template(template): - continue - try: - client.indices.delete_template(name=template) - except NotFoundError as e: - if f"index_template [{template}] missing" in str(e): - client.indices.delete_index_template(name=template) - - # Delete component templates - templates = client.cluster.get_component_template()["component_templates"] - templates_to_delete = [ - template["name"] - for template in templates - if not is_xpack_template(template["name"]) - ] - if templates_to_delete: - client.cluster.delete_component_template(name=",".join(templates_to_delete)) - - -def wipe_ilm_policies(client): - for policy in client.ilm.get_lifecycle(): - if ( - policy - not in { - "ilm-history-ilm-policy", - "slm-history-ilm-policy", - "watch-history-ilm-policy", - "watch-history-ilm-policy-16", - "ml-size-based-ilm-policy", - "logs", - "metrics", - "synthetics", - "7-days-default", - "30-days-default", - "90-days-default", - "180-days-default", - "365-days-default", - ".fleet-actions-results-ilm-policy", - ".deprecation-indexing-ilm-policy", - ".monitoring-8-ilm-policy", - } - and "-history-ilm-polcy" not in policy - and "-meta-ilm-policy" not in policy - and "-data-ilm-policy" not in policy - and "@lifecycle" not in policy - ): - client.ilm.delete_lifecycle(name=policy) - - -def wipe_slm_policies(client): - policies = client.slm.get_lifecycle() - for policy in policies: - if policy not in {"cloud-snapshot-policy"}: - client.slm.delete_lifecycle(policy_id=policy) - - -def wipe_auto_follow_patterns(client): - for pattern in client.ccr.get_auto_follow_pattern()["patterns"]: - client.ccr.delete_auto_follow_pattern(name=pattern["name"]) - - -def wipe_node_shutdown_metadata(client): - try: - shutdown_status = client.shutdown.get_node() - # If response contains these two keys the feature flag isn't enabled - # on this cluster so skip this step now. - if "_nodes" in shutdown_status and "cluster_name" in shutdown_status: - return - - for shutdown_node in shutdown_status.get("nodes", []): - node_id = shutdown_node["node_id"] - client.shutdown.delete_node(node_id=node_id) - - # Elastic Cloud doesn't allow this so we skip. - except AuthorizationException: - pass - - -def wipe_tasks(client): - tasks = client.tasks.list() - for node_name, node in tasks.get("node", {}).items(): - for task_id in node.get("tasks", ()): - client.tasks.cancel(task_id=task_id, wait_for_completion=True) - - -def wait_for_pending_tasks(client, filter, timeout=30): - end_time = time.time() + timeout - while time.time() < end_time: - tasks = client.cat.tasks(detailed=True).split("\n") - if not any(filter in task for task in tasks): - break - - -def wait_for_pending_datafeeds_and_jobs(client: Elasticsearch, timeout=30): - end_time = time.time() + timeout - while time.time() < end_time: - resp = client.ml.get_datafeeds(datafeed_id="*", allow_no_match=True) - if resp["count"] == 0: - break - for datafeed in resp["datafeeds"]: - client.options(ignore_status=404).ml.delete_datafeed( - datafeed_id=datafeed["datafeed_id"] - ) - - end_time = time.time() + timeout - while time.time() < end_time: - resp = client.ml.get_jobs(job_id="*", allow_no_match=True) - if resp["count"] == 0: - break - for job in resp["jobs"]: - client.options(ignore_status=404).ml.close_job(job_id=job["job_id"]) - client.options(ignore_status=404).ml.delete_job(job_id=job["job_id"]) - - end_time = time.time() + timeout - while time.time() < end_time: - resp = client.ml.get_data_frame_analytics(id="*") - if resp["count"] == 0: - break - for job in resp["data_frame_analytics"]: - client.options(ignore_status=404).ml.stop_data_frame_analytics(id=job["id"]) - client.options(ignore_status=404).ml.delete_data_frame_analytics( - id=job["id"] - ) - - -def wipe_filters(client: Elasticsearch, timeout=30): - end_time = time.time() + timeout - while time.time() < end_time: - resp = client.ml.get_filters(filter_id="*") - if resp["count"] == 0: - break - for filter in resp["filters"]: - client.options(ignore_status=404).ml.delete_filter( - filter_id=filter["filter_id"] - ) - - -def wipe_calendars(client: Elasticsearch, timeout=30): - end_time = time.time() + timeout - while time.time() < end_time: - resp = client.ml.get_calendars(calendar_id="*") - if resp["count"] == 0: - break - for calendar in resp["calendars"]: - client.options(ignore_status=404).ml.delete_calendar( - calendar_id=calendar["calendar_id"] - ) - - -def wipe_transforms(client: Elasticsearch, timeout=30): - end_time = time.time() + timeout - while time.time() < end_time: - resp = client.transform.get_transform(transform_id="*") - if resp["count"] == 0: - break - for trasnform in resp["transforms"]: - client.options(ignore_status=404).transform.stop_transform( - transform_id=trasnform["id"] - ) - client.options(ignore_status=404).transform.delete_transform( - transform_id=trasnform["id"] - ) - - def wait_for_cluster_state_updates_to_finish(client, timeout=30): end_time = time.time() + timeout while time.time() < end_time: if not client.cluster.pending_tasks().get("tasks", ()): break - - -def is_xpack_template(name): - if name.startswith("."): - return True - elif name.startswith("behavioral_analytics-events"): - return True - elif name.startswith("elastic-connectors-"): - return True - elif name.startswith("entities_v1_"): - return True - elif name.endswith("@ilm"): - return True - elif name.endswith("@template"): - return True - - return name in { - "agentless", - "agentless@mappings", - "agentless@settings", - "apm-10d@lifecycle", - "apm-180d@lifecycle", - "apm-390d@lifecycle", - "apm-90d@lifecycle", - "apm@mappings", - "apm@settings", - "data-streams-mappings", - "data-streams@mappings", - "elastic-connectors", - "ecs@dynamic_templates", - "ecs@mappings", - "ilm-history-7", - "kibana-reporting@settings", - "logs", - "logs-apm.error@mappings", - "logs-apm@settings", - "logs-mappings", - "logs@mappings", - "logs-settings", - "logs@settings", - "metrics", - "metrics-apm@mappings", - "metrics-apm.service_destination@mappings", - "metrics-apm.service_summary@mappings", - "metrics-apm.service_transaction@mappings", - "metrics-apm@settings", - "metrics-apm.transaction@mappings", - "metrics-mappings", - "metrics@mappings", - "metrics-settings", - "metrics@settings", - "metrics-tsdb-settings", - "metrics@tsdb-settings", - "search-acl-filter", - "synthetics", - "synthetics-mappings", - "synthetics@mappings", - "synthetics-settings", - "synthetics@settings", - "traces-apm@mappings", - "traces-apm.rum@mappings", - "traces@mappings", - "traces@settings", - # otel - "metrics-otel@mappings", - "semconv-resource-to-ecs@mappings", - "traces-otel@mappings", - "ecs-tsdb@mappings", - "logs-otel@mappings", - "otel@mappings", - } From c97c385abf4ecd0bc9437c1e5075f1ee524ae7e8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 12:05:11 +0400 Subject: [PATCH 26/57] update links pointing to elasticsearch repo (#2904) (#2905) (cherry picked from commit a5a8b52ac063baece542cfc6bd89a931e921417a) Co-authored-by: Charlotte Hoblik <116336412+charlotte-hoblik@users.noreply.github.com> --- docs/reference/esql-pandas.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/esql-pandas.md b/docs/reference/esql-pandas.md index 506ea6579..6c0b1f96a 100644 --- a/docs/reference/esql-pandas.md +++ b/docs/reference/esql-pandas.md @@ -355,7 +355,7 @@ You can now analyze the data with Pandas or you can also continue transforming t ## Analyze the data with Pandas [analyze-data] -In the next example, the [STATS …​ BY](elasticsearch://reference/query-languages/esql/esql-commands.md#esql-stats-by) command is utilized to count how many employees are speaking a given language. The results are sorted with the `languages` column using [SORT](elasticsearch://reference/query-languages/esql/esql-commands.md#esql-sort): +In the next example, the [STATS …​ BY](elasticsearch://reference/query-languages/esql/commands/processing-commands.md#esql-stats-by) command is utilized to count how many employees are speaking a given language. The results are sorted with the `languages` column using [SORT](elasticsearch://reference/query-languages/esql/commands/processing-commands.md#esql-sort): ```python response = client.esql.query( From 7603376c1114d6e6849c8cd46d062061a68a0b14 Mon Sep 17 00:00:00 2001 From: Elastic Machine Date: Mon, 14 Apr 2025 12:03:19 +0200 Subject: [PATCH 27/57] Auto-generated API code (#2910) --- elasticsearch/_async/client/__init__.py | 86 +++++----- elasticsearch/_async/client/async_search.py | 8 +- elasticsearch/_async/client/autoscaling.py | 8 +- elasticsearch/_async/client/cat.py | 52 +++--- elasticsearch/_async/client/ccr.py | 26 +-- elasticsearch/_async/client/cluster.py | 32 ++-- elasticsearch/_async/client/connector.py | 60 +++---- .../_async/client/dangling_indices.py | 6 +- elasticsearch/_async/client/enrich.py | 10 +- elasticsearch/_async/client/eql.py | 8 +- elasticsearch/_async/client/esql.py | 10 +- elasticsearch/_async/client/features.py | 4 +- elasticsearch/_async/client/fleet.py | 18 +- elasticsearch/_async/client/graph.py | 2 +- elasticsearch/_async/client/ilm.py | 22 +-- elasticsearch/_async/client/indices.py | 126 +++++++------- elasticsearch/_async/client/inference.py | 155 +++++++++++++++--- elasticsearch/_async/client/ingest.py | 24 +-- elasticsearch/_async/client/license.py | 14 +- elasticsearch/_async/client/logstash.py | 6 +- elasticsearch/_async/client/migration.py | 6 +- elasticsearch/_async/client/ml.py | 144 ++++++++-------- elasticsearch/_async/client/monitoring.py | 2 +- elasticsearch/_async/client/nodes.py | 16 +- elasticsearch/_async/client/query_rules.py | 16 +- elasticsearch/_async/client/rollup.py | 16 +- .../_async/client/search_application.py | 20 +-- .../_async/client/searchable_snapshots.py | 8 +- elasticsearch/_async/client/security.py | 128 +++++++-------- elasticsearch/_async/client/shutdown.py | 6 +- elasticsearch/_async/client/simulate.py | 2 +- elasticsearch/_async/client/slm.py | 18 +- elasticsearch/_async/client/snapshot.py | 31 ++-- elasticsearch/_async/client/sql.py | 12 +- elasticsearch/_async/client/ssl.py | 2 +- elasticsearch/_async/client/synonyms.py | 14 +- elasticsearch/_async/client/tasks.py | 6 +- elasticsearch/_async/client/text_structure.py | 8 +- elasticsearch/_async/client/transform.py | 22 +-- elasticsearch/_async/client/watcher.py | 26 +-- elasticsearch/_async/client/xpack.py | 4 +- elasticsearch/_sync/client/__init__.py | 86 +++++----- elasticsearch/_sync/client/async_search.py | 8 +- elasticsearch/_sync/client/autoscaling.py | 8 +- elasticsearch/_sync/client/cat.py | 52 +++--- elasticsearch/_sync/client/ccr.py | 26 +-- elasticsearch/_sync/client/cluster.py | 32 ++-- elasticsearch/_sync/client/connector.py | 60 +++---- .../_sync/client/dangling_indices.py | 6 +- elasticsearch/_sync/client/enrich.py | 10 +- elasticsearch/_sync/client/eql.py | 8 +- elasticsearch/_sync/client/esql.py | 10 +- elasticsearch/_sync/client/features.py | 4 +- elasticsearch/_sync/client/fleet.py | 18 +- elasticsearch/_sync/client/graph.py | 2 +- elasticsearch/_sync/client/ilm.py | 22 +-- elasticsearch/_sync/client/indices.py | 126 +++++++------- elasticsearch/_sync/client/inference.py | 155 +++++++++++++++--- elasticsearch/_sync/client/ingest.py | 24 +-- elasticsearch/_sync/client/license.py | 14 +- elasticsearch/_sync/client/logstash.py | 6 +- elasticsearch/_sync/client/migration.py | 6 +- elasticsearch/_sync/client/ml.py | 144 ++++++++-------- elasticsearch/_sync/client/monitoring.py | 2 +- elasticsearch/_sync/client/nodes.py | 16 +- elasticsearch/_sync/client/query_rules.py | 16 +- elasticsearch/_sync/client/rollup.py | 16 +- .../_sync/client/search_application.py | 20 +-- .../_sync/client/searchable_snapshots.py | 8 +- elasticsearch/_sync/client/security.py | 128 +++++++-------- elasticsearch/_sync/client/shutdown.py | 6 +- elasticsearch/_sync/client/simulate.py | 2 +- elasticsearch/_sync/client/slm.py | 18 +- elasticsearch/_sync/client/snapshot.py | 31 ++-- elasticsearch/_sync/client/sql.py | 12 +- elasticsearch/_sync/client/ssl.py | 2 +- elasticsearch/_sync/client/synonyms.py | 14 +- elasticsearch/_sync/client/tasks.py | 6 +- elasticsearch/_sync/client/text_structure.py | 8 +- elasticsearch/_sync/client/transform.py | 22 +-- elasticsearch/_sync/client/watcher.py | 26 +-- elasticsearch/_sync/client/xpack.py | 4 +- elasticsearch/dsl/aggs.py | 5 +- 83 files changed, 1288 insertions(+), 1085 deletions(-) diff --git a/elasticsearch/_async/client/__init__.py b/elasticsearch/_async/client/__init__.py index 1e594cac7..dd69cc9e7 100644 --- a/elasticsearch/_async/client/__init__.py +++ b/elasticsearch/_async/client/__init__.py @@ -639,7 +639,7 @@ async def bulk( The other two shards that make up the index do not participate in the _bulk request at all.

- ``_ + ``_ :param operations: :param index: The name of the data stream, index, or index alias to perform bulk @@ -764,7 +764,7 @@ async def clear_scroll( Clear the search context and results for a scrolling search.

- ``_ + ``_ :param scroll_id: The scroll IDs to clear. To clear all scroll IDs, use `_all`. """ @@ -821,7 +821,7 @@ async def close_point_in_time( However, keeping points in time has a cost; close them as soon as they are no longer required for search requests.

- ``_ + ``_ :param id: The ID of the point-in-time. """ @@ -905,7 +905,7 @@ async def count( This means that replicas increase the scalability of the count.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases to search. It supports wildcards (`*`). To search all data streams and indices, @@ -1107,7 +1107,7 @@ async def create( The _shards section of the API response reveals the number of shard copies on which replication succeeded and failed.

- ``_ + ``_ :param index: The name of the data stream or index to target. If the target doesn't exist and matches the name or wildcard (`*`) pattern of an index template @@ -1274,7 +1274,7 @@ async def delete( It then gets redirected into the primary shard within that ID group and replicated (if needed) to shard replicas within that ID group.

- ``_ + ``_ :param index: The name of the target index. :param id: A unique identifier for the document. @@ -1463,7 +1463,7 @@ async def delete_by_query( The get task status API will continue to list the delete by query task until this task checks that it has been cancelled and terminates itself.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases to search. It supports wildcards (`*`). To search all data streams or indices, @@ -1660,7 +1660,7 @@ async def delete_by_query_rethrottle( Rethrottling that speeds up the query takes effect immediately but rethrotting that slows down the query takes effect after completing the current batch to prevent scroll timeouts.

- ``_ + ``_ :param task_id: The ID for the task. :param requests_per_second: The throttle for this request in sub-requests per @@ -1710,7 +1710,7 @@ async def delete_script( Deletes a stored script or search template.

- ``_ + ``_ :param id: The identifier for the stored script or search template. :param master_timeout: The period to wait for a connection to the master node. @@ -1794,7 +1794,7 @@ async def exists( Elasticsearch cleans up deleted documents in the background as you continue to index more data.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases. It supports wildcards (`*`). @@ -1917,7 +1917,7 @@ async def exists_source(

A document's source is not available if it is disabled in the mapping.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases. It supports wildcards (`*`). @@ -2023,7 +2023,7 @@ async def explain( It computes a score explanation for a query and a specific document.

- ``_ + ``_ :param index: Index names that are used to limit the request. Only a single index name can be provided to this parameter. @@ -2158,7 +2158,7 @@ async def field_caps( For example, a runtime field with a type of keyword is returned the same as any other field that belongs to the keyword family.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (*). To target all data streams @@ -2319,7 +2319,7 @@ async def get( Elasticsearch cleans up deleted documents in the background as you continue to index more data.

- ``_ + ``_ :param index: The name of the index that contains the document. :param id: A unique document identifier. @@ -2426,7 +2426,7 @@ async def get_script( Retrieves a stored script or search template.

- ``_ + ``_ :param id: The identifier for the stored script or search template. :param master_timeout: The period to wait for the master node. If the master @@ -2475,7 +2475,7 @@ async def get_script_context(

Get a list of supported script contexts and their methods.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_script_context" @@ -2514,7 +2514,7 @@ async def get_script_languages(

Get a list of available script types, languages, and contexts.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_script_language" @@ -2579,7 +2579,7 @@ async def get_source( - ``_ + ``_ :param index: The name of the index that contains the document. :param id: A unique document identifier. @@ -2679,7 +2679,7 @@ async def health_report( When setting up automated polling of the API for health status, set verbose to false to disable the more expensive analysis logic.

- ``_ + ``_ :param feature: A feature of the cluster, as returned by the top-level health report API. @@ -2844,7 +2844,7 @@ async def index( - ``_ + ``_ :param index: The name of the data stream or index to target. If the target doesn't exist and matches the name or wildcard (`*`) pattern of an index template @@ -2976,7 +2976,7 @@ async def info( Get basic build, version, and cluster information.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/" @@ -3050,7 +3050,7 @@ async def knn_search( - ``_ + ``_ :param index: A comma-separated list of index names to search; use `_all` or to perform the operation on all indices. @@ -3166,7 +3166,7 @@ async def mget( You can include the stored_fields query parameter in the request URI to specify the defaults to use when there are no per-document instructions.

- ``_ + ``_ :param index: Name of the index to retrieve documents from when `ids` are specified, or when a document in the `docs` array does not specify an index. @@ -3301,7 +3301,7 @@ async def msearch( When sending requests to this endpoint the Content-Type header should be set to application/x-ndjson.

- ``_ + ``_ :param searches: :param index: Comma-separated list of data streams, indices, and index aliases @@ -3448,7 +3448,7 @@ async def msearch_template( - ``_ + ``_ :param search_templates: :param index: A comma-separated list of data streams, indices, and aliases to @@ -3553,7 +3553,7 @@ async def mtermvectors( The mapping used is determined by the specified _index.

- ``_ + ``_ :param index: The name of the index that contains the documents. :param docs: An array of existing or artificial documents. @@ -3694,7 +3694,7 @@ async def open_point_in_time( You can check how many point-in-times (that is, search contexts) are open with the nodes stats API.

- ``_ + ``_ :param index: A comma-separated list of index names to open point in time; use `_all` or empty string to perform the operation on all indices @@ -3792,7 +3792,7 @@ async def put_script( Creates or updates a stored script or search template.

- ``_ + ``_ :param id: The identifier for the stored script or search template. It must be unique within the cluster. @@ -3882,7 +3882,7 @@ async def rank_eval(

Evaluate the quality of ranked search results over a set of typical search queries.

- ``_ + ``_ :param requests: A set of typical search requests, together with their provided ratings. @@ -4114,7 +4114,7 @@ async def reindex( It is not possible to configure SSL in the body of the reindex request.

- ``_ + ``_ :param dest: The destination you are copying to. :param source: The source you are copying from. @@ -4238,7 +4238,7 @@ async def reindex_rethrottle( This behavior prevents scroll timeouts.

- ``_ + ``_ :param task_id: The task identifier, which can be found by using the tasks API. :param requests_per_second: The throttle for this request in sub-requests per @@ -4294,7 +4294,7 @@ async def render_search_template(

Render a search template as a search request body.

- ``_ + ``_ :param id: The ID of the search template to render. If no `source` is specified, this or the `id` request body parameter is required. @@ -4388,7 +4388,7 @@ async def scripts_painless_execute(

Each context requires a script, but additional parameters depend on the context you're using for that script.

- ``_ + ``_ :param context: The context that the script should run in. NOTE: Result ordering in the field contexts is not guaranteed. @@ -4461,7 +4461,7 @@ async def scroll(

IMPORTANT: Results from a scrolling search reflect the state of the index at the time of the initial search request. Subsequent indexing or document changes only affect later search and scroll requests.

- ``_ + ``_ :param scroll_id: The scroll ID of the search. :param rest_total_hits_as_int: If true, the API response’s hit.total property @@ -4666,7 +4666,7 @@ async def search( This situation can occur because the splitting criterion is based on Lucene document IDs, which are not stable across changes to the index.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases to search. It supports wildcards (`*`). To search all data streams and indices, @@ -5414,7 +5414,7 @@ async def search_mvt( Elasticsearch uses the H3 resolution that is closest to the corresponding geotile density.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, or aliases to search :param field: Field containing geospatial data to return @@ -5588,7 +5588,7 @@ async def search_shards(

If the Elasticsearch security features are enabled, you must have the view_index_metadata or manage index privilege for the target data stream, index, or alias.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases to search. It supports wildcards (`*`). To search all data streams and indices, @@ -5699,7 +5699,7 @@ async def search_template(

Run a search with a search template.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases to search. It supports wildcards (`*`). @@ -5842,7 +5842,7 @@ async def terms_enum( - ``_ + ``_ :param index: A comma-separated list of data streams, indices, and index aliases to search. Wildcard (`*`) expressions are supported. To search all data streams @@ -5991,7 +5991,7 @@ async def termvectors( Use routing only to hit a particular shard.

- ``_ + ``_ :param index: The name of the index that contains the document. :param id: A unique identifier for the document. @@ -6162,7 +6162,7 @@ async def update( In addition to _source, you can access the following variables through the ctx map: _index, _type, _id, _version, _routing, and _now (the current timestamp).

- ``_ + ``_ :param index: The name of the target index. By default, the index is created automatically if it doesn't exist. @@ -6400,7 +6400,7 @@ async def update_by_query( This API enables you to only modify the source of matching documents; you cannot move them.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases to search. It supports wildcards (`*`). To search all data streams or indices, @@ -6620,7 +6620,7 @@ async def update_by_query_rethrottle( Rethrottling that speeds up the query takes effect immediately but rethrotting that slows down the query takes effect after completing the current batch to prevent scroll timeouts.

- ``_ + ``_ :param task_id: The ID for the task. :param requests_per_second: The throttle for this request in sub-requests per diff --git a/elasticsearch/_async/client/async_search.py b/elasticsearch/_async/client/async_search.py index 4d1c32974..7b7a76144 100644 --- a/elasticsearch/_async/client/async_search.py +++ b/elasticsearch/_async/client/async_search.py @@ -44,7 +44,7 @@ async def delete( If the Elasticsearch security features are enabled, the deletion of a specific async search is restricted to: the authenticated user that submitted the original search request; users that have the cancel_task cluster privilege.

- ``_ + ``_ :param id: A unique identifier for the async search. """ @@ -94,7 +94,7 @@ async def get( If the Elasticsearch security features are enabled, access to the results of a specific async search is restricted to the user or API key that submitted it.

- ``_ + ``_ :param id: A unique identifier for the async search. :param keep_alive: The length of time that the async search should be available @@ -164,7 +164,7 @@ async def status( - ``_ + ``_ :param id: A unique identifier for the async search. :param keep_alive: The length of time that the async search needs to be available. @@ -345,7 +345,7 @@ async def submit( The maximum allowed size for a stored async search response can be set by changing the search.max_async_search_response_size cluster level setting.

- ``_ + ``_ :param index: A comma-separated list of index names to search; use `_all` or empty string to perform the operation on all indices diff --git a/elasticsearch/_async/client/autoscaling.py b/elasticsearch/_async/client/autoscaling.py index 5b41caa38..f0a3dd1a9 100644 --- a/elasticsearch/_async/client/autoscaling.py +++ b/elasticsearch/_async/client/autoscaling.py @@ -44,7 +44,7 @@ async def delete_autoscaling_policy(

NOTE: This feature is designed for indirect use by Elasticsearch Service, Elastic Cloud Enterprise, and Elastic Cloud on Kubernetes. Direct use is not supported.

- ``_ + ``_ :param name: the name of the autoscaling policy :param master_timeout: Period to wait for a connection to the master node. If @@ -104,7 +104,7 @@ async def get_autoscaling_capacity( Do not use this information to make autoscaling decisions.

- ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails and @@ -151,7 +151,7 @@ async def get_autoscaling_policy(

NOTE: This feature is designed for indirect use by Elasticsearch Service, Elastic Cloud Enterprise, and Elastic Cloud on Kubernetes. Direct use is not supported.

- ``_ + ``_ :param name: the name of the autoscaling policy :param master_timeout: Period to wait for a connection to the master node. If @@ -206,7 +206,7 @@ async def put_autoscaling_policy(

NOTE: This feature is designed for indirect use by Elasticsearch Service, Elastic Cloud Enterprise, and Elastic Cloud on Kubernetes. Direct use is not supported.

- ``_ + ``_ :param name: the name of the autoscaling policy :param policy: diff --git a/elasticsearch/_async/client/cat.py b/elasticsearch/_async/client/cat.py index 299ee83ac..bb289c12d 100644 --- a/elasticsearch/_async/client/cat.py +++ b/elasticsearch/_async/client/cat.py @@ -64,7 +64,7 @@ async def aliases(

IMPORTANT: CAT APIs are only intended for human consumption using the command line or the Kibana console. They are not intended for use by applications. For application consumption, use the aliases API.

- ``_ + ``_ :param name: A comma-separated list of aliases to retrieve. Supports wildcards (`*`). To retrieve all aliases, omit this parameter or use `*` or `_all`. @@ -154,7 +154,7 @@ async def allocation(

IMPORTANT: CAT APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications.

- ``_ + ``_ :param node_id: A comma-separated list of node identifiers or names used to limit the returned information. @@ -243,7 +243,7 @@ async def component_templates( They are not intended for use by applications. For application consumption, use the get component template API.

- ``_ + ``_ :param name: The name of the component template. It accepts wildcard expressions. If it is omitted, all component templates are returned. @@ -327,7 +327,7 @@ async def count( They are not intended for use by applications. For application consumption, use the count API.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases used to limit the request. It supports wildcards (`*`). To target all data streams @@ -405,7 +405,7 @@ async def fielddata( They are not intended for use by applications. For application consumption, use the nodes stats API.

- ``_ + ``_ :param fields: Comma-separated list of fields used to limit returned information. To retrieve all fields, omit this parameter. @@ -491,7 +491,7 @@ async def health( You also can use the API to track the recovery of a large cluster over a longer period of time.

- ``_ + ``_ :param format: Specifies the format to return the columnar data in, can be set to `text`, `json`, `cbor`, `yaml`, or `smile`. @@ -549,7 +549,7 @@ async def help(self) -> TextApiResponse:

Get help for the CAT APIs.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_cat" @@ -616,7 +616,7 @@ async def indices( They are not intended for use by applications. For application consumption, use an index endpoint.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). To target all data streams @@ -714,7 +714,7 @@ async def master(

IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the nodes info API.

- ``_ + ``_ :param format: Specifies the format to return the columnar data in, can be set to `text`, `json`, `cbor`, `yaml`, or `smile`. @@ -892,7 +892,7 @@ async def ml_data_frame_analytics( application consumption, use the get data frame analytics jobs statistics API.

- ``_ + ``_ :param id: The ID of the data frame analytics to fetch :param allow_no_match: Whether to ignore if a wildcard expression matches no @@ -1060,7 +1060,7 @@ async def ml_datafeeds( application consumption, use the get datafeed statistics API.

- ``_ + ``_ :param datafeed_id: A numerical character string that uniquely identifies the datafeed. @@ -1426,7 +1426,7 @@ async def ml_jobs( application consumption, use the get anomaly detection job statistics API.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param allow_no_match: Specifies what to do when the request: * Contains wildcard @@ -1611,7 +1611,7 @@ async def ml_trained_models( application consumption, use the get trained models statistics API.

- ``_ + ``_ :param model_id: A unique identifier for the trained model. :param allow_no_match: Specifies what to do when the request: contains wildcard @@ -1704,7 +1704,7 @@ async def nodeattrs( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the nodes info API.

- ``_ + ``_ :param format: Specifies the format to return the columnar data in, can be set to `text`, `json`, `cbor`, `yaml`, or `smile`. @@ -1787,7 +1787,7 @@ async def nodes( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the nodes info API.

- ``_ + ``_ :param bytes: The unit used to display byte values. :param format: Specifies the format to return the columnar data in, can be set @@ -1874,7 +1874,7 @@ async def pending_tasks( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the pending cluster tasks API.

- ``_ + ``_ :param format: Specifies the format to return the columnar data in, can be set to `text`, `json`, `cbor`, `yaml`, or `smile`. @@ -1954,7 +1954,7 @@ async def plugins( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the nodes info API.

- ``_ + ``_ :param format: Specifies the format to return the columnar data in, can be set to `text`, `json`, `cbor`, `yaml`, or `smile`. @@ -2042,7 +2042,7 @@ async def recovery( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the index recovery API.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). To target all data streams @@ -2130,7 +2130,7 @@ async def repositories( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the get snapshot repository API.

- ``_ + ``_ :param format: Specifies the format to return the columnar data in, can be set to `text`, `json`, `cbor`, `yaml`, or `smile`. @@ -2211,7 +2211,7 @@ async def segments( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the index segments API.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). To target all data streams @@ -2305,7 +2305,7 @@ async def shards( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). To target all data streams @@ -2394,7 +2394,7 @@ async def snapshots( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the get snapshot API.

- ``_ + ``_ :param repository: A comma-separated list of snapshot repositories used to limit the request. Accepts wildcard expressions. `_all` returns all repositories. @@ -2487,7 +2487,7 @@ async def tasks( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the task management API.

- ``_ + ``_ :param actions: The task action names, which are used to limit the response. :param detailed: If `true`, the response includes detailed information about @@ -2581,7 +2581,7 @@ async def templates( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the get index template API.

- ``_ + ``_ :param name: The name of the template to return. Accepts wildcard expressions. If omitted, all templates are returned. @@ -2669,7 +2669,7 @@ async def thread_pool( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the nodes info API.

- ``_ + ``_ :param thread_pool_patterns: A comma-separated list of thread pool names used to limit the request. Accepts wildcard expressions. @@ -2926,7 +2926,7 @@ async def transforms( application consumption, use the get transform statistics API.

- ``_ + ``_ :param transform_id: A transform identifier or a wildcard expression. If you do not specify one of these options, the API returns information for all diff --git a/elasticsearch/_async/client/ccr.py b/elasticsearch/_async/client/ccr.py index a98428ffb..6617f2403 100644 --- a/elasticsearch/_async/client/ccr.py +++ b/elasticsearch/_async/client/ccr.py @@ -43,7 +43,7 @@ async def delete_auto_follow_pattern(

Delete a collection of cross-cluster replication auto-follow patterns.

- ``_ + ``_ :param name: The auto-follow pattern collection to delete. :param master_timeout: The period to wait for a connection to the master node. @@ -130,7 +130,7 @@ async def follow( When the API returns, the follower index exists and cross-cluster replication starts replicating operations from the leader index to the follower index.

- ``_ + ``_ :param index: The name of the follower index. :param leader_index: The name of the index in the leader cluster to follow. @@ -259,7 +259,7 @@ async def follow_info( For example, the results include follower index names, leader index names, replication options, and whether the follower indices are active or paused.

- ``_ + ``_ :param index: A comma-delimited list of follower index patterns. :param master_timeout: The period to wait for a connection to the master node. @@ -311,7 +311,7 @@ async def follow_stats( The API returns shard-level stats about the "following tasks" associated with each shard for the specified indices.

- ``_ + ``_ :param index: A comma-delimited list of index patterns. :param timeout: The period to wait for a response. If no response is received @@ -380,7 +380,7 @@ async def forget_follower( The only purpose of this API is to handle the case of failure to remove the following retention leases after the unfollow API is invoked.

- ``_ + ``_ :param index: the name of the leader index for which specified follower retention leases should be removed @@ -445,7 +445,7 @@ async def get_auto_follow_pattern(

Get cross-cluster replication auto-follow patterns.

- ``_ + ``_ :param name: The auto-follow pattern collection that you want to retrieve. If you do not specify a name, the API returns information for all collections. @@ -505,7 +505,7 @@ async def pause_auto_follow_pattern( Remote indices that were created while the pattern was paused will also be followed, unless they have been deleted or closed in the interim.

- ``_ + ``_ :param name: The name of the auto-follow pattern to pause. :param master_timeout: The period to wait for a connection to the master node. @@ -559,7 +559,7 @@ async def pause_follow( You can pause and resume a follower index to change the configuration of the following task.

- ``_ + ``_ :param index: The name of the follower index. :param master_timeout: The period to wait for a connection to the master node. @@ -648,7 +648,7 @@ async def put_auto_follow_pattern( NOTE: Follower indices that were configured automatically before updating an auto-follow pattern will remain unchanged even if they do not match against the new patterns.

- ``_ + ``_ :param name: The name of the collection of auto-follow patterns. :param remote_cluster: The remote cluster containing the leader indices to match @@ -782,7 +782,7 @@ async def resume_auto_follow_pattern( Remote indices created while the pattern was paused will also be followed unless they have been deleted or closed in the interim.

- ``_ + ``_ :param name: The name of the auto-follow pattern to resume. :param master_timeout: The period to wait for a connection to the master node. @@ -860,7 +860,7 @@ async def resume_follow( When this API returns, the follower index will resume fetching operations from the leader index.

- ``_ + ``_ :param index: The name of the follow index to resume following. :param master_timeout: Period to wait for a connection to the master node. @@ -951,7 +951,7 @@ async def stats(

This API returns stats about auto-following and the same shard-level stats as the get follower stats API.

- ``_ + ``_ :param master_timeout: The period to wait for a connection to the master node. If the master node is not available before the timeout expires, the request @@ -1009,7 +1009,7 @@ async def unfollow( - ``_ + ``_ :param index: The name of the follower index. :param master_timeout: The period to wait for a connection to the master node. diff --git a/elasticsearch/_async/client/cluster.py b/elasticsearch/_async/client/cluster.py index 074bdc0e8..14a340a02 100644 --- a/elasticsearch/_async/client/cluster.py +++ b/elasticsearch/_async/client/cluster.py @@ -54,7 +54,7 @@ async def allocation_explain( This API can be very useful when attempting to diagnose why a shard is unassigned or why a shard continues to remain on its current node when you might expect otherwise.

- ``_ + ``_ :param current_node: Specifies the node ID or the name of the node to only explain a shard that is currently located on the specified node. @@ -130,7 +130,7 @@ async def delete_component_template( Component templates are building blocks for constructing index templates that specify index mappings, settings, and aliases.

- ``_ + ``_ :param name: Comma-separated list or wildcard expression of component template names used to limit the request. @@ -185,7 +185,7 @@ async def delete_voting_config_exclusions( Remove master-eligible nodes from the voting configuration exclusion list.

- ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. :param wait_for_removal: Specifies whether to wait for all excluded nodes to @@ -239,7 +239,7 @@ async def exists_component_template( Returns information about whether a particular component template exists.

- ``_ + ``_ :param name: Comma-separated list of component template names used to limit the request. Wildcard (*) expressions are supported. @@ -298,7 +298,7 @@ async def get_component_template( Get information about component templates.

- ``_ + ``_ :param name: Comma-separated list of component template names used to limit the request. Wildcard (`*`) expressions are supported. @@ -365,7 +365,7 @@ async def get_settings( By default, it returns only settings that have been explicitly defined.

- ``_ + ``_ :param flat_settings: If `true`, returns settings in flat format. :param include_defaults: If `true`, returns default cluster settings from the @@ -457,7 +457,7 @@ async def health( The cluster status is controlled by the worst index status.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and index aliases used to limit the request. Wildcard expressions (`*`) are supported. To target @@ -565,7 +565,7 @@ async def info( Returns basic information about the cluster.

- ``_ + ``_ :param target: Limits the information returned to the specific target. Supports a comma-separated list, such as http,ingest. @@ -614,7 +614,7 @@ async def pending_tasks( However, if a user-initiated task such as a create index command causes a cluster state update, the activity of this task might be reported by both task api and pending cluster tasks API.

- ``_ + ``_ :param local: If `true`, the request retrieves information from the local node only. If `false`, information is retrieved from the master node. @@ -680,7 +680,7 @@ async def post_voting_config_exclusions( They are not required when removing master-ineligible nodes or when removing fewer than half of the master-eligible nodes.

- ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. :param node_ids: A comma-separated list of the persistent ids of the nodes to @@ -761,7 +761,7 @@ async def put_component_template( To be applied, a component template must be included in an index template's composed_of list.

- ``_ + ``_ :param name: Name of the component template to create. Elasticsearch includes the following built-in component templates: `logs-mappings`; `logs-settings`; @@ -866,7 +866,7 @@ async def put_settings( If a cluster becomes unstable, transient settings can clear unexpectedly, resulting in a potentially undesired cluster configuration.

- ``_ + ``_ :param flat_settings: Return settings in flat format (default: false) :param master_timeout: Explicit operation timeout for connection to master node @@ -932,7 +932,7 @@ async def remote_info( - ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_remote/info" @@ -989,7 +989,7 @@ async def reroute(

Once the problem has been corrected, allocation can be manually retried by calling the reroute API with the ?retry_failed URI query parameter, which will attempt a single retry round for these shards.

- ``_ + ``_ :param commands: Defines the commands to perform. :param dry_run: If true, then the request simulates the operation. It will calculate @@ -1094,7 +1094,7 @@ async def state( Instead, obtain the information you require using other more stable cluster APIs.

- ``_ + ``_ :param metric: Limit the information returned to the specified metrics :param index: A comma-separated list of index names; use `_all` or empty string @@ -1182,7 +1182,7 @@ async def stats( Get basic index metrics (shard numbers, store size, memory usage) and information about the current nodes that form the cluster (number, roles, os, jvm versions, memory usage, cpu and installed plugins).

- ``_ + ``_ :param node_id: Comma-separated list of node filters used to limit returned information. Defaults to all nodes in the cluster. diff --git a/elasticsearch/_async/client/connector.py b/elasticsearch/_async/client/connector.py index 3a55163bb..31fecb03c 100644 --- a/elasticsearch/_async/client/connector.py +++ b/elasticsearch/_async/client/connector.py @@ -49,7 +49,7 @@ async def check_in(

Update the last_seen field in the connector and set it to the current timestamp.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be checked in """ @@ -99,7 +99,7 @@ async def delete( These need to be removed manually.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be deleted :param delete_sync_jobs: A flag indicating if associated sync jobs should be @@ -152,7 +152,7 @@ async def get(

Get the details about a connector.

- ``_ + ``_ :param connector_id: The unique identifier of the connector :param include_deleted: A flag to indicate if the desired connector should be @@ -256,7 +256,7 @@ async def last_sync( This action is used for analytics and monitoring.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param last_access_control_sync_error: @@ -356,7 +356,7 @@ async def list(

Get information about all connectors.

- ``_ + ``_ :param connector_name: A comma-separated list of connector names to fetch connector documents for @@ -441,7 +441,7 @@ async def post( Self-managed connectors (Connector clients) are self-managed on your infrastructure.

- ``_ + ``_ :param description: :param index_name: @@ -523,7 +523,7 @@ async def put(

Create or update a connector.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be created or updated. ID is auto-generated if not provided. @@ -598,7 +598,7 @@ async def sync_job_cancel( The connector service is then responsible for setting the status of connector sync jobs to cancelled.

- ``_ + ``_ :param connector_sync_job_id: The unique identifier of the connector sync job """ @@ -649,7 +649,7 @@ async def sync_job_check_in( This service runs automatically on Elastic Cloud for Elastic managed connectors.

- ``_ + ``_ :param connector_sync_job_id: The unique identifier of the connector sync job to be checked in. @@ -709,7 +709,7 @@ async def sync_job_claim( This service runs automatically on Elastic Cloud for Elastic managed connectors.

- ``_ + ``_ :param connector_sync_job_id: The unique identifier of the connector sync job. :param worker_hostname: The host name of the current system that will run the @@ -771,7 +771,7 @@ async def sync_job_delete( This is a destructive action that is not recoverable.

- ``_ + ``_ :param connector_sync_job_id: The unique identifier of the connector sync job to be deleted @@ -825,7 +825,7 @@ async def sync_job_error( This service runs automatically on Elastic Cloud for Elastic managed connectors.

- ``_ + ``_ :param connector_sync_job_id: The unique identifier for the connector sync job. :param error: The error for the connector sync job error field. @@ -879,7 +879,7 @@ async def sync_job_get(

Get a connector sync job.

- ``_ + ``_ :param connector_sync_job_id: The unique identifier of the connector sync job """ @@ -952,7 +952,7 @@ async def sync_job_list(

Get information about all stored connector sync jobs listed by their creation date in ascending order.

- ``_ + ``_ :param connector_id: A connector id to fetch connector sync jobs for :param from_: Starting offset (default: 0) @@ -1018,7 +1018,7 @@ async def sync_job_post(

Create a connector sync job document in the internal index and initialize its counters and timestamps with default values.

- ``_ + ``_ :param id: The id of the associated connector :param job_type: @@ -1094,7 +1094,7 @@ async def sync_job_update_stats( This service runs automatically on Elastic Cloud for Elastic managed connectors.

- ``_ + ``_ :param connector_sync_job_id: The unique identifier of the connector sync job. :param deleted_document_count: The number of documents the sync job deleted. @@ -1177,7 +1177,7 @@ async def update_active_filtering(

Activates the valid draft filtering for a connector.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated """ @@ -1230,7 +1230,7 @@ async def update_api_key_id( Self-managed connectors (connector clients) do not use this field.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param api_key_id: @@ -1289,7 +1289,7 @@ async def update_configuration(

Update the configuration field in the connector document.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param configuration: @@ -1349,7 +1349,7 @@ async def update_error( Otherwise, if the error is reset to null, the connector status is updated to connected.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param error: @@ -1417,7 +1417,7 @@ async def update_features( This service runs automatically on Elastic Cloud for Elastic managed connectors.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated. :param features: @@ -1478,7 +1478,7 @@ async def update_filtering( The filtering property is used to configure sync rules (both basic and advanced) for a connector.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param advanced_snippet: @@ -1539,7 +1539,7 @@ async def update_filtering_validation(

Update the draft filtering validation info for a connector.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param validation: @@ -1596,7 +1596,7 @@ async def update_index_name(

Update the index_name field of a connector, specifying the index where the data ingested by the connector is stored.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param index_name: @@ -1653,7 +1653,7 @@ async def update_name(

Update the connector name and description.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param description: @@ -1710,7 +1710,7 @@ async def update_native(

Update the connector is_native flag.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param is_native: @@ -1767,7 +1767,7 @@ async def update_pipeline(

When you create a new connector, the configuration of an ingest pipeline is populated with default settings.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param pipeline: @@ -1823,7 +1823,7 @@ async def update_scheduling(

Update the connector scheduling.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param scheduling: @@ -1879,7 +1879,7 @@ async def update_service_type(

Update the connector service type.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param service_type: @@ -1942,7 +1942,7 @@ async def update_status(

Update the connector status.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param status: diff --git a/elasticsearch/_async/client/dangling_indices.py b/elasticsearch/_async/client/dangling_indices.py index 57289c91a..b681b95ea 100644 --- a/elasticsearch/_async/client/dangling_indices.py +++ b/elasticsearch/_async/client/dangling_indices.py @@ -46,7 +46,7 @@ async def delete_dangling_index( For example, this can happen if you delete more than cluster.indices.tombstones.size indices while an Elasticsearch node is offline.

- ``_ + ``_ :param index_uuid: The UUID of the index to delete. Use the get dangling indices API to find the UUID. @@ -107,7 +107,7 @@ async def import_dangling_index( For example, this can happen if you delete more than cluster.indices.tombstones.size indices while an Elasticsearch node is offline.

- ``_ + ``_ :param index_uuid: The UUID of the index to import. Use the get dangling indices API to locate the UUID. @@ -168,7 +168,7 @@ async def list_dangling_indices(

Use this API to list dangling indices, which you can then import or delete.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_dangling" diff --git a/elasticsearch/_async/client/enrich.py b/elasticsearch/_async/client/enrich.py index ae37254ca..47a33ed28 100644 --- a/elasticsearch/_async/client/enrich.py +++ b/elasticsearch/_async/client/enrich.py @@ -43,7 +43,7 @@ async def delete_policy( Deletes an existing enrich policy and its enrich index.

- ``_ + ``_ :param name: Enrich policy to delete. :param master_timeout: Period to wait for a connection to the master node. @@ -92,7 +92,7 @@ async def execute_policy( Create the enrich index for an existing enrich policy.

- ``_ + ``_ :param name: Enrich policy to execute. :param master_timeout: Period to wait for a connection to the master node. @@ -144,7 +144,7 @@ async def get_policy( Returns information about an enrich policy.

- ``_ + ``_ :param name: Comma-separated list of enrich policy names used to limit the request. To return information for all enrich policies, omit this parameter. @@ -202,7 +202,7 @@ async def put_policy( Creates an enrich policy.

- ``_ + ``_ :param name: Name of the enrich policy to create or update. :param geo_match: Matches enrich data to incoming documents based on a `geo_shape` @@ -263,7 +263,7 @@ async def stats( Returns enrich coordinator statistics and information about enrich policies that are currently executing.

- ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. """ diff --git a/elasticsearch/_async/client/eql.py b/elasticsearch/_async/client/eql.py index 524604f17..61c282c1b 100644 --- a/elasticsearch/_async/client/eql.py +++ b/elasticsearch/_async/client/eql.py @@ -43,7 +43,7 @@ async def delete( The API also deletes results for the search.

- ``_ + ``_ :param id: Identifier for the search to delete. A search ID is provided in the EQL search API's response for an async search. A search ID is also provided @@ -93,7 +93,7 @@ async def get( Get the current status and available results for an async EQL search or a stored synchronous EQL search.

- ``_ + ``_ :param id: Identifier for the search. :param keep_alive: Period for which the search and its results are stored on @@ -147,7 +147,7 @@ async def get_status( Get the current status for an async EQL search or a stored synchronous EQL search without returning results.

- ``_ + ``_ :param id: Identifier for the search. """ @@ -246,7 +246,7 @@ async def search( EQL assumes each document in a data stream or index corresponds to an event.

- ``_ + ``_ :param index: The name of the index to scope the operation :param query: EQL query you wish to run. diff --git a/elasticsearch/_async/client/esql.py b/elasticsearch/_async/client/esql.py index d1a83e00b..d84c1e438 100644 --- a/elasticsearch/_async/client/esql.py +++ b/elasticsearch/_async/client/esql.py @@ -81,7 +81,7 @@ async def async_query(

The API accepts the same parameters and request body as the synchronous query API, along with additional async related properties.

- ``_ + ``_ :param query: The ES|QL query API accepts an ES|QL query string in the query parameter, runs it, and returns the results. @@ -204,7 +204,7 @@ async def async_query_delete( - ``_ + ``_ :param id: The unique identifier of the query. A query ID is provided in the ES|QL async query API response for a query that does not complete in the @@ -257,7 +257,7 @@ async def async_query_get( If the Elasticsearch security features are enabled, only the user who first submitted the ES|QL query can retrieve the results using this API.

- ``_ + ``_ :param id: The unique identifier of the query. A query ID is provided in the ES|QL async query API response for a query that does not complete in the @@ -324,7 +324,7 @@ async def async_query_stop( If the Elasticsearch security features are enabled, only the user who first submitted the ES|QL query can stop it.

- ``_ + ``_ :param id: The unique identifier of the query. A query ID is provided in the ES|QL async query API response for a query that does not complete in the @@ -409,7 +409,7 @@ async def query( Get search results for an ES|QL (Elasticsearch query language) query.

- ``_ + ``_ :param query: The ES|QL query API accepts an ES|QL query string in the query parameter, runs it, and returns the results. diff --git a/elasticsearch/_async/client/features.py b/elasticsearch/_async/client/features.py index 2fb86fe23..7e139ed48 100644 --- a/elasticsearch/_async/client/features.py +++ b/elasticsearch/_async/client/features.py @@ -48,7 +48,7 @@ async def get_features( In order for a feature state to be listed in this API and recognized as a valid feature state by the create snapshot API, the plugin that defines that feature must be installed on the master node.

- ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. """ @@ -102,7 +102,7 @@ async def reset_features(

IMPORTANT: The features installed on the node you submit this request to are the features that will be reset. Run on the master node if you have any doubts about which plugins are installed on individual nodes.

- ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. """ diff --git a/elasticsearch/_async/client/fleet.py b/elasticsearch/_async/client/fleet.py index 9778bb1d5..66a04d0bf 100644 --- a/elasticsearch/_async/client/fleet.py +++ b/elasticsearch/_async/client/fleet.py @@ -53,7 +53,7 @@ async def global_checkpoints( This API is designed for internal use by the Fleet server project.

- ``_ + ``_ :param index: A single index or index alias that resolves to a single index. :param checkpoints: A comma separated list of previous global checkpoints. When @@ -144,7 +144,7 @@ async def msearch( However, similar to the Fleet search API, it supports the wait_for_checkpoints parameter.

- ``_ + ``_ :param searches: :param index: A single target to search. If the target is an index alias, it @@ -155,9 +155,9 @@ async def msearch( example, a request targeting foo*,bar* returns an error if an index starts with foo but no index starts with bar. :param allow_partial_search_results: If true, returns partial results if there - are shard request timeouts or [shard failures](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-replication.html#shard-failures). - If false, returns an error with no partial results. Defaults to the configured - cluster setting `search.default_allow_partial_results` which is true by default. + are shard request timeouts or shard failures. If false, returns an error + with no partial results. Defaults to the configured cluster setting `search.default_allow_partial_results`, + which is true by default. :param ccs_minimize_roundtrips: If true, network roundtrips between the coordinating node and remote clusters are minimized for cross-cluster search requests. :param expand_wildcards: Type of index that wildcard expressions can match. If @@ -393,7 +393,7 @@ async def search( after the provided checkpoint has been processed and is visible for searches inside of Elasticsearch.

- ``_ + ``_ :param index: A single target to search. If the target is an index alias, it must resolve to a single index. @@ -401,9 +401,9 @@ async def search( :param aggs: :param allow_no_indices: :param allow_partial_search_results: If true, returns partial results if there - are shard request timeouts or [shard failures](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-replication.html#shard-failures). - If false, returns an error with no partial results. Defaults to the configured - cluster setting `search.default_allow_partial_results` which is true by default. + are shard request timeouts or shard failures. If false, returns an error + with no partial results. Defaults to the configured cluster setting `search.default_allow_partial_results`, + which is true by default. :param analyze_wildcard: :param analyzer: :param batched_reduce_size: diff --git a/elasticsearch/_async/client/graph.py b/elasticsearch/_async/client/graph.py index a8c35dbfe..d8556b539 100644 --- a/elasticsearch/_async/client/graph.py +++ b/elasticsearch/_async/client/graph.py @@ -55,7 +55,7 @@ async def explore( You can exclude vertices that have already been returned.

- ``_ + ``_ :param index: Name of the index. :param connections: Specifies or more fields from which you want to extract terms diff --git a/elasticsearch/_async/client/ilm.py b/elasticsearch/_async/client/ilm.py index c15aaa807..f5ab66c5b 100644 --- a/elasticsearch/_async/client/ilm.py +++ b/elasticsearch/_async/client/ilm.py @@ -44,7 +44,7 @@ async def delete_lifecycle( You cannot delete policies that are currently in use. If the policy is being used to manage any indices, the request fails and returns an error.

- ``_ + ``_ :param name: Identifier for the policy. :param master_timeout: Period to wait for a connection to the master node. If @@ -102,7 +102,7 @@ async def explain_lifecycle(

The response indicates when the index entered each lifecycle state, provides the definition of the running phase, and information about any failures.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases to target. Supports wildcards (`*`). To target all data streams and indices, use `*` @@ -163,7 +163,7 @@ async def get_lifecycle(

Get lifecycle policies.

- ``_ + ``_ :param name: Identifier for the policy. :param master_timeout: Period to wait for a connection to the master node. If @@ -218,7 +218,7 @@ async def get_status(

Get the current index lifecycle management status.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_ilm/status" @@ -275,7 +275,7 @@ async def migrate_to_data_tiers( Use the stop ILM and get ILM status APIs to wait until the reported operation mode is STOPPED.

- ``_ + ``_ :param dry_run: If true, simulates the migration from node attributes based allocation filters to data tiers, but does not perform the migration. This provides @@ -354,7 +354,7 @@ async def move_to_step( An index cannot move to a step that is not part of its policy.

- ``_ + ``_ :param index: The name of the index whose lifecycle step is to change :param current_step: The step that the index is expected to be in. @@ -422,7 +422,7 @@ async def put_lifecycle(

NOTE: Only the latest version of the policy is stored, you cannot revert to previous versions.

- ``_ + ``_ :param name: Identifier for the policy. :param master_timeout: Period to wait for a connection to the master node. If @@ -486,7 +486,7 @@ async def remove_policy( It also stops managing the indices.

- ``_ + ``_ :param index: The name of the index to remove policy on """ @@ -532,7 +532,7 @@ async def retry( Use the explain lifecycle state API to determine whether an index is in the ERROR step.

- ``_ + ``_ :param index: The name of the indices (comma-separated) whose failed lifecycle step is to be retry @@ -580,7 +580,7 @@ async def start( Restarting ILM is necessary only when it has been stopped using the stop ILM API.

- ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails and @@ -634,7 +634,7 @@ async def stop( Use the get ILM status API to check whether ILM is running.

- ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails and diff --git a/elasticsearch/_async/client/indices.py b/elasticsearch/_async/client/indices.py index 0c128e9d9..c2472f314 100644 --- a/elasticsearch/_async/client/indices.py +++ b/elasticsearch/_async/client/indices.py @@ -62,7 +62,7 @@ async def add_block( Index blocks limit the operations allowed on an index by blocking specific operation types.

- ``_ + ``_ :param index: A comma-separated list or wildcard expression of index names used to limit the request. By default, you must explicitly name the indices you @@ -173,7 +173,7 @@ async def analyze( The _analyze endpoint without a specified index will always use 10000 as its limit.

- ``_ + ``_ :param index: Index used to derive the analyzer. If specified, the `analyzer` or field parameter overrides this value. If no index is specified or the @@ -265,7 +265,7 @@ async def cancel_migrate_reindex(

Cancel a migration reindex attempt for a data stream or index.

- ``_ + ``_ :param index: The index or data stream name """ @@ -327,7 +327,7 @@ async def clear_cache( To clear the cache only of specific fields, use the fields parameter.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). To target all data streams @@ -449,7 +449,7 @@ async def clone(

Because the clone operation creates a new index to clone the shards to, the wait for active shards setting on index creation applies to the clone index action as well.

- ``_ + ``_ :param index: Name of the source index to clone. :param target: Name of the target index to create. @@ -553,7 +553,7 @@ async def close( Closing indices can be turned off with the cluster settings API by setting cluster.indices.close.enable to false.

- ``_ + ``_ :param index: Comma-separated list or wildcard expression of index names used to limit the request. @@ -654,7 +654,7 @@ async def create( Note that changing this setting will also affect the wait_for_active_shards value on all subsequent write operations.

- ``_ + ``_ :param index: Name of the index you wish to create. :param aliases: Aliases for the index. @@ -731,7 +731,7 @@ async def create_data_stream(

You must have a matching index template with data stream enabled.

- ``_ + ``_ :param name: Name of the data stream, which must meet the following criteria: Lowercase only; Cannot include `\\`, `/`, `*`, `?`, `"`, `<`, `>`, `|`, `,`, @@ -794,7 +794,7 @@ async def create_from(

Copy the mappings and settings from the source index to a destination index while allowing request settings and mappings to override the source values.

- ``_ + ``_ :param source: The source index or data stream name :param dest: The destination index or data stream name @@ -861,7 +861,7 @@ async def data_streams_stats(

Get statistics for one or more data streams.

- ``_ + ``_ :param name: Comma-separated list of data streams used to limit the request. Wildcard expressions (`*`) are supported. To target all data streams in a @@ -930,7 +930,7 @@ async def delete( You can then use the delete index API to delete the previous write index.

- ``_ + ``_ :param index: Comma-separated list of indices to delete. You cannot specify index aliases. By default, this parameter does not support wildcards (`*`) or `_all`. @@ -1004,7 +1004,7 @@ async def delete_alias( Removes a data stream or index from an alias.

- ``_ + ``_ :param index: Comma-separated list of data streams or indices used to limit the request. Supports wildcards (`*`). @@ -1072,7 +1072,7 @@ async def delete_data_lifecycle( Removes the data stream lifecycle from a data stream, rendering it not managed by the data stream lifecycle.

- ``_ + ``_ :param name: A comma-separated list of data streams of which the data stream lifecycle will be deleted; use `*` to get all data streams @@ -1136,7 +1136,7 @@ async def delete_data_stream( Deletes one or more data streams and their backing indices.

- ``_ + ``_ :param name: Comma-separated list of data streams to delete. Wildcard (`*`) expressions are supported. @@ -1194,7 +1194,7 @@ async def delete_index_template( existing templates.

- ``_ + ``_ :param name: Comma-separated list of index template names used to limit the request. Wildcard (*) expressions are supported. @@ -1249,7 +1249,7 @@ async def delete_template(

Delete a legacy index template.

- ``_ + ``_ :param name: The name of the legacy index template to delete. Wildcard (`*`) expressions are supported. @@ -1321,7 +1321,7 @@ async def disk_usage( The stored size of the _id field is likely underestimated while the _source field is overestimated.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases used to limit the request. It’s recommended to execute this API with a single @@ -1404,7 +1404,7 @@ async def downsample( The source index must be read only (index.blocks.write: true).

- ``_ + ``_ :param index: Name of the time series index to downsample. :param target_index: Name of the index to create. @@ -1476,7 +1476,7 @@ async def exists( Check if one or more indices, index aliases, or data streams exist.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases. Supports wildcards (`*`). @@ -1558,7 +1558,7 @@ async def exists_alias(

Check if one or more data stream or index aliases exist.

- ``_ + ``_ :param name: Comma-separated list of aliases to check. Supports wildcards (`*`). :param index: Comma-separated list of data streams or indices used to limit the @@ -1635,7 +1635,7 @@ async def exists_index_template(

Check whether index templates exist.

- ``_ + ``_ :param name: Comma-separated list of index template names used to limit the request. Wildcard (*) expressions are supported. @@ -1698,7 +1698,7 @@ async def exists_template(

IMPORTANT: This documentation is about legacy index templates, which are deprecated and will be replaced by the composable templates introduced in Elasticsearch 7.8.

- ``_ + ``_ :param name: A comma-separated list of index template names used to limit the request. Wildcard (`*`) expressions are supported. @@ -1756,7 +1756,7 @@ async def explain_data_lifecycle( Get information about an index or data stream's current data stream lifecycle status, such as time since index creation, time since rollover, the lifecycle configuration managing the index, or any errors encountered during lifecycle execution.

- ``_ + ``_ :param index: The name of the index to explain :param include_defaults: indicates if the API should return the default values @@ -1823,7 +1823,7 @@ async def field_usage_stats( A given request will increment each count by a maximum value of 1, even if the request accesses the same field multiple times.

- ``_ + ``_ :param index: Comma-separated list or wildcard expression of index names used to limit the request. @@ -1908,7 +1908,7 @@ async def flush( If you call the flush API after indexing some documents then a successful response indicates that Elasticsearch has flushed all the documents that were indexed before the flush API was called.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases to flush. Supports wildcards (`*`). To flush all data streams and indices, omit this @@ -2033,7 +2033,7 @@ async def forcemerge( - ``_ + ``_ :param index: A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices @@ -2131,7 +2131,7 @@ async def get( stream’s backing indices.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and index aliases used to limit the request. Wildcard expressions (*) are supported. @@ -2224,7 +2224,7 @@ async def get_alias( Retrieves information for one or more data stream or index aliases.

- ``_ + ``_ :param index: Comma-separated list of data streams or indices used to limit the request. Supports wildcards (`*`). To target all data streams and indices, @@ -2311,7 +2311,7 @@ async def get_data_lifecycle(

Get the data stream lifecycle configuration of one or more data streams.

- ``_ + ``_ :param name: Comma-separated list of data streams to limit the request. Supports wildcards (`*`). To target all data streams, omit this parameter or use `*` @@ -2369,7 +2369,7 @@ async def get_data_lifecycle_stats( Get statistics about the data streams that are managed by a data stream lifecycle.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_lifecycle/stats" @@ -2420,7 +2420,7 @@ async def get_data_stream(

Get information about one or more data streams.

- ``_ + ``_ :param name: Comma-separated list of data stream names used to limit the request. Wildcard (`*`) expressions are supported. If omitted, all data streams are @@ -2501,7 +2501,7 @@ async def get_field_mapping(

This API is useful if you don't need a complete mapping or if an index mapping contains a large number of fields.

- ``_ + ``_ :param fields: Comma-separated list or wildcard expression of fields used to limit returned information. Supports wildcards (`*`). @@ -2582,7 +2582,7 @@ async def get_index_template( Get information about one or more index templates.

- ``_ + ``_ :param name: Comma-separated list of index template names used to limit the request. Wildcard (*) expressions are supported. @@ -2659,7 +2659,7 @@ async def get_mapping( For data streams, the API retrieves mappings for the stream’s backing indices.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). To target all data streams @@ -2733,7 +2733,7 @@ async def get_migrate_reindex_status(

Get the status of a migration reindex attempt for a data stream or index.

- ``_ + ``_ :param index: The index or data stream name. """ @@ -2793,7 +2793,7 @@ async def get_settings( For data streams, it returns setting information for the stream's backing indices.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). To target all data streams @@ -2885,7 +2885,7 @@ async def get_template(

IMPORTANT: This documentation is about legacy index templates, which are deprecated and will be replaced by the composable templates introduced in Elasticsearch 7.8.

- ``_ + ``_ :param name: Comma-separated list of index template names used to limit the request. Wildcard (`*`) expressions are supported. To return all index templates, @@ -2952,7 +2952,7 @@ async def migrate_reindex( The persistent task ID is returned immediately and the reindexing work is completed in that task.

- ``_ + ``_ :param reindex: """ @@ -3013,7 +3013,7 @@ async def migrate_to_data_stream( The write index for the alias becomes the write index for the stream.

- ``_ + ``_ :param name: Name of the index alias to convert to a data stream. :param master_timeout: Period to wait for a connection to the master node. If @@ -3069,7 +3069,7 @@ async def modify_data_stream( Performs one or more data stream modification actions in a single atomic operation.

- ``_ + ``_ :param actions: Actions to perform. """ @@ -3148,7 +3148,7 @@ async def open(

Because opening or closing an index allocates its shards, the wait_for_active_shards setting on index creation applies to the _open and _close index actions as well.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). By default, you must explicitly @@ -3234,7 +3234,7 @@ async def promote_data_stream( This will affect the lifecycle management of the data stream and interfere with the data stream size and retention.

- ``_ + ``_ :param name: The name of the data stream :param master_timeout: Period to wait for a connection to the master node. If @@ -3300,7 +3300,7 @@ async def put_alias( Adds a data stream or index to an alias.

- ``_ + ``_ :param index: Comma-separated list of data streams or indices to add. Supports wildcards (`*`). Wildcard patterns that match both data streams and indices @@ -3407,7 +3407,7 @@ async def put_data_lifecycle( Update the data stream lifecycle of the specified data streams.

- ``_ + ``_ :param name: Comma-separated list of data streams used to limit the request. Supports wildcards (`*`). To target all data streams use `*` or `_all`. @@ -3535,7 +3535,7 @@ async def put_index_template( If an entry already exists with the same key, then it is overwritten by the new definition.

- ``_ + ``_ :param name: Index or template name :param allow_auto_create: This setting overrides the value of the `action.auto_create_index` @@ -3718,7 +3718,7 @@ async def put_mapping( Instead, add an alias field to create an alternate field name.

- ``_ + ``_ :param index: A comma-separated list of index names the mapping should be added to (supports wildcards); use `_all` or omit to add the mapping on all indices. @@ -3864,7 +3864,7 @@ async def put_settings( To change the analyzer for existing backing indices, you must create a new data stream and reindex your data into it.

- ``_ + ``_ :param settings: :param index: Comma-separated list of data streams, indices, and aliases used @@ -3990,7 +3990,7 @@ async def put_template( NOTE: Multiple matching templates with the same order value will result in a non-deterministic merging order.

- ``_ + ``_ :param name: The name of the template :param aliases: Aliases for the index. @@ -4092,7 +4092,7 @@ async def recovery( This means that if a shard copy completes a recovery and then Elasticsearch relocates it onto a different node then the information about the original recovery will not be shown in the recovery API.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). To target all data streams @@ -4166,7 +4166,7 @@ async def refresh( This option ensures the indexing operation waits for a periodic refresh before running the search.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). To target all data streams @@ -4250,7 +4250,7 @@ async def reload_search_analyzers( This ensures the synonym file is updated everywhere in the cluster in case shards are relocated in the future.

- ``_ + ``_ :param index: A comma-separated list of index names to reload analyzers for :param allow_no_indices: Whether to ignore if a wildcard indices expression resolves @@ -4357,7 +4357,7 @@ async def resolve_cluster( If a connection was (re-)established, this will also cause the remote/info endpoint to now indicate a connected status.

- ``_ + ``_ :param name: A comma-separated list of names or index patterns for the indices, aliases, and data streams to resolve. Resources on remote clusters can be @@ -4459,7 +4459,7 @@ async def resolve_index( Multiple patterns and remote clusters are supported.

- ``_ + ``_ :param name: Comma-separated name(s) or index pattern(s) of the indices, aliases, and data streams to resolve. Resources on remote clusters can be specified @@ -4561,7 +4561,7 @@ async def rollover( If you roll over the alias on May 7, 2099, the new index's name is my-index-2099.05.07-000002.

- ``_ + ``_ :param alias: Name of the data stream or index alias to roll over. :param new_index: Name of the index to create. Supports date math. Data streams @@ -4675,7 +4675,7 @@ async def segments( For data streams, the API returns information about the stream's backing indices.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). To target all data streams @@ -4764,7 +4764,7 @@ async def shard_stores(

By default, the API returns store information only for primary shards that are unassigned or have one or more unassigned replica shards.

- ``_ + ``_ :param index: List of data streams, indices, and aliases used to limit the request. :param allow_no_indices: If false, the request returns an error if any wildcard @@ -4866,7 +4866,7 @@ async def shrink( - ``_ + ``_ :param index: Name of the source index to shrink. :param target: Name of the target index to create. @@ -4947,7 +4947,7 @@ async def simulate_index_template( Get the index configuration that would be applied to the specified index from an existing index template.

- ``_ + ``_ :param name: Name of the index to simulate :param cause: User defined reason for dry-run creating the new template for simulation @@ -5037,7 +5037,7 @@ async def simulate_template( Get the index configuration that would be applied by a particular index template.

- ``_ + ``_ :param name: Name of the index template to simulate. To test a template configuration before you add it to the cluster, omit this parameter and specify the template @@ -5209,7 +5209,7 @@ async def split( - ``_ + ``_ :param index: Name of the source index to split. :param target: Name of the target index to create. @@ -5311,7 +5311,7 @@ async def stats( Although the shard is no longer part of the node, that node retains any node-level statistics to which the shard contributed.

- ``_ + ``_ :param index: A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices @@ -5410,7 +5410,7 @@ async def update_aliases( Adds a data stream or index to an alias.

- ``_ + ``_ :param actions: Actions to perform. :param master_timeout: Period to wait for a connection to the master node. If @@ -5489,7 +5489,7 @@ async def validate_query( Validates a query without running it.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases to search. Supports wildcards (`*`). To search all data streams or indices, omit this diff --git a/elasticsearch/_async/client/inference.py b/elasticsearch/_async/client/inference.py index b0c0a5d33..71318b954 100644 --- a/elasticsearch/_async/client/inference.py +++ b/elasticsearch/_async/client/inference.py @@ -47,7 +47,7 @@ async def completion(

Perform completion inference on the service

- ``_ + ``_ :param inference_id: The inference Id :param input: Inference input. Either a string or an array of strings. @@ -123,7 +123,7 @@ async def delete(

Delete an inference endpoint

- ``_ + ``_ :param inference_id: The inference identifier. :param task_type: The task type @@ -197,7 +197,7 @@ async def get(

Get an inference endpoint

- ``_ + ``_ :param task_type: The task type :param inference_id: The inference Id @@ -234,6 +234,113 @@ async def get( path_parts=__path_parts, ) + @_rewrite_parameters( + body_fields=("input", "query", "task_settings"), + ) + async def inference( + self, + *, + inference_id: str, + input: t.Optional[t.Union[str, t.Sequence[str]]] = None, + task_type: t.Optional[ + t.Union[ + str, + t.Literal[ + "chat_completion", + "completion", + "rerank", + "sparse_embedding", + "text_embedding", + ], + ] + ] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + query: t.Optional[str] = None, + task_settings: t.Optional[t.Any] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Perform inference on the service.

+

This API enables you to use machine learning models to perform specific tasks on data that you provide as an input. + It returns a response with the results of the tasks. + The inference endpoint you use can perform one specific task that has been defined when the endpoint was created with the create inference API.

+

For details about using this API with a service, such as Amazon Bedrock, Anthropic, or HuggingFace, refer to the service-specific documentation.

+
+

info + The inference APIs enable you to use certain services, such as built-in machine learning models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Azure, Google AI Studio, Google Vertex AI, Anthropic, Watsonx.ai, or Hugging Face. For built-in models and models uploaded through Eland, the inference APIs offer an alternative way to use and manage trained models. However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.

+
+ + + ``_ + + :param inference_id: The unique identifier for the inference endpoint. + :param input: The text on which you want to perform the inference task. It can + be a single string or an array. > info > Inference endpoints for the `completion` + task type currently only support a single string as input. + :param task_type: The type of inference task that the model performs. + :param query: The query input, which is required only for the `rerank` task. + It is not required for other tasks. + :param task_settings: Task settings for the individual inference request. These + settings are specific to the task type you specified and override the task + settings specified when initializing the service. + :param timeout: The amount of time to wait for the inference request to complete. + """ + if inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'inference_id'") + if input is None and body is None: + raise ValueError("Empty value passed for parameter 'input'") + __path_parts: t.Dict[str, str] + if task_type not in SKIP_IN_PATH and inference_id not in SKIP_IN_PATH: + __path_parts = { + "task_type": _quote(task_type), + "inference_id": _quote(inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["inference_id"]}' + elif inference_id not in SKIP_IN_PATH: + __path_parts = {"inference_id": _quote(inference_id)} + __path = f'/_inference/{__path_parts["inference_id"]}' + else: + raise ValueError("Couldn't find a path for the given parameters") + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout + if not __body: + if input is not None: + __body["input"] = input + if query is not None: + __body["query"] = query + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return await self.perform_request( # type: ignore[return-value] + "POST", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.inference", + path_parts=__path_parts, + ) + @_rewrite_parameters( body_name="inference_config", ) @@ -274,7 +381,7 @@ async def put( However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.

- ``_ + ``_ :param inference_id: The inference Id :param inference_config: @@ -358,7 +465,7 @@ async def put_alibabacloud( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param alibabacloud_inference_id: The unique identifier of the inference endpoint. @@ -458,7 +565,7 @@ async def put_amazonbedrock( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param amazonbedrock_inference_id: The unique identifier of the inference endpoint. @@ -554,7 +661,7 @@ async def put_anthropic( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The task type. The only valid task type for the model to perform is `completion`. @@ -651,7 +758,7 @@ async def put_azureaistudio( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param azureaistudio_inference_id: The unique identifier of the inference endpoint. @@ -753,7 +860,7 @@ async def put_azureopenai( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. NOTE: The `chat_completion` task type only supports streaming and only through @@ -851,7 +958,7 @@ async def put_cohere( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param cohere_inference_id: The unique identifier of the inference endpoint. @@ -955,7 +1062,7 @@ async def put_elasticsearch( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param elasticsearch_inference_id: The unique identifier of the inference endpoint. @@ -1055,7 +1162,7 @@ async def put_elser( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param elser_inference_id: The unique identifier of the inference endpoint. @@ -1139,7 +1246,7 @@ async def put_googleaistudio( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param googleaistudio_inference_id: The unique identifier of the inference endpoint. @@ -1231,7 +1338,7 @@ async def put_googlevertexai( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param googlevertexai_inference_id: The unique identifier of the inference endpoint. @@ -1334,7 +1441,7 @@ async def put_hugging_face( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param huggingface_inference_id: The unique identifier of the inference endpoint. @@ -1428,7 +1535,7 @@ async def put_jinaai( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param jinaai_inference_id: The unique identifier of the inference endpoint. @@ -1516,7 +1623,7 @@ async def put_mistral( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The task type. The only valid task type for the model to perform is `text_embedding`. @@ -1609,7 +1716,7 @@ async def put_openai( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. NOTE: The `chat_completion` task type only supports streaming and only through @@ -1701,7 +1808,7 @@ async def put_voyageai(

Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param voyageai_inference_id: The unique identifier of the inference endpoint. @@ -1790,7 +1897,7 @@ async def put_watsonx( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The task type. The only valid task type for the model to perform is `text_embedding`. @@ -1866,7 +1973,7 @@ async def rerank(

Perform rereanking inference on the service

- ``_ + ``_ :param inference_id: The unique identifier for the inference endpoint. :param input: The text on which you want to perform the inference task. It can @@ -1942,7 +2049,7 @@ async def sparse_embedding(

Perform sparse embedding inference on the service

- ``_ + ``_ :param inference_id: The inference Id :param input: Inference input. Either a string or an array of strings. @@ -2010,7 +2117,7 @@ async def text_embedding(

Perform text embedding inference on the service

- ``_ + ``_ :param inference_id: The inference Id :param input: Inference input. Either a string or an array of strings. @@ -2092,7 +2199,7 @@ async def update( However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.

- ``_ + ``_ :param inference_id: The unique identifier of the inference endpoint. :param inference_config: diff --git a/elasticsearch/_async/client/ingest.py b/elasticsearch/_async/client/ingest.py index 27a0f09f3..ebc47151a 100644 --- a/elasticsearch/_async/client/ingest.py +++ b/elasticsearch/_async/client/ingest.py @@ -44,7 +44,7 @@ async def delete_geoip_database(

Delete one or more IP geolocation database configurations.

- ``_ + ``_ :param id: A comma-separated list of geoip database configurations to delete :param master_timeout: The period to wait for a connection to the master node. @@ -98,7 +98,7 @@ async def delete_ip_location_database(

Delete IP geolocation database configurations.

- ``_ + ``_ :param id: A comma-separated list of IP location database configurations. :param master_timeout: The period to wait for a connection to the master node. @@ -155,7 +155,7 @@ async def delete_pipeline( Delete one or more ingest pipelines.

- ``_ + ``_ :param id: Pipeline ID or wildcard expression of pipeline IDs used to limit the request. To delete all ingest pipelines in a cluster, use a value of `*`. @@ -208,7 +208,7 @@ async def geo_ip_stats( Get download statistics for GeoIP2 databases that are used with the GeoIP processor.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_ingest/geoip/stats" @@ -248,7 +248,7 @@ async def get_geoip_database(

Get information about one or more IP geolocation database configurations.

- ``_ + ``_ :param id: A comma-separated list of database configuration IDs to retrieve. Wildcard (`*`) expressions are supported. To get all database configurations, @@ -297,7 +297,7 @@ async def get_ip_location_database(

Get IP geolocation database configurations.

- ``_ + ``_ :param id: Comma-separated list of database configuration IDs to retrieve. Wildcard (`*`) expressions are supported. To get all database configurations, omit @@ -355,7 +355,7 @@ async def get_pipeline( This API returns a local reference of the pipeline.

- ``_ + ``_ :param id: Comma-separated list of pipeline IDs to retrieve. Wildcard (`*`) expressions are supported. To get all ingest pipelines, omit this parameter or use `*`. @@ -412,7 +412,7 @@ async def processor_grok( A grok pattern is like a regular expression that supports aliased expressions that can be reused.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_ingest/processor/grok" @@ -459,7 +459,7 @@ async def put_geoip_database(

Refer to the create or update IP geolocation database configuration API.

- ``_ + ``_ :param id: ID of the database configuration to create or update. :param maxmind: The configuration necessary to identify which IP geolocation @@ -534,7 +534,7 @@ async def put_ip_location_database(

Create or update an IP geolocation database configuration.

- ``_ + ``_ :param id: The database configuration identifier. :param configuration: @@ -620,7 +620,7 @@ async def put_pipeline( Changes made using this API take effect immediately.

- ``_ + ``_ :param id: ID of the ingest pipeline to create or update. :param deprecated: Marks this ingest pipeline as deprecated. When a deprecated @@ -717,7 +717,7 @@ async def simulate( You can either specify an existing pipeline to use with the provided documents or supply a pipeline definition in the body of the request.

- ``_ + ``_ :param docs: Sample documents to test in the pipeline. :param id: The pipeline to test. If you don't specify a `pipeline` in the request diff --git a/elasticsearch/_async/client/license.py b/elasticsearch/_async/client/license.py index c6809725f..5f4976a81 100644 --- a/elasticsearch/_async/client/license.py +++ b/elasticsearch/_async/client/license.py @@ -44,7 +44,7 @@ async def delete(

If the operator privileges feature is enabled, only operator users can use this API.

- ``_ + ``_ :param master_timeout: The period to wait for a connection to the master node. :param timeout: The period to wait for a response. If no response is received @@ -98,7 +98,7 @@ async def get( - ``_ + ``_ :param accept_enterprise: If `true`, this parameter returns enterprise for Enterprise license types. If `false`, this parameter returns platinum for both platinum @@ -147,7 +147,7 @@ async def get_basic_status(

Get the basic license status.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_license/basic_status" @@ -185,7 +185,7 @@ async def get_trial_status(

Get the trial status.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_license/trial_status" @@ -237,7 +237,7 @@ async def post( If the operator privileges feature is enabled, only operator users can use this API.

- ``_ + ``_ :param acknowledge: Specifies whether you acknowledge the license changes. :param license: @@ -308,7 +308,7 @@ async def post_start_basic(

To check the status of your basic license, use the get basic license API.

- ``_ + ``_ :param acknowledge: whether the user has acknowledged acknowledge messages (default: false) @@ -365,7 +365,7 @@ async def post_start_trial(

To check the status of your trial, use the get trial status API.

- ``_ + ``_ :param acknowledge: whether the user has acknowledged acknowledge messages (default: false) diff --git a/elasticsearch/_async/client/logstash.py b/elasticsearch/_async/client/logstash.py index c63983710..5d71258e8 100644 --- a/elasticsearch/_async/client/logstash.py +++ b/elasticsearch/_async/client/logstash.py @@ -43,7 +43,7 @@ async def delete_pipeline( If the request succeeds, you receive an empty response with an appropriate status code.

- ``_ + ``_ :param id: An identifier for the pipeline. """ @@ -87,7 +87,7 @@ async def get_pipeline( Get pipelines that are used for Logstash Central Management.

- ``_ + ``_ :param id: A comma-separated list of pipeline identifiers. """ @@ -139,7 +139,7 @@ async def put_pipeline( If the specified pipeline exists, it is replaced.

- ``_ + ``_ :param id: An identifier for the pipeline. :param pipeline: diff --git a/elasticsearch/_async/client/migration.py b/elasticsearch/_async/client/migration.py index 4ff5a18fc..ce74c5aa0 100644 --- a/elasticsearch/_async/client/migration.py +++ b/elasticsearch/_async/client/migration.py @@ -44,7 +44,7 @@ async def deprecations( You are strongly recommended to use the Upgrade Assistant.

- ``_ + ``_ :param index: Comma-separate list of data streams or indices to check. Wildcard (*) expressions are supported. @@ -94,7 +94,7 @@ async def get_feature_upgrade_status( You are strongly recommended to use the Upgrade Assistant.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_migration/system_features" @@ -136,7 +136,7 @@ async def post_feature_upgrade(

TIP: The API is designed for indirect use by the Upgrade Assistant. We strongly recommend you use the Upgrade Assistant.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_migration/system_features" diff --git a/elasticsearch/_async/client/ml.py b/elasticsearch/_async/client/ml.py index acee1e6ea..517cb0b74 100644 --- a/elasticsearch/_async/client/ml.py +++ b/elasticsearch/_async/client/ml.py @@ -45,7 +45,7 @@ async def clear_trained_model_deployment_cache( Calling this API clears the caches without restarting the deployment.

- ``_ + ``_ :param model_id: The unique identifier of the trained model. """ @@ -100,7 +100,7 @@ async def close_job( When a datafeed that has a specified end date stops, it automatically closes its associated job.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. It can be a job identifier, a group name, or a wildcard expression. You can close multiple anomaly detection @@ -165,7 +165,7 @@ async def delete_calendar(

Remove all scheduled events from a calendar, then delete it.

- ``_ + ``_ :param calendar_id: A string that uniquely identifies a calendar. """ @@ -209,7 +209,7 @@ async def delete_calendar_event(

Delete events from a calendar.

- ``_ + ``_ :param calendar_id: A string that uniquely identifies a calendar. :param event_id: Identifier for the scheduled event. You can obtain this identifier @@ -260,7 +260,7 @@ async def delete_calendar_job(

Delete anomaly jobs from a calendar.

- ``_ + ``_ :param calendar_id: A string that uniquely identifies a calendar. :param job_id: An identifier for the anomaly detection jobs. It can be a job @@ -312,7 +312,7 @@ async def delete_data_frame_analytics(

Delete a data frame analytics job.

- ``_ + ``_ :param id: Identifier for the data frame analytics job. :param force: If `true`, it deletes a job that is not stopped; this method is @@ -363,7 +363,7 @@ async def delete_datafeed(

Delete a datafeed.

- ``_ + ``_ :param datafeed_id: A numerical character string that uniquely identifies the datafeed. This identifier can contain lowercase alphanumeric characters (a-z @@ -426,7 +426,7 @@ async def delete_expired_data( <job_id>.

- ``_ + ``_ :param job_id: Identifier for an anomaly detection job. It can be a job identifier, a group name, or a wildcard expression. @@ -490,7 +490,7 @@ async def delete_filter( filter. You must update or delete the job before you can delete the filter.

- ``_ + ``_ :param filter_id: A string that uniquely identifies a filter. """ @@ -540,7 +540,7 @@ async def delete_forecast( forecasts before they expire.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param forecast_id: A comma-separated list of forecast identifiers. If you do @@ -616,7 +616,7 @@ async def delete_job( delete job request.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param delete_user_annotations: Specifies whether annotations that have been @@ -676,7 +676,7 @@ async def delete_model_snapshot( the model_snapshot_id in the results from the get jobs API.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param snapshot_id: Identifier for the model snapshot. @@ -728,7 +728,7 @@ async def delete_trained_model(

The request deletes a trained inference model that is not referenced by an ingest pipeline.

- ``_ + ``_ :param model_id: The unique identifier of the trained model. :param force: Forcefully deletes a trained model that is referenced by ingest @@ -783,7 +783,7 @@ async def delete_trained_model_alias( by the model_id, this API returns an error.

- ``_ + ``_ :param model_id: The trained model ID to which the model alias refers. :param model_alias: The model alias to delete. @@ -844,7 +844,7 @@ async def estimate_model_memory( estimates for the fields it references.

- ``_ + ``_ :param analysis_config: For a list of the properties that you can specify in the `analysis_config` component of the body of this API. @@ -916,7 +916,7 @@ async def evaluate_data_frame( field and an analytics result field to be present.

- ``_ + ``_ :param evaluation: Defines the type of evaluation you want to perform. :param index: Defines the `index` in which the evaluation will be performed. @@ -1001,7 +1001,7 @@ async def explain_data_frame_analytics( - ``_ + ``_ :param id: Identifier for the data frame analytics job. This identifier can contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and underscores. @@ -1112,7 +1112,7 @@ async def flush_job( analyzing further data.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param advance_time: Refer to the description for the `advance_time` query parameter. @@ -1187,7 +1187,7 @@ async def forecast( based on historical data.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. The job must be open when you create a forecast; otherwise, an error occurs. @@ -1273,7 +1273,7 @@ async def get_buckets( The API presents a chronological view of the records, grouped by bucket.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param timestamp: The timestamp of a single bucket result. If you do not specify @@ -1371,7 +1371,7 @@ async def get_calendar_events(

Get info about events in calendars.

- ``_ + ``_ :param calendar_id: A string that uniquely identifies a calendar. You can get information for multiple calendars by using a comma-separated list of ids @@ -1440,7 +1440,7 @@ async def get_calendars(

Get calendar configuration info.

- ``_ + ``_ :param calendar_id: A string that uniquely identifies a calendar. You can get information for multiple calendars by using a comma-separated list of ids @@ -1516,7 +1516,7 @@ async def get_categories(

Get anomaly detection job results for categories.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param category_id: Identifier for the category, which is unique in the job. @@ -1604,7 +1604,7 @@ async def get_data_frame_analytics( wildcard expression.

- ``_ + ``_ :param id: Identifier for the data frame analytics job. If you do not specify this option, the API returns information for the first hundred data frame @@ -1679,7 +1679,7 @@ async def get_data_frame_analytics_stats(

Get data frame analytics jobs usage info.

- ``_ + ``_ :param id: Identifier for the data frame analytics job. If you do not specify this option, the API returns information for the first hundred data frame @@ -1753,7 +1753,7 @@ async def get_datafeed_stats( This API returns a maximum of 10,000 datafeeds.

- ``_ + ``_ :param datafeed_id: Identifier for the datafeed. It can be a datafeed identifier or a wildcard expression. If you do not specify one of these options, the @@ -1817,7 +1817,7 @@ async def get_datafeeds( This API returns a maximum of 10,000 datafeeds.

- ``_ + ``_ :param datafeed_id: Identifier for the datafeed. It can be a datafeed identifier or a wildcard expression. If you do not specify one of these options, the @@ -1884,7 +1884,7 @@ async def get_filters( You can get a single filter or all filters.

- ``_ + ``_ :param filter_id: A string that uniquely identifies a filter. :param from_: Skips the specified number of filters. @@ -1952,7 +1952,7 @@ async def get_influencers( influencer_field_name is specified in the job configuration.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param desc: If true, the results are sorted in descending order. @@ -2036,7 +2036,7 @@ async def get_job_stats(

Get anomaly detection jobs usage info.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. It can be a job identifier, a group name, a comma-separated list of jobs, or a wildcard expression. If @@ -2100,7 +2100,7 @@ async def get_jobs( _all, by specifying * as the <job_id>, or by omitting the <job_id>.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. It can be a job identifier, a group name, or a wildcard expression. If you do not specify one of these @@ -2166,7 +2166,7 @@ async def get_memory_stats( on each node, both within the JVM heap, and natively, outside of the JVM.

- ``_ + ``_ :param node_id: The names of particular nodes in the cluster to target. For example, `nodeId1,nodeId2` or `ml:true` @@ -2224,7 +2224,7 @@ async def get_model_snapshot_upgrade_stats(

Get anomaly detection job model snapshot upgrade usage info.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param snapshot_id: A numerical character string that uniquely identifies the @@ -2298,7 +2298,7 @@ async def get_model_snapshots(

Get model snapshots info.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param snapshot_id: A numerical character string that uniquely identifies the @@ -2418,7 +2418,7 @@ async def get_overall_buckets( jobs' largest bucket span.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. It can be a job identifier, a group name, a comma-separated list of jobs or groups, or a wildcard expression. @@ -2528,7 +2528,7 @@ async def get_records( number of detectors.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param desc: Refer to the description for the `desc` query parameter. @@ -2626,7 +2626,7 @@ async def get_trained_models(

Get trained model configuration info.

- ``_ + ``_ :param model_id: The unique identifier of the trained model or a model alias. You can get information for multiple trained models in a single API request @@ -2713,7 +2713,7 @@ async def get_trained_models_stats( models in a single API request by using a comma-separated list of model IDs or a wildcard expression.

- ``_ + ``_ :param model_id: The unique identifier of the trained model or a model alias. It can be a comma-separated list or a wildcard expression. @@ -2779,7 +2779,7 @@ async def infer_trained_model(

Evaluate a trained model.

- ``_ + ``_ :param model_id: The unique identifier of the trained model. :param docs: An array of objects to pass to the model for inference. The objects @@ -2846,7 +2846,7 @@ async def info( cluster configuration.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_ml/info" @@ -2895,7 +2895,7 @@ async def open_job( new data is received.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param timeout: Refer to the description for the `timeout` query parameter. @@ -2952,7 +2952,7 @@ async def post_calendar_events(

Add scheduled events to the calendar.

- ``_ + ``_ :param calendar_id: A string that uniquely identifies a calendar. :param events: A list of one of more scheduled events. The event’s start and @@ -3013,7 +3013,7 @@ async def post_data( It is not currently possible to post data to multiple jobs using wildcards or a comma-separated list.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. The job must have a state of open to receive and process the data. @@ -3080,7 +3080,7 @@ async def preview_data_frame_analytics( Preview the extracted features used by a data frame analytics config.

- ``_ + ``_ :param id: Identifier for the data frame analytics job. :param config: A data frame analytics config as described in create data frame @@ -3153,7 +3153,7 @@ async def preview_datafeed( You can also use secondary authorization headers to supply the credentials.

- ``_ + ``_ :param datafeed_id: A numerical character string that uniquely identifies the datafeed. This identifier can contain lowercase alphanumeric characters (a-z @@ -3232,7 +3232,7 @@ async def put_calendar(

Create a calendar.

- ``_ + ``_ :param calendar_id: A string that uniquely identifies a calendar. :param description: A description of the calendar. @@ -3289,7 +3289,7 @@ async def put_calendar_job(

Add anomaly detection job to calendar.

- ``_ + ``_ :param calendar_id: A string that uniquely identifies a calendar. :param job_id: An identifier for the anomaly detection jobs. It can be a job @@ -3372,7 +3372,7 @@ async def put_data_frame_analytics(

If you supply only a subset of the regression or classification parameters, hyperparameter optimization occurs. It determines a value for each of the undefined parameters.

- ``_ + ``_ :param id: Identifier for the data frame analytics job. This identifier can contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and underscores. @@ -3557,7 +3557,7 @@ async def put_datafeed( directly to the .ml-config index. Do not give users write privileges on the .ml-config index.

- ``_ + ``_ :param datafeed_id: A numerical character string that uniquely identifies the datafeed. This identifier can contain lowercase alphanumeric characters (a-z @@ -3719,7 +3719,7 @@ async def put_filter( Specifically, filters are referenced in the custom_rules property of detector configuration objects.

- ``_ + ``_ :param filter_id: A string that uniquely identifies a filter. :param description: A description of the filter. @@ -3821,7 +3821,7 @@ async def put_job( If you include a datafeed_config but do not provide a query, the datafeed uses {"match_all": {"boost": 1}}.

- ``_ + ``_ :param job_id: The identifier for the anomaly detection job. This identifier can contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and @@ -4029,7 +4029,7 @@ async def put_trained_model( Enable you to supply a trained model that is not created by data frame analytics.

- ``_ + ``_ :param model_id: The unique identifier of the trained model. :param compressed_definition: The compressed (GZipped and Base64 encoded) inference @@ -4150,7 +4150,7 @@ async def put_trained_model_alias( returns a warning.

- ``_ + ``_ :param model_id: The identifier for the trained model that the alias refers to. :param model_alias: The alias to create or update. This value cannot end in numbers. @@ -4211,7 +4211,7 @@ async def put_trained_model_definition_part(

Create part of a trained model definition.

- ``_ + ``_ :param model_id: The unique identifier of the trained model. :param part: The definition part number. When the definition is loaded for inference @@ -4293,7 +4293,7 @@ async def put_trained_model_vocabulary( The vocabulary is stored in the index as described in inference_config.*.vocabulary of the trained model definition.

- ``_ + ``_ :param model_id: The unique identifier of the trained model. :param vocabulary: The model vocabulary, which must not be empty. @@ -4356,7 +4356,7 @@ async def reset_job( comma separated list.

- ``_ + ``_ :param job_id: The ID of the job to reset. :param delete_user_annotations: Specifies whether annotations that have been @@ -4420,7 +4420,7 @@ async def revert_model_snapshot( snapshot after Black Friday or a critical system failure.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param snapshot_id: You can specify `empty` as the . Reverting to @@ -4495,7 +4495,7 @@ async def set_upgrade_mode( machine learning info API.

- ``_ + ``_ :param enabled: When `true`, it enables `upgrade_mode` which temporarily halts all job and datafeed tasks and prohibits new job and datafeed tasks from @@ -4555,7 +4555,7 @@ async def start_data_frame_analytics( the destination index in advance with custom settings and mappings.

- ``_ + ``_ :param id: Identifier for the data frame analytics job. This identifier can contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and underscores. @@ -4618,7 +4618,7 @@ async def start_datafeed( authorization headers when you created or updated the datafeed, those credentials are used instead.

- ``_ + ``_ :param datafeed_id: A numerical character string that uniquely identifies the datafeed. This identifier can contain lowercase alphanumeric characters (a-z @@ -4695,7 +4695,7 @@ async def start_trained_model_deployment( It allocates the model to every machine learning node.

- ``_ + ``_ :param model_id: The unique identifier of the trained model. Currently, only PyTorch models are supported. @@ -4796,7 +4796,7 @@ async def stop_data_frame_analytics( throughout its lifecycle.

- ``_ + ``_ :param id: Identifier for the data frame analytics job. This identifier can contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and underscores. @@ -4866,7 +4866,7 @@ async def stop_datafeed( multiple times throughout its lifecycle.

- ``_ + ``_ :param datafeed_id: Identifier for the datafeed. You can stop multiple datafeeds in a single API request by using a comma-separated list of datafeeds or a @@ -4931,7 +4931,7 @@ async def stop_trained_model_deployment(

Stop a trained model deployment.

- ``_ + ``_ :param model_id: The unique identifier of the trained model. :param allow_no_match: Specifies what to do when the request: contains wildcard @@ -4999,7 +4999,7 @@ async def update_data_frame_analytics(

Update a data frame analytics job.

- ``_ + ``_ :param id: Identifier for the data frame analytics job. This identifier can contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and underscores. @@ -5114,7 +5114,7 @@ async def update_datafeed( those credentials are used instead.

- ``_ + ``_ :param datafeed_id: A numerical character string that uniquely identifies the datafeed. This identifier can contain lowercase alphanumeric characters (a-z @@ -5281,7 +5281,7 @@ async def update_filter( Updates the description of a filter, adds items, or removes items from the list.

- ``_ + ``_ :param filter_id: A string that uniquely identifies a filter. :param add_items: The items to add to the filter. @@ -5375,7 +5375,7 @@ async def update_job( Updates certain properties of an anomaly detection job.

- ``_ + ``_ :param job_id: Identifier for the job. :param allow_lazy_open: Advanced configuration option. Specifies whether this @@ -5507,7 +5507,7 @@ async def update_model_snapshot( Updates certain properties of a snapshot.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param snapshot_id: Identifier for the model snapshot. @@ -5572,7 +5572,7 @@ async def update_trained_model_deployment(

Update a trained model deployment.

- ``_ + ``_ :param model_id: The unique identifier of the trained model. Currently, only PyTorch models are supported. @@ -5649,7 +5649,7 @@ async def upgrade_job_snapshot( job.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param snapshot_id: A numerical character string that uniquely identifies the @@ -5801,7 +5801,7 @@ async def validate_detector(

Validate an anomaly detection job.

- ``_ + ``_ :param detector: """ diff --git a/elasticsearch/_async/client/monitoring.py b/elasticsearch/_async/client/monitoring.py index afc6406da..4ab6dd02e 100644 --- a/elasticsearch/_async/client/monitoring.py +++ b/elasticsearch/_async/client/monitoring.py @@ -48,7 +48,7 @@ async def bulk( This API is used by the monitoring features to send monitoring data.

- ``_ + ``_ :param interval: Collection interval (e.g., '10s' or '10000ms') of the payload :param operations: diff --git a/elasticsearch/_async/client/nodes.py b/elasticsearch/_async/client/nodes.py index be00377a0..cd4e95a7d 100644 --- a/elasticsearch/_async/client/nodes.py +++ b/elasticsearch/_async/client/nodes.py @@ -50,7 +50,7 @@ async def clear_repositories_metering_archive( Clear the archived repositories metering information in the cluster.

- ``_ + ``_ :param node_id: Comma-separated list of node IDs or names used to limit returned information. @@ -105,10 +105,10 @@ async def get_repositories_metering_info( Additionally, the information exposed by this API is volatile, meaning that it will not be present after node restarts.

- ``_ + ``_ :param node_id: Comma-separated list of node IDs or names used to limit returned - information. All the nodes selective options are explained [here](https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster.html#cluster-nodes). + information. """ if node_id in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'node_id'") @@ -162,7 +162,7 @@ async def hot_threads( The output is plain text with a breakdown of the top hot threads for each node.

- ``_ + ``_ :param node_id: List of node IDs or names used to limit returned information. :param ignore_idle_threads: If true, known idle threads (e.g. waiting in a socket @@ -235,7 +235,7 @@ async def info(

By default, the API returns all attributes and core settings for cluster nodes.

- ``_ + ``_ :param node_id: Comma-separated list of node IDs or names used to limit returned information. @@ -308,7 +308,7 @@ async def reload_secure_settings( Alternatively, you can reload the secure settings on each node by locally accessing the API and passing the node-specific Elasticsearch keystore password.

- ``_ + ``_ :param node_id: The names of particular nodes in the cluster to target. :param secure_settings_password: The password for the Elasticsearch keystore. @@ -383,7 +383,7 @@ async def stats( By default, all stats are returned. You can limit the returned information by using metrics.

- ``_ + ``_ :param node_id: Comma-separated list of node IDs or names used to limit returned information. @@ -498,7 +498,7 @@ async def usage(

Get feature usage information.

- ``_ + ``_ :param node_id: A comma-separated list of node IDs or names to limit the returned information; use `_local` to return information from the node you're connecting diff --git a/elasticsearch/_async/client/query_rules.py b/elasticsearch/_async/client/query_rules.py index 4e056f817..80d95053b 100644 --- a/elasticsearch/_async/client/query_rules.py +++ b/elasticsearch/_async/client/query_rules.py @@ -44,7 +44,7 @@ async def delete_rule( This is a destructive action that is only recoverable by re-adding the same rule with the create or update query rule API.

- ``_ + ``_ :param ruleset_id: The unique identifier of the query ruleset containing the rule to delete @@ -97,7 +97,7 @@ async def delete_ruleset( This is a destructive action that is not recoverable.

- ``_ + ``_ :param ruleset_id: The unique identifier of the query ruleset to delete """ @@ -142,7 +142,7 @@ async def get_rule( Get details about a query rule within a query ruleset.

- ``_ + ``_ :param ruleset_id: The unique identifier of the query ruleset containing the rule to retrieve @@ -194,7 +194,7 @@ async def get_ruleset( Get details about a query ruleset.

- ``_ + ``_ :param ruleset_id: The unique identifier of the query ruleset """ @@ -241,7 +241,7 @@ async def list_rulesets( Get summarized information about the query rulesets.

- ``_ + ``_ :param from_: The offset from the first result to fetch. :param size: The maximum number of results to retrieve. @@ -302,7 +302,7 @@ async def put_rule( If multiple matching rules pin more than 100 documents, only the first 100 documents are pinned in the order they are specified in the ruleset.

- ``_ + ``_ :param ruleset_id: The unique identifier of the query ruleset containing the rule to be created or updated. @@ -389,7 +389,7 @@ async def put_ruleset( If multiple matching rules pin more than 100 documents, only the first 100 documents are pinned in the order they are specified in the ruleset.

- ``_ + ``_ :param ruleset_id: The unique identifier of the query ruleset to be created or updated. @@ -446,7 +446,7 @@ async def test( Evaluate match criteria against a query ruleset to identify the rules that would match that criteria.

- ``_ + ``_ :param ruleset_id: The unique identifier of the query ruleset to be created or updated diff --git a/elasticsearch/_async/client/rollup.py b/elasticsearch/_async/client/rollup.py index e0d581d77..1324175e5 100644 --- a/elasticsearch/_async/client/rollup.py +++ b/elasticsearch/_async/client/rollup.py @@ -67,7 +67,7 @@ async def delete_job( - ``_ + ``_ :param id: Identifier for the job. """ @@ -115,7 +115,7 @@ async def get_jobs( For details about a historical rollup job, the rollup capabilities API may be more useful.

- ``_ + ``_ :param id: Identifier for the rollup job. If it is `_all` or omitted, the API returns all rollup jobs. @@ -171,7 +171,7 @@ async def get_rollup_caps( - ``_ + ``_ :param id: Index, indices or index-pattern to return rollup capabilities for. `_all` may be used to fetch rollup capabilities from all jobs. @@ -225,7 +225,7 @@ async def get_rollup_index_caps( - ``_ + ``_ :param index: Data stream or index to check for rollup capabilities. Wildcard (`*`) expressions are supported. @@ -295,7 +295,7 @@ async def put_job(

Jobs are created in a STOPPED state. You can start them with the start rollup jobs API.

- ``_ + ``_ :param id: Identifier for the rollup job. This can be any alphanumeric string and uniquely identifies the data that is associated with the rollup job. @@ -443,7 +443,7 @@ async def rollup_search( During the merging process, if there is any overlap in buckets between the two responses, the buckets from the non-rollup index are used.

- ``_ + ``_ :param index: A comma-separated list of data streams and indices used to limit the request. This parameter has the following rules: * At least one data @@ -521,7 +521,7 @@ async def start_job( If you try to start a job that is already started, nothing happens.

- ``_ + ``_ :param id: Identifier for the rollup job. """ @@ -575,7 +575,7 @@ async def stop_job( If the specified time elapses without the job moving to STOPPED, a timeout exception occurs.

- ``_ + ``_ :param id: Identifier for the rollup job. :param timeout: If `wait_for_completion` is `true`, the API blocks for (at maximum) diff --git a/elasticsearch/_async/client/search_application.py b/elasticsearch/_async/client/search_application.py index 30352bd67..5e02c132c 100644 --- a/elasticsearch/_async/client/search_application.py +++ b/elasticsearch/_async/client/search_application.py @@ -49,7 +49,7 @@ async def delete(

Remove a search application and its associated alias. Indices attached to the search application are not removed.

- ``_ + ``_ :param name: The name of the search application to delete. """ @@ -94,7 +94,7 @@ async def delete_behavioral_analytics( The associated data stream is also deleted.

- ``_ + ``_ :param name: The name of the analytics collection to be deleted """ @@ -138,7 +138,7 @@ async def get(

Get search application details.

- ``_ + ``_ :param name: The name of the search application """ @@ -182,7 +182,7 @@ async def get_behavioral_analytics(

Get behavioral analytics collections.

- ``_ + ``_ :param name: A list of analytics collections to limit the returned information """ @@ -234,7 +234,7 @@ async def list( Get information about search applications.

- ``_ + ``_ :param from_: Starting offset. :param q: Query in the Lucene query string syntax. @@ -290,7 +290,7 @@ async def post_behavioral_analytics_event(

Create a behavioral analytics collection event.

- ``_ + ``_ :param collection_name: The name of the behavioral analytics collection. :param event_type: The analytics event type. @@ -357,7 +357,7 @@ async def put(

Create or update a search application.

- ``_ + ``_ :param name: The name of the search application to be created or updated. :param search_application: @@ -414,7 +414,7 @@ async def put_behavioral_analytics(

Create a behavioral analytics collection.

- ``_ + ``_ :param name: The name of the analytics collection to be created or updated. """ @@ -467,7 +467,7 @@ async def render_query(

You must have read privileges on the backing alias of the search application.

- ``_ + ``_ :param name: The name of the search application to render teh query for. :param params: @@ -531,7 +531,7 @@ async def search( Unspecified template parameters are assigned their default values if applicable.

- ``_ + ``_ :param name: The name of the search application to be searched. :param params: Query parameters specific to this request, which will override diff --git a/elasticsearch/_async/client/searchable_snapshots.py b/elasticsearch/_async/client/searchable_snapshots.py index 9b6902fac..dc55f3a6e 100644 --- a/elasticsearch/_async/client/searchable_snapshots.py +++ b/elasticsearch/_async/client/searchable_snapshots.py @@ -50,7 +50,7 @@ async def cache_stats( Get statistics about the shared cache for partially mounted indices.

- ``_ + ``_ :param node_id: The names of the nodes in the cluster to target. :param master_timeout: @@ -111,7 +111,7 @@ async def clear_cache( Clear indices and data streams from the shared cache for partially mounted indices.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases to clear from the cache. It supports wildcards (`*`). @@ -190,7 +190,7 @@ async def mount( Manually mounting ILM-managed snapshots can interfere with ILM processes.

- ``_ + ``_ :param repository: The name of the repository containing the snapshot of the index to mount. @@ -278,7 +278,7 @@ async def stats(

Get searchable snapshot statistics.

- ``_ + ``_ :param index: A comma-separated list of data streams and indices to retrieve statistics for. diff --git a/elasticsearch/_async/client/security.py b/elasticsearch/_async/client/security.py index 840a3d249..cc6fa3ccb 100644 --- a/elasticsearch/_async/client/security.py +++ b/elasticsearch/_async/client/security.py @@ -58,7 +58,7 @@ async def activate_user_profile( Any updates do not change existing content for either the labels or data fields.

- ``_ + ``_ :param grant_type: The type of grant. :param access_token: The user's Elasticsearch access token or JWT. Both `access` @@ -124,7 +124,7 @@ async def authenticate( If the user cannot be authenticated, this API returns a 401 status code.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_security/_authenticate" @@ -171,7 +171,7 @@ async def bulk_delete_role( The bulk delete roles API cannot delete roles that are defined in roles files.

- ``_ + ``_ :param names: An array of role names to delete :param refresh: If `true` (the default) then refresh the affected shards to make @@ -232,7 +232,7 @@ async def bulk_put_role( The bulk create or update roles API cannot update roles that are defined in roles files.

- ``_ + ``_ :param roles: A dictionary of role name to RoleDescriptor objects to add or update :param refresh: If `true` (the default) then refresh the affected shards to make @@ -300,7 +300,7 @@ async def bulk_update_api_keys(

A successful request returns a JSON structure that contains the IDs of all updated API keys, the IDs of API keys that already had the requested changes and did not require an update, and error details for any failed update.

- ``_ + ``_ :param ids: The API key identifiers. :param expiration: Expiration time for the API keys. By default, API keys never @@ -378,7 +378,7 @@ async def change_password(

Change the passwords of users in the native realm and built-in users.

- ``_ + ``_ :param username: The user whose password you want to change. If you do not specify this parameter, the password is changed for the current user. @@ -445,7 +445,7 @@ async def clear_api_key_cache( The cache is also automatically cleared on state changes of the security index.

- ``_ + ``_ :param ids: Comma-separated list of API key IDs to evict from the API key cache. To evict all API keys, use `*`. Does not support other wildcard patterns. @@ -491,7 +491,7 @@ async def clear_cached_privileges( The cache is also automatically cleared for applications that have their privileges updated.

- ``_ + ``_ :param application: A comma-separated list of applications. To clear all applications, use an asterism (`*`). It does not support other wildcard patterns. @@ -541,7 +541,7 @@ async def clear_cached_realms( For more information, refer to the documentation about controlling the user cache.

- ``_ + ``_ :param realms: A comma-separated list of realms. To clear all realms, use an asterisk (`*`). It does not support other wildcard patterns. @@ -591,7 +591,7 @@ async def clear_cached_roles(

Evict roles from the native role cache.

- ``_ + ``_ :param name: A comma-separated list of roles to evict from the role cache. To evict all roles, use an asterisk (`*`). It does not support other wildcard @@ -643,7 +643,7 @@ async def clear_cached_service_tokens( The cache for tokens backed by the service_tokens file is cleared automatically on file changes.

- ``_ + ``_ :param namespace: The namespace, which is a top-level grouping of service accounts. :param service: The name of the service, which must be unique within its namespace. @@ -715,7 +715,7 @@ async def create_api_key( To configure or turn off the API key service, refer to API key service setting documentation.

- ``_ + ``_ :param expiration: The expiration time for the API key. By default, API keys never expire. @@ -805,7 +805,7 @@ async def create_cross_cluster_api_key( Attempting to update them with the update REST API key API or the bulk update REST API keys API will result in an error.

- ``_ + ``_ :param access: The access to be granted to this API key. The access is composed of permissions for cross-cluster search and cross-cluster replication. At @@ -880,7 +880,7 @@ async def create_service_token( You must actively delete them if they are no longer needed.

- ``_ + ``_ :param namespace: The name of the namespace, which is a top-level grouping of service accounts. @@ -966,7 +966,7 @@ async def delegate_pki( The proxy is trusted to have performed the TLS authentication and this API translates that authentication into an Elasticsearch access token.

- ``_ + ``_ :param x509_certificate_chain: The X509Certificate chain, which is represented as an ordered string array. Each string in the array is a base64-encoded @@ -1030,7 +1030,7 @@ async def delete_privileges( - ``_ + ``_ :param application: The name of the application. Application privileges are always associated with exactly one application. @@ -1093,7 +1093,7 @@ async def delete_role( The delete roles API cannot remove roles that are defined in roles files.

- ``_ + ``_ :param name: The name of the role. :param refresh: If `true` (the default) then refresh the affected shards to make @@ -1147,7 +1147,7 @@ async def delete_role_mapping( The delete role mappings API cannot remove role mappings that are defined in role mapping files.

- ``_ + ``_ :param name: The distinct name that identifies the role mapping. The name is used solely as an identifier to facilitate interaction via the API; it does @@ -1203,7 +1203,7 @@ async def delete_service_token(

Delete service account tokens for a service in a specified namespace.

- ``_ + ``_ :param namespace: The namespace, which is a top-level grouping of service accounts. :param service: The service name. @@ -1265,7 +1265,7 @@ async def delete_user(

Delete users from the native realm.

- ``_ + ``_ :param username: An identifier for the user. :param refresh: If `true` (the default) then refresh the affected shards to make @@ -1319,7 +1319,7 @@ async def disable_user( You can use this API to revoke a user's access to Elasticsearch.

- ``_ + ``_ :param username: An identifier for the user. :param refresh: If `true` (the default) then refresh the affected shards to make @@ -1376,7 +1376,7 @@ async def disable_user_profile( To re-enable a disabled user profile, use the enable user profile API .

- ``_ + ``_ :param uid: Unique identifier for the user profile. :param refresh: If 'true', Elasticsearch refreshes the affected shards to make @@ -1429,7 +1429,7 @@ async def enable_user( By default, when you create users, they are enabled.

- ``_ + ``_ :param username: An identifier for the user. :param refresh: If `true` (the default) then refresh the affected shards to make @@ -1486,7 +1486,7 @@ async def enable_user_profile( If you later disable the user profile, you can use the enable user profile API to make the profile visible in these searches again.

- ``_ + ``_ :param uid: A unique identifier for the user profile. :param refresh: If 'true', Elasticsearch refreshes the affected shards to make @@ -1536,7 +1536,7 @@ async def enroll_kibana( Kibana uses this API internally to configure itself for communications with an Elasticsearch cluster that already has security features enabled.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_security/enroll/kibana" @@ -1577,7 +1577,7 @@ async def enroll_node( The response contains key and certificate material that allows the caller to generate valid signed certificates for the HTTP layer of all nodes in the cluster.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_security/enroll/node" @@ -1626,7 +1626,7 @@ async def get_api_key( If you have read_security, manage_api_key or greater privileges (including manage_security), this API returns all API keys regardless of ownership.

- ``_ + ``_ :param active_only: A boolean flag that can be used to query API keys that are currently active. An API key is considered active if it is neither invalidated, @@ -1704,7 +1704,7 @@ async def get_builtin_privileges(

Get the list of cluster privileges and index privileges that are available in this version of Elasticsearch.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_security/privilege/_builtin" @@ -1749,7 +1749,7 @@ async def get_privileges( - ``_ + ``_ :param application: The name of the application. Application privileges are always associated with exactly one application. If you do not specify this parameter, @@ -1805,7 +1805,7 @@ async def get_role( The get roles API cannot retrieve roles that are defined in roles files.

- ``_ + ``_ :param name: The name of the role. You can specify multiple roles as a comma-separated list. If you do not specify this parameter, the API returns information about @@ -1856,7 +1856,7 @@ async def get_role_mapping( The get role mappings API cannot retrieve role mappings that are defined in role mapping files.

- ``_ + ``_ :param name: The distinct name that identifies the role mapping. The name is used solely as an identifier to facilitate interaction via the API; it does @@ -1909,7 +1909,7 @@ async def get_service_accounts(

NOTE: Currently, only the elastic/fleet-server service account is available.

- ``_ + ``_ :param namespace: The name of the namespace. Omit this parameter to retrieve information about all service accounts. If you omit this parameter, you must @@ -1967,7 +1967,7 @@ async def get_service_credentials( Tokens with the same name from different nodes are assumed to be the same token and are only counted once towards the total number of service tokens.

- ``_ + ``_ :param namespace: The name of the namespace. :param service: The service name. @@ -2023,7 +2023,7 @@ async def get_settings( - ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails and @@ -2099,7 +2099,7 @@ async def get_token( If you want to invalidate a token immediately, you can do so by using the invalidate token API.

- ``_ + ``_ :param grant_type: The type of grant. Supported grant types are: `password`, `_kerberos`, `client_credentials`, and `refresh_token`. @@ -2173,7 +2173,7 @@ async def get_user(

Get information about users in the native realm and built-in users.

- ``_ + ``_ :param username: An identifier for the user. You can specify multiple usernames as a comma-separated list. If you omit this parameter, the API retrieves @@ -2231,7 +2231,7 @@ async def get_user_privileges( To check whether a user has a specific list of privileges, use the has privileges API.

- ``_ + ``_ :param application: The name of the application. Application privileges are always associated with exactly one application. If you do not specify this parameter, @@ -2288,7 +2288,7 @@ async def get_user_profile( Elastic reserves the right to change or remove this feature in future releases without prior notice.

- ``_ + ``_ :param uid: A unique identifier for the user profile. :param data: A comma-separated list of filters for the `data` field of the profile @@ -2372,7 +2372,7 @@ async def grant_api_key(

By default, API keys never expire. You can specify expiration information when you create the API keys.

- ``_ + ``_ :param api_key: The API key. :param grant_type: The type of grant. Supported grant types are: `access_token`, @@ -2519,7 +2519,7 @@ async def has_privileges( To check the privileges of other users, you must use the run as feature.

- ``_ + ``_ :param user: Username :param application: @@ -2584,7 +2584,7 @@ async def has_privileges_user_profile( Elastic reserves the right to change or remove this feature in future releases without prior notice.

- ``_ + ``_ :param privileges: An object containing all the privileges to be checked. :param uids: A list of profile IDs. The privileges are checked for associated @@ -2658,7 +2658,7 @@ async def invalidate_api_key( - ``_ + ``_ :param id: :param ids: A list of API key ids. This parameter cannot be used with any of @@ -2742,7 +2742,7 @@ async def invalidate_token( If none of these two are specified, then realm_name and/or username need to be specified.

- ``_ + ``_ :param realm_name: The name of an authentication realm. This parameter cannot be used with either `refresh_token` or `token`. @@ -2810,7 +2810,7 @@ async def oidc_authenticate( These APIs are used internally by Kibana in order to provide OpenID Connect based authentication, but can also be used by other, custom web applications or other clients.

- ``_ + ``_ :param nonce: Associate a client session with an ID token and mitigate replay attacks. This value needs to be the same as the one that was provided to @@ -2890,7 +2890,7 @@ async def oidc_logout( These APIs are used internally by Kibana in order to provide OpenID Connect based authentication, but can also be used by other, custom web applications or other clients.

- ``_ + ``_ :param token: The access token to be invalidated. :param refresh_token: The refresh token to be invalidated. @@ -2952,7 +2952,7 @@ async def oidc_prepare_authentication( These APIs are used internally by Kibana in order to provide OpenID Connect based authentication, but can also be used by other, custom web applications or other clients.

- ``_ + ``_ :param iss: In the case of a third party initiated single sign on, this is the issuer identifier for the OP that the RP is to send the authentication request @@ -3048,7 +3048,7 @@ async def put_privileges(

Action names can contain any number of printable ASCII characters and must contain at least one of the following characters: /, *, :.

- ``_ + ``_ :param privileges: :param refresh: If `true` (the default) then refresh the affected shards to make @@ -3200,7 +3200,7 @@ async def put_role( File-based role management is not available in Elastic Serverless.

- ``_ + ``_ :param name: The name of the role that is being created or updated. On Elasticsearch Serverless, the role name must begin with a letter or digit and can only @@ -3335,7 +3335,7 @@ async def put_role_mapping( If the format of the template is set to "json" then the template is expected to produce a JSON string or an array of JSON strings for the role names.

- ``_ + ``_ :param name: The distinct name that identifies the role mapping. The name is used solely as an identifier to facilitate interaction via the API; it does @@ -3437,7 +3437,7 @@ async def put_user( To change a user's password without updating any other fields, use the change password API.

- ``_ + ``_ :param username: An identifier for the user. NOTE: Usernames must be at least 1 and no more than 507 characters. They can contain alphanumeric characters @@ -3556,7 +3556,7 @@ async def query_api_keys( If you have the read_security, manage_api_key, or greater privileges (including manage_security), this API returns all API keys regardless of ownership.

- ``_ + ``_ :param aggregations: Any aggregations to run over the corpus of returned API keys. Aggregations and queries work together. Aggregations are computed only @@ -3699,7 +3699,7 @@ async def query_role( Also, the results can be paginated and sorted.

- ``_ + ``_ :param from_: The starting document offset. It must not be negative. By default, you cannot page through more than 10,000 hits using the `from` and `size` @@ -3792,7 +3792,7 @@ async def query_user( This API is only for native users.

- ``_ + ``_ :param from_: The starting document offset. It must not be negative. By default, you cannot page through more than 10,000 hits using the `from` and `size` @@ -3885,7 +3885,7 @@ async def saml_authenticate( This API endpoint essentially exchanges SAML responses that indicate successful authentication in the IdP for Elasticsearch access and refresh tokens, which can be used for authentication against Elasticsearch.

- ``_ + ``_ :param content: The SAML response as it was sent by the user's browser, usually a Base64 encoded XML document. @@ -3958,7 +3958,7 @@ async def saml_complete_logout( The caller of this API must prepare the request accordingly so that this API can handle either of them.

- ``_ + ``_ :param ids: A JSON array with all the valid SAML Request Ids that the caller of the API has for the current user. @@ -4034,7 +4034,7 @@ async def saml_invalidate( Thus the user can be redirected back to their IdP.

- ``_ + ``_ :param query_string: The query part of the URL that the user was redirected to by the SAML IdP to initiate the Single Logout. This query should include @@ -4109,7 +4109,7 @@ async def saml_logout( If the SAML realm in Elasticsearch is configured accordingly and the SAML IdP supports this, the Elasticsearch response contains a URL to redirect the user to the IdP that contains a SAML logout request (starting an SP-initiated SAML Single Logout).

- ``_ + ``_ :param token: The access token that was returned as a response to calling the SAML authenticate API. Alternatively, the most recent token that was received @@ -4179,7 +4179,7 @@ async def saml_prepare_authentication( The caller of this API needs to store this identifier as it needs to be used in a following step of the authentication process.

- ``_ + ``_ :param acs: The Assertion Consumer Service URL that matches the one of the SAML realms in Elasticsearch. The realm is used to generate the authentication @@ -4240,7 +4240,7 @@ async def saml_service_provider_metadata( This API generates Service Provider metadata based on the configuration of a SAML realm in Elasticsearch.

- ``_ + ``_ :param realm_name: The name of the SAML realm in Elasticsearch. """ @@ -4293,7 +4293,7 @@ async def suggest_user_profiles( Elastic reserves the right to change or remove this feature in future releases without prior notice.

- ``_ + ``_ :param data: A comma-separated list of filters for the `data` field of the profile document. To return all content use `data=*`. To return a subset of content, @@ -4380,7 +4380,7 @@ async def update_api_key( This change can occur if the owner user's permissions have changed since the API key was created or last modified.

- ``_ + ``_ :param id: The ID of the API key to update. :param expiration: The expiration time for the API key. By default, API keys @@ -4468,7 +4468,7 @@ async def update_cross_cluster_api_key(

NOTE: This API cannot update REST API keys, which should be updated by either the update API key or bulk update API keys API.

- ``_ + ``_ :param id: The ID of the cross-cluster API key to update. :param access: The access to be granted to this API key. The access is composed @@ -4547,7 +4547,7 @@ async def update_settings( This API does not yet support configuring the settings for indices before they are in use.

- ``_ + ``_ :param master_timeout: The period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails @@ -4632,7 +4632,7 @@ async def update_user_profile_data( The update_profile_data global privilege grants privileges for updating only the allowed namespaces.

- ``_ + ``_ :param uid: A unique identifier for the user profile. :param data: Non-searchable data that you want to associate with the user profile. diff --git a/elasticsearch/_async/client/shutdown.py b/elasticsearch/_async/client/shutdown.py index 5dbc33e92..fce85995d 100644 --- a/elasticsearch/_async/client/shutdown.py +++ b/elasticsearch/_async/client/shutdown.py @@ -53,7 +53,7 @@ async def delete_node(

If the operator privileges feature is enabled, you must be an operator to use this API.

- ``_ + ``_ :param node_id: The node id of node to be removed from the shutdown state :param master_timeout: Period to wait for a connection to the master node. If @@ -112,7 +112,7 @@ async def get_node(

If the operator privileges feature is enabled, you must be an operator to use this API.

- ``_ + ``_ :param node_id: Which node for which to retrieve the shutdown status :param master_timeout: Period to wait for a connection to the master node. If @@ -187,7 +187,7 @@ async def put_node( Monitor the node shutdown status to determine when it is safe to stop Elasticsearch.

- ``_ + ``_ :param node_id: The node identifier. This parameter is not validated against the cluster's active nodes. This enables you to register a node for shut diff --git a/elasticsearch/_async/client/simulate.py b/elasticsearch/_async/client/simulate.py index bb636ddb6..d3c13f311 100644 --- a/elasticsearch/_async/client/simulate.py +++ b/elasticsearch/_async/client/simulate.py @@ -81,7 +81,7 @@ async def ingest( These will be used in place of the pipeline definitions that are already in the system. This can be used to replace existing pipeline definitions or to create new ones. The pipeline substitutions are used only within this request.

- ``_ + ``_ :param docs: Sample documents to test in the pipeline. :param index: The index to simulate ingesting into. This value can be overridden diff --git a/elasticsearch/_async/client/slm.py b/elasticsearch/_async/client/slm.py index 3eaafd865..aefc3f4fa 100644 --- a/elasticsearch/_async/client/slm.py +++ b/elasticsearch/_async/client/slm.py @@ -45,7 +45,7 @@ async def delete_lifecycle( This operation prevents any future snapshots from being taken but does not cancel in-progress snapshots or remove previously-taken snapshots.

- ``_ + ``_ :param policy_id: The id of the snapshot lifecycle policy to remove :param master_timeout: The period to wait for a connection to the master node. @@ -101,7 +101,7 @@ async def execute_lifecycle( The snapshot policy is normally applied according to its schedule, but you might want to manually run a policy before performing an upgrade or other maintenance.

- ``_ + ``_ :param policy_id: The id of the snapshot lifecycle policy to be executed :param master_timeout: The period to wait for a connection to the master node. @@ -156,7 +156,7 @@ async def execute_retention( The retention policy is normally applied according to its schedule.

- ``_ + ``_ :param master_timeout: The period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails @@ -208,7 +208,7 @@ async def get_lifecycle( Get snapshot lifecycle policy definitions and information about the latest snapshot attempts.

- ``_ + ``_ :param policy_id: Comma-separated list of snapshot lifecycle policies to retrieve :param master_timeout: The period to wait for a connection to the master node. @@ -265,7 +265,7 @@ async def get_stats( Get global and policy-level statistics about actions taken by snapshot lifecycle management.

- ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails and @@ -315,7 +315,7 @@ async def get_status(

Get the snapshot lifecycle management status.

- ``_ + ``_ :param master_timeout: The period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails @@ -379,7 +379,7 @@ async def put_lifecycle( Only the latest version of a policy is stored.

- ``_ + ``_ :param policy_id: The identifier for the snapshot lifecycle policy you want to create or update. @@ -465,7 +465,7 @@ async def start( Manually starting SLM is necessary only if it has been stopped using the stop SLM API.

- ``_ + ``_ :param master_timeout: The period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails @@ -523,7 +523,7 @@ async def stop( Use the get snapshot lifecycle management status API to see if SLM is running.

- ``_ + ``_ :param master_timeout: The period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails diff --git a/elasticsearch/_async/client/snapshot.py b/elasticsearch/_async/client/snapshot.py index 9c1f993c4..0669c6971 100644 --- a/elasticsearch/_async/client/snapshot.py +++ b/elasticsearch/_async/client/snapshot.py @@ -50,7 +50,7 @@ async def cleanup_repository( Trigger the review of the contents of a snapshot repository and delete any stale data not referenced by existing snapshots.

- ``_ + ``_ :param name: The name of the snapshot repository to clean up. :param master_timeout: The period to wait for a connection to the master node. @@ -105,7 +105,6 @@ async def clone( human: t.Optional[bool] = None, master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, pretty: t.Optional[bool] = None, - timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -115,7 +114,7 @@ async def clone( Clone part of all of a snapshot into another snapshot in the same repository.

- ``_ + ``_ :param repository: The name of the snapshot repository that both source and target snapshot belong to. @@ -126,8 +125,6 @@ async def clone( :param master_timeout: The period to wait for the master node. If the master node is not available before the timeout expires, the request fails and returns an error. To indicate that the request should never timeout, set it to `-1`. - :param timeout: The period of time to wait for a response. If no response is - received before the timeout expires, the request fails and returns an error. """ if repository in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'repository'") @@ -155,8 +152,6 @@ async def clone( __query["master_timeout"] = master_timeout if pretty is not None: __query["pretty"] = pretty - if timeout is not None: - __query["timeout"] = timeout if not __body: if indices is not None: __body["indices"] = indices @@ -216,7 +211,7 @@ async def create( Take a snapshot of a cluster or of data streams and indices.

- ``_ + ``_ :param repository: The name of the repository for the snapshot. :param snapshot: The name of the snapshot. It supportes date math. It must be @@ -343,7 +338,7 @@ async def create_repository( If both parameters are specified, only the query parameter is used.

- ``_ + ``_ :param name: The name of the snapshot repository to register or update. :param repository: @@ -415,7 +410,7 @@ async def delete(

Delete snapshots.

- ``_ + ``_ :param repository: The name of the repository to delete a snapshot from. :param snapshot: A comma-separated list of snapshot names to delete. It also @@ -474,7 +469,7 @@ async def delete_repository( The snapshots themselves are left untouched and in place.

- ``_ + ``_ :param name: The ame of the snapshot repositories to unregister. Wildcard (`*`) patterns are supported. @@ -560,7 +555,7 @@ async def get( Snapshots concurrently created may be seen during an iteration.

- ``_ + ``_ :param repository: A comma-separated list of snapshot repository names used to limit the request. Wildcard (`*`) expressions are supported. @@ -686,7 +681,7 @@ async def get_repository(

Get snapshot repository information.

- ``_ + ``_ :param name: A comma-separated list of snapshot repository names used to limit the request. Wildcard (`*`) expressions are supported including combining @@ -830,7 +825,7 @@ async def repository_analyze( Some operations also verify the behavior on small blobs with sizes other than 8 bytes.

- ``_ + ``_ :param name: The name of the repository. :param blob_count: The total number of blobs to write to the repository during @@ -963,7 +958,7 @@ async def repository_verify_integrity( The response body format is therefore not considered stable and may be different in newer versions.

- ``_ + ``_ :param name: The name of the snapshot repository. :param blob_thread_pool_concurrency: If `verify_blob_contents` is `true`, this @@ -1085,7 +1080,7 @@ async def restore(

If your snapshot contains data from App Search or Workplace Search, you must restore the Enterprise Search encryption key before you restore the snapshot.

- ``_ + ``_ :param repository: The name of the repository to restore a snapshot from. :param snapshot: The name of the snapshot to restore. @@ -1235,7 +1230,7 @@ async def status( These requests can also tax machine resources and, when using cloud storage, incur high processing costs.

- ``_ + ``_ :param repository: The snapshot repository name used to limit the request. It supports wildcards (`*`) if `` isn't specified. @@ -1303,7 +1298,7 @@ async def verify_repository( Check for common misconfigurations in a snapshot repository.

- ``_ + ``_ :param name: The name of the snapshot repository to verify. :param master_timeout: The period to wait for the master node. If the master diff --git a/elasticsearch/_async/client/sql.py b/elasticsearch/_async/client/sql.py index 3eb37a6cc..8b868c777 100644 --- a/elasticsearch/_async/client/sql.py +++ b/elasticsearch/_async/client/sql.py @@ -44,7 +44,7 @@ async def clear_cursor(

Clear an SQL search cursor.

- ``_ + ``_ :param cursor: Cursor to clear. """ @@ -99,7 +99,7 @@ async def delete_async( - ``_ + ``_ :param id: The identifier for the search. """ @@ -150,7 +150,7 @@ async def get_async(

If the Elasticsearch security features are enabled, only the user who first submitted the SQL search can retrieve the search using this API.

- ``_ + ``_ :param id: The identifier for the search. :param delimiter: The separator for CSV results. The API supports this parameter @@ -212,7 +212,7 @@ async def get_async_status( Get the current status of an async SQL search or a stored synchronous SQL search.

- ``_ + ``_ :param id: The identifier for the search. """ @@ -301,7 +301,7 @@ async def query( Run an SQL request.

- ``_ + ``_ :param allow_partial_search_results: If `true`, the response has partial results when there are shard request timeouts or shard failures. If `false`, the @@ -427,7 +427,7 @@ async def translate( It accepts the same request body parameters as the SQL search API, excluding cursor.

- ``_ + ``_ :param query: The SQL query to run. :param fetch_size: The maximum number of rows (or entries) to return in one response. diff --git a/elasticsearch/_async/client/ssl.py b/elasticsearch/_async/client/ssl.py index 468c7b93c..8d5e68258 100644 --- a/elasticsearch/_async/client/ssl.py +++ b/elasticsearch/_async/client/ssl.py @@ -52,7 +52,7 @@ async def certificates(

If Elasticsearch is configured to use a keystore or truststore, the API output includes all certificates in that store, even though some of the certificates might not be in active use within the cluster.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_ssl/certificates" diff --git a/elasticsearch/_async/client/synonyms.py b/elasticsearch/_async/client/synonyms.py index 26b248a35..5807a29c0 100644 --- a/elasticsearch/_async/client/synonyms.py +++ b/elasticsearch/_async/client/synonyms.py @@ -53,7 +53,7 @@ async def delete_synonym( When the synonyms set is not used in analyzers, you will be able to delete it.

- ``_ + ``_ :param id: The synonyms set identifier to delete. """ @@ -98,7 +98,7 @@ async def delete_synonym_rule( Delete a synonym rule from a synonym set.

- ``_ + ``_ :param set_id: The ID of the synonym set to update. :param rule_id: The ID of the synonym rule to delete. @@ -151,7 +151,7 @@ async def get_synonym(

Get a synonym set.

- ``_ + ``_ :param id: The synonyms set identifier to retrieve. :param from_: The starting offset for query rules to retrieve. @@ -202,7 +202,7 @@ async def get_synonym_rule( Get a synonym rule from a synonym set.

- ``_ + ``_ :param set_id: The ID of the synonym set to retrieve the synonym rule from. :param rule_id: The ID of the synonym rule to retrieve. @@ -255,7 +255,7 @@ async def get_synonyms_sets( Get a summary of all defined synonym sets.

- ``_ + ``_ :param from_: The starting offset for synonyms sets to retrieve. :param size: The maximum number of synonyms sets to retrieve. @@ -311,7 +311,7 @@ async def put_synonym( This is equivalent to invoking the reload search analyzers API for all indices that use the synonyms set.

- ``_ + ``_ :param id: The ID of the synonyms set to be created or updated. :param synonyms_set: The synonym rules definitions for the synonyms set. @@ -370,7 +370,7 @@ async def put_synonym_rule(

When you update a synonym rule, all analyzers using the synonyms set will be reloaded automatically to reflect the new rule.

- ``_ + ``_ :param set_id: The ID of the synonym set. :param rule_id: The ID of the synonym rule to be updated or created. diff --git a/elasticsearch/_async/client/tasks.py b/elasticsearch/_async/client/tasks.py index e03f0d363..629d68129 100644 --- a/elasticsearch/_async/client/tasks.py +++ b/elasticsearch/_async/client/tasks.py @@ -60,7 +60,7 @@ async def cancel( You can also use the node hot threads API to obtain detailed information about the work the system is doing instead of completing the cancelled task.

- ``_ + ``_ :param task_id: The task identifier. :param actions: A comma-separated list or wildcard expression of actions that @@ -128,7 +128,7 @@ async def get(

If the task identifier is not found, a 404 response code indicates that there are no resources that match the request.

- ``_ + ``_ :param task_id: The task identifier. :param timeout: The period to wait for a response. If no response is received @@ -238,7 +238,7 @@ async def list( The X-Opaque-Id in the children headers is the child task of the task that was initiated by the REST request.

- ``_ + ``_ :param actions: A comma-separated list or wildcard expression of actions used to limit the request. For example, you can use `cluser:*` to retrieve all diff --git a/elasticsearch/_async/client/text_structure.py b/elasticsearch/_async/client/text_structure.py index 6307f20bb..08b29d2b8 100644 --- a/elasticsearch/_async/client/text_structure.py +++ b/elasticsearch/_async/client/text_structure.py @@ -72,7 +72,7 @@ async def find_field_structure( It helps determine why the returned structure was chosen.

- ``_ + ``_ :param field: The field that should be analyzed. :param index: The name of the index that contains the analyzed field. @@ -259,7 +259,7 @@ async def find_message_structure( It helps determine why the returned structure was chosen.

- ``_ + ``_ :param messages: The list of messages you want to analyze. :param column_names: If the format is `delimited`, you can specify the column @@ -433,7 +433,7 @@ async def find_structure( However, you can optionally override some of the decisions about the text structure by specifying one or more query parameters.

- ``_ + ``_ :param text_files: :param charset: The text's character set. It must be a character set that is @@ -620,7 +620,7 @@ async def test_grok_pattern( The API indicates whether the lines match the pattern together with the offsets and lengths of the matched substrings.

- ``_ + ``_ :param grok_pattern: The Grok pattern to run on the text. :param text: The lines of text to run the Grok pattern on. diff --git a/elasticsearch/_async/client/transform.py b/elasticsearch/_async/client/transform.py index 191c959d3..27a512139 100644 --- a/elasticsearch/_async/client/transform.py +++ b/elasticsearch/_async/client/transform.py @@ -44,7 +44,7 @@ async def delete_transform(

Delete a transform.

- ``_ + ``_ :param transform_id: Identifier for the transform. :param delete_dest_index: If this value is true, the destination index is deleted @@ -108,7 +108,7 @@ async def get_transform( Get configuration information for transforms.

- ``_ + ``_ :param transform_id: Identifier for the transform. It can be a transform identifier or a wildcard expression. You can get information for all transforms by using @@ -181,7 +181,7 @@ async def get_transform_stats(

Get usage information for transforms.

- ``_ + ``_ :param transform_id: Identifier for the transform. It can be a transform identifier or a wildcard expression. You can get information for all transforms by using @@ -269,7 +269,7 @@ async def preview_transform( types of the source index and the transform aggregations.

- ``_ + ``_ :param transform_id: Identifier for the transform to preview. If you specify this path parameter, you cannot provide transform configuration details in @@ -406,7 +406,7 @@ async def put_transform( give users any privileges on .data-frame-internal* indices.

- ``_ + ``_ :param transform_id: Identifier for the transform. This identifier can contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and underscores. @@ -512,7 +512,7 @@ async def reset_transform( If the destination index was created by the transform, it is deleted.

- ``_ + ``_ :param transform_id: Identifier for the transform. This identifier can contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and underscores. @@ -572,7 +572,7 @@ async def schedule_now_transform( is called again in the meantime.

- ``_ + ``_ :param transform_id: Identifier for the transform. :param timeout: Controls the time to wait for the scheduling to take place @@ -635,7 +635,7 @@ async def start_transform( destination indices, the transform fails when it attempts unauthorized operations.

- ``_ + ``_ :param transform_id: Identifier for the transform. :param from_: Restricts the set of transformed entities to those changed after @@ -693,7 +693,7 @@ async def stop_transform( Stops one or more transforms.

- ``_ + ``_ :param transform_id: Identifier for the transform. To stop multiple transforms, use a comma-separated list or a wildcard expression. To stop all transforms, @@ -795,7 +795,7 @@ async def update_transform( time of update and runs with those privileges.

- ``_ + ``_ :param transform_id: Identifier for the transform. :param defer_validation: When true, deferrable validations are not run. This @@ -890,7 +890,7 @@ async def upgrade_transforms( You may want to perform a recent cluster backup prior to the upgrade.

- ``_ + ``_ :param dry_run: When true, the request checks for updates but does not run them. :param timeout: Period to wait for a response. If no response is received before diff --git a/elasticsearch/_async/client/watcher.py b/elasticsearch/_async/client/watcher.py index 30f69d0e7..5afde82bd 100644 --- a/elasticsearch/_async/client/watcher.py +++ b/elasticsearch/_async/client/watcher.py @@ -48,7 +48,7 @@ async def ack_watch( This happens when the condition of the watch is not met (the condition evaluates to false).

- ``_ + ``_ :param watch_id: The watch identifier. :param action_id: A comma-separated list of the action identifiers to acknowledge. @@ -104,7 +104,7 @@ async def activate_watch( A watch can be either active or inactive.

- ``_ + ``_ :param watch_id: The watch identifier. """ @@ -148,7 +148,7 @@ async def deactivate_watch( A watch can be either active or inactive.

- ``_ + ``_ :param watch_id: The watch identifier. """ @@ -196,7 +196,7 @@ async def delete_watch( When Elasticsearch security features are enabled, make sure no write privileges are granted to anyone for the .watches index.

- ``_ + ``_ :param id: The watch identifier. """ @@ -277,7 +277,7 @@ async def execute_watch(

When using the run watch API, the authorization data of the user that called the API will be used as a base, instead of the information who stored the watch.

- ``_ + ``_ :param id: The watch identifier. :param action_modes: Determines how to handle the watch actions as part of the @@ -365,7 +365,7 @@ async def get_settings( Only a subset of settings are shown, for example index.auto_expand_replicas and index.number_of_replicas.

- ``_ + ``_ :param master_timeout: The period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails @@ -410,7 +410,7 @@ async def get_watch(

Get a watch.

- ``_ + ``_ :param id: The watch identifier. """ @@ -485,7 +485,7 @@ async def put_watch( If the user is able to read index a, but not index b, the same will apply when the watch runs.

- ``_ + ``_ :param id: The identifier for the watch. :param actions: The list of actions that will be run if the condition matches. @@ -598,7 +598,7 @@ async def query_watches(

Note that only the _id and metadata.* fields are queryable or sortable.

- ``_ + ``_ :param from_: The offset from the first result to fetch. It must be non-negative. :param query: A query that filters the watches to be returned. @@ -673,7 +673,7 @@ async def start( Start the Watcher service if it is not already running.

- ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. """ @@ -739,7 +739,7 @@ async def stats( You retrieve more metrics by using the metric parameter.

- ``_ + ``_ :param metric: Defines which additional metrics are included in the response. :param emit_stacktraces: Defines whether stack traces are generated for each @@ -790,7 +790,7 @@ async def stop( Stop the Watcher service if it is running.

- ``_ + ``_ :param master_timeout: The period to wait for the master node. If the master node is not available before the timeout expires, the request fails and returns @@ -851,7 +851,7 @@ async def update_settings( Watcher shards must always be in the data_content tier.

- ``_ + ``_ :param index_auto_expand_replicas: :param index_number_of_replicas: diff --git a/elasticsearch/_async/client/xpack.py b/elasticsearch/_async/client/xpack.py index 710d36cb1..543e651ba 100644 --- a/elasticsearch/_async/client/xpack.py +++ b/elasticsearch/_async/client/xpack.py @@ -54,7 +54,7 @@ async def info( - ``_ + ``_ :param accept_enterprise: If this param is used it must be set to true :param categories: A comma-separated list of the information categories to include @@ -103,7 +103,7 @@ async def usage( The API also provides some usage statistics.

- ``_ + ``_ :param master_timeout: The period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails diff --git a/elasticsearch/_sync/client/__init__.py b/elasticsearch/_sync/client/__init__.py index 7b70b1b13..6e97b41e6 100644 --- a/elasticsearch/_sync/client/__init__.py +++ b/elasticsearch/_sync/client/__init__.py @@ -637,7 +637,7 @@ def bulk( The other two shards that make up the index do not participate in the _bulk request at all.

- ``_ + ``_ :param operations: :param index: The name of the data stream, index, or index alias to perform bulk @@ -762,7 +762,7 @@ def clear_scroll( Clear the search context and results for a scrolling search.

- ``_ + ``_ :param scroll_id: The scroll IDs to clear. To clear all scroll IDs, use `_all`. """ @@ -819,7 +819,7 @@ def close_point_in_time( However, keeping points in time has a cost; close them as soon as they are no longer required for search requests.

- ``_ + ``_ :param id: The ID of the point-in-time. """ @@ -903,7 +903,7 @@ def count( This means that replicas increase the scalability of the count.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases to search. It supports wildcards (`*`). To search all data streams and indices, @@ -1105,7 +1105,7 @@ def create( The _shards section of the API response reveals the number of shard copies on which replication succeeded and failed.

- ``_ + ``_ :param index: The name of the data stream or index to target. If the target doesn't exist and matches the name or wildcard (`*`) pattern of an index template @@ -1272,7 +1272,7 @@ def delete( It then gets redirected into the primary shard within that ID group and replicated (if needed) to shard replicas within that ID group.

- ``_ + ``_ :param index: The name of the target index. :param id: A unique identifier for the document. @@ -1461,7 +1461,7 @@ def delete_by_query( The get task status API will continue to list the delete by query task until this task checks that it has been cancelled and terminates itself.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases to search. It supports wildcards (`*`). To search all data streams or indices, @@ -1658,7 +1658,7 @@ def delete_by_query_rethrottle( Rethrottling that speeds up the query takes effect immediately but rethrotting that slows down the query takes effect after completing the current batch to prevent scroll timeouts.

- ``_ + ``_ :param task_id: The ID for the task. :param requests_per_second: The throttle for this request in sub-requests per @@ -1708,7 +1708,7 @@ def delete_script( Deletes a stored script or search template.

- ``_ + ``_ :param id: The identifier for the stored script or search template. :param master_timeout: The period to wait for a connection to the master node. @@ -1792,7 +1792,7 @@ def exists( Elasticsearch cleans up deleted documents in the background as you continue to index more data.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases. It supports wildcards (`*`). @@ -1915,7 +1915,7 @@ def exists_source(

A document's source is not available if it is disabled in the mapping.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases. It supports wildcards (`*`). @@ -2021,7 +2021,7 @@ def explain( It computes a score explanation for a query and a specific document.

- ``_ + ``_ :param index: Index names that are used to limit the request. Only a single index name can be provided to this parameter. @@ -2156,7 +2156,7 @@ def field_caps( For example, a runtime field with a type of keyword is returned the same as any other field that belongs to the keyword family.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (*). To target all data streams @@ -2317,7 +2317,7 @@ def get( Elasticsearch cleans up deleted documents in the background as you continue to index more data.

- ``_ + ``_ :param index: The name of the index that contains the document. :param id: A unique document identifier. @@ -2424,7 +2424,7 @@ def get_script( Retrieves a stored script or search template.

- ``_ + ``_ :param id: The identifier for the stored script or search template. :param master_timeout: The period to wait for the master node. If the master @@ -2473,7 +2473,7 @@ def get_script_context(

Get a list of supported script contexts and their methods.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_script_context" @@ -2512,7 +2512,7 @@ def get_script_languages(

Get a list of available script types, languages, and contexts.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_script_language" @@ -2577,7 +2577,7 @@ def get_source( - ``_ + ``_ :param index: The name of the index that contains the document. :param id: A unique document identifier. @@ -2677,7 +2677,7 @@ def health_report( When setting up automated polling of the API for health status, set verbose to false to disable the more expensive analysis logic.

- ``_ + ``_ :param feature: A feature of the cluster, as returned by the top-level health report API. @@ -2842,7 +2842,7 @@ def index( - ``_ + ``_ :param index: The name of the data stream or index to target. If the target doesn't exist and matches the name or wildcard (`*`) pattern of an index template @@ -2974,7 +2974,7 @@ def info( Get basic build, version, and cluster information.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/" @@ -3048,7 +3048,7 @@ def knn_search( - ``_ + ``_ :param index: A comma-separated list of index names to search; use `_all` or to perform the operation on all indices. @@ -3164,7 +3164,7 @@ def mget( You can include the stored_fields query parameter in the request URI to specify the defaults to use when there are no per-document instructions.

- ``_ + ``_ :param index: Name of the index to retrieve documents from when `ids` are specified, or when a document in the `docs` array does not specify an index. @@ -3299,7 +3299,7 @@ def msearch( When sending requests to this endpoint the Content-Type header should be set to application/x-ndjson.

- ``_ + ``_ :param searches: :param index: Comma-separated list of data streams, indices, and index aliases @@ -3446,7 +3446,7 @@ def msearch_template( - ``_ + ``_ :param search_templates: :param index: A comma-separated list of data streams, indices, and aliases to @@ -3551,7 +3551,7 @@ def mtermvectors( The mapping used is determined by the specified _index.

- ``_ + ``_ :param index: The name of the index that contains the documents. :param docs: An array of existing or artificial documents. @@ -3692,7 +3692,7 @@ def open_point_in_time( You can check how many point-in-times (that is, search contexts) are open with the nodes stats API.

- ``_ + ``_ :param index: A comma-separated list of index names to open point in time; use `_all` or empty string to perform the operation on all indices @@ -3790,7 +3790,7 @@ def put_script( Creates or updates a stored script or search template.

- ``_ + ``_ :param id: The identifier for the stored script or search template. It must be unique within the cluster. @@ -3880,7 +3880,7 @@ def rank_eval(

Evaluate the quality of ranked search results over a set of typical search queries.

- ``_ + ``_ :param requests: A set of typical search requests, together with their provided ratings. @@ -4112,7 +4112,7 @@ def reindex( It is not possible to configure SSL in the body of the reindex request.

- ``_ + ``_ :param dest: The destination you are copying to. :param source: The source you are copying from. @@ -4236,7 +4236,7 @@ def reindex_rethrottle( This behavior prevents scroll timeouts.

- ``_ + ``_ :param task_id: The task identifier, which can be found by using the tasks API. :param requests_per_second: The throttle for this request in sub-requests per @@ -4292,7 +4292,7 @@ def render_search_template(

Render a search template as a search request body.

- ``_ + ``_ :param id: The ID of the search template to render. If no `source` is specified, this or the `id` request body parameter is required. @@ -4386,7 +4386,7 @@ def scripts_painless_execute(

Each context requires a script, but additional parameters depend on the context you're using for that script.

- ``_ + ``_ :param context: The context that the script should run in. NOTE: Result ordering in the field contexts is not guaranteed. @@ -4459,7 +4459,7 @@ def scroll(

IMPORTANT: Results from a scrolling search reflect the state of the index at the time of the initial search request. Subsequent indexing or document changes only affect later search and scroll requests.

- ``_ + ``_ :param scroll_id: The scroll ID of the search. :param rest_total_hits_as_int: If true, the API response’s hit.total property @@ -4664,7 +4664,7 @@ def search( This situation can occur because the splitting criterion is based on Lucene document IDs, which are not stable across changes to the index.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases to search. It supports wildcards (`*`). To search all data streams and indices, @@ -5412,7 +5412,7 @@ def search_mvt( Elasticsearch uses the H3 resolution that is closest to the corresponding geotile density.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, or aliases to search :param field: Field containing geospatial data to return @@ -5586,7 +5586,7 @@ def search_shards(

If the Elasticsearch security features are enabled, you must have the view_index_metadata or manage index privilege for the target data stream, index, or alias.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases to search. It supports wildcards (`*`). To search all data streams and indices, @@ -5697,7 +5697,7 @@ def search_template(

Run a search with a search template.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases to search. It supports wildcards (`*`). @@ -5840,7 +5840,7 @@ def terms_enum( - ``_ + ``_ :param index: A comma-separated list of data streams, indices, and index aliases to search. Wildcard (`*`) expressions are supported. To search all data streams @@ -5989,7 +5989,7 @@ def termvectors( Use routing only to hit a particular shard.

- ``_ + ``_ :param index: The name of the index that contains the document. :param id: A unique identifier for the document. @@ -6160,7 +6160,7 @@ def update( In addition to _source, you can access the following variables through the ctx map: _index, _type, _id, _version, _routing, and _now (the current timestamp).

- ``_ + ``_ :param index: The name of the target index. By default, the index is created automatically if it doesn't exist. @@ -6398,7 +6398,7 @@ def update_by_query( This API enables you to only modify the source of matching documents; you cannot move them.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases to search. It supports wildcards (`*`). To search all data streams or indices, @@ -6618,7 +6618,7 @@ def update_by_query_rethrottle( Rethrottling that speeds up the query takes effect immediately but rethrotting that slows down the query takes effect after completing the current batch to prevent scroll timeouts.

- ``_ + ``_ :param task_id: The ID for the task. :param requests_per_second: The throttle for this request in sub-requests per diff --git a/elasticsearch/_sync/client/async_search.py b/elasticsearch/_sync/client/async_search.py index 3042ae07a..fae94879a 100644 --- a/elasticsearch/_sync/client/async_search.py +++ b/elasticsearch/_sync/client/async_search.py @@ -44,7 +44,7 @@ def delete( If the Elasticsearch security features are enabled, the deletion of a specific async search is restricted to: the authenticated user that submitted the original search request; users that have the cancel_task cluster privilege.

- ``_ + ``_ :param id: A unique identifier for the async search. """ @@ -94,7 +94,7 @@ def get( If the Elasticsearch security features are enabled, access to the results of a specific async search is restricted to the user or API key that submitted it.

- ``_ + ``_ :param id: A unique identifier for the async search. :param keep_alive: The length of time that the async search should be available @@ -164,7 +164,7 @@ def status( - ``_ + ``_ :param id: A unique identifier for the async search. :param keep_alive: The length of time that the async search needs to be available. @@ -345,7 +345,7 @@ def submit( The maximum allowed size for a stored async search response can be set by changing the search.max_async_search_response_size cluster level setting.

- ``_ + ``_ :param index: A comma-separated list of index names to search; use `_all` or empty string to perform the operation on all indices diff --git a/elasticsearch/_sync/client/autoscaling.py b/elasticsearch/_sync/client/autoscaling.py index 98fe5d109..82dcdcc93 100644 --- a/elasticsearch/_sync/client/autoscaling.py +++ b/elasticsearch/_sync/client/autoscaling.py @@ -44,7 +44,7 @@ def delete_autoscaling_policy(

NOTE: This feature is designed for indirect use by Elasticsearch Service, Elastic Cloud Enterprise, and Elastic Cloud on Kubernetes. Direct use is not supported.

- ``_ + ``_ :param name: the name of the autoscaling policy :param master_timeout: Period to wait for a connection to the master node. If @@ -104,7 +104,7 @@ def get_autoscaling_capacity( Do not use this information to make autoscaling decisions.

- ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails and @@ -151,7 +151,7 @@ def get_autoscaling_policy(

NOTE: This feature is designed for indirect use by Elasticsearch Service, Elastic Cloud Enterprise, and Elastic Cloud on Kubernetes. Direct use is not supported.

- ``_ + ``_ :param name: the name of the autoscaling policy :param master_timeout: Period to wait for a connection to the master node. If @@ -206,7 +206,7 @@ def put_autoscaling_policy(

NOTE: This feature is designed for indirect use by Elasticsearch Service, Elastic Cloud Enterprise, and Elastic Cloud on Kubernetes. Direct use is not supported.

- ``_ + ``_ :param name: the name of the autoscaling policy :param policy: diff --git a/elasticsearch/_sync/client/cat.py b/elasticsearch/_sync/client/cat.py index af14bf7f8..2a218a36c 100644 --- a/elasticsearch/_sync/client/cat.py +++ b/elasticsearch/_sync/client/cat.py @@ -64,7 +64,7 @@ def aliases(

IMPORTANT: CAT APIs are only intended for human consumption using the command line or the Kibana console. They are not intended for use by applications. For application consumption, use the aliases API.

- ``_ + ``_ :param name: A comma-separated list of aliases to retrieve. Supports wildcards (`*`). To retrieve all aliases, omit this parameter or use `*` or `_all`. @@ -154,7 +154,7 @@ def allocation(

IMPORTANT: CAT APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications.

- ``_ + ``_ :param node_id: A comma-separated list of node identifiers or names used to limit the returned information. @@ -243,7 +243,7 @@ def component_templates( They are not intended for use by applications. For application consumption, use the get component template API.

- ``_ + ``_ :param name: The name of the component template. It accepts wildcard expressions. If it is omitted, all component templates are returned. @@ -327,7 +327,7 @@ def count( They are not intended for use by applications. For application consumption, use the count API.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases used to limit the request. It supports wildcards (`*`). To target all data streams @@ -405,7 +405,7 @@ def fielddata( They are not intended for use by applications. For application consumption, use the nodes stats API.

- ``_ + ``_ :param fields: Comma-separated list of fields used to limit returned information. To retrieve all fields, omit this parameter. @@ -491,7 +491,7 @@ def health( You also can use the API to track the recovery of a large cluster over a longer period of time.

- ``_ + ``_ :param format: Specifies the format to return the columnar data in, can be set to `text`, `json`, `cbor`, `yaml`, or `smile`. @@ -549,7 +549,7 @@ def help(self) -> TextApiResponse:

Get help for the CAT APIs.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_cat" @@ -616,7 +616,7 @@ def indices( They are not intended for use by applications. For application consumption, use an index endpoint.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). To target all data streams @@ -714,7 +714,7 @@ def master(

IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the nodes info API.

- ``_ + ``_ :param format: Specifies the format to return the columnar data in, can be set to `text`, `json`, `cbor`, `yaml`, or `smile`. @@ -892,7 +892,7 @@ def ml_data_frame_analytics( application consumption, use the get data frame analytics jobs statistics API.

- ``_ + ``_ :param id: The ID of the data frame analytics to fetch :param allow_no_match: Whether to ignore if a wildcard expression matches no @@ -1060,7 +1060,7 @@ def ml_datafeeds( application consumption, use the get datafeed statistics API.

- ``_ + ``_ :param datafeed_id: A numerical character string that uniquely identifies the datafeed. @@ -1426,7 +1426,7 @@ def ml_jobs( application consumption, use the get anomaly detection job statistics API.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param allow_no_match: Specifies what to do when the request: * Contains wildcard @@ -1611,7 +1611,7 @@ def ml_trained_models( application consumption, use the get trained models statistics API.

- ``_ + ``_ :param model_id: A unique identifier for the trained model. :param allow_no_match: Specifies what to do when the request: contains wildcard @@ -1704,7 +1704,7 @@ def nodeattrs( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the nodes info API.

- ``_ + ``_ :param format: Specifies the format to return the columnar data in, can be set to `text`, `json`, `cbor`, `yaml`, or `smile`. @@ -1787,7 +1787,7 @@ def nodes( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the nodes info API.

- ``_ + ``_ :param bytes: The unit used to display byte values. :param format: Specifies the format to return the columnar data in, can be set @@ -1874,7 +1874,7 @@ def pending_tasks( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the pending cluster tasks API.

- ``_ + ``_ :param format: Specifies the format to return the columnar data in, can be set to `text`, `json`, `cbor`, `yaml`, or `smile`. @@ -1954,7 +1954,7 @@ def plugins( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the nodes info API.

- ``_ + ``_ :param format: Specifies the format to return the columnar data in, can be set to `text`, `json`, `cbor`, `yaml`, or `smile`. @@ -2042,7 +2042,7 @@ def recovery( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the index recovery API.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). To target all data streams @@ -2130,7 +2130,7 @@ def repositories( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the get snapshot repository API.

- ``_ + ``_ :param format: Specifies the format to return the columnar data in, can be set to `text`, `json`, `cbor`, `yaml`, or `smile`. @@ -2211,7 +2211,7 @@ def segments( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the index segments API.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). To target all data streams @@ -2305,7 +2305,7 @@ def shards( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). To target all data streams @@ -2394,7 +2394,7 @@ def snapshots( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the get snapshot API.

- ``_ + ``_ :param repository: A comma-separated list of snapshot repositories used to limit the request. Accepts wildcard expressions. `_all` returns all repositories. @@ -2487,7 +2487,7 @@ def tasks( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the task management API.

- ``_ + ``_ :param actions: The task action names, which are used to limit the response. :param detailed: If `true`, the response includes detailed information about @@ -2581,7 +2581,7 @@ def templates( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the get index template API.

- ``_ + ``_ :param name: The name of the template to return. Accepts wildcard expressions. If omitted, all templates are returned. @@ -2669,7 +2669,7 @@ def thread_pool( IMPORTANT: cat APIs are only intended for human consumption using the command line or Kibana console. They are not intended for use by applications. For application consumption, use the nodes info API.

- ``_ + ``_ :param thread_pool_patterns: A comma-separated list of thread pool names used to limit the request. Accepts wildcard expressions. @@ -2926,7 +2926,7 @@ def transforms( application consumption, use the get transform statistics API.

- ``_ + ``_ :param transform_id: A transform identifier or a wildcard expression. If you do not specify one of these options, the API returns information for all diff --git a/elasticsearch/_sync/client/ccr.py b/elasticsearch/_sync/client/ccr.py index 0eec10516..adc108f8b 100644 --- a/elasticsearch/_sync/client/ccr.py +++ b/elasticsearch/_sync/client/ccr.py @@ -43,7 +43,7 @@ def delete_auto_follow_pattern(

Delete a collection of cross-cluster replication auto-follow patterns.

- ``_ + ``_ :param name: The auto-follow pattern collection to delete. :param master_timeout: The period to wait for a connection to the master node. @@ -130,7 +130,7 @@ def follow( When the API returns, the follower index exists and cross-cluster replication starts replicating operations from the leader index to the follower index.

- ``_ + ``_ :param index: The name of the follower index. :param leader_index: The name of the index in the leader cluster to follow. @@ -259,7 +259,7 @@ def follow_info( For example, the results include follower index names, leader index names, replication options, and whether the follower indices are active or paused.

- ``_ + ``_ :param index: A comma-delimited list of follower index patterns. :param master_timeout: The period to wait for a connection to the master node. @@ -311,7 +311,7 @@ def follow_stats( The API returns shard-level stats about the "following tasks" associated with each shard for the specified indices.

- ``_ + ``_ :param index: A comma-delimited list of index patterns. :param timeout: The period to wait for a response. If no response is received @@ -380,7 +380,7 @@ def forget_follower( The only purpose of this API is to handle the case of failure to remove the following retention leases after the unfollow API is invoked.

- ``_ + ``_ :param index: the name of the leader index for which specified follower retention leases should be removed @@ -445,7 +445,7 @@ def get_auto_follow_pattern(

Get cross-cluster replication auto-follow patterns.

- ``_ + ``_ :param name: The auto-follow pattern collection that you want to retrieve. If you do not specify a name, the API returns information for all collections. @@ -505,7 +505,7 @@ def pause_auto_follow_pattern( Remote indices that were created while the pattern was paused will also be followed, unless they have been deleted or closed in the interim.

- ``_ + ``_ :param name: The name of the auto-follow pattern to pause. :param master_timeout: The period to wait for a connection to the master node. @@ -559,7 +559,7 @@ def pause_follow( You can pause and resume a follower index to change the configuration of the following task.

- ``_ + ``_ :param index: The name of the follower index. :param master_timeout: The period to wait for a connection to the master node. @@ -648,7 +648,7 @@ def put_auto_follow_pattern( NOTE: Follower indices that were configured automatically before updating an auto-follow pattern will remain unchanged even if they do not match against the new patterns.

- ``_ + ``_ :param name: The name of the collection of auto-follow patterns. :param remote_cluster: The remote cluster containing the leader indices to match @@ -782,7 +782,7 @@ def resume_auto_follow_pattern( Remote indices created while the pattern was paused will also be followed unless they have been deleted or closed in the interim.

- ``_ + ``_ :param name: The name of the auto-follow pattern to resume. :param master_timeout: The period to wait for a connection to the master node. @@ -860,7 +860,7 @@ def resume_follow( When this API returns, the follower index will resume fetching operations from the leader index.

- ``_ + ``_ :param index: The name of the follow index to resume following. :param master_timeout: Period to wait for a connection to the master node. @@ -951,7 +951,7 @@ def stats(

This API returns stats about auto-following and the same shard-level stats as the get follower stats API.

- ``_ + ``_ :param master_timeout: The period to wait for a connection to the master node. If the master node is not available before the timeout expires, the request @@ -1009,7 +1009,7 @@ def unfollow( - ``_ + ``_ :param index: The name of the follower index. :param master_timeout: The period to wait for a connection to the master node. diff --git a/elasticsearch/_sync/client/cluster.py b/elasticsearch/_sync/client/cluster.py index f7b1269cb..c8992f80d 100644 --- a/elasticsearch/_sync/client/cluster.py +++ b/elasticsearch/_sync/client/cluster.py @@ -54,7 +54,7 @@ def allocation_explain( This API can be very useful when attempting to diagnose why a shard is unassigned or why a shard continues to remain on its current node when you might expect otherwise.

- ``_ + ``_ :param current_node: Specifies the node ID or the name of the node to only explain a shard that is currently located on the specified node. @@ -130,7 +130,7 @@ def delete_component_template( Component templates are building blocks for constructing index templates that specify index mappings, settings, and aliases.

- ``_ + ``_ :param name: Comma-separated list or wildcard expression of component template names used to limit the request. @@ -185,7 +185,7 @@ def delete_voting_config_exclusions( Remove master-eligible nodes from the voting configuration exclusion list.

- ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. :param wait_for_removal: Specifies whether to wait for all excluded nodes to @@ -239,7 +239,7 @@ def exists_component_template( Returns information about whether a particular component template exists.

- ``_ + ``_ :param name: Comma-separated list of component template names used to limit the request. Wildcard (*) expressions are supported. @@ -298,7 +298,7 @@ def get_component_template( Get information about component templates.

- ``_ + ``_ :param name: Comma-separated list of component template names used to limit the request. Wildcard (`*`) expressions are supported. @@ -365,7 +365,7 @@ def get_settings( By default, it returns only settings that have been explicitly defined.

- ``_ + ``_ :param flat_settings: If `true`, returns settings in flat format. :param include_defaults: If `true`, returns default cluster settings from the @@ -457,7 +457,7 @@ def health( The cluster status is controlled by the worst index status.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and index aliases used to limit the request. Wildcard expressions (`*`) are supported. To target @@ -565,7 +565,7 @@ def info( Returns basic information about the cluster.

- ``_ + ``_ :param target: Limits the information returned to the specific target. Supports a comma-separated list, such as http,ingest. @@ -614,7 +614,7 @@ def pending_tasks( However, if a user-initiated task such as a create index command causes a cluster state update, the activity of this task might be reported by both task api and pending cluster tasks API.

- ``_ + ``_ :param local: If `true`, the request retrieves information from the local node only. If `false`, information is retrieved from the master node. @@ -680,7 +680,7 @@ def post_voting_config_exclusions( They are not required when removing master-ineligible nodes or when removing fewer than half of the master-eligible nodes.

- ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. :param node_ids: A comma-separated list of the persistent ids of the nodes to @@ -761,7 +761,7 @@ def put_component_template( To be applied, a component template must be included in an index template's composed_of list.

- ``_ + ``_ :param name: Name of the component template to create. Elasticsearch includes the following built-in component templates: `logs-mappings`; `logs-settings`; @@ -866,7 +866,7 @@ def put_settings( If a cluster becomes unstable, transient settings can clear unexpectedly, resulting in a potentially undesired cluster configuration.

- ``_ + ``_ :param flat_settings: Return settings in flat format (default: false) :param master_timeout: Explicit operation timeout for connection to master node @@ -932,7 +932,7 @@ def remote_info( - ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_remote/info" @@ -989,7 +989,7 @@ def reroute(

Once the problem has been corrected, allocation can be manually retried by calling the reroute API with the ?retry_failed URI query parameter, which will attempt a single retry round for these shards.

- ``_ + ``_ :param commands: Defines the commands to perform. :param dry_run: If true, then the request simulates the operation. It will calculate @@ -1094,7 +1094,7 @@ def state( Instead, obtain the information you require using other more stable cluster APIs.

- ``_ + ``_ :param metric: Limit the information returned to the specified metrics :param index: A comma-separated list of index names; use `_all` or empty string @@ -1182,7 +1182,7 @@ def stats( Get basic index metrics (shard numbers, store size, memory usage) and information about the current nodes that form the cluster (number, roles, os, jvm versions, memory usage, cpu and installed plugins).

- ``_ + ``_ :param node_id: Comma-separated list of node filters used to limit returned information. Defaults to all nodes in the cluster. diff --git a/elasticsearch/_sync/client/connector.py b/elasticsearch/_sync/client/connector.py index fe2b931da..9e6272faf 100644 --- a/elasticsearch/_sync/client/connector.py +++ b/elasticsearch/_sync/client/connector.py @@ -49,7 +49,7 @@ def check_in(

Update the last_seen field in the connector and set it to the current timestamp.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be checked in """ @@ -99,7 +99,7 @@ def delete( These need to be removed manually.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be deleted :param delete_sync_jobs: A flag indicating if associated sync jobs should be @@ -152,7 +152,7 @@ def get(

Get the details about a connector.

- ``_ + ``_ :param connector_id: The unique identifier of the connector :param include_deleted: A flag to indicate if the desired connector should be @@ -256,7 +256,7 @@ def last_sync( This action is used for analytics and monitoring.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param last_access_control_sync_error: @@ -356,7 +356,7 @@ def list(

Get information about all connectors.

- ``_ + ``_ :param connector_name: A comma-separated list of connector names to fetch connector documents for @@ -441,7 +441,7 @@ def post( Self-managed connectors (Connector clients) are self-managed on your infrastructure.

- ``_ + ``_ :param description: :param index_name: @@ -523,7 +523,7 @@ def put(

Create or update a connector.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be created or updated. ID is auto-generated if not provided. @@ -598,7 +598,7 @@ def sync_job_cancel( The connector service is then responsible for setting the status of connector sync jobs to cancelled.

- ``_ + ``_ :param connector_sync_job_id: The unique identifier of the connector sync job """ @@ -649,7 +649,7 @@ def sync_job_check_in( This service runs automatically on Elastic Cloud for Elastic managed connectors.

- ``_ + ``_ :param connector_sync_job_id: The unique identifier of the connector sync job to be checked in. @@ -709,7 +709,7 @@ def sync_job_claim( This service runs automatically on Elastic Cloud for Elastic managed connectors.

- ``_ + ``_ :param connector_sync_job_id: The unique identifier of the connector sync job. :param worker_hostname: The host name of the current system that will run the @@ -771,7 +771,7 @@ def sync_job_delete( This is a destructive action that is not recoverable.

- ``_ + ``_ :param connector_sync_job_id: The unique identifier of the connector sync job to be deleted @@ -825,7 +825,7 @@ def sync_job_error( This service runs automatically on Elastic Cloud for Elastic managed connectors.

- ``_ + ``_ :param connector_sync_job_id: The unique identifier for the connector sync job. :param error: The error for the connector sync job error field. @@ -879,7 +879,7 @@ def sync_job_get(

Get a connector sync job.

- ``_ + ``_ :param connector_sync_job_id: The unique identifier of the connector sync job """ @@ -952,7 +952,7 @@ def sync_job_list(

Get information about all stored connector sync jobs listed by their creation date in ascending order.

- ``_ + ``_ :param connector_id: A connector id to fetch connector sync jobs for :param from_: Starting offset (default: 0) @@ -1018,7 +1018,7 @@ def sync_job_post(

Create a connector sync job document in the internal index and initialize its counters and timestamps with default values.

- ``_ + ``_ :param id: The id of the associated connector :param job_type: @@ -1094,7 +1094,7 @@ def sync_job_update_stats( This service runs automatically on Elastic Cloud for Elastic managed connectors.

- ``_ + ``_ :param connector_sync_job_id: The unique identifier of the connector sync job. :param deleted_document_count: The number of documents the sync job deleted. @@ -1177,7 +1177,7 @@ def update_active_filtering(

Activates the valid draft filtering for a connector.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated """ @@ -1230,7 +1230,7 @@ def update_api_key_id( Self-managed connectors (connector clients) do not use this field.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param api_key_id: @@ -1289,7 +1289,7 @@ def update_configuration(

Update the configuration field in the connector document.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param configuration: @@ -1349,7 +1349,7 @@ def update_error( Otherwise, if the error is reset to null, the connector status is updated to connected.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param error: @@ -1417,7 +1417,7 @@ def update_features( This service runs automatically on Elastic Cloud for Elastic managed connectors.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated. :param features: @@ -1478,7 +1478,7 @@ def update_filtering( The filtering property is used to configure sync rules (both basic and advanced) for a connector.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param advanced_snippet: @@ -1539,7 +1539,7 @@ def update_filtering_validation(

Update the draft filtering validation info for a connector.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param validation: @@ -1596,7 +1596,7 @@ def update_index_name(

Update the index_name field of a connector, specifying the index where the data ingested by the connector is stored.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param index_name: @@ -1653,7 +1653,7 @@ def update_name(

Update the connector name and description.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param description: @@ -1710,7 +1710,7 @@ def update_native(

Update the connector is_native flag.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param is_native: @@ -1767,7 +1767,7 @@ def update_pipeline(

When you create a new connector, the configuration of an ingest pipeline is populated with default settings.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param pipeline: @@ -1823,7 +1823,7 @@ def update_scheduling(

Update the connector scheduling.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param scheduling: @@ -1879,7 +1879,7 @@ def update_service_type(

Update the connector service type.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param service_type: @@ -1942,7 +1942,7 @@ def update_status(

Update the connector status.

- ``_ + ``_ :param connector_id: The unique identifier of the connector to be updated :param status: diff --git a/elasticsearch/_sync/client/dangling_indices.py b/elasticsearch/_sync/client/dangling_indices.py index b40de169e..61d13df21 100644 --- a/elasticsearch/_sync/client/dangling_indices.py +++ b/elasticsearch/_sync/client/dangling_indices.py @@ -46,7 +46,7 @@ def delete_dangling_index( For example, this can happen if you delete more than cluster.indices.tombstones.size indices while an Elasticsearch node is offline.

- ``_ + ``_ :param index_uuid: The UUID of the index to delete. Use the get dangling indices API to find the UUID. @@ -107,7 +107,7 @@ def import_dangling_index( For example, this can happen if you delete more than cluster.indices.tombstones.size indices while an Elasticsearch node is offline.

- ``_ + ``_ :param index_uuid: The UUID of the index to import. Use the get dangling indices API to locate the UUID. @@ -168,7 +168,7 @@ def list_dangling_indices(

Use this API to list dangling indices, which you can then import or delete.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_dangling" diff --git a/elasticsearch/_sync/client/enrich.py b/elasticsearch/_sync/client/enrich.py index a12372552..f2e3a179e 100644 --- a/elasticsearch/_sync/client/enrich.py +++ b/elasticsearch/_sync/client/enrich.py @@ -43,7 +43,7 @@ def delete_policy( Deletes an existing enrich policy and its enrich index.

- ``_ + ``_ :param name: Enrich policy to delete. :param master_timeout: Period to wait for a connection to the master node. @@ -92,7 +92,7 @@ def execute_policy( Create the enrich index for an existing enrich policy.

- ``_ + ``_ :param name: Enrich policy to execute. :param master_timeout: Period to wait for a connection to the master node. @@ -144,7 +144,7 @@ def get_policy( Returns information about an enrich policy.

- ``_ + ``_ :param name: Comma-separated list of enrich policy names used to limit the request. To return information for all enrich policies, omit this parameter. @@ -202,7 +202,7 @@ def put_policy( Creates an enrich policy.

- ``_ + ``_ :param name: Name of the enrich policy to create or update. :param geo_match: Matches enrich data to incoming documents based on a `geo_shape` @@ -263,7 +263,7 @@ def stats( Returns enrich coordinator statistics and information about enrich policies that are currently executing.

- ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. """ diff --git a/elasticsearch/_sync/client/eql.py b/elasticsearch/_sync/client/eql.py index 274cdffeb..138169023 100644 --- a/elasticsearch/_sync/client/eql.py +++ b/elasticsearch/_sync/client/eql.py @@ -43,7 +43,7 @@ def delete( The API also deletes results for the search.

- ``_ + ``_ :param id: Identifier for the search to delete. A search ID is provided in the EQL search API's response for an async search. A search ID is also provided @@ -93,7 +93,7 @@ def get( Get the current status and available results for an async EQL search or a stored synchronous EQL search.

- ``_ + ``_ :param id: Identifier for the search. :param keep_alive: Period for which the search and its results are stored on @@ -147,7 +147,7 @@ def get_status( Get the current status for an async EQL search or a stored synchronous EQL search without returning results.

- ``_ + ``_ :param id: Identifier for the search. """ @@ -246,7 +246,7 @@ def search( EQL assumes each document in a data stream or index corresponds to an event.

- ``_ + ``_ :param index: The name of the index to scope the operation :param query: EQL query you wish to run. diff --git a/elasticsearch/_sync/client/esql.py b/elasticsearch/_sync/client/esql.py index 7ef16cde1..48e855fd0 100644 --- a/elasticsearch/_sync/client/esql.py +++ b/elasticsearch/_sync/client/esql.py @@ -81,7 +81,7 @@ def async_query(

The API accepts the same parameters and request body as the synchronous query API, along with additional async related properties.

- ``_ + ``_ :param query: The ES|QL query API accepts an ES|QL query string in the query parameter, runs it, and returns the results. @@ -204,7 +204,7 @@ def async_query_delete( - ``_ + ``_ :param id: The unique identifier of the query. A query ID is provided in the ES|QL async query API response for a query that does not complete in the @@ -257,7 +257,7 @@ def async_query_get( If the Elasticsearch security features are enabled, only the user who first submitted the ES|QL query can retrieve the results using this API.

- ``_ + ``_ :param id: The unique identifier of the query. A query ID is provided in the ES|QL async query API response for a query that does not complete in the @@ -324,7 +324,7 @@ def async_query_stop( If the Elasticsearch security features are enabled, only the user who first submitted the ES|QL query can stop it.

- ``_ + ``_ :param id: The unique identifier of the query. A query ID is provided in the ES|QL async query API response for a query that does not complete in the @@ -409,7 +409,7 @@ def query( Get search results for an ES|QL (Elasticsearch query language) query.

- ``_ + ``_ :param query: The ES|QL query API accepts an ES|QL query string in the query parameter, runs it, and returns the results. diff --git a/elasticsearch/_sync/client/features.py b/elasticsearch/_sync/client/features.py index 85432324e..7f1e143b7 100644 --- a/elasticsearch/_sync/client/features.py +++ b/elasticsearch/_sync/client/features.py @@ -48,7 +48,7 @@ def get_features( In order for a feature state to be listed in this API and recognized as a valid feature state by the create snapshot API, the plugin that defines that feature must be installed on the master node.

- ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. """ @@ -102,7 +102,7 @@ def reset_features(

IMPORTANT: The features installed on the node you submit this request to are the features that will be reset. Run on the master node if you have any doubts about which plugins are installed on individual nodes.

- ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. """ diff --git a/elasticsearch/_sync/client/fleet.py b/elasticsearch/_sync/client/fleet.py index 820e661cb..a4230440d 100644 --- a/elasticsearch/_sync/client/fleet.py +++ b/elasticsearch/_sync/client/fleet.py @@ -53,7 +53,7 @@ def global_checkpoints( This API is designed for internal use by the Fleet server project.

- ``_ + ``_ :param index: A single index or index alias that resolves to a single index. :param checkpoints: A comma separated list of previous global checkpoints. When @@ -144,7 +144,7 @@ def msearch( However, similar to the Fleet search API, it supports the wait_for_checkpoints parameter.

- ``_ + ``_ :param searches: :param index: A single target to search. If the target is an index alias, it @@ -155,9 +155,9 @@ def msearch( example, a request targeting foo*,bar* returns an error if an index starts with foo but no index starts with bar. :param allow_partial_search_results: If true, returns partial results if there - are shard request timeouts or [shard failures](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-replication.html#shard-failures). - If false, returns an error with no partial results. Defaults to the configured - cluster setting `search.default_allow_partial_results` which is true by default. + are shard request timeouts or shard failures. If false, returns an error + with no partial results. Defaults to the configured cluster setting `search.default_allow_partial_results`, + which is true by default. :param ccs_minimize_roundtrips: If true, network roundtrips between the coordinating node and remote clusters are minimized for cross-cluster search requests. :param expand_wildcards: Type of index that wildcard expressions can match. If @@ -393,7 +393,7 @@ def search( after the provided checkpoint has been processed and is visible for searches inside of Elasticsearch.

- ``_ + ``_ :param index: A single target to search. If the target is an index alias, it must resolve to a single index. @@ -401,9 +401,9 @@ def search( :param aggs: :param allow_no_indices: :param allow_partial_search_results: If true, returns partial results if there - are shard request timeouts or [shard failures](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-replication.html#shard-failures). - If false, returns an error with no partial results. Defaults to the configured - cluster setting `search.default_allow_partial_results` which is true by default. + are shard request timeouts or shard failures. If false, returns an error + with no partial results. Defaults to the configured cluster setting `search.default_allow_partial_results`, + which is true by default. :param analyze_wildcard: :param analyzer: :param batched_reduce_size: diff --git a/elasticsearch/_sync/client/graph.py b/elasticsearch/_sync/client/graph.py index 735917b80..8a6b8653a 100644 --- a/elasticsearch/_sync/client/graph.py +++ b/elasticsearch/_sync/client/graph.py @@ -55,7 +55,7 @@ def explore( You can exclude vertices that have already been returned.

- ``_ + ``_ :param index: Name of the index. :param connections: Specifies or more fields from which you want to extract terms diff --git a/elasticsearch/_sync/client/ilm.py b/elasticsearch/_sync/client/ilm.py index 26424284a..79ce0fed7 100644 --- a/elasticsearch/_sync/client/ilm.py +++ b/elasticsearch/_sync/client/ilm.py @@ -44,7 +44,7 @@ def delete_lifecycle( You cannot delete policies that are currently in use. If the policy is being used to manage any indices, the request fails and returns an error.

- ``_ + ``_ :param name: Identifier for the policy. :param master_timeout: Period to wait for a connection to the master node. If @@ -102,7 +102,7 @@ def explain_lifecycle(

The response indicates when the index entered each lifecycle state, provides the definition of the running phase, and information about any failures.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases to target. Supports wildcards (`*`). To target all data streams and indices, use `*` @@ -163,7 +163,7 @@ def get_lifecycle(

Get lifecycle policies.

- ``_ + ``_ :param name: Identifier for the policy. :param master_timeout: Period to wait for a connection to the master node. If @@ -218,7 +218,7 @@ def get_status(

Get the current index lifecycle management status.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_ilm/status" @@ -275,7 +275,7 @@ def migrate_to_data_tiers( Use the stop ILM and get ILM status APIs to wait until the reported operation mode is STOPPED.

- ``_ + ``_ :param dry_run: If true, simulates the migration from node attributes based allocation filters to data tiers, but does not perform the migration. This provides @@ -354,7 +354,7 @@ def move_to_step( An index cannot move to a step that is not part of its policy.

- ``_ + ``_ :param index: The name of the index whose lifecycle step is to change :param current_step: The step that the index is expected to be in. @@ -422,7 +422,7 @@ def put_lifecycle(

NOTE: Only the latest version of the policy is stored, you cannot revert to previous versions.

- ``_ + ``_ :param name: Identifier for the policy. :param master_timeout: Period to wait for a connection to the master node. If @@ -486,7 +486,7 @@ def remove_policy( It also stops managing the indices.

- ``_ + ``_ :param index: The name of the index to remove policy on """ @@ -532,7 +532,7 @@ def retry( Use the explain lifecycle state API to determine whether an index is in the ERROR step.

- ``_ + ``_ :param index: The name of the indices (comma-separated) whose failed lifecycle step is to be retry @@ -580,7 +580,7 @@ def start( Restarting ILM is necessary only when it has been stopped using the stop ILM API.

- ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails and @@ -634,7 +634,7 @@ def stop( Use the get ILM status API to check whether ILM is running.

- ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails and diff --git a/elasticsearch/_sync/client/indices.py b/elasticsearch/_sync/client/indices.py index 4f697b9a1..131e4a06a 100644 --- a/elasticsearch/_sync/client/indices.py +++ b/elasticsearch/_sync/client/indices.py @@ -62,7 +62,7 @@ def add_block( Index blocks limit the operations allowed on an index by blocking specific operation types.

- ``_ + ``_ :param index: A comma-separated list or wildcard expression of index names used to limit the request. By default, you must explicitly name the indices you @@ -173,7 +173,7 @@ def analyze( The _analyze endpoint without a specified index will always use 10000 as its limit.

- ``_ + ``_ :param index: Index used to derive the analyzer. If specified, the `analyzer` or field parameter overrides this value. If no index is specified or the @@ -265,7 +265,7 @@ def cancel_migrate_reindex(

Cancel a migration reindex attempt for a data stream or index.

- ``_ + ``_ :param index: The index or data stream name """ @@ -327,7 +327,7 @@ def clear_cache( To clear the cache only of specific fields, use the fields parameter.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). To target all data streams @@ -449,7 +449,7 @@ def clone(

Because the clone operation creates a new index to clone the shards to, the wait for active shards setting on index creation applies to the clone index action as well.

- ``_ + ``_ :param index: Name of the source index to clone. :param target: Name of the target index to create. @@ -553,7 +553,7 @@ def close( Closing indices can be turned off with the cluster settings API by setting cluster.indices.close.enable to false.

- ``_ + ``_ :param index: Comma-separated list or wildcard expression of index names used to limit the request. @@ -654,7 +654,7 @@ def create( Note that changing this setting will also affect the wait_for_active_shards value on all subsequent write operations.

- ``_ + ``_ :param index: Name of the index you wish to create. :param aliases: Aliases for the index. @@ -731,7 +731,7 @@ def create_data_stream(

You must have a matching index template with data stream enabled.

- ``_ + ``_ :param name: Name of the data stream, which must meet the following criteria: Lowercase only; Cannot include `\\`, `/`, `*`, `?`, `"`, `<`, `>`, `|`, `,`, @@ -794,7 +794,7 @@ def create_from(

Copy the mappings and settings from the source index to a destination index while allowing request settings and mappings to override the source values.

- ``_ + ``_ :param source: The source index or data stream name :param dest: The destination index or data stream name @@ -861,7 +861,7 @@ def data_streams_stats(

Get statistics for one or more data streams.

- ``_ + ``_ :param name: Comma-separated list of data streams used to limit the request. Wildcard expressions (`*`) are supported. To target all data streams in a @@ -930,7 +930,7 @@ def delete( You can then use the delete index API to delete the previous write index.

- ``_ + ``_ :param index: Comma-separated list of indices to delete. You cannot specify index aliases. By default, this parameter does not support wildcards (`*`) or `_all`. @@ -1004,7 +1004,7 @@ def delete_alias( Removes a data stream or index from an alias.

- ``_ + ``_ :param index: Comma-separated list of data streams or indices used to limit the request. Supports wildcards (`*`). @@ -1072,7 +1072,7 @@ def delete_data_lifecycle( Removes the data stream lifecycle from a data stream, rendering it not managed by the data stream lifecycle.

- ``_ + ``_ :param name: A comma-separated list of data streams of which the data stream lifecycle will be deleted; use `*` to get all data streams @@ -1136,7 +1136,7 @@ def delete_data_stream( Deletes one or more data streams and their backing indices.

- ``_ + ``_ :param name: Comma-separated list of data streams to delete. Wildcard (`*`) expressions are supported. @@ -1194,7 +1194,7 @@ def delete_index_template( existing templates.

- ``_ + ``_ :param name: Comma-separated list of index template names used to limit the request. Wildcard (*) expressions are supported. @@ -1249,7 +1249,7 @@ def delete_template(

Delete a legacy index template.

- ``_ + ``_ :param name: The name of the legacy index template to delete. Wildcard (`*`) expressions are supported. @@ -1321,7 +1321,7 @@ def disk_usage( The stored size of the _id field is likely underestimated while the _source field is overestimated.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases used to limit the request. It’s recommended to execute this API with a single @@ -1404,7 +1404,7 @@ def downsample( The source index must be read only (index.blocks.write: true).

- ``_ + ``_ :param index: Name of the time series index to downsample. :param target_index: Name of the index to create. @@ -1476,7 +1476,7 @@ def exists( Check if one or more indices, index aliases, or data streams exist.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases. Supports wildcards (`*`). @@ -1558,7 +1558,7 @@ def exists_alias(

Check if one or more data stream or index aliases exist.

- ``_ + ``_ :param name: Comma-separated list of aliases to check. Supports wildcards (`*`). :param index: Comma-separated list of data streams or indices used to limit the @@ -1635,7 +1635,7 @@ def exists_index_template(

Check whether index templates exist.

- ``_ + ``_ :param name: Comma-separated list of index template names used to limit the request. Wildcard (*) expressions are supported. @@ -1698,7 +1698,7 @@ def exists_template(

IMPORTANT: This documentation is about legacy index templates, which are deprecated and will be replaced by the composable templates introduced in Elasticsearch 7.8.

- ``_ + ``_ :param name: A comma-separated list of index template names used to limit the request. Wildcard (`*`) expressions are supported. @@ -1756,7 +1756,7 @@ def explain_data_lifecycle( Get information about an index or data stream's current data stream lifecycle status, such as time since index creation, time since rollover, the lifecycle configuration managing the index, or any errors encountered during lifecycle execution.

- ``_ + ``_ :param index: The name of the index to explain :param include_defaults: indicates if the API should return the default values @@ -1823,7 +1823,7 @@ def field_usage_stats( A given request will increment each count by a maximum value of 1, even if the request accesses the same field multiple times.

- ``_ + ``_ :param index: Comma-separated list or wildcard expression of index names used to limit the request. @@ -1908,7 +1908,7 @@ def flush( If you call the flush API after indexing some documents then a successful response indicates that Elasticsearch has flushed all the documents that were indexed before the flush API was called.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases to flush. Supports wildcards (`*`). To flush all data streams and indices, omit this @@ -2033,7 +2033,7 @@ def forcemerge( - ``_ + ``_ :param index: A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices @@ -2131,7 +2131,7 @@ def get( stream’s backing indices.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and index aliases used to limit the request. Wildcard expressions (*) are supported. @@ -2224,7 +2224,7 @@ def get_alias( Retrieves information for one or more data stream or index aliases.

- ``_ + ``_ :param index: Comma-separated list of data streams or indices used to limit the request. Supports wildcards (`*`). To target all data streams and indices, @@ -2311,7 +2311,7 @@ def get_data_lifecycle(

Get the data stream lifecycle configuration of one or more data streams.

- ``_ + ``_ :param name: Comma-separated list of data streams to limit the request. Supports wildcards (`*`). To target all data streams, omit this parameter or use `*` @@ -2369,7 +2369,7 @@ def get_data_lifecycle_stats( Get statistics about the data streams that are managed by a data stream lifecycle.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_lifecycle/stats" @@ -2420,7 +2420,7 @@ def get_data_stream(

Get information about one or more data streams.

- ``_ + ``_ :param name: Comma-separated list of data stream names used to limit the request. Wildcard (`*`) expressions are supported. If omitted, all data streams are @@ -2501,7 +2501,7 @@ def get_field_mapping(

This API is useful if you don't need a complete mapping or if an index mapping contains a large number of fields.

- ``_ + ``_ :param fields: Comma-separated list or wildcard expression of fields used to limit returned information. Supports wildcards (`*`). @@ -2582,7 +2582,7 @@ def get_index_template( Get information about one or more index templates.

- ``_ + ``_ :param name: Comma-separated list of index template names used to limit the request. Wildcard (*) expressions are supported. @@ -2659,7 +2659,7 @@ def get_mapping( For data streams, the API retrieves mappings for the stream’s backing indices.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). To target all data streams @@ -2733,7 +2733,7 @@ def get_migrate_reindex_status(

Get the status of a migration reindex attempt for a data stream or index.

- ``_ + ``_ :param index: The index or data stream name. """ @@ -2793,7 +2793,7 @@ def get_settings( For data streams, it returns setting information for the stream's backing indices.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). To target all data streams @@ -2885,7 +2885,7 @@ def get_template(

IMPORTANT: This documentation is about legacy index templates, which are deprecated and will be replaced by the composable templates introduced in Elasticsearch 7.8.

- ``_ + ``_ :param name: Comma-separated list of index template names used to limit the request. Wildcard (`*`) expressions are supported. To return all index templates, @@ -2952,7 +2952,7 @@ def migrate_reindex( The persistent task ID is returned immediately and the reindexing work is completed in that task.

- ``_ + ``_ :param reindex: """ @@ -3013,7 +3013,7 @@ def migrate_to_data_stream( The write index for the alias becomes the write index for the stream.

- ``_ + ``_ :param name: Name of the index alias to convert to a data stream. :param master_timeout: Period to wait for a connection to the master node. If @@ -3069,7 +3069,7 @@ def modify_data_stream( Performs one or more data stream modification actions in a single atomic operation.

- ``_ + ``_ :param actions: Actions to perform. """ @@ -3148,7 +3148,7 @@ def open(

Because opening or closing an index allocates its shards, the wait_for_active_shards setting on index creation applies to the _open and _close index actions as well.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). By default, you must explicitly @@ -3234,7 +3234,7 @@ def promote_data_stream( This will affect the lifecycle management of the data stream and interfere with the data stream size and retention.

- ``_ + ``_ :param name: The name of the data stream :param master_timeout: Period to wait for a connection to the master node. If @@ -3300,7 +3300,7 @@ def put_alias( Adds a data stream or index to an alias.

- ``_ + ``_ :param index: Comma-separated list of data streams or indices to add. Supports wildcards (`*`). Wildcard patterns that match both data streams and indices @@ -3407,7 +3407,7 @@ def put_data_lifecycle( Update the data stream lifecycle of the specified data streams.

- ``_ + ``_ :param name: Comma-separated list of data streams used to limit the request. Supports wildcards (`*`). To target all data streams use `*` or `_all`. @@ -3535,7 +3535,7 @@ def put_index_template( If an entry already exists with the same key, then it is overwritten by the new definition.

- ``_ + ``_ :param name: Index or template name :param allow_auto_create: This setting overrides the value of the `action.auto_create_index` @@ -3718,7 +3718,7 @@ def put_mapping( Instead, add an alias field to create an alternate field name.

- ``_ + ``_ :param index: A comma-separated list of index names the mapping should be added to (supports wildcards); use `_all` or omit to add the mapping on all indices. @@ -3864,7 +3864,7 @@ def put_settings( To change the analyzer for existing backing indices, you must create a new data stream and reindex your data into it.

- ``_ + ``_ :param settings: :param index: Comma-separated list of data streams, indices, and aliases used @@ -3990,7 +3990,7 @@ def put_template( NOTE: Multiple matching templates with the same order value will result in a non-deterministic merging order.

- ``_ + ``_ :param name: The name of the template :param aliases: Aliases for the index. @@ -4092,7 +4092,7 @@ def recovery( This means that if a shard copy completes a recovery and then Elasticsearch relocates it onto a different node then the information about the original recovery will not be shown in the recovery API.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). To target all data streams @@ -4166,7 +4166,7 @@ def refresh( This option ensures the indexing operation waits for a periodic refresh before running the search.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). To target all data streams @@ -4250,7 +4250,7 @@ def reload_search_analyzers( This ensures the synonym file is updated everywhere in the cluster in case shards are relocated in the future.

- ``_ + ``_ :param index: A comma-separated list of index names to reload analyzers for :param allow_no_indices: Whether to ignore if a wildcard indices expression resolves @@ -4357,7 +4357,7 @@ def resolve_cluster( If a connection was (re-)established, this will also cause the remote/info endpoint to now indicate a connected status.

- ``_ + ``_ :param name: A comma-separated list of names or index patterns for the indices, aliases, and data streams to resolve. Resources on remote clusters can be @@ -4459,7 +4459,7 @@ def resolve_index( Multiple patterns and remote clusters are supported.

- ``_ + ``_ :param name: Comma-separated name(s) or index pattern(s) of the indices, aliases, and data streams to resolve. Resources on remote clusters can be specified @@ -4561,7 +4561,7 @@ def rollover( If you roll over the alias on May 7, 2099, the new index's name is my-index-2099.05.07-000002.

- ``_ + ``_ :param alias: Name of the data stream or index alias to roll over. :param new_index: Name of the index to create. Supports date math. Data streams @@ -4675,7 +4675,7 @@ def segments( For data streams, the API returns information about the stream's backing indices.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases used to limit the request. Supports wildcards (`*`). To target all data streams @@ -4764,7 +4764,7 @@ def shard_stores(

By default, the API returns store information only for primary shards that are unassigned or have one or more unassigned replica shards.

- ``_ + ``_ :param index: List of data streams, indices, and aliases used to limit the request. :param allow_no_indices: If false, the request returns an error if any wildcard @@ -4866,7 +4866,7 @@ def shrink( - ``_ + ``_ :param index: Name of the source index to shrink. :param target: Name of the target index to create. @@ -4947,7 +4947,7 @@ def simulate_index_template( Get the index configuration that would be applied to the specified index from an existing index template.

- ``_ + ``_ :param name: Name of the index to simulate :param cause: User defined reason for dry-run creating the new template for simulation @@ -5037,7 +5037,7 @@ def simulate_template( Get the index configuration that would be applied by a particular index template.

- ``_ + ``_ :param name: Name of the index template to simulate. To test a template configuration before you add it to the cluster, omit this parameter and specify the template @@ -5209,7 +5209,7 @@ def split( - ``_ + ``_ :param index: Name of the source index to split. :param target: Name of the target index to create. @@ -5311,7 +5311,7 @@ def stats( Although the shard is no longer part of the node, that node retains any node-level statistics to which the shard contributed.

- ``_ + ``_ :param index: A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices @@ -5410,7 +5410,7 @@ def update_aliases( Adds a data stream or index to an alias.

- ``_ + ``_ :param actions: Actions to perform. :param master_timeout: Period to wait for a connection to the master node. If @@ -5489,7 +5489,7 @@ def validate_query( Validates a query without running it.

- ``_ + ``_ :param index: Comma-separated list of data streams, indices, and aliases to search. Supports wildcards (`*`). To search all data streams or indices, omit this diff --git a/elasticsearch/_sync/client/inference.py b/elasticsearch/_sync/client/inference.py index bcea34db5..2dfcfd671 100644 --- a/elasticsearch/_sync/client/inference.py +++ b/elasticsearch/_sync/client/inference.py @@ -47,7 +47,7 @@ def completion(

Perform completion inference on the service

- ``_ + ``_ :param inference_id: The inference Id :param input: Inference input. Either a string or an array of strings. @@ -123,7 +123,7 @@ def delete(

Delete an inference endpoint

- ``_ + ``_ :param inference_id: The inference identifier. :param task_type: The task type @@ -197,7 +197,7 @@ def get(

Get an inference endpoint

- ``_ + ``_ :param task_type: The task type :param inference_id: The inference Id @@ -234,6 +234,113 @@ def get( path_parts=__path_parts, ) + @_rewrite_parameters( + body_fields=("input", "query", "task_settings"), + ) + def inference( + self, + *, + inference_id: str, + input: t.Optional[t.Union[str, t.Sequence[str]]] = None, + task_type: t.Optional[ + t.Union[ + str, + t.Literal[ + "chat_completion", + "completion", + "rerank", + "sparse_embedding", + "text_embedding", + ], + ] + ] = None, + error_trace: t.Optional[bool] = None, + filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + human: t.Optional[bool] = None, + pretty: t.Optional[bool] = None, + query: t.Optional[str] = None, + task_settings: t.Optional[t.Any] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, + body: t.Optional[t.Dict[str, t.Any]] = None, + ) -> ObjectApiResponse[t.Any]: + """ + .. raw:: html + +

Perform inference on the service.

+

This API enables you to use machine learning models to perform specific tasks on data that you provide as an input. + It returns a response with the results of the tasks. + The inference endpoint you use can perform one specific task that has been defined when the endpoint was created with the create inference API.

+

For details about using this API with a service, such as Amazon Bedrock, Anthropic, or HuggingFace, refer to the service-specific documentation.

+
+

info + The inference APIs enable you to use certain services, such as built-in machine learning models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Azure, Google AI Studio, Google Vertex AI, Anthropic, Watsonx.ai, or Hugging Face. For built-in models and models uploaded through Eland, the inference APIs offer an alternative way to use and manage trained models. However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.

+
+ + + ``_ + + :param inference_id: The unique identifier for the inference endpoint. + :param input: The text on which you want to perform the inference task. It can + be a single string or an array. > info > Inference endpoints for the `completion` + task type currently only support a single string as input. + :param task_type: The type of inference task that the model performs. + :param query: The query input, which is required only for the `rerank` task. + It is not required for other tasks. + :param task_settings: Task settings for the individual inference request. These + settings are specific to the task type you specified and override the task + settings specified when initializing the service. + :param timeout: The amount of time to wait for the inference request to complete. + """ + if inference_id in SKIP_IN_PATH: + raise ValueError("Empty value passed for parameter 'inference_id'") + if input is None and body is None: + raise ValueError("Empty value passed for parameter 'input'") + __path_parts: t.Dict[str, str] + if task_type not in SKIP_IN_PATH and inference_id not in SKIP_IN_PATH: + __path_parts = { + "task_type": _quote(task_type), + "inference_id": _quote(inference_id), + } + __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["inference_id"]}' + elif inference_id not in SKIP_IN_PATH: + __path_parts = {"inference_id": _quote(inference_id)} + __path = f'/_inference/{__path_parts["inference_id"]}' + else: + raise ValueError("Couldn't find a path for the given parameters") + __query: t.Dict[str, t.Any] = {} + __body: t.Dict[str, t.Any] = body if body is not None else {} + if error_trace is not None: + __query["error_trace"] = error_trace + if filter_path is not None: + __query["filter_path"] = filter_path + if human is not None: + __query["human"] = human + if pretty is not None: + __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout + if not __body: + if input is not None: + __body["input"] = input + if query is not None: + __body["query"] = query + if task_settings is not None: + __body["task_settings"] = task_settings + if not __body: + __body = None # type: ignore[assignment] + __headers = {"accept": "application/json"} + if __body is not None: + __headers["content-type"] = "application/json" + return self.perform_request( # type: ignore[return-value] + "POST", + __path, + params=__query, + headers=__headers, + body=__body, + endpoint_id="inference.inference", + path_parts=__path_parts, + ) + @_rewrite_parameters( body_name="inference_config", ) @@ -274,7 +381,7 @@ def put( However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.

- ``_ + ``_ :param inference_id: The inference Id :param inference_config: @@ -358,7 +465,7 @@ def put_alibabacloud( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param alibabacloud_inference_id: The unique identifier of the inference endpoint. @@ -458,7 +565,7 @@ def put_amazonbedrock( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param amazonbedrock_inference_id: The unique identifier of the inference endpoint. @@ -554,7 +661,7 @@ def put_anthropic( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The task type. The only valid task type for the model to perform is `completion`. @@ -651,7 +758,7 @@ def put_azureaistudio( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param azureaistudio_inference_id: The unique identifier of the inference endpoint. @@ -753,7 +860,7 @@ def put_azureopenai( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. NOTE: The `chat_completion` task type only supports streaming and only through @@ -851,7 +958,7 @@ def put_cohere( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param cohere_inference_id: The unique identifier of the inference endpoint. @@ -955,7 +1062,7 @@ def put_elasticsearch( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param elasticsearch_inference_id: The unique identifier of the inference endpoint. @@ -1055,7 +1162,7 @@ def put_elser( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param elser_inference_id: The unique identifier of the inference endpoint. @@ -1139,7 +1246,7 @@ def put_googleaistudio( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param googleaistudio_inference_id: The unique identifier of the inference endpoint. @@ -1231,7 +1338,7 @@ def put_googlevertexai( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param googlevertexai_inference_id: The unique identifier of the inference endpoint. @@ -1334,7 +1441,7 @@ def put_hugging_face( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param huggingface_inference_id: The unique identifier of the inference endpoint. @@ -1428,7 +1535,7 @@ def put_jinaai( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param jinaai_inference_id: The unique identifier of the inference endpoint. @@ -1516,7 +1623,7 @@ def put_mistral( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The task type. The only valid task type for the model to perform is `text_embedding`. @@ -1609,7 +1716,7 @@ def put_openai( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. NOTE: The `chat_completion` task type only supports streaming and only through @@ -1701,7 +1808,7 @@ def put_voyageai(

Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The type of the inference task that the model will perform. :param voyageai_inference_id: The unique identifier of the inference endpoint. @@ -1790,7 +1897,7 @@ def put_watsonx( Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

- ``_ + ``_ :param task_type: The task type. The only valid task type for the model to perform is `text_embedding`. @@ -1866,7 +1973,7 @@ def rerank(

Perform rereanking inference on the service

- ``_ + ``_ :param inference_id: The unique identifier for the inference endpoint. :param input: The text on which you want to perform the inference task. It can @@ -1942,7 +2049,7 @@ def sparse_embedding(

Perform sparse embedding inference on the service

- ``_ + ``_ :param inference_id: The inference Id :param input: Inference input. Either a string or an array of strings. @@ -2010,7 +2117,7 @@ def text_embedding(

Perform text embedding inference on the service

- ``_ + ``_ :param inference_id: The inference Id :param input: Inference input. Either a string or an array of strings. @@ -2092,7 +2199,7 @@ def update( However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.

- ``_ + ``_ :param inference_id: The unique identifier of the inference endpoint. :param inference_config: diff --git a/elasticsearch/_sync/client/ingest.py b/elasticsearch/_sync/client/ingest.py index 3a66284e9..798653d1f 100644 --- a/elasticsearch/_sync/client/ingest.py +++ b/elasticsearch/_sync/client/ingest.py @@ -44,7 +44,7 @@ def delete_geoip_database(

Delete one or more IP geolocation database configurations.

- ``_ + ``_ :param id: A comma-separated list of geoip database configurations to delete :param master_timeout: The period to wait for a connection to the master node. @@ -98,7 +98,7 @@ def delete_ip_location_database(

Delete IP geolocation database configurations.

- ``_ + ``_ :param id: A comma-separated list of IP location database configurations. :param master_timeout: The period to wait for a connection to the master node. @@ -155,7 +155,7 @@ def delete_pipeline( Delete one or more ingest pipelines.

- ``_ + ``_ :param id: Pipeline ID or wildcard expression of pipeline IDs used to limit the request. To delete all ingest pipelines in a cluster, use a value of `*`. @@ -208,7 +208,7 @@ def geo_ip_stats( Get download statistics for GeoIP2 databases that are used with the GeoIP processor.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_ingest/geoip/stats" @@ -248,7 +248,7 @@ def get_geoip_database(

Get information about one or more IP geolocation database configurations.

- ``_ + ``_ :param id: A comma-separated list of database configuration IDs to retrieve. Wildcard (`*`) expressions are supported. To get all database configurations, @@ -297,7 +297,7 @@ def get_ip_location_database(

Get IP geolocation database configurations.

- ``_ + ``_ :param id: Comma-separated list of database configuration IDs to retrieve. Wildcard (`*`) expressions are supported. To get all database configurations, omit @@ -355,7 +355,7 @@ def get_pipeline( This API returns a local reference of the pipeline.

- ``_ + ``_ :param id: Comma-separated list of pipeline IDs to retrieve. Wildcard (`*`) expressions are supported. To get all ingest pipelines, omit this parameter or use `*`. @@ -412,7 +412,7 @@ def processor_grok( A grok pattern is like a regular expression that supports aliased expressions that can be reused.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_ingest/processor/grok" @@ -459,7 +459,7 @@ def put_geoip_database(

Refer to the create or update IP geolocation database configuration API.

- ``_ + ``_ :param id: ID of the database configuration to create or update. :param maxmind: The configuration necessary to identify which IP geolocation @@ -534,7 +534,7 @@ def put_ip_location_database(

Create or update an IP geolocation database configuration.

- ``_ + ``_ :param id: The database configuration identifier. :param configuration: @@ -620,7 +620,7 @@ def put_pipeline( Changes made using this API take effect immediately.

- ``_ + ``_ :param id: ID of the ingest pipeline to create or update. :param deprecated: Marks this ingest pipeline as deprecated. When a deprecated @@ -717,7 +717,7 @@ def simulate( You can either specify an existing pipeline to use with the provided documents or supply a pipeline definition in the body of the request.

- ``_ + ``_ :param docs: Sample documents to test in the pipeline. :param id: The pipeline to test. If you don't specify a `pipeline` in the request diff --git a/elasticsearch/_sync/client/license.py b/elasticsearch/_sync/client/license.py index bd36f430b..452cbd20c 100644 --- a/elasticsearch/_sync/client/license.py +++ b/elasticsearch/_sync/client/license.py @@ -44,7 +44,7 @@ def delete(

If the operator privileges feature is enabled, only operator users can use this API.

- ``_ + ``_ :param master_timeout: The period to wait for a connection to the master node. :param timeout: The period to wait for a response. If no response is received @@ -98,7 +98,7 @@ def get( - ``_ + ``_ :param accept_enterprise: If `true`, this parameter returns enterprise for Enterprise license types. If `false`, this parameter returns platinum for both platinum @@ -147,7 +147,7 @@ def get_basic_status(

Get the basic license status.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_license/basic_status" @@ -185,7 +185,7 @@ def get_trial_status(

Get the trial status.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_license/trial_status" @@ -237,7 +237,7 @@ def post( If the operator privileges feature is enabled, only operator users can use this API.

- ``_ + ``_ :param acknowledge: Specifies whether you acknowledge the license changes. :param license: @@ -308,7 +308,7 @@ def post_start_basic(

To check the status of your basic license, use the get basic license API.

- ``_ + ``_ :param acknowledge: whether the user has acknowledged acknowledge messages (default: false) @@ -365,7 +365,7 @@ def post_start_trial(

To check the status of your trial, use the get trial status API.

- ``_ + ``_ :param acknowledge: whether the user has acknowledged acknowledge messages (default: false) diff --git a/elasticsearch/_sync/client/logstash.py b/elasticsearch/_sync/client/logstash.py index f8abefa14..bacf7ba01 100644 --- a/elasticsearch/_sync/client/logstash.py +++ b/elasticsearch/_sync/client/logstash.py @@ -43,7 +43,7 @@ def delete_pipeline( If the request succeeds, you receive an empty response with an appropriate status code.

- ``_ + ``_ :param id: An identifier for the pipeline. """ @@ -87,7 +87,7 @@ def get_pipeline( Get pipelines that are used for Logstash Central Management.

- ``_ + ``_ :param id: A comma-separated list of pipeline identifiers. """ @@ -139,7 +139,7 @@ def put_pipeline( If the specified pipeline exists, it is replaced.

- ``_ + ``_ :param id: An identifier for the pipeline. :param pipeline: diff --git a/elasticsearch/_sync/client/migration.py b/elasticsearch/_sync/client/migration.py index 20ebb44fd..9ec38edef 100644 --- a/elasticsearch/_sync/client/migration.py +++ b/elasticsearch/_sync/client/migration.py @@ -44,7 +44,7 @@ def deprecations( You are strongly recommended to use the Upgrade Assistant.

- ``_ + ``_ :param index: Comma-separate list of data streams or indices to check. Wildcard (*) expressions are supported. @@ -94,7 +94,7 @@ def get_feature_upgrade_status( You are strongly recommended to use the Upgrade Assistant.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_migration/system_features" @@ -136,7 +136,7 @@ def post_feature_upgrade(

TIP: The API is designed for indirect use by the Upgrade Assistant. We strongly recommend you use the Upgrade Assistant.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_migration/system_features" diff --git a/elasticsearch/_sync/client/ml.py b/elasticsearch/_sync/client/ml.py index d162abe82..0b21fb264 100644 --- a/elasticsearch/_sync/client/ml.py +++ b/elasticsearch/_sync/client/ml.py @@ -45,7 +45,7 @@ def clear_trained_model_deployment_cache( Calling this API clears the caches without restarting the deployment.

- ``_ + ``_ :param model_id: The unique identifier of the trained model. """ @@ -100,7 +100,7 @@ def close_job( When a datafeed that has a specified end date stops, it automatically closes its associated job.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. It can be a job identifier, a group name, or a wildcard expression. You can close multiple anomaly detection @@ -165,7 +165,7 @@ def delete_calendar(

Remove all scheduled events from a calendar, then delete it.

- ``_ + ``_ :param calendar_id: A string that uniquely identifies a calendar. """ @@ -209,7 +209,7 @@ def delete_calendar_event(

Delete events from a calendar.

- ``_ + ``_ :param calendar_id: A string that uniquely identifies a calendar. :param event_id: Identifier for the scheduled event. You can obtain this identifier @@ -260,7 +260,7 @@ def delete_calendar_job(

Delete anomaly jobs from a calendar.

- ``_ + ``_ :param calendar_id: A string that uniquely identifies a calendar. :param job_id: An identifier for the anomaly detection jobs. It can be a job @@ -312,7 +312,7 @@ def delete_data_frame_analytics(

Delete a data frame analytics job.

- ``_ + ``_ :param id: Identifier for the data frame analytics job. :param force: If `true`, it deletes a job that is not stopped; this method is @@ -363,7 +363,7 @@ def delete_datafeed(

Delete a datafeed.

- ``_ + ``_ :param datafeed_id: A numerical character string that uniquely identifies the datafeed. This identifier can contain lowercase alphanumeric characters (a-z @@ -426,7 +426,7 @@ def delete_expired_data( <job_id>.

- ``_ + ``_ :param job_id: Identifier for an anomaly detection job. It can be a job identifier, a group name, or a wildcard expression. @@ -490,7 +490,7 @@ def delete_filter( filter. You must update or delete the job before you can delete the filter.

- ``_ + ``_ :param filter_id: A string that uniquely identifies a filter. """ @@ -540,7 +540,7 @@ def delete_forecast( forecasts before they expire.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param forecast_id: A comma-separated list of forecast identifiers. If you do @@ -616,7 +616,7 @@ def delete_job( delete job request.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param delete_user_annotations: Specifies whether annotations that have been @@ -676,7 +676,7 @@ def delete_model_snapshot( the model_snapshot_id in the results from the get jobs API.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param snapshot_id: Identifier for the model snapshot. @@ -728,7 +728,7 @@ def delete_trained_model(

The request deletes a trained inference model that is not referenced by an ingest pipeline.

- ``_ + ``_ :param model_id: The unique identifier of the trained model. :param force: Forcefully deletes a trained model that is referenced by ingest @@ -783,7 +783,7 @@ def delete_trained_model_alias( by the model_id, this API returns an error.

- ``_ + ``_ :param model_id: The trained model ID to which the model alias refers. :param model_alias: The model alias to delete. @@ -844,7 +844,7 @@ def estimate_model_memory( estimates for the fields it references.

- ``_ + ``_ :param analysis_config: For a list of the properties that you can specify in the `analysis_config` component of the body of this API. @@ -916,7 +916,7 @@ def evaluate_data_frame( field and an analytics result field to be present.

- ``_ + ``_ :param evaluation: Defines the type of evaluation you want to perform. :param index: Defines the `index` in which the evaluation will be performed. @@ -1001,7 +1001,7 @@ def explain_data_frame_analytics( - ``_ + ``_ :param id: Identifier for the data frame analytics job. This identifier can contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and underscores. @@ -1112,7 +1112,7 @@ def flush_job( analyzing further data.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param advance_time: Refer to the description for the `advance_time` query parameter. @@ -1187,7 +1187,7 @@ def forecast( based on historical data.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. The job must be open when you create a forecast; otherwise, an error occurs. @@ -1273,7 +1273,7 @@ def get_buckets( The API presents a chronological view of the records, grouped by bucket.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param timestamp: The timestamp of a single bucket result. If you do not specify @@ -1371,7 +1371,7 @@ def get_calendar_events(

Get info about events in calendars.

- ``_ + ``_ :param calendar_id: A string that uniquely identifies a calendar. You can get information for multiple calendars by using a comma-separated list of ids @@ -1440,7 +1440,7 @@ def get_calendars(

Get calendar configuration info.

- ``_ + ``_ :param calendar_id: A string that uniquely identifies a calendar. You can get information for multiple calendars by using a comma-separated list of ids @@ -1516,7 +1516,7 @@ def get_categories(

Get anomaly detection job results for categories.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param category_id: Identifier for the category, which is unique in the job. @@ -1604,7 +1604,7 @@ def get_data_frame_analytics( wildcard expression.

- ``_ + ``_ :param id: Identifier for the data frame analytics job. If you do not specify this option, the API returns information for the first hundred data frame @@ -1679,7 +1679,7 @@ def get_data_frame_analytics_stats(

Get data frame analytics jobs usage info.

- ``_ + ``_ :param id: Identifier for the data frame analytics job. If you do not specify this option, the API returns information for the first hundred data frame @@ -1753,7 +1753,7 @@ def get_datafeed_stats( This API returns a maximum of 10,000 datafeeds.

- ``_ + ``_ :param datafeed_id: Identifier for the datafeed. It can be a datafeed identifier or a wildcard expression. If you do not specify one of these options, the @@ -1817,7 +1817,7 @@ def get_datafeeds( This API returns a maximum of 10,000 datafeeds.

- ``_ + ``_ :param datafeed_id: Identifier for the datafeed. It can be a datafeed identifier or a wildcard expression. If you do not specify one of these options, the @@ -1884,7 +1884,7 @@ def get_filters( You can get a single filter or all filters.

- ``_ + ``_ :param filter_id: A string that uniquely identifies a filter. :param from_: Skips the specified number of filters. @@ -1952,7 +1952,7 @@ def get_influencers( influencer_field_name is specified in the job configuration.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param desc: If true, the results are sorted in descending order. @@ -2036,7 +2036,7 @@ def get_job_stats(

Get anomaly detection jobs usage info.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. It can be a job identifier, a group name, a comma-separated list of jobs, or a wildcard expression. If @@ -2100,7 +2100,7 @@ def get_jobs( _all, by specifying * as the <job_id>, or by omitting the <job_id>.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. It can be a job identifier, a group name, or a wildcard expression. If you do not specify one of these @@ -2166,7 +2166,7 @@ def get_memory_stats( on each node, both within the JVM heap, and natively, outside of the JVM.

- ``_ + ``_ :param node_id: The names of particular nodes in the cluster to target. For example, `nodeId1,nodeId2` or `ml:true` @@ -2224,7 +2224,7 @@ def get_model_snapshot_upgrade_stats(

Get anomaly detection job model snapshot upgrade usage info.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param snapshot_id: A numerical character string that uniquely identifies the @@ -2298,7 +2298,7 @@ def get_model_snapshots(

Get model snapshots info.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param snapshot_id: A numerical character string that uniquely identifies the @@ -2418,7 +2418,7 @@ def get_overall_buckets( jobs' largest bucket span.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. It can be a job identifier, a group name, a comma-separated list of jobs or groups, or a wildcard expression. @@ -2528,7 +2528,7 @@ def get_records( number of detectors.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param desc: Refer to the description for the `desc` query parameter. @@ -2626,7 +2626,7 @@ def get_trained_models(

Get trained model configuration info.

- ``_ + ``_ :param model_id: The unique identifier of the trained model or a model alias. You can get information for multiple trained models in a single API request @@ -2713,7 +2713,7 @@ def get_trained_models_stats( models in a single API request by using a comma-separated list of model IDs or a wildcard expression.

- ``_ + ``_ :param model_id: The unique identifier of the trained model or a model alias. It can be a comma-separated list or a wildcard expression. @@ -2779,7 +2779,7 @@ def infer_trained_model(

Evaluate a trained model.

- ``_ + ``_ :param model_id: The unique identifier of the trained model. :param docs: An array of objects to pass to the model for inference. The objects @@ -2846,7 +2846,7 @@ def info( cluster configuration.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_ml/info" @@ -2895,7 +2895,7 @@ def open_job( new data is received.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param timeout: Refer to the description for the `timeout` query parameter. @@ -2952,7 +2952,7 @@ def post_calendar_events(

Add scheduled events to the calendar.

- ``_ + ``_ :param calendar_id: A string that uniquely identifies a calendar. :param events: A list of one of more scheduled events. The event’s start and @@ -3013,7 +3013,7 @@ def post_data( It is not currently possible to post data to multiple jobs using wildcards or a comma-separated list.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. The job must have a state of open to receive and process the data. @@ -3080,7 +3080,7 @@ def preview_data_frame_analytics( Preview the extracted features used by a data frame analytics config.

- ``_ + ``_ :param id: Identifier for the data frame analytics job. :param config: A data frame analytics config as described in create data frame @@ -3153,7 +3153,7 @@ def preview_datafeed( You can also use secondary authorization headers to supply the credentials.

- ``_ + ``_ :param datafeed_id: A numerical character string that uniquely identifies the datafeed. This identifier can contain lowercase alphanumeric characters (a-z @@ -3232,7 +3232,7 @@ def put_calendar(

Create a calendar.

- ``_ + ``_ :param calendar_id: A string that uniquely identifies a calendar. :param description: A description of the calendar. @@ -3289,7 +3289,7 @@ def put_calendar_job(

Add anomaly detection job to calendar.

- ``_ + ``_ :param calendar_id: A string that uniquely identifies a calendar. :param job_id: An identifier for the anomaly detection jobs. It can be a job @@ -3372,7 +3372,7 @@ def put_data_frame_analytics(

If you supply only a subset of the regression or classification parameters, hyperparameter optimization occurs. It determines a value for each of the undefined parameters.

- ``_ + ``_ :param id: Identifier for the data frame analytics job. This identifier can contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and underscores. @@ -3557,7 +3557,7 @@ def put_datafeed( directly to the .ml-config index. Do not give users write privileges on the .ml-config index.

- ``_ + ``_ :param datafeed_id: A numerical character string that uniquely identifies the datafeed. This identifier can contain lowercase alphanumeric characters (a-z @@ -3719,7 +3719,7 @@ def put_filter( Specifically, filters are referenced in the custom_rules property of detector configuration objects.

- ``_ + ``_ :param filter_id: A string that uniquely identifies a filter. :param description: A description of the filter. @@ -3821,7 +3821,7 @@ def put_job( If you include a datafeed_config but do not provide a query, the datafeed uses {"match_all": {"boost": 1}}.

- ``_ + ``_ :param job_id: The identifier for the anomaly detection job. This identifier can contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and @@ -4029,7 +4029,7 @@ def put_trained_model( Enable you to supply a trained model that is not created by data frame analytics.

- ``_ + ``_ :param model_id: The unique identifier of the trained model. :param compressed_definition: The compressed (GZipped and Base64 encoded) inference @@ -4150,7 +4150,7 @@ def put_trained_model_alias( returns a warning.

- ``_ + ``_ :param model_id: The identifier for the trained model that the alias refers to. :param model_alias: The alias to create or update. This value cannot end in numbers. @@ -4211,7 +4211,7 @@ def put_trained_model_definition_part(

Create part of a trained model definition.

- ``_ + ``_ :param model_id: The unique identifier of the trained model. :param part: The definition part number. When the definition is loaded for inference @@ -4293,7 +4293,7 @@ def put_trained_model_vocabulary( The vocabulary is stored in the index as described in inference_config.*.vocabulary of the trained model definition.

- ``_ + ``_ :param model_id: The unique identifier of the trained model. :param vocabulary: The model vocabulary, which must not be empty. @@ -4356,7 +4356,7 @@ def reset_job( comma separated list.

- ``_ + ``_ :param job_id: The ID of the job to reset. :param delete_user_annotations: Specifies whether annotations that have been @@ -4420,7 +4420,7 @@ def revert_model_snapshot( snapshot after Black Friday or a critical system failure.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param snapshot_id: You can specify `empty` as the . Reverting to @@ -4495,7 +4495,7 @@ def set_upgrade_mode( machine learning info API.

- ``_ + ``_ :param enabled: When `true`, it enables `upgrade_mode` which temporarily halts all job and datafeed tasks and prohibits new job and datafeed tasks from @@ -4555,7 +4555,7 @@ def start_data_frame_analytics( the destination index in advance with custom settings and mappings.

- ``_ + ``_ :param id: Identifier for the data frame analytics job. This identifier can contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and underscores. @@ -4618,7 +4618,7 @@ def start_datafeed( authorization headers when you created or updated the datafeed, those credentials are used instead.

- ``_ + ``_ :param datafeed_id: A numerical character string that uniquely identifies the datafeed. This identifier can contain lowercase alphanumeric characters (a-z @@ -4695,7 +4695,7 @@ def start_trained_model_deployment( It allocates the model to every machine learning node.

- ``_ + ``_ :param model_id: The unique identifier of the trained model. Currently, only PyTorch models are supported. @@ -4796,7 +4796,7 @@ def stop_data_frame_analytics( throughout its lifecycle.

- ``_ + ``_ :param id: Identifier for the data frame analytics job. This identifier can contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and underscores. @@ -4866,7 +4866,7 @@ def stop_datafeed( multiple times throughout its lifecycle.

- ``_ + ``_ :param datafeed_id: Identifier for the datafeed. You can stop multiple datafeeds in a single API request by using a comma-separated list of datafeeds or a @@ -4931,7 +4931,7 @@ def stop_trained_model_deployment(

Stop a trained model deployment.

- ``_ + ``_ :param model_id: The unique identifier of the trained model. :param allow_no_match: Specifies what to do when the request: contains wildcard @@ -4999,7 +4999,7 @@ def update_data_frame_analytics(

Update a data frame analytics job.

- ``_ + ``_ :param id: Identifier for the data frame analytics job. This identifier can contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and underscores. @@ -5114,7 +5114,7 @@ def update_datafeed( those credentials are used instead.

- ``_ + ``_ :param datafeed_id: A numerical character string that uniquely identifies the datafeed. This identifier can contain lowercase alphanumeric characters (a-z @@ -5281,7 +5281,7 @@ def update_filter( Updates the description of a filter, adds items, or removes items from the list.

- ``_ + ``_ :param filter_id: A string that uniquely identifies a filter. :param add_items: The items to add to the filter. @@ -5375,7 +5375,7 @@ def update_job( Updates certain properties of an anomaly detection job.

- ``_ + ``_ :param job_id: Identifier for the job. :param allow_lazy_open: Advanced configuration option. Specifies whether this @@ -5507,7 +5507,7 @@ def update_model_snapshot( Updates certain properties of a snapshot.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param snapshot_id: Identifier for the model snapshot. @@ -5572,7 +5572,7 @@ def update_trained_model_deployment(

Update a trained model deployment.

- ``_ + ``_ :param model_id: The unique identifier of the trained model. Currently, only PyTorch models are supported. @@ -5649,7 +5649,7 @@ def upgrade_job_snapshot( job.

- ``_ + ``_ :param job_id: Identifier for the anomaly detection job. :param snapshot_id: A numerical character string that uniquely identifies the @@ -5801,7 +5801,7 @@ def validate_detector(

Validate an anomaly detection job.

- ``_ + ``_ :param detector: """ diff --git a/elasticsearch/_sync/client/monitoring.py b/elasticsearch/_sync/client/monitoring.py index 59cee2235..b075447d5 100644 --- a/elasticsearch/_sync/client/monitoring.py +++ b/elasticsearch/_sync/client/monitoring.py @@ -48,7 +48,7 @@ def bulk( This API is used by the monitoring features to send monitoring data.

- ``_ + ``_ :param interval: Collection interval (e.g., '10s' or '10000ms') of the payload :param operations: diff --git a/elasticsearch/_sync/client/nodes.py b/elasticsearch/_sync/client/nodes.py index e300ba3e3..2dedf4b77 100644 --- a/elasticsearch/_sync/client/nodes.py +++ b/elasticsearch/_sync/client/nodes.py @@ -50,7 +50,7 @@ def clear_repositories_metering_archive( Clear the archived repositories metering information in the cluster.

- ``_ + ``_ :param node_id: Comma-separated list of node IDs or names used to limit returned information. @@ -105,10 +105,10 @@ def get_repositories_metering_info( Additionally, the information exposed by this API is volatile, meaning that it will not be present after node restarts.

- ``_ + ``_ :param node_id: Comma-separated list of node IDs or names used to limit returned - information. All the nodes selective options are explained [here](https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster.html#cluster-nodes). + information. """ if node_id in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'node_id'") @@ -162,7 +162,7 @@ def hot_threads( The output is plain text with a breakdown of the top hot threads for each node.

- ``_ + ``_ :param node_id: List of node IDs or names used to limit returned information. :param ignore_idle_threads: If true, known idle threads (e.g. waiting in a socket @@ -235,7 +235,7 @@ def info(

By default, the API returns all attributes and core settings for cluster nodes.

- ``_ + ``_ :param node_id: Comma-separated list of node IDs or names used to limit returned information. @@ -308,7 +308,7 @@ def reload_secure_settings( Alternatively, you can reload the secure settings on each node by locally accessing the API and passing the node-specific Elasticsearch keystore password.

- ``_ + ``_ :param node_id: The names of particular nodes in the cluster to target. :param secure_settings_password: The password for the Elasticsearch keystore. @@ -383,7 +383,7 @@ def stats( By default, all stats are returned. You can limit the returned information by using metrics.

- ``_ + ``_ :param node_id: Comma-separated list of node IDs or names used to limit returned information. @@ -498,7 +498,7 @@ def usage(

Get feature usage information.

- ``_ + ``_ :param node_id: A comma-separated list of node IDs or names to limit the returned information; use `_local` to return information from the node you're connecting diff --git a/elasticsearch/_sync/client/query_rules.py b/elasticsearch/_sync/client/query_rules.py index 351c4dd80..7620755f2 100644 --- a/elasticsearch/_sync/client/query_rules.py +++ b/elasticsearch/_sync/client/query_rules.py @@ -44,7 +44,7 @@ def delete_rule( This is a destructive action that is only recoverable by re-adding the same rule with the create or update query rule API.

- ``_ + ``_ :param ruleset_id: The unique identifier of the query ruleset containing the rule to delete @@ -97,7 +97,7 @@ def delete_ruleset( This is a destructive action that is not recoverable.

- ``_ + ``_ :param ruleset_id: The unique identifier of the query ruleset to delete """ @@ -142,7 +142,7 @@ def get_rule( Get details about a query rule within a query ruleset.

- ``_ + ``_ :param ruleset_id: The unique identifier of the query ruleset containing the rule to retrieve @@ -194,7 +194,7 @@ def get_ruleset( Get details about a query ruleset.

- ``_ + ``_ :param ruleset_id: The unique identifier of the query ruleset """ @@ -241,7 +241,7 @@ def list_rulesets( Get summarized information about the query rulesets.

- ``_ + ``_ :param from_: The offset from the first result to fetch. :param size: The maximum number of results to retrieve. @@ -302,7 +302,7 @@ def put_rule( If multiple matching rules pin more than 100 documents, only the first 100 documents are pinned in the order they are specified in the ruleset.

- ``_ + ``_ :param ruleset_id: The unique identifier of the query ruleset containing the rule to be created or updated. @@ -389,7 +389,7 @@ def put_ruleset( If multiple matching rules pin more than 100 documents, only the first 100 documents are pinned in the order they are specified in the ruleset.

- ``_ + ``_ :param ruleset_id: The unique identifier of the query ruleset to be created or updated. @@ -446,7 +446,7 @@ def test( Evaluate match criteria against a query ruleset to identify the rules that would match that criteria.

- ``_ + ``_ :param ruleset_id: The unique identifier of the query ruleset to be created or updated diff --git a/elasticsearch/_sync/client/rollup.py b/elasticsearch/_sync/client/rollup.py index 5e34d954f..cc88f0a06 100644 --- a/elasticsearch/_sync/client/rollup.py +++ b/elasticsearch/_sync/client/rollup.py @@ -67,7 +67,7 @@ def delete_job( - ``_ + ``_ :param id: Identifier for the job. """ @@ -115,7 +115,7 @@ def get_jobs( For details about a historical rollup job, the rollup capabilities API may be more useful.

- ``_ + ``_ :param id: Identifier for the rollup job. If it is `_all` or omitted, the API returns all rollup jobs. @@ -171,7 +171,7 @@ def get_rollup_caps( - ``_ + ``_ :param id: Index, indices or index-pattern to return rollup capabilities for. `_all` may be used to fetch rollup capabilities from all jobs. @@ -225,7 +225,7 @@ def get_rollup_index_caps( - ``_ + ``_ :param index: Data stream or index to check for rollup capabilities. Wildcard (`*`) expressions are supported. @@ -295,7 +295,7 @@ def put_job(

Jobs are created in a STOPPED state. You can start them with the start rollup jobs API.

- ``_ + ``_ :param id: Identifier for the rollup job. This can be any alphanumeric string and uniquely identifies the data that is associated with the rollup job. @@ -443,7 +443,7 @@ def rollup_search( During the merging process, if there is any overlap in buckets between the two responses, the buckets from the non-rollup index are used.

- ``_ + ``_ :param index: A comma-separated list of data streams and indices used to limit the request. This parameter has the following rules: * At least one data @@ -521,7 +521,7 @@ def start_job( If you try to start a job that is already started, nothing happens.

- ``_ + ``_ :param id: Identifier for the rollup job. """ @@ -575,7 +575,7 @@ def stop_job( If the specified time elapses without the job moving to STOPPED, a timeout exception occurs.

- ``_ + ``_ :param id: Identifier for the rollup job. :param timeout: If `wait_for_completion` is `true`, the API blocks for (at maximum) diff --git a/elasticsearch/_sync/client/search_application.py b/elasticsearch/_sync/client/search_application.py index b81980475..3776cc740 100644 --- a/elasticsearch/_sync/client/search_application.py +++ b/elasticsearch/_sync/client/search_application.py @@ -49,7 +49,7 @@ def delete(

Remove a search application and its associated alias. Indices attached to the search application are not removed.

- ``_ + ``_ :param name: The name of the search application to delete. """ @@ -94,7 +94,7 @@ def delete_behavioral_analytics( The associated data stream is also deleted.

- ``_ + ``_ :param name: The name of the analytics collection to be deleted """ @@ -138,7 +138,7 @@ def get(

Get search application details.

- ``_ + ``_ :param name: The name of the search application """ @@ -182,7 +182,7 @@ def get_behavioral_analytics(

Get behavioral analytics collections.

- ``_ + ``_ :param name: A list of analytics collections to limit the returned information """ @@ -234,7 +234,7 @@ def list( Get information about search applications.

- ``_ + ``_ :param from_: Starting offset. :param q: Query in the Lucene query string syntax. @@ -290,7 +290,7 @@ def post_behavioral_analytics_event(

Create a behavioral analytics collection event.

- ``_ + ``_ :param collection_name: The name of the behavioral analytics collection. :param event_type: The analytics event type. @@ -357,7 +357,7 @@ def put(

Create or update a search application.

- ``_ + ``_ :param name: The name of the search application to be created or updated. :param search_application: @@ -414,7 +414,7 @@ def put_behavioral_analytics(

Create a behavioral analytics collection.

- ``_ + ``_ :param name: The name of the analytics collection to be created or updated. """ @@ -467,7 +467,7 @@ def render_query(

You must have read privileges on the backing alias of the search application.

- ``_ + ``_ :param name: The name of the search application to render teh query for. :param params: @@ -531,7 +531,7 @@ def search( Unspecified template parameters are assigned their default values if applicable.

- ``_ + ``_ :param name: The name of the search application to be searched. :param params: Query parameters specific to this request, which will override diff --git a/elasticsearch/_sync/client/searchable_snapshots.py b/elasticsearch/_sync/client/searchable_snapshots.py index 2160988c0..f44a18797 100644 --- a/elasticsearch/_sync/client/searchable_snapshots.py +++ b/elasticsearch/_sync/client/searchable_snapshots.py @@ -50,7 +50,7 @@ def cache_stats( Get statistics about the shared cache for partially mounted indices.

- ``_ + ``_ :param node_id: The names of the nodes in the cluster to target. :param master_timeout: @@ -111,7 +111,7 @@ def clear_cache( Clear indices and data streams from the shared cache for partially mounted indices.

- ``_ + ``_ :param index: A comma-separated list of data streams, indices, and aliases to clear from the cache. It supports wildcards (`*`). @@ -190,7 +190,7 @@ def mount( Manually mounting ILM-managed snapshots can interfere with ILM processes.

- ``_ + ``_ :param repository: The name of the repository containing the snapshot of the index to mount. @@ -278,7 +278,7 @@ def stats(

Get searchable snapshot statistics.

- ``_ + ``_ :param index: A comma-separated list of data streams and indices to retrieve statistics for. diff --git a/elasticsearch/_sync/client/security.py b/elasticsearch/_sync/client/security.py index 5aac0202f..8ebed4b1d 100644 --- a/elasticsearch/_sync/client/security.py +++ b/elasticsearch/_sync/client/security.py @@ -58,7 +58,7 @@ def activate_user_profile( Any updates do not change existing content for either the labels or data fields.

- ``_ + ``_ :param grant_type: The type of grant. :param access_token: The user's Elasticsearch access token or JWT. Both `access` @@ -124,7 +124,7 @@ def authenticate( If the user cannot be authenticated, this API returns a 401 status code.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_security/_authenticate" @@ -171,7 +171,7 @@ def bulk_delete_role( The bulk delete roles API cannot delete roles that are defined in roles files.

- ``_ + ``_ :param names: An array of role names to delete :param refresh: If `true` (the default) then refresh the affected shards to make @@ -232,7 +232,7 @@ def bulk_put_role( The bulk create or update roles API cannot update roles that are defined in roles files.

- ``_ + ``_ :param roles: A dictionary of role name to RoleDescriptor objects to add or update :param refresh: If `true` (the default) then refresh the affected shards to make @@ -300,7 +300,7 @@ def bulk_update_api_keys(

A successful request returns a JSON structure that contains the IDs of all updated API keys, the IDs of API keys that already had the requested changes and did not require an update, and error details for any failed update.

- ``_ + ``_ :param ids: The API key identifiers. :param expiration: Expiration time for the API keys. By default, API keys never @@ -378,7 +378,7 @@ def change_password(

Change the passwords of users in the native realm and built-in users.

- ``_ + ``_ :param username: The user whose password you want to change. If you do not specify this parameter, the password is changed for the current user. @@ -445,7 +445,7 @@ def clear_api_key_cache( The cache is also automatically cleared on state changes of the security index.

- ``_ + ``_ :param ids: Comma-separated list of API key IDs to evict from the API key cache. To evict all API keys, use `*`. Does not support other wildcard patterns. @@ -491,7 +491,7 @@ def clear_cached_privileges( The cache is also automatically cleared for applications that have their privileges updated.

- ``_ + ``_ :param application: A comma-separated list of applications. To clear all applications, use an asterism (`*`). It does not support other wildcard patterns. @@ -541,7 +541,7 @@ def clear_cached_realms( For more information, refer to the documentation about controlling the user cache.

- ``_ + ``_ :param realms: A comma-separated list of realms. To clear all realms, use an asterisk (`*`). It does not support other wildcard patterns. @@ -591,7 +591,7 @@ def clear_cached_roles(

Evict roles from the native role cache.

- ``_ + ``_ :param name: A comma-separated list of roles to evict from the role cache. To evict all roles, use an asterisk (`*`). It does not support other wildcard @@ -643,7 +643,7 @@ def clear_cached_service_tokens( The cache for tokens backed by the service_tokens file is cleared automatically on file changes.

- ``_ + ``_ :param namespace: The namespace, which is a top-level grouping of service accounts. :param service: The name of the service, which must be unique within its namespace. @@ -715,7 +715,7 @@ def create_api_key( To configure or turn off the API key service, refer to API key service setting documentation.

- ``_ + ``_ :param expiration: The expiration time for the API key. By default, API keys never expire. @@ -805,7 +805,7 @@ def create_cross_cluster_api_key( Attempting to update them with the update REST API key API or the bulk update REST API keys API will result in an error.

- ``_ + ``_ :param access: The access to be granted to this API key. The access is composed of permissions for cross-cluster search and cross-cluster replication. At @@ -880,7 +880,7 @@ def create_service_token( You must actively delete them if they are no longer needed.

- ``_ + ``_ :param namespace: The name of the namespace, which is a top-level grouping of service accounts. @@ -966,7 +966,7 @@ def delegate_pki( The proxy is trusted to have performed the TLS authentication and this API translates that authentication into an Elasticsearch access token.

- ``_ + ``_ :param x509_certificate_chain: The X509Certificate chain, which is represented as an ordered string array. Each string in the array is a base64-encoded @@ -1030,7 +1030,7 @@ def delete_privileges( - ``_ + ``_ :param application: The name of the application. Application privileges are always associated with exactly one application. @@ -1093,7 +1093,7 @@ def delete_role( The delete roles API cannot remove roles that are defined in roles files.

- ``_ + ``_ :param name: The name of the role. :param refresh: If `true` (the default) then refresh the affected shards to make @@ -1147,7 +1147,7 @@ def delete_role_mapping( The delete role mappings API cannot remove role mappings that are defined in role mapping files.

- ``_ + ``_ :param name: The distinct name that identifies the role mapping. The name is used solely as an identifier to facilitate interaction via the API; it does @@ -1203,7 +1203,7 @@ def delete_service_token(

Delete service account tokens for a service in a specified namespace.

- ``_ + ``_ :param namespace: The namespace, which is a top-level grouping of service accounts. :param service: The service name. @@ -1265,7 +1265,7 @@ def delete_user(

Delete users from the native realm.

- ``_ + ``_ :param username: An identifier for the user. :param refresh: If `true` (the default) then refresh the affected shards to make @@ -1319,7 +1319,7 @@ def disable_user( You can use this API to revoke a user's access to Elasticsearch.

- ``_ + ``_ :param username: An identifier for the user. :param refresh: If `true` (the default) then refresh the affected shards to make @@ -1376,7 +1376,7 @@ def disable_user_profile( To re-enable a disabled user profile, use the enable user profile API .

- ``_ + ``_ :param uid: Unique identifier for the user profile. :param refresh: If 'true', Elasticsearch refreshes the affected shards to make @@ -1429,7 +1429,7 @@ def enable_user( By default, when you create users, they are enabled.

- ``_ + ``_ :param username: An identifier for the user. :param refresh: If `true` (the default) then refresh the affected shards to make @@ -1486,7 +1486,7 @@ def enable_user_profile( If you later disable the user profile, you can use the enable user profile API to make the profile visible in these searches again.

- ``_ + ``_ :param uid: A unique identifier for the user profile. :param refresh: If 'true', Elasticsearch refreshes the affected shards to make @@ -1536,7 +1536,7 @@ def enroll_kibana( Kibana uses this API internally to configure itself for communications with an Elasticsearch cluster that already has security features enabled.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_security/enroll/kibana" @@ -1577,7 +1577,7 @@ def enroll_node( The response contains key and certificate material that allows the caller to generate valid signed certificates for the HTTP layer of all nodes in the cluster.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_security/enroll/node" @@ -1626,7 +1626,7 @@ def get_api_key( If you have read_security, manage_api_key or greater privileges (including manage_security), this API returns all API keys regardless of ownership.

- ``_ + ``_ :param active_only: A boolean flag that can be used to query API keys that are currently active. An API key is considered active if it is neither invalidated, @@ -1704,7 +1704,7 @@ def get_builtin_privileges(

Get the list of cluster privileges and index privileges that are available in this version of Elasticsearch.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_security/privilege/_builtin" @@ -1749,7 +1749,7 @@ def get_privileges( - ``_ + ``_ :param application: The name of the application. Application privileges are always associated with exactly one application. If you do not specify this parameter, @@ -1805,7 +1805,7 @@ def get_role( The get roles API cannot retrieve roles that are defined in roles files.

- ``_ + ``_ :param name: The name of the role. You can specify multiple roles as a comma-separated list. If you do not specify this parameter, the API returns information about @@ -1856,7 +1856,7 @@ def get_role_mapping( The get role mappings API cannot retrieve role mappings that are defined in role mapping files.

- ``_ + ``_ :param name: The distinct name that identifies the role mapping. The name is used solely as an identifier to facilitate interaction via the API; it does @@ -1909,7 +1909,7 @@ def get_service_accounts(

NOTE: Currently, only the elastic/fleet-server service account is available.

- ``_ + ``_ :param namespace: The name of the namespace. Omit this parameter to retrieve information about all service accounts. If you omit this parameter, you must @@ -1967,7 +1967,7 @@ def get_service_credentials( Tokens with the same name from different nodes are assumed to be the same token and are only counted once towards the total number of service tokens.

- ``_ + ``_ :param namespace: The name of the namespace. :param service: The service name. @@ -2023,7 +2023,7 @@ def get_settings( - ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails and @@ -2099,7 +2099,7 @@ def get_token( If you want to invalidate a token immediately, you can do so by using the invalidate token API.

- ``_ + ``_ :param grant_type: The type of grant. Supported grant types are: `password`, `_kerberos`, `client_credentials`, and `refresh_token`. @@ -2173,7 +2173,7 @@ def get_user(

Get information about users in the native realm and built-in users.

- ``_ + ``_ :param username: An identifier for the user. You can specify multiple usernames as a comma-separated list. If you omit this parameter, the API retrieves @@ -2231,7 +2231,7 @@ def get_user_privileges( To check whether a user has a specific list of privileges, use the has privileges API.

- ``_ + ``_ :param application: The name of the application. Application privileges are always associated with exactly one application. If you do not specify this parameter, @@ -2288,7 +2288,7 @@ def get_user_profile( Elastic reserves the right to change or remove this feature in future releases without prior notice.

- ``_ + ``_ :param uid: A unique identifier for the user profile. :param data: A comma-separated list of filters for the `data` field of the profile @@ -2372,7 +2372,7 @@ def grant_api_key(

By default, API keys never expire. You can specify expiration information when you create the API keys.

- ``_ + ``_ :param api_key: The API key. :param grant_type: The type of grant. Supported grant types are: `access_token`, @@ -2519,7 +2519,7 @@ def has_privileges( To check the privileges of other users, you must use the run as feature.

- ``_ + ``_ :param user: Username :param application: @@ -2584,7 +2584,7 @@ def has_privileges_user_profile( Elastic reserves the right to change or remove this feature in future releases without prior notice.

- ``_ + ``_ :param privileges: An object containing all the privileges to be checked. :param uids: A list of profile IDs. The privileges are checked for associated @@ -2658,7 +2658,7 @@ def invalidate_api_key( - ``_ + ``_ :param id: :param ids: A list of API key ids. This parameter cannot be used with any of @@ -2742,7 +2742,7 @@ def invalidate_token( If none of these two are specified, then realm_name and/or username need to be specified.

- ``_ + ``_ :param realm_name: The name of an authentication realm. This parameter cannot be used with either `refresh_token` or `token`. @@ -2810,7 +2810,7 @@ def oidc_authenticate( These APIs are used internally by Kibana in order to provide OpenID Connect based authentication, but can also be used by other, custom web applications or other clients.

- ``_ + ``_ :param nonce: Associate a client session with an ID token and mitigate replay attacks. This value needs to be the same as the one that was provided to @@ -2890,7 +2890,7 @@ def oidc_logout( These APIs are used internally by Kibana in order to provide OpenID Connect based authentication, but can also be used by other, custom web applications or other clients.

- ``_ + ``_ :param token: The access token to be invalidated. :param refresh_token: The refresh token to be invalidated. @@ -2952,7 +2952,7 @@ def oidc_prepare_authentication( These APIs are used internally by Kibana in order to provide OpenID Connect based authentication, but can also be used by other, custom web applications or other clients.

- ``_ + ``_ :param iss: In the case of a third party initiated single sign on, this is the issuer identifier for the OP that the RP is to send the authentication request @@ -3048,7 +3048,7 @@ def put_privileges(

Action names can contain any number of printable ASCII characters and must contain at least one of the following characters: /, *, :.

- ``_ + ``_ :param privileges: :param refresh: If `true` (the default) then refresh the affected shards to make @@ -3200,7 +3200,7 @@ def put_role( File-based role management is not available in Elastic Serverless.

- ``_ + ``_ :param name: The name of the role that is being created or updated. On Elasticsearch Serverless, the role name must begin with a letter or digit and can only @@ -3335,7 +3335,7 @@ def put_role_mapping( If the format of the template is set to "json" then the template is expected to produce a JSON string or an array of JSON strings for the role names.

- ``_ + ``_ :param name: The distinct name that identifies the role mapping. The name is used solely as an identifier to facilitate interaction via the API; it does @@ -3437,7 +3437,7 @@ def put_user( To change a user's password without updating any other fields, use the change password API.

- ``_ + ``_ :param username: An identifier for the user. NOTE: Usernames must be at least 1 and no more than 507 characters. They can contain alphanumeric characters @@ -3556,7 +3556,7 @@ def query_api_keys( If you have the read_security, manage_api_key, or greater privileges (including manage_security), this API returns all API keys regardless of ownership.

- ``_ + ``_ :param aggregations: Any aggregations to run over the corpus of returned API keys. Aggregations and queries work together. Aggregations are computed only @@ -3699,7 +3699,7 @@ def query_role( Also, the results can be paginated and sorted.

- ``_ + ``_ :param from_: The starting document offset. It must not be negative. By default, you cannot page through more than 10,000 hits using the `from` and `size` @@ -3792,7 +3792,7 @@ def query_user( This API is only for native users.

- ``_ + ``_ :param from_: The starting document offset. It must not be negative. By default, you cannot page through more than 10,000 hits using the `from` and `size` @@ -3885,7 +3885,7 @@ def saml_authenticate( This API endpoint essentially exchanges SAML responses that indicate successful authentication in the IdP for Elasticsearch access and refresh tokens, which can be used for authentication against Elasticsearch.

- ``_ + ``_ :param content: The SAML response as it was sent by the user's browser, usually a Base64 encoded XML document. @@ -3958,7 +3958,7 @@ def saml_complete_logout( The caller of this API must prepare the request accordingly so that this API can handle either of them.

- ``_ + ``_ :param ids: A JSON array with all the valid SAML Request Ids that the caller of the API has for the current user. @@ -4034,7 +4034,7 @@ def saml_invalidate( Thus the user can be redirected back to their IdP.

- ``_ + ``_ :param query_string: The query part of the URL that the user was redirected to by the SAML IdP to initiate the Single Logout. This query should include @@ -4109,7 +4109,7 @@ def saml_logout( If the SAML realm in Elasticsearch is configured accordingly and the SAML IdP supports this, the Elasticsearch response contains a URL to redirect the user to the IdP that contains a SAML logout request (starting an SP-initiated SAML Single Logout).

- ``_ + ``_ :param token: The access token that was returned as a response to calling the SAML authenticate API. Alternatively, the most recent token that was received @@ -4179,7 +4179,7 @@ def saml_prepare_authentication( The caller of this API needs to store this identifier as it needs to be used in a following step of the authentication process.

- ``_ + ``_ :param acs: The Assertion Consumer Service URL that matches the one of the SAML realms in Elasticsearch. The realm is used to generate the authentication @@ -4240,7 +4240,7 @@ def saml_service_provider_metadata( This API generates Service Provider metadata based on the configuration of a SAML realm in Elasticsearch.

- ``_ + ``_ :param realm_name: The name of the SAML realm in Elasticsearch. """ @@ -4293,7 +4293,7 @@ def suggest_user_profiles( Elastic reserves the right to change or remove this feature in future releases without prior notice.

- ``_ + ``_ :param data: A comma-separated list of filters for the `data` field of the profile document. To return all content use `data=*`. To return a subset of content, @@ -4380,7 +4380,7 @@ def update_api_key( This change can occur if the owner user's permissions have changed since the API key was created or last modified.

- ``_ + ``_ :param id: The ID of the API key to update. :param expiration: The expiration time for the API key. By default, API keys @@ -4468,7 +4468,7 @@ def update_cross_cluster_api_key(

NOTE: This API cannot update REST API keys, which should be updated by either the update API key or bulk update API keys API.

- ``_ + ``_ :param id: The ID of the cross-cluster API key to update. :param access: The access to be granted to this API key. The access is composed @@ -4547,7 +4547,7 @@ def update_settings( This API does not yet support configuring the settings for indices before they are in use.

- ``_ + ``_ :param master_timeout: The period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails @@ -4632,7 +4632,7 @@ def update_user_profile_data( The update_profile_data global privilege grants privileges for updating only the allowed namespaces.

- ``_ + ``_ :param uid: A unique identifier for the user profile. :param data: Non-searchable data that you want to associate with the user profile. diff --git a/elasticsearch/_sync/client/shutdown.py b/elasticsearch/_sync/client/shutdown.py index d7ec41511..b1166feb0 100644 --- a/elasticsearch/_sync/client/shutdown.py +++ b/elasticsearch/_sync/client/shutdown.py @@ -53,7 +53,7 @@ def delete_node(

If the operator privileges feature is enabled, you must be an operator to use this API.

- ``_ + ``_ :param node_id: The node id of node to be removed from the shutdown state :param master_timeout: Period to wait for a connection to the master node. If @@ -112,7 +112,7 @@ def get_node(

If the operator privileges feature is enabled, you must be an operator to use this API.

- ``_ + ``_ :param node_id: Which node for which to retrieve the shutdown status :param master_timeout: Period to wait for a connection to the master node. If @@ -187,7 +187,7 @@ def put_node( Monitor the node shutdown status to determine when it is safe to stop Elasticsearch.

- ``_ + ``_ :param node_id: The node identifier. This parameter is not validated against the cluster's active nodes. This enables you to register a node for shut diff --git a/elasticsearch/_sync/client/simulate.py b/elasticsearch/_sync/client/simulate.py index 5f22ae433..db0a85092 100644 --- a/elasticsearch/_sync/client/simulate.py +++ b/elasticsearch/_sync/client/simulate.py @@ -81,7 +81,7 @@ def ingest( These will be used in place of the pipeline definitions that are already in the system. This can be used to replace existing pipeline definitions or to create new ones. The pipeline substitutions are used only within this request.

- ``_ + ``_ :param docs: Sample documents to test in the pipeline. :param index: The index to simulate ingesting into. This value can be overridden diff --git a/elasticsearch/_sync/client/slm.py b/elasticsearch/_sync/client/slm.py index 9b701de80..201840fd5 100644 --- a/elasticsearch/_sync/client/slm.py +++ b/elasticsearch/_sync/client/slm.py @@ -45,7 +45,7 @@ def delete_lifecycle( This operation prevents any future snapshots from being taken but does not cancel in-progress snapshots or remove previously-taken snapshots.

- ``_ + ``_ :param policy_id: The id of the snapshot lifecycle policy to remove :param master_timeout: The period to wait for a connection to the master node. @@ -101,7 +101,7 @@ def execute_lifecycle( The snapshot policy is normally applied according to its schedule, but you might want to manually run a policy before performing an upgrade or other maintenance.

- ``_ + ``_ :param policy_id: The id of the snapshot lifecycle policy to be executed :param master_timeout: The period to wait for a connection to the master node. @@ -156,7 +156,7 @@ def execute_retention( The retention policy is normally applied according to its schedule.

- ``_ + ``_ :param master_timeout: The period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails @@ -208,7 +208,7 @@ def get_lifecycle( Get snapshot lifecycle policy definitions and information about the latest snapshot attempts.

- ``_ + ``_ :param policy_id: Comma-separated list of snapshot lifecycle policies to retrieve :param master_timeout: The period to wait for a connection to the master node. @@ -265,7 +265,7 @@ def get_stats( Get global and policy-level statistics about actions taken by snapshot lifecycle management.

- ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails and @@ -315,7 +315,7 @@ def get_status(

Get the snapshot lifecycle management status.

- ``_ + ``_ :param master_timeout: The period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails @@ -379,7 +379,7 @@ def put_lifecycle( Only the latest version of a policy is stored.

- ``_ + ``_ :param policy_id: The identifier for the snapshot lifecycle policy you want to create or update. @@ -465,7 +465,7 @@ def start( Manually starting SLM is necessary only if it has been stopped using the stop SLM API.

- ``_ + ``_ :param master_timeout: The period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails @@ -523,7 +523,7 @@ def stop( Use the get snapshot lifecycle management status API to see if SLM is running.

- ``_ + ``_ :param master_timeout: The period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails diff --git a/elasticsearch/_sync/client/snapshot.py b/elasticsearch/_sync/client/snapshot.py index 26c841765..0f8ce9f13 100644 --- a/elasticsearch/_sync/client/snapshot.py +++ b/elasticsearch/_sync/client/snapshot.py @@ -50,7 +50,7 @@ def cleanup_repository( Trigger the review of the contents of a snapshot repository and delete any stale data not referenced by existing snapshots.

- ``_ + ``_ :param name: The name of the snapshot repository to clean up. :param master_timeout: The period to wait for a connection to the master node. @@ -105,7 +105,6 @@ def clone( human: t.Optional[bool] = None, master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, pretty: t.Optional[bool] = None, - timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -115,7 +114,7 @@ def clone( Clone part of all of a snapshot into another snapshot in the same repository.

- ``_ + ``_ :param repository: The name of the snapshot repository that both source and target snapshot belong to. @@ -126,8 +125,6 @@ def clone( :param master_timeout: The period to wait for the master node. If the master node is not available before the timeout expires, the request fails and returns an error. To indicate that the request should never timeout, set it to `-1`. - :param timeout: The period of time to wait for a response. If no response is - received before the timeout expires, the request fails and returns an error. """ if repository in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'repository'") @@ -155,8 +152,6 @@ def clone( __query["master_timeout"] = master_timeout if pretty is not None: __query["pretty"] = pretty - if timeout is not None: - __query["timeout"] = timeout if not __body: if indices is not None: __body["indices"] = indices @@ -216,7 +211,7 @@ def create( Take a snapshot of a cluster or of data streams and indices.

- ``_ + ``_ :param repository: The name of the repository for the snapshot. :param snapshot: The name of the snapshot. It supportes date math. It must be @@ -343,7 +338,7 @@ def create_repository( If both parameters are specified, only the query parameter is used.

- ``_ + ``_ :param name: The name of the snapshot repository to register or update. :param repository: @@ -415,7 +410,7 @@ def delete(

Delete snapshots.

- ``_ + ``_ :param repository: The name of the repository to delete a snapshot from. :param snapshot: A comma-separated list of snapshot names to delete. It also @@ -474,7 +469,7 @@ def delete_repository( The snapshots themselves are left untouched and in place.

- ``_ + ``_ :param name: The ame of the snapshot repositories to unregister. Wildcard (`*`) patterns are supported. @@ -560,7 +555,7 @@ def get( Snapshots concurrently created may be seen during an iteration.

- ``_ + ``_ :param repository: A comma-separated list of snapshot repository names used to limit the request. Wildcard (`*`) expressions are supported. @@ -686,7 +681,7 @@ def get_repository(

Get snapshot repository information.

- ``_ + ``_ :param name: A comma-separated list of snapshot repository names used to limit the request. Wildcard (`*`) expressions are supported including combining @@ -830,7 +825,7 @@ def repository_analyze( Some operations also verify the behavior on small blobs with sizes other than 8 bytes.

- ``_ + ``_ :param name: The name of the repository. :param blob_count: The total number of blobs to write to the repository during @@ -963,7 +958,7 @@ def repository_verify_integrity( The response body format is therefore not considered stable and may be different in newer versions.

- ``_ + ``_ :param name: The name of the snapshot repository. :param blob_thread_pool_concurrency: If `verify_blob_contents` is `true`, this @@ -1085,7 +1080,7 @@ def restore(

If your snapshot contains data from App Search or Workplace Search, you must restore the Enterprise Search encryption key before you restore the snapshot.

- ``_ + ``_ :param repository: The name of the repository to restore a snapshot from. :param snapshot: The name of the snapshot to restore. @@ -1235,7 +1230,7 @@ def status( These requests can also tax machine resources and, when using cloud storage, incur high processing costs.

- ``_ + ``_ :param repository: The snapshot repository name used to limit the request. It supports wildcards (`*`) if `` isn't specified. @@ -1303,7 +1298,7 @@ def verify_repository( Check for common misconfigurations in a snapshot repository.

- ``_ + ``_ :param name: The name of the snapshot repository to verify. :param master_timeout: The period to wait for the master node. If the master diff --git a/elasticsearch/_sync/client/sql.py b/elasticsearch/_sync/client/sql.py index 90cb01681..21c28217b 100644 --- a/elasticsearch/_sync/client/sql.py +++ b/elasticsearch/_sync/client/sql.py @@ -44,7 +44,7 @@ def clear_cursor(

Clear an SQL search cursor.

- ``_ + ``_ :param cursor: Cursor to clear. """ @@ -99,7 +99,7 @@ def delete_async( - ``_ + ``_ :param id: The identifier for the search. """ @@ -150,7 +150,7 @@ def get_async(

If the Elasticsearch security features are enabled, only the user who first submitted the SQL search can retrieve the search using this API.

- ``_ + ``_ :param id: The identifier for the search. :param delimiter: The separator for CSV results. The API supports this parameter @@ -212,7 +212,7 @@ def get_async_status( Get the current status of an async SQL search or a stored synchronous SQL search.

- ``_ + ``_ :param id: The identifier for the search. """ @@ -301,7 +301,7 @@ def query( Run an SQL request.

- ``_ + ``_ :param allow_partial_search_results: If `true`, the response has partial results when there are shard request timeouts or shard failures. If `false`, the @@ -427,7 +427,7 @@ def translate( It accepts the same request body parameters as the SQL search API, excluding cursor.

- ``_ + ``_ :param query: The SQL query to run. :param fetch_size: The maximum number of rows (or entries) to return in one response. diff --git a/elasticsearch/_sync/client/ssl.py b/elasticsearch/_sync/client/ssl.py index 6a07966d4..173d56536 100644 --- a/elasticsearch/_sync/client/ssl.py +++ b/elasticsearch/_sync/client/ssl.py @@ -52,7 +52,7 @@ def certificates(

If Elasticsearch is configured to use a keystore or truststore, the API output includes all certificates in that store, even though some of the certificates might not be in active use within the cluster.

- ``_ + ``_ """ __path_parts: t.Dict[str, str] = {} __path = "/_ssl/certificates" diff --git a/elasticsearch/_sync/client/synonyms.py b/elasticsearch/_sync/client/synonyms.py index 1c9613196..37d5530b6 100644 --- a/elasticsearch/_sync/client/synonyms.py +++ b/elasticsearch/_sync/client/synonyms.py @@ -53,7 +53,7 @@ def delete_synonym( When the synonyms set is not used in analyzers, you will be able to delete it.

- ``_ + ``_ :param id: The synonyms set identifier to delete. """ @@ -98,7 +98,7 @@ def delete_synonym_rule( Delete a synonym rule from a synonym set.

- ``_ + ``_ :param set_id: The ID of the synonym set to update. :param rule_id: The ID of the synonym rule to delete. @@ -151,7 +151,7 @@ def get_synonym(

Get a synonym set.

- ``_ + ``_ :param id: The synonyms set identifier to retrieve. :param from_: The starting offset for query rules to retrieve. @@ -202,7 +202,7 @@ def get_synonym_rule( Get a synonym rule from a synonym set.

- ``_ + ``_ :param set_id: The ID of the synonym set to retrieve the synonym rule from. :param rule_id: The ID of the synonym rule to retrieve. @@ -255,7 +255,7 @@ def get_synonyms_sets( Get a summary of all defined synonym sets.

- ``_ + ``_ :param from_: The starting offset for synonyms sets to retrieve. :param size: The maximum number of synonyms sets to retrieve. @@ -311,7 +311,7 @@ def put_synonym( This is equivalent to invoking the reload search analyzers API for all indices that use the synonyms set.

- ``_ + ``_ :param id: The ID of the synonyms set to be created or updated. :param synonyms_set: The synonym rules definitions for the synonyms set. @@ -370,7 +370,7 @@ def put_synonym_rule(

When you update a synonym rule, all analyzers using the synonyms set will be reloaded automatically to reflect the new rule.

- ``_ + ``_ :param set_id: The ID of the synonym set. :param rule_id: The ID of the synonym rule to be updated or created. diff --git a/elasticsearch/_sync/client/tasks.py b/elasticsearch/_sync/client/tasks.py index e341b371c..d542e593b 100644 --- a/elasticsearch/_sync/client/tasks.py +++ b/elasticsearch/_sync/client/tasks.py @@ -60,7 +60,7 @@ def cancel( You can also use the node hot threads API to obtain detailed information about the work the system is doing instead of completing the cancelled task.

- ``_ + ``_ :param task_id: The task identifier. :param actions: A comma-separated list or wildcard expression of actions that @@ -128,7 +128,7 @@ def get(

If the task identifier is not found, a 404 response code indicates that there are no resources that match the request.

- ``_ + ``_ :param task_id: The task identifier. :param timeout: The period to wait for a response. If no response is received @@ -238,7 +238,7 @@ def list( The X-Opaque-Id in the children headers is the child task of the task that was initiated by the REST request.

- ``_ + ``_ :param actions: A comma-separated list or wildcard expression of actions used to limit the request. For example, you can use `cluser:*` to retrieve all diff --git a/elasticsearch/_sync/client/text_structure.py b/elasticsearch/_sync/client/text_structure.py index fa3218f81..03884b9d3 100644 --- a/elasticsearch/_sync/client/text_structure.py +++ b/elasticsearch/_sync/client/text_structure.py @@ -72,7 +72,7 @@ def find_field_structure( It helps determine why the returned structure was chosen.

- ``_ + ``_ :param field: The field that should be analyzed. :param index: The name of the index that contains the analyzed field. @@ -259,7 +259,7 @@ def find_message_structure( It helps determine why the returned structure was chosen.

- ``_ + ``_ :param messages: The list of messages you want to analyze. :param column_names: If the format is `delimited`, you can specify the column @@ -433,7 +433,7 @@ def find_structure( However, you can optionally override some of the decisions about the text structure by specifying one or more query parameters.

- ``_ + ``_ :param text_files: :param charset: The text's character set. It must be a character set that is @@ -620,7 +620,7 @@ def test_grok_pattern( The API indicates whether the lines match the pattern together with the offsets and lengths of the matched substrings.

- ``_ + ``_ :param grok_pattern: The Grok pattern to run on the text. :param text: The lines of text to run the Grok pattern on. diff --git a/elasticsearch/_sync/client/transform.py b/elasticsearch/_sync/client/transform.py index ea9941f74..10ea15e1f 100644 --- a/elasticsearch/_sync/client/transform.py +++ b/elasticsearch/_sync/client/transform.py @@ -44,7 +44,7 @@ def delete_transform(

Delete a transform.

- ``_ + ``_ :param transform_id: Identifier for the transform. :param delete_dest_index: If this value is true, the destination index is deleted @@ -108,7 +108,7 @@ def get_transform( Get configuration information for transforms.

- ``_ + ``_ :param transform_id: Identifier for the transform. It can be a transform identifier or a wildcard expression. You can get information for all transforms by using @@ -181,7 +181,7 @@ def get_transform_stats(

Get usage information for transforms.

- ``_ + ``_ :param transform_id: Identifier for the transform. It can be a transform identifier or a wildcard expression. You can get information for all transforms by using @@ -269,7 +269,7 @@ def preview_transform( types of the source index and the transform aggregations.

- ``_ + ``_ :param transform_id: Identifier for the transform to preview. If you specify this path parameter, you cannot provide transform configuration details in @@ -406,7 +406,7 @@ def put_transform( give users any privileges on .data-frame-internal* indices.

- ``_ + ``_ :param transform_id: Identifier for the transform. This identifier can contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and underscores. @@ -512,7 +512,7 @@ def reset_transform( If the destination index was created by the transform, it is deleted.

- ``_ + ``_ :param transform_id: Identifier for the transform. This identifier can contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and underscores. @@ -572,7 +572,7 @@ def schedule_now_transform( is called again in the meantime.

- ``_ + ``_ :param transform_id: Identifier for the transform. :param timeout: Controls the time to wait for the scheduling to take place @@ -635,7 +635,7 @@ def start_transform( destination indices, the transform fails when it attempts unauthorized operations.

- ``_ + ``_ :param transform_id: Identifier for the transform. :param from_: Restricts the set of transformed entities to those changed after @@ -693,7 +693,7 @@ def stop_transform( Stops one or more transforms.

- ``_ + ``_ :param transform_id: Identifier for the transform. To stop multiple transforms, use a comma-separated list or a wildcard expression. To stop all transforms, @@ -795,7 +795,7 @@ def update_transform( time of update and runs with those privileges.

- ``_ + ``_ :param transform_id: Identifier for the transform. :param defer_validation: When true, deferrable validations are not run. This @@ -890,7 +890,7 @@ def upgrade_transforms( You may want to perform a recent cluster backup prior to the upgrade.

- ``_ + ``_ :param dry_run: When true, the request checks for updates but does not run them. :param timeout: Period to wait for a response. If no response is received before diff --git a/elasticsearch/_sync/client/watcher.py b/elasticsearch/_sync/client/watcher.py index 92c70da27..8a235d7a5 100644 --- a/elasticsearch/_sync/client/watcher.py +++ b/elasticsearch/_sync/client/watcher.py @@ -48,7 +48,7 @@ def ack_watch( This happens when the condition of the watch is not met (the condition evaluates to false).

- ``_ + ``_ :param watch_id: The watch identifier. :param action_id: A comma-separated list of the action identifiers to acknowledge. @@ -104,7 +104,7 @@ def activate_watch( A watch can be either active or inactive.

- ``_ + ``_ :param watch_id: The watch identifier. """ @@ -148,7 +148,7 @@ def deactivate_watch( A watch can be either active or inactive.

- ``_ + ``_ :param watch_id: The watch identifier. """ @@ -196,7 +196,7 @@ def delete_watch( When Elasticsearch security features are enabled, make sure no write privileges are granted to anyone for the .watches index.

- ``_ + ``_ :param id: The watch identifier. """ @@ -277,7 +277,7 @@ def execute_watch(

When using the run watch API, the authorization data of the user that called the API will be used as a base, instead of the information who stored the watch.

- ``_ + ``_ :param id: The watch identifier. :param action_modes: Determines how to handle the watch actions as part of the @@ -365,7 +365,7 @@ def get_settings( Only a subset of settings are shown, for example index.auto_expand_replicas and index.number_of_replicas.

- ``_ + ``_ :param master_timeout: The period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails @@ -410,7 +410,7 @@ def get_watch(

Get a watch.

- ``_ + ``_ :param id: The watch identifier. """ @@ -485,7 +485,7 @@ def put_watch( If the user is able to read index a, but not index b, the same will apply when the watch runs.

- ``_ + ``_ :param id: The identifier for the watch. :param actions: The list of actions that will be run if the condition matches. @@ -598,7 +598,7 @@ def query_watches(

Note that only the _id and metadata.* fields are queryable or sortable.

- ``_ + ``_ :param from_: The offset from the first result to fetch. It must be non-negative. :param query: A query that filters the watches to be returned. @@ -673,7 +673,7 @@ def start( Start the Watcher service if it is not already running.

- ``_ + ``_ :param master_timeout: Period to wait for a connection to the master node. """ @@ -739,7 +739,7 @@ def stats( You retrieve more metrics by using the metric parameter.

- ``_ + ``_ :param metric: Defines which additional metrics are included in the response. :param emit_stacktraces: Defines whether stack traces are generated for each @@ -790,7 +790,7 @@ def stop( Stop the Watcher service if it is running.

- ``_ + ``_ :param master_timeout: The period to wait for the master node. If the master node is not available before the timeout expires, the request fails and returns @@ -851,7 +851,7 @@ def update_settings( Watcher shards must always be in the data_content tier.

- ``_ + ``_ :param index_auto_expand_replicas: :param index_number_of_replicas: diff --git a/elasticsearch/_sync/client/xpack.py b/elasticsearch/_sync/client/xpack.py index b44cd0909..a201f4570 100644 --- a/elasticsearch/_sync/client/xpack.py +++ b/elasticsearch/_sync/client/xpack.py @@ -54,7 +54,7 @@ def info( - ``_ + ``_ :param accept_enterprise: If this param is used it must be set to true :param categories: A comma-separated list of the information categories to include @@ -103,7 +103,7 @@ def usage( The API also provides some usage statistics.

- ``_ + ``_ :param master_timeout: The period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails diff --git a/elasticsearch/dsl/aggs.py b/elasticsearch/dsl/aggs.py index a20373163..97ef48d59 100644 --- a/elasticsearch/dsl/aggs.py +++ b/elasticsearch/dsl/aggs.py @@ -679,9 +679,8 @@ class CategorizeText(Bucket[_R]): :arg categorization_analyzer: The categorization analyzer specifies how the text is analyzed and tokenized before being categorized. The syntax is very similar to that used to define the analyzer in - the [Analyze endpoint](https://www.elastic.co/guide/en/elasticsear - ch/reference/8.0/indices-analyze.html). This property cannot be - used at the same time as categorization_filters. + the analyze API. This property cannot be used at the same time as + `categorization_filters`. :arg shard_size: The number of categorization buckets to return from each shard before merging all the results. :arg size: The number of buckets to return. Defaults to `10` if From 10b85dbb8412406e09a4090742d1560c122c0751 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 17:37:32 +0400 Subject: [PATCH 28/57] Fix release notes URL (#2911) (#2915) (cherry picked from commit fe1b3dc21c93f119aec9da51ac4176b792f7e09a) Co-authored-by: Quentin Pradet --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb156ae2a..df468b466 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1 @@ -See: https://www.elastic.co/guide/en/elasticsearch/client/python-api/master/release-notes.html +See: https://www.elastic.co/guide/en/elasticsearch/client/python-api/current/release-notes.html From 482170d2ca029e93f2e1800806c1aeb407c67a7e Mon Sep 17 00:00:00 2001 From: Elastic Machine Date: Mon, 14 Apr 2025 18:28:42 +0200 Subject: [PATCH 29/57] Auto-generated API code (#2920) --- elasticsearch/_async/client/__init__.py | 121 ------------------------ elasticsearch/_sync/client/__init__.py | 121 ------------------------ 2 files changed, 242 deletions(-) diff --git a/elasticsearch/_async/client/__init__.py b/elasticsearch/_async/client/__init__.py index dd69cc9e7..97765ed16 100644 --- a/elasticsearch/_async/client/__init__.py +++ b/elasticsearch/_async/client/__init__.py @@ -2999,127 +2999,6 @@ async def info( path_parts=__path_parts, ) - @_rewrite_parameters( - body_fields=( - "knn", - "docvalue_fields", - "fields", - "filter", - "source", - "stored_fields", - ), - parameter_aliases={"_source": "source"}, - ) - @_stability_warning(Stability.EXPERIMENTAL) - async def knn_search( - self, - *, - index: t.Union[str, t.Sequence[str]], - knn: t.Optional[t.Mapping[str, t.Any]] = None, - docvalue_fields: t.Optional[t.Sequence[t.Mapping[str, t.Any]]] = None, - error_trace: t.Optional[bool] = None, - fields: t.Optional[t.Union[str, t.Sequence[str]]] = None, - filter: t.Optional[ - t.Union[t.Mapping[str, t.Any], t.Sequence[t.Mapping[str, t.Any]]] - ] = None, - filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, - human: t.Optional[bool] = None, - pretty: t.Optional[bool] = None, - routing: t.Optional[str] = None, - source: t.Optional[t.Union[bool, t.Mapping[str, t.Any]]] = None, - stored_fields: t.Optional[t.Union[str, t.Sequence[str]]] = None, - body: t.Optional[t.Dict[str, t.Any]] = None, - ) -> ObjectApiResponse[t.Any]: - """ - .. raw:: html - -

Run a knn search.

-

NOTE: The kNN search API has been replaced by the knn option in the search API.

-

Perform a k-nearest neighbor (kNN) search on a dense_vector field and return the matching documents. - Given a query vector, the API finds the k closest vectors and returns those documents as search hits.

-

Elasticsearch uses the HNSW algorithm to support efficient kNN search. - Like most kNN algorithms, HNSW is an approximate method that sacrifices result accuracy for improved search speed. - This means the results returned are not always the true k closest neighbors.

-

The kNN search API supports restricting the search using a filter. - The search will return the top k documents that also match the filter query.

-

A kNN search response has the exact same structure as a search API response. - However, certain sections have a meaning specific to kNN search:

-
    -
  • The document _score is determined by the similarity between the query and document vector.
  • -
  • The hits.total object contains the total number of nearest neighbor candidates considered, which is num_candidates * num_shards. The hits.total.relation will always be eq, indicating an exact value.
  • -
- - - ``_ - - :param index: A comma-separated list of index names to search; use `_all` or - to perform the operation on all indices. - :param knn: The kNN query to run. - :param docvalue_fields: The request returns doc values for field names matching - these patterns in the `hits.fields` property of the response. It accepts - wildcard (`*`) patterns. - :param fields: The request returns values for field names matching these patterns - in the `hits.fields` property of the response. It accepts wildcard (`*`) - patterns. - :param filter: A query to filter the documents that can match. The kNN search - will return the top `k` documents that also match this filter. The value - can be a single query or a list of queries. If `filter` isn't provided, all - documents are allowed to match. - :param routing: A comma-separated list of specific routing values. - :param source: Indicates which source fields are returned for matching documents. - These fields are returned in the `hits._source` property of the search response. - :param stored_fields: A list of stored fields to return as part of a hit. If - no fields are specified, no stored fields are included in the response. If - this field is specified, the `_source` parameter defaults to `false`. You - can pass `_source: true` to return both source fields and stored fields in - the search response. - """ - if index in SKIP_IN_PATH: - raise ValueError("Empty value passed for parameter 'index'") - if knn is None and body is None: - raise ValueError("Empty value passed for parameter 'knn'") - __path_parts: t.Dict[str, str] = {"index": _quote(index)} - __path = f'/{__path_parts["index"]}/_knn_search' - __query: t.Dict[str, t.Any] = {} - __body: t.Dict[str, t.Any] = body if body is not None else {} - if error_trace is not None: - __query["error_trace"] = error_trace - if filter_path is not None: - __query["filter_path"] = filter_path - if human is not None: - __query["human"] = human - if pretty is not None: - __query["pretty"] = pretty - if routing is not None: - __query["routing"] = routing - if not __body: - if knn is not None: - __body["knn"] = knn - if docvalue_fields is not None: - __body["docvalue_fields"] = docvalue_fields - if fields is not None: - __body["fields"] = fields - if filter is not None: - __body["filter"] = filter - if source is not None: - __body["_source"] = source - if stored_fields is not None: - __body["stored_fields"] = stored_fields - if not __body: - __body = None # type: ignore[assignment] - __headers = {"accept": "application/json"} - if __body is not None: - __headers["content-type"] = "application/json" - return await self.perform_request( # type: ignore[return-value] - "POST", - __path, - params=__query, - headers=__headers, - body=__body, - endpoint_id="knn_search", - path_parts=__path_parts, - ) - @_rewrite_parameters( body_fields=("docs", "ids"), parameter_aliases={ diff --git a/elasticsearch/_sync/client/__init__.py b/elasticsearch/_sync/client/__init__.py index 6e97b41e6..56ecd4f2f 100644 --- a/elasticsearch/_sync/client/__init__.py +++ b/elasticsearch/_sync/client/__init__.py @@ -2997,127 +2997,6 @@ def info( path_parts=__path_parts, ) - @_rewrite_parameters( - body_fields=( - "knn", - "docvalue_fields", - "fields", - "filter", - "source", - "stored_fields", - ), - parameter_aliases={"_source": "source"}, - ) - @_stability_warning(Stability.EXPERIMENTAL) - def knn_search( - self, - *, - index: t.Union[str, t.Sequence[str]], - knn: t.Optional[t.Mapping[str, t.Any]] = None, - docvalue_fields: t.Optional[t.Sequence[t.Mapping[str, t.Any]]] = None, - error_trace: t.Optional[bool] = None, - fields: t.Optional[t.Union[str, t.Sequence[str]]] = None, - filter: t.Optional[ - t.Union[t.Mapping[str, t.Any], t.Sequence[t.Mapping[str, t.Any]]] - ] = None, - filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, - human: t.Optional[bool] = None, - pretty: t.Optional[bool] = None, - routing: t.Optional[str] = None, - source: t.Optional[t.Union[bool, t.Mapping[str, t.Any]]] = None, - stored_fields: t.Optional[t.Union[str, t.Sequence[str]]] = None, - body: t.Optional[t.Dict[str, t.Any]] = None, - ) -> ObjectApiResponse[t.Any]: - """ - .. raw:: html - -

Run a knn search.

-

NOTE: The kNN search API has been replaced by the knn option in the search API.

-

Perform a k-nearest neighbor (kNN) search on a dense_vector field and return the matching documents. - Given a query vector, the API finds the k closest vectors and returns those documents as search hits.

-

Elasticsearch uses the HNSW algorithm to support efficient kNN search. - Like most kNN algorithms, HNSW is an approximate method that sacrifices result accuracy for improved search speed. - This means the results returned are not always the true k closest neighbors.

-

The kNN search API supports restricting the search using a filter. - The search will return the top k documents that also match the filter query.

-

A kNN search response has the exact same structure as a search API response. - However, certain sections have a meaning specific to kNN search:

-
    -
  • The document _score is determined by the similarity between the query and document vector.
  • -
  • The hits.total object contains the total number of nearest neighbor candidates considered, which is num_candidates * num_shards. The hits.total.relation will always be eq, indicating an exact value.
  • -
- - - ``_ - - :param index: A comma-separated list of index names to search; use `_all` or - to perform the operation on all indices. - :param knn: The kNN query to run. - :param docvalue_fields: The request returns doc values for field names matching - these patterns in the `hits.fields` property of the response. It accepts - wildcard (`*`) patterns. - :param fields: The request returns values for field names matching these patterns - in the `hits.fields` property of the response. It accepts wildcard (`*`) - patterns. - :param filter: A query to filter the documents that can match. The kNN search - will return the top `k` documents that also match this filter. The value - can be a single query or a list of queries. If `filter` isn't provided, all - documents are allowed to match. - :param routing: A comma-separated list of specific routing values. - :param source: Indicates which source fields are returned for matching documents. - These fields are returned in the `hits._source` property of the search response. - :param stored_fields: A list of stored fields to return as part of a hit. If - no fields are specified, no stored fields are included in the response. If - this field is specified, the `_source` parameter defaults to `false`. You - can pass `_source: true` to return both source fields and stored fields in - the search response. - """ - if index in SKIP_IN_PATH: - raise ValueError("Empty value passed for parameter 'index'") - if knn is None and body is None: - raise ValueError("Empty value passed for parameter 'knn'") - __path_parts: t.Dict[str, str] = {"index": _quote(index)} - __path = f'/{__path_parts["index"]}/_knn_search' - __query: t.Dict[str, t.Any] = {} - __body: t.Dict[str, t.Any] = body if body is not None else {} - if error_trace is not None: - __query["error_trace"] = error_trace - if filter_path is not None: - __query["filter_path"] = filter_path - if human is not None: - __query["human"] = human - if pretty is not None: - __query["pretty"] = pretty - if routing is not None: - __query["routing"] = routing - if not __body: - if knn is not None: - __body["knn"] = knn - if docvalue_fields is not None: - __body["docvalue_fields"] = docvalue_fields - if fields is not None: - __body["fields"] = fields - if filter is not None: - __body["filter"] = filter - if source is not None: - __body["_source"] = source - if stored_fields is not None: - __body["stored_fields"] = stored_fields - if not __body: - __body = None # type: ignore[assignment] - __headers = {"accept": "application/json"} - if __body is not None: - __headers["content-type"] = "application/json" - return self.perform_request( # type: ignore[return-value] - "POST", - __path, - params=__query, - headers=__headers, - body=__body, - endpoint_id="knn_search", - path_parts=__path_parts, - ) - @_rewrite_parameters( body_fields=("docs", "ids"), parameter_aliases={ From d9442d03890ad3924ffd1371fd20deed9c998dd4 Mon Sep 17 00:00:00 2001 From: Quentin Pradet Date: Mon, 14 Apr 2025 22:02:08 +0400 Subject: [PATCH 30/57] Release 9.0.0 (#2918) --- docs/release-notes/index.md | 53 +++++++++++++++++-- elasticsearch/_async/client/_base.py | 2 +- elasticsearch/_sync/client/_base.py | 2 +- elasticsearch/_version.py | 2 +- .../test_async/test_transport.py | 10 ++-- .../test_client/test_options.py | 34 ++++++------ .../test_client/test_serializers.py | 18 +++---- test_elasticsearch/test_serializer.py | 8 +-- test_elasticsearch/test_transport.py | 10 ++-- 9 files changed, 93 insertions(+), 46 deletions(-) diff --git a/docs/release-notes/index.md b/docs/release-notes/index.md index d2dccfd8a..5d47dd45b 100644 --- a/docs/release-notes/index.md +++ b/docs/release-notes/index.md @@ -18,10 +18,57 @@ To check for security updates, go to [Security announcements for the Elastic sta % * % ### Fixes [elasticsearch-python-client-next-fixes] -% * -## 9.0.0 [elasticsearch-python-client-900-release-notes] +## 9.0.0 (2025-04-15) [elasticsearch-python-client-900-release-notes] + +* Remove deprecated `Elasticsearch()` options ([#2840](https://github.com/elastic/elasticsearch-py/pull/2840)) +* Remove deprecated `url_prefix` and `use_ssl` options ([#2797](https://github.com/elastic/elasticsearch-py/pull/2797)) +* Merge `Elasticsearch-DSL `_ package ([#2736](https://github.com/elastic/elasticsearch-py/pull/2736)) +* Add Python DSL documentation ([#2761](https://github.com/elastic/elasticsearch-py/pull/2761)) +* Autogenerate DSL field classes from schema ([#2780](https://github.com/elastic/elasticsearch-py/pull/2780)) +* Improve DSL documentation examples with class-based queries and type hints ([#2857](https://github.com/elastic/elasticsearch-py/pull/2857)) +* Document the use of `param()` in Python DSL methods ([#2861](https://github.com/elastic/elasticsearch-py/pull/2861)) +* Migrate documentation from AsciiDoc to Markdown format ([#2806](https://github.com/elastic/elasticsearch-py/pull/2806)) +* Document use of sub-clients ([#2798](https://github.com/elastic/elasticsearch-py/pull/2798)) +* Document how to making API calls ([#2843](https://github.com/elastic/elasticsearch-py/pull/2843)) +* Fix `simulate` sub-client documentation ([#2749](https://github.com/elastic/elasticsearch-py/pull/2749)) +* Update APIs + * Remove deprecated `/_knn_search` API + * Remove Unfreeze an index API + * Remove min_compatible_shard_node from Search and Async Search Submit APIs + * Remove local parameter from cat alias, Alias exists, and Get alias APIs + * Remove `verbose` from Index segments API + * Remove `include_model_definition` from Get trained model configuration info API + * Remove `wait_for_active_shards` from experimental Get field usage stats API + * Support soft-deletes in connectors: + * Add `hard` to Delete connector API + * Add `include_deleted` to Get and List Connector APIs + * Add `master_timeout` to Migrate to data tiers routing APIs + * Add `master_timeout` to the Alias exists and Get alias APIs. + * Add `expand_wildcards` to Create snapshot API + * Rename incorrect `access_token` to `token` in Logout of OpenID Connect API + * Add inference APIs: Alibaba Cloud AI Search, Amazon Bedrock, Anthropic, Azure AI Studio, Azure OpenAI, Cohere, Elastic Inference Service (EIS), Elasticsearch, ELSER, Google AI Studio, Google Vertex AI, Hugging Face, Jina AI, Mistral, OpenAI, and Voyage AI + * Add Elastic Inference Service (EIS) chat completion API + * Add Reindex legacy backing indices APIs + * Add Create an index from a source index API + * Add `include_source_on_error` to Create, Index, Update and Bulk APIs + * Add Stop async ES|QL query API + * Add `timeout` to Resolve Cluster API + * Add `adaptive_allocations` body field to Start and Update a trained model deployment API + * Rename `index_template_subtitutions` to `index_template_substitutions` in Simulate data ingestion API* Add `if_primary_term`, `if_seq_no`, `op_type`, `require_alias` and `require_data_stream` to Create API + * Add `max_concurrent_shard_requests` to Open point in time API + * Add `local` and `flat_settings` to Check index templates API + * Add `reopen` to Update index settings API + * Add `resource` to Reload search analyzer API + * Add `lazy` to Roll over to a new index API + * Add `cause` and `create` to Simulate index template APIs + * Add Elastic Inference Service (EIS) chat completion + * Add inference APIs: Alibaba Cloud AI Search, Amazon Bedrock, Anthropic, Azure AI Studio, Azure OpenAI, Cohere, Elastic Inference Service (EIS), Elasticsearch, ELSER, Google AI Studio, Google Vertex AI, Hugging Face, Jina AI, Mistral, OpenAI, and Voyage AI +* Update DSL + * Add `ignore_malformed`, `script`, `on_script_error` and `time_series_dimension` to Boolean field + * Add `index` to GeoShape field + * Add `search_inference_id` to SemanticText field ### Features and enhancements [elasticsearch-python-client-900-features-enhancements] -### Fixes [elasticsearch-python-client-900-fixes] \ No newline at end of file +### Fixes [elasticsearch-python-client-900-fixes] diff --git a/elasticsearch/_async/client/_base.py b/elasticsearch/_async/client/_base.py index cc090671c..4e49e7156 100644 --- a/elasticsearch/_async/client/_base.py +++ b/elasticsearch/_async/client/_base.py @@ -174,7 +174,7 @@ async def sniff_callback( "GET", "/_nodes/_all/http", headers={ - "accept": "application/vnd.elasticsearch+json; compatible-with=8" + "accept": "application/vnd.elasticsearch+json; compatible-with=9" }, request_timeout=( sniff_options.sniff_timeout diff --git a/elasticsearch/_sync/client/_base.py b/elasticsearch/_sync/client/_base.py index 868b71073..9ee9c3d1b 100644 --- a/elasticsearch/_sync/client/_base.py +++ b/elasticsearch/_sync/client/_base.py @@ -174,7 +174,7 @@ def sniff_callback( "GET", "/_nodes/_all/http", headers={ - "accept": "application/vnd.elasticsearch+json; compatible-with=8" + "accept": "application/vnd.elasticsearch+json; compatible-with=9" }, request_timeout=( sniff_options.sniff_timeout diff --git a/elasticsearch/_version.py b/elasticsearch/_version.py index 00e2789aa..f0ae401fc 100644 --- a/elasticsearch/_version.py +++ b/elasticsearch/_version.py @@ -15,4 +15,4 @@ # specific language governing permissions and limitations # under the License. -__versionstr__ = "8.17.2" +__versionstr__ = "9.0.0" diff --git a/test_elasticsearch/test_async/test_transport.py b/test_elasticsearch/test_async/test_transport.py index baebc0671..ef52ca85c 100644 --- a/test_elasticsearch/test_async/test_transport.py +++ b/test_elasticsearch/test_async/test_transport.py @@ -256,7 +256,7 @@ async def test_client_meta_header_not_sent(self): calls = client.transport.node_pool.get().calls assert 1 == len(calls) assert calls[0][1]["headers"] == { - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", } async def test_body_surrogates_replaced_encoded_into_bytes(self): @@ -426,7 +426,7 @@ async def test_sniff_on_start_ignores_sniff_timeout(self): { "body": None, "headers": { - "accept": "application/vnd.elasticsearch+json; compatible-with=8" + "accept": "application/vnd.elasticsearch+json; compatible-with=9" }, "request_timeout": None, # <-- Should be None instead of 12 }, @@ -454,7 +454,7 @@ async def test_sniff_uses_sniff_timeout(self): { "body": None, "headers": { - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", }, "request_timeout": DEFAULT, }, @@ -464,7 +464,7 @@ async def test_sniff_uses_sniff_timeout(self): { "body": None, "headers": { - "accept": "application/vnd.elasticsearch+json; compatible-with=8" + "accept": "application/vnd.elasticsearch+json; compatible-with=9" }, "request_timeout": 12, }, @@ -681,7 +681,7 @@ async def test_unsupported_product_error(headers): { "body": None, "headers": { - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", }, "request_timeout": DEFAULT, }, diff --git a/test_elasticsearch/test_client/test_options.py b/test_elasticsearch/test_client/test_options.py index c2050d186..4c719edb0 100644 --- a/test_elasticsearch/test_client/test_options.py +++ b/test_elasticsearch/test_client/test_options.py @@ -156,7 +156,7 @@ def test_options_passed_to_perform_request(self): assert isinstance(call.pop("otel_span"), OpenTelemetrySpan) assert call == { "headers": { - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", }, "body": None, } @@ -175,7 +175,7 @@ def test_options_passed_to_perform_request(self): assert isinstance(call.pop("otel_span"), OpenTelemetrySpan) assert call == { "headers": { - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", }, "body": None, "request_timeout": 1, @@ -201,7 +201,7 @@ def test_options_passed_to_perform_request(self): assert isinstance(call.pop("otel_span"), OpenTelemetrySpan) assert call == { "headers": { - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", }, "body": None, "request_timeout": 1, @@ -229,7 +229,7 @@ async def test_options_passed_to_async_perform_request(self): assert isinstance(call.pop("otel_span"), OpenTelemetrySpan) assert call == { "headers": { - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", }, "body": None, } @@ -248,7 +248,7 @@ async def test_options_passed_to_async_perform_request(self): assert isinstance(call.pop("otel_span"), OpenTelemetrySpan) assert call == { "headers": { - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", }, "body": None, "request_timeout": 1, @@ -274,7 +274,7 @@ async def test_options_passed_to_async_perform_request(self): assert isinstance(call.pop("otel_span"), OpenTelemetrySpan) assert call == { "headers": { - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", }, "body": None, "request_timeout": 1, @@ -316,7 +316,7 @@ def test_http_headers_overrides(self): assert call["headers"] == { "key": "val", - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", } client.options(headers={"key1": "val"}).indices.get(index="2") @@ -325,7 +325,7 @@ def test_http_headers_overrides(self): assert call["headers"] == { "key": "val", "key1": "val", - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", } client.options(headers={"key": "val2"}).indices.get(index="3") @@ -333,7 +333,7 @@ def test_http_headers_overrides(self): assert call["headers"] == { "key": "val2", - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", } client = Elasticsearch( @@ -360,14 +360,14 @@ def test_user_agent_override(self): call = calls[("GET", "/1")][0] assert call["headers"] == { "user-agent": "custom1", - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", } client.indices.get(index="2", headers={"user-agent": "custom2"}) call = calls[("GET", "/2")][0] assert call["headers"] == { "user-agent": "custom2", - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", } client = Elasticsearch( @@ -381,14 +381,14 @@ def test_user_agent_override(self): call = calls[("GET", "/1")][0] assert call["headers"] == { "user-agent": "custom3", - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", } client.indices.get(index="2", headers={"user-agent": "custom4"}) call = calls[("GET", "/2")][0] assert call["headers"] == { "user-agent": "custom4", - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", } def test_options_timeout_parameters(self): @@ -410,7 +410,7 @@ def test_options_timeout_parameters(self): assert isinstance(call.pop("otel_span"), OpenTelemetrySpan) assert call == { "headers": { - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", }, "body": None, "request_timeout": 1, @@ -440,7 +440,7 @@ def test_options_timeout_parameters(self): assert isinstance(call.pop("otel_span"), OpenTelemetrySpan) assert call == { "headers": { - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", }, "body": None, "request_timeout": 2, @@ -465,7 +465,7 @@ def test_options_timeout_parameters(self): assert isinstance(call.pop("otel_span"), OpenTelemetrySpan) assert call == { "headers": { - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", }, "body": None, } @@ -487,7 +487,7 @@ def test_options_timeout_parameters(self): assert isinstance(call.pop("otel_span"), OpenTelemetrySpan) assert call == { "headers": { - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", }, "body": None, "request_timeout": 1, diff --git a/test_elasticsearch/test_client/test_serializers.py b/test_elasticsearch/test_client/test_serializers.py index 986160b92..192c561f8 100644 --- a/test_elasticsearch/test_client/test_serializers.py +++ b/test_elasticsearch/test_client/test_serializers.py @@ -46,22 +46,22 @@ def test_compat_mode_on_by_default(self): self.client.get(index="test0", id="1") assert len(calls) == 1 assert calls[("GET", "/test0/_doc/1")][0]["headers"] == { - "Accept": "application/vnd.elasticsearch+json; compatible-with=8" + "Accept": "application/vnd.elasticsearch+json; compatible-with=9" } # Search with body self.client.search(index="test1", query={"match_all": {}}) assert len(calls) == 2 assert calls[("POST", "/test1/_search")][0]["headers"] == { - "Accept": "application/vnd.elasticsearch+json; compatible-with=8", - "Content-Type": "application/vnd.elasticsearch+json; compatible-with=8", + "Accept": "application/vnd.elasticsearch+json; compatible-with=9", + "Content-Type": "application/vnd.elasticsearch+json; compatible-with=9", } # Search without body self.client.search(index="test2") assert len(calls) == 3 assert calls[("POST", "/test2/_search")][0]["headers"] == { - "Accept": "application/vnd.elasticsearch+json; compatible-with=8", + "Accept": "application/vnd.elasticsearch+json; compatible-with=9", } # Multiple mimetypes in Accept @@ -69,15 +69,15 @@ def test_compat_mode_on_by_default(self): assert len(calls) == 4 assert calls[("GET", "/_cat/nodes")][0]["headers"] == { # text/plain isn't modified. - "Accept": "text/plain,application/vnd.elasticsearch+json; compatible-with=8", + "Accept": "text/plain,application/vnd.elasticsearch+json; compatible-with=9", } # Bulk uses x-ndjson self.client.bulk(operations=[]) assert len(calls) == 5 assert calls[("PUT", "/_bulk")][0]["headers"] == { - "Accept": "application/vnd.elasticsearch+json; compatible-with=8", - "Content-Type": "application/vnd.elasticsearch+x-ndjson; compatible-with=8", + "Accept": "application/vnd.elasticsearch+json; compatible-with=9", + "Content-Type": "application/vnd.elasticsearch+x-ndjson; compatible-with=9", } # Mapbox vector tiles @@ -91,8 +91,8 @@ def test_compat_mode_on_by_default(self): ) assert len(calls) == 6 assert calls[("POST", "/test3/_mvt/field/z/x/y")][0]["headers"] == { - "Accept": "application/vnd.elasticsearch+vnd.mapbox-vector-tile; compatible-with=8", - "Content-Type": "application/vnd.elasticsearch+json; compatible-with=8", + "Accept": "application/vnd.elasticsearch+vnd.mapbox-vector-tile; compatible-with=9", + "Content-Type": "application/vnd.elasticsearch+json; compatible-with=9", } @pytest.mark.parametrize("mime_subtype", ["json", "x-ndjson"]) diff --git a/test_elasticsearch/test_serializer.py b/test_elasticsearch/test_serializer.py index 21c6b94b5..311605c3a 100644 --- a/test_elasticsearch/test_serializer.py +++ b/test_elasticsearch/test_serializer.py @@ -223,10 +223,10 @@ def test_deserializes_text_with_correct_ct(self, data): def test_deserialize_compatibility_header(self): for content_type in ( - "application/vnd.elasticsearch+json;compatible-with=7", - "application/vnd.elasticsearch+json; compatible-with=7", "application/vnd.elasticsearch+json;compatible-with=8", "application/vnd.elasticsearch+json; compatible-with=8", + "application/vnd.elasticsearch+json;compatible-with=9", + "application/vnd.elasticsearch+json; compatible-with=9", ): assert {"some": "data"} == self.serializers.loads( '{"some":"data"}', content_type @@ -236,10 +236,10 @@ def test_deserialize_compatibility_header(self): ) for content_type in ( - "application/vnd.elasticsearch+x-ndjson;compatible-with=7", - "application/vnd.elasticsearch+x-ndjson; compatible-with=7", "application/vnd.elasticsearch+x-ndjson;compatible-with=8", "application/vnd.elasticsearch+x-ndjson; compatible-with=8", + "application/vnd.elasticsearch+x-ndjson;compatible-with=9", + "application/vnd.elasticsearch+x-ndjson; compatible-with=9", ): assert b'{"some":"data"}\n{"some":"data"}\n' == self.serializers.dumps( ['{"some":"data"}', {"some": "data"}], content_type diff --git a/test_elasticsearch/test_transport.py b/test_elasticsearch/test_transport.py index 4978d52fc..237f21ac1 100644 --- a/test_elasticsearch/test_transport.py +++ b/test_elasticsearch/test_transport.py @@ -267,7 +267,7 @@ def test_client_meta_header_not_sent(self): calls = client.transport.node_pool.get().calls assert 1 == len(calls) assert calls[0][1]["headers"] == { - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", } def test_meta_header_type_error(self): @@ -428,7 +428,7 @@ def test_sniff_on_start_ignores_sniff_timeout(self): { "body": None, "headers": { - "accept": "application/vnd.elasticsearch+json; compatible-with=8" + "accept": "application/vnd.elasticsearch+json; compatible-with=9" }, "request_timeout": None, # <-- Should be None instead of 12 }, @@ -452,7 +452,7 @@ def test_sniff_uses_sniff_timeout(self): { "body": None, "headers": { - "accept": "application/vnd.elasticsearch+json; compatible-with=8" + "accept": "application/vnd.elasticsearch+json; compatible-with=9" }, "request_timeout": 12, }, @@ -462,7 +462,7 @@ def test_sniff_uses_sniff_timeout(self): { "body": None, "headers": { - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", }, "request_timeout": DEFAULT, }, @@ -592,7 +592,7 @@ def test_unsupported_product_error(headers): { "body": None, "headers": { - "accept": "application/vnd.elasticsearch+json; compatible-with=8", + "accept": "application/vnd.elasticsearch+json; compatible-with=9", }, "request_timeout": DEFAULT, }, From ae22b5088cde92df0fe9f381f89d6bf4f794fcc8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 15 Apr 2025 17:41:32 +0100 Subject: [PATCH 31/57] Reorganization of the Sphinx docs to only include reference pages (#2776) (#2924) * add DSL module reference documentation to sphinx docs * only reference docs * renamed pages to avoid collisions with redirects (cherry picked from commit a1b458e37e62f1abe0582b4c28d838dfe1e364e8) Co-authored-by: Miguel Grinberg --- docs/sphinx/api_helpers.rst | 26 +++ docs/sphinx/async.rst | 237 ---------------------------- docs/sphinx/async_api_helpers.rst | 29 ++++ docs/sphinx/async_dsl.rst | 49 ++++++ docs/sphinx/async_es_api.rst | 15 ++ docs/sphinx/dsl.rst | 49 ++++++ docs/sphinx/{api.rst => es_api.rst} | 4 +- docs/sphinx/helpers.rst | 146 ----------------- docs/sphinx/index.rst | 142 ++--------------- docs/sphinx/interactive.rst | 107 ------------- docs/sphinx/quickstart.rst | 167 -------------------- 11 files changed, 182 insertions(+), 789 deletions(-) create mode 100644 docs/sphinx/api_helpers.rst delete mode 100644 docs/sphinx/async.rst create mode 100644 docs/sphinx/async_api_helpers.rst create mode 100644 docs/sphinx/async_dsl.rst create mode 100644 docs/sphinx/async_es_api.rst create mode 100644 docs/sphinx/dsl.rst rename docs/sphinx/{api.rst => es_api.rst} (95%) delete mode 100644 docs/sphinx/helpers.rst delete mode 100644 docs/sphinx/interactive.rst delete mode 100644 docs/sphinx/quickstart.rst diff --git a/docs/sphinx/api_helpers.rst b/docs/sphinx/api_helpers.rst new file mode 100644 index 000000000..31d5b241d --- /dev/null +++ b/docs/sphinx/api_helpers.rst @@ -0,0 +1,26 @@ +.. _helpers: + +Helpers +======= + +.. py:module:: elasticsearch.helpers + +Streaming Bulk +-------------- +.. autofunction:: streaming_bulk + +Parallel Bulk +------------- +.. autofunction:: parallel_bulk + +Bulk +---- +.. autofunction:: bulk + +Scan +---- +.. autofunction:: scan + +Reindex +------- +.. autofunction:: reindex diff --git a/docs/sphinx/async.rst b/docs/sphinx/async.rst deleted file mode 100644 index 22a49b312..000000000 --- a/docs/sphinx/async.rst +++ /dev/null @@ -1,237 +0,0 @@ -Using asyncio with Elasticsearch -================================ - - .. py:module:: elasticsearch - :no-index: - -The ``elasticsearch`` package supports async/await with -`asyncio `_ and `aiohttp `_. -You can either install ``aiohttp`` directly or use the ``[async]`` extra: - - .. code-block:: bash - - $ python -m pip install elasticsearch aiohttp - - # - OR - - - $ python -m pip install elasticsearch[async] - -Getting Started with Async --------------------------- - -After installation all async API endpoints are available via :class:`~elasticsearch.AsyncElasticsearch` -and are used in the same way as other APIs, just with an extra ``await``: - - .. code-block:: python - - import asyncio - from elasticsearch import AsyncElasticsearch - - client = AsyncElasticsearch() - - async def main(): - resp = await client.search( - index="documents", - body={"query": {"match_all": {}}}, - size=20, - ) - print(resp) - - loop = asyncio.get_event_loop() - loop.run_until_complete(main()) - -All APIs that are available under the sync client are also available under the async client. - -ASGI Applications and Elastic APM ---------------------------------- - -`ASGI `_ (Asynchronous Server Gateway Interface) is a new way to -serve Python web applications making use of async I/O to achieve better performance. -Some examples of ASGI frameworks include FastAPI, Django 3.0+, and Starlette. -If you're using one of these frameworks along with Elasticsearch then you -should be using :py:class:`~elasticsearch.AsyncElasticsearch` to avoid blocking -the event loop with synchronous network calls for optimal performance. - -`Elastic APM `_ -also supports tracing of async Elasticsearch queries just the same as -synchronous queries. For an example on how to configure ``AsyncElasticsearch`` with -a popular ASGI framework `FastAPI `_ and APM tracing -there is a `pre-built example `_ -in the ``examples/fastapi-apm`` directory. - -Frequently Asked Questions --------------------------- - -ValueError when initializing ``AsyncElasticsearch``? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If when trying to use ``AsyncElasticsearch`` you receive ``ValueError: You must -have 'aiohttp' installed to use AiohttpHttpNode`` you should ensure that you -have ``aiohttp`` installed in your environment (check with ``$ python -m pip -freeze | grep aiohttp``). Otherwise, async support won't be available. - -What about the ``elasticsearch-async`` package? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Previously asyncio was supported separately via the `elasticsearch-async `_ -package. The ``elasticsearch-async`` package has been deprecated in favor of -``AsyncElasticsearch`` provided by the ``elasticsearch`` package -in v7.8 and onwards. - -Receiving 'Unclosed client session / connector' warning? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This warning is created by ``aiohttp`` when an open HTTP connection is -garbage collected. You'll typically run into this when closing your application. -To resolve the issue ensure that :meth:`~elasticsearch.AsyncElasticsearch.close` -is called before the :py:class:`~elasticsearch.AsyncElasticsearch` instance is garbage collected. - -For example if using FastAPI that might look like this: - - .. code-block:: python - - import os - from contextlib import asynccontextmanager - - from fastapi import FastAPI - from elasticsearch import AsyncElasticsearch - - ELASTICSEARCH_URL = os.environ["ELASTICSEARCH_URL"] - client = None - - @asynccontextmanager - async def lifespan(app: FastAPI): - global client - client = AsyncElasticsearch(ELASTICSEARCH_URL) - yield - await client.close() - - app = FastAPI(lifespan=lifespan) - - @app.get("/") - async def main(): - return await client.info() - -You can run this example by saving it to ``main.py`` and executing -``ELASTICSEARCH_URL=http://localhost:9200 uvicorn main:app``. - - -Async Helpers -------------- - -Async variants of all helpers are available in ``elasticsearch.helpers`` -and are all prefixed with ``async_*``. You'll notice that these APIs -are identical to the ones in the sync :ref:`helpers` documentation. - -All async helpers that accept an iterator or generator also accept async iterators -and async generators. - - .. py:module:: elasticsearch.helpers - :no-index: - -Bulk and Streaming Bulk -~~~~~~~~~~~~~~~~~~~~~~~ - - .. autofunction:: async_bulk - - .. code-block:: python - - import asyncio - from elasticsearch import AsyncElasticsearch - from elasticsearch.helpers import async_bulk - - client = AsyncElasticsearch() - - async def gendata(): - mywords = ['foo', 'bar', 'baz'] - for word in mywords: - yield { - "_index": "mywords", - "doc": {"word": word}, - } - - async def main(): - await async_bulk(client, gendata()) - - loop = asyncio.get_event_loop() - loop.run_until_complete(main()) - - .. autofunction:: async_streaming_bulk - - .. code-block:: python - - import asyncio - from elasticsearch import AsyncElasticsearch - from elasticsearch.helpers import async_streaming_bulk - - client = AsyncElasticsearch() - - async def gendata(): - mywords = ['foo', 'bar', 'baz'] - for word in mywords: - yield { - "_index": "mywords", - "word": word, - } - - async def main(): - async for ok, result in async_streaming_bulk(client, gendata()): - action, result = result.popitem() - if not ok: - print("failed to %s document %s" % ()) - - loop = asyncio.get_event_loop() - loop.run_until_complete(main()) - -Scan -~~~~ - - .. autofunction:: async_scan - - .. code-block:: python - - import asyncio - from elasticsearch import AsyncElasticsearch - from elasticsearch.helpers import async_scan - - client = AsyncElasticsearch() - - async def main(): - async for doc in async_scan( - client=client, - query={"query": {"match": {"title": "python"}}}, - index="orders-*" - ): - print(doc) - - loop = asyncio.get_event_loop() - loop.run_until_complete(main()) - -Reindex -~~~~~~~ - - .. autofunction:: async_reindex - - -API Reference -------------- - - .. py:module:: elasticsearch - :no-index: - -The API of :class:`~elasticsearch.AsyncElasticsearch` is nearly identical -to the API of :class:`~elasticsearch.Elasticsearch` with the exception that -every API call like :py:func:`~elasticsearch.AsyncElasticsearch.search` is -an ``async`` function and requires an ``await`` to properly return the response -body. - -AsyncElasticsearch -~~~~~~~~~~~~~~~~~~ - - .. note:: - - To reference Elasticsearch APIs that are namespaced like ``.indices.create()`` - refer to the sync API reference. These APIs are identical between sync and async. - - .. autoclass:: AsyncElasticsearch - :members: diff --git a/docs/sphinx/async_api_helpers.rst b/docs/sphinx/async_api_helpers.rst new file mode 100644 index 000000000..61dbb5c24 --- /dev/null +++ b/docs/sphinx/async_api_helpers.rst @@ -0,0 +1,29 @@ +Async Helpers +============= + +Async variants of all helpers are available in ``elasticsearch.helpers`` +and are all prefixed with ``async_*``. You'll notice that these APIs +are identical to the ones in the sync :ref:`helpers` documentation. + +All async helpers that accept an iterator or generator also accept async iterators +and async generators. + + .. py:module:: elasticsearch.helpers + :no-index: + +Streaming Bulk +-------------- + .. autofunction:: async_streaming_bulk + +Bulk +---- + .. autofunction:: async_bulk + +Scan +---- + .. autofunction:: async_scan + +Reindex +------- + .. autofunction:: async_reindex + diff --git a/docs/sphinx/async_dsl.rst b/docs/sphinx/async_dsl.rst new file mode 100644 index 000000000..89ac8565d --- /dev/null +++ b/docs/sphinx/async_dsl.rst @@ -0,0 +1,49 @@ +.. _async_dsl: + +Async DSL +========= + +.. py:module:: elasticsearch.dsl + :no-index: + +Search +------ +.. autoclass:: AsyncSearch + :inherited-members: + :members: + +Multi-Search +------------ +.. autoclass:: AsyncMultiSearch + :inherited-members: + :members: + +Document +-------- +.. autoclass:: AsyncDocument + :inherited-members: + :members: + +Index +----- +.. autoclass:: AsyncIndex + :inherited-members: + :members: + +Mapping +------- +.. autoclass:: AsyncMapping + :inherited-members: + :members: + +Faceted Search +-------------- +.. autoclass:: AsyncFacetedSearch + :inherited-members: + :members: + +Update by Query +--------------- +.. autoclass:: AsyncUpdateByQuery + :inherited-members: + :members: diff --git a/docs/sphinx/async_es_api.rst b/docs/sphinx/async_es_api.rst new file mode 100644 index 000000000..d4acf2ff0 --- /dev/null +++ b/docs/sphinx/async_es_api.rst @@ -0,0 +1,15 @@ +Async Elasticsearch API +======================= + + .. py:module:: elasticsearch + :no-index: + + .. note:: + + To reference Elasticsearch APIs that are namespaced like ``.indices.create()`` + refer to the sync API reference. These APIs are identical between sync and async. + +Elasticsearch +------------- + .. autoclass:: AsyncElasticsearch + :members: diff --git a/docs/sphinx/dsl.rst b/docs/sphinx/dsl.rst new file mode 100644 index 000000000..08ab3c935 --- /dev/null +++ b/docs/sphinx/dsl.rst @@ -0,0 +1,49 @@ +.. _dsl: + +DSL +=== + +.. py:module:: elasticsearch.dsl + +Search +------ +.. autoclass:: Search + :inherited-members: + :members: + +Multi-Search +------------ +.. autoclass:: MultiSearch + :inherited-members: + :members: + +Document +-------- +.. autoclass:: Document + :inherited-members: + :members: + +Index +----- +.. autoclass:: Index + :inherited-members: + :members: + +Mapping +------- +.. autoclass:: Mapping + :inherited-members: + :members: + +Faceted Search +-------------- +.. autoclass:: FacetedSearch + :inherited-members: + :members: + +Update by Query +--------------- +.. autoclass:: UpdateByQuery + :inherited-members: + :members: + diff --git a/docs/sphinx/api.rst b/docs/sphinx/es_api.rst similarity index 95% rename from docs/sphinx/api.rst rename to docs/sphinx/es_api.rst index 61d3214e6..d246ec6f5 100644 --- a/docs/sphinx/api.rst +++ b/docs/sphinx/es_api.rst @@ -1,7 +1,7 @@ .. _api: -Elasticsearch API Reference -=========================== +Elasticsearch API +================= All the API calls map the raw REST API as closely as possible, including the distinction between required and optional arguments to the calls. Keyword diff --git a/docs/sphinx/helpers.rst b/docs/sphinx/helpers.rst deleted file mode 100644 index 3390958a8..000000000 --- a/docs/sphinx/helpers.rst +++ /dev/null @@ -1,146 +0,0 @@ -.. _helpers: - -Helpers -======= - -Collection of simple helper functions that abstract some specifics of the raw API. - -Connecting ----------- - -.. code-block:: python - - from elasticsearch import Elasticsearch - - client = Elasticsearch("https://.../", api_key="YOUR_API_KEY") - - -Bulk helpers ------------- - -There are several helpers for the ``bulk`` API since its requirement for -specific formatting and other considerations can make it cumbersome if used directly. - -All bulk helpers accept an instance of ``Elasticsearch`` class and an iterable -``actions`` (any iterable, can also be a generator, which is ideal in most -cases since it will allow you to index large datasets without the need of -loading them into memory). - -The items in the ``action`` iterable should be the documents we wish to index -in several formats. The most common one is the same as returned by -:meth:`~elasticsearch.Elasticsearch.search`, for example: - -.. code:: python - - { - '_index': 'index-name', - '_id': 42, - '_routing': 5, - 'pipeline': 'my-ingest-pipeline', - '_source': { - "title": "Hello World!", - "body": "..." - } - } - -Alternatively, if `_source` is not present, it will pop all metadata fields -from the doc and use the rest as the document data: - -.. code:: python - - { - "_id": 42, - "_routing": 5, - "title": "Hello World!", - "body": "..." - } - -The :meth:`~elasticsearch.Elasticsearch.bulk` api accepts ``index``, ``create``, -``delete``, and ``update`` actions. Use the ``_op_type`` field to specify an -action (``_op_type`` defaults to ``index``): - -.. code:: python - - { - '_op_type': 'delete', - '_index': 'index-name', - '_id': 42, - } - { - '_op_type': 'update', - '_index': 'index-name', - '_id': 42, - 'doc': {'question': 'The life, universe and everything.'} - } - - -Example: -~~~~~~~~ - -Lets say we have an iterable of data. Lets say a list of words called ``mywords`` -and we want to index those words into individual documents where the structure of the -document is like ``{"word": ""}``. - -.. code:: python - - from elasticsearch.helpers import bulk - - def gendata(): - mywords = ['foo', 'bar', 'baz'] - for word in mywords: - yield { - "_index": "mywords", - "word": word, - } - - bulk(client, gendata()) - - -For a more complete and complex example please take a look at -https://github.com/elastic/elasticsearch-py/blob/main/examples/bulk-ingest - -The :meth:`~elasticsearch.Elasticsearch.parallel_bulk` api is a wrapper around the :meth:`~elasticsearch.Elasticsearch.bulk` api to provide threading. :meth:`~elasticsearch.Elasticsearch.parallel_bulk` returns a generator which must be consumed to produce results. - -To see the results use: - -.. code:: python - - for success, info in parallel_bulk(...): - if not success: - print('A document failed:', info) - -If you don't care about the results, you can use deque from collections: - -.. code:: python - - from collections import deque - deque(parallel_bulk(...), maxlen=0) - -.. note:: - - When reading raw json strings from a file, you can also pass them in - directly (without decoding to dicts first). In that case, however, you lose - the ability to specify anything (index, op_type and even id) on a per-record - basis, all documents will just be sent to elasticsearch to be indexed - as-is. - - -.. py:module:: elasticsearch.helpers - -.. autofunction:: streaming_bulk - -.. autofunction:: parallel_bulk - -.. autofunction:: bulk - - -Scan ----- - -.. autofunction:: scan - - -Reindex -------- - -.. autofunction:: reindex diff --git a/docs/sphinx/index.rst b/docs/sphinx/index.rst index 70ab257d3..7c7b5d6fa 100644 --- a/docs/sphinx/index.rst +++ b/docs/sphinx/index.rst @@ -1,140 +1,22 @@ Python Elasticsearch Client =========================== -Official low-level client for Elasticsearch. Its goal is to provide common -ground for all Elasticsearch-related code in Python; because of this it tries -to be opinion-free and very extendable. - -`Download the latest version of Elasticsearch `_ -or -`sign-up `_ -for a free trial of Elastic Cloud. - - -Installation ------------- - -Install the ``elasticsearch`` package with `pip -`_: - -.. code-block:: console - - $ python -m pip install elasticsearch - -If your application uses async/await in Python you can install with -the ``async`` extra: - -.. code-block:: console - - $ python -m pip install elasticsearch[async] - -Read more about `how to use asyncio with this project `_. - - -Compatibility -------------- - -Language clients are forward compatible; meaning that the clients support -communicating with greater or equal minor versions of Elasticsearch without -breaking. It does not mean that the clients automatically support new features -of newer Elasticsearch versions; it is only possible after a release of a new -client version. For example, a 8.12 client version won't automatically support -the new features of the 8.13 version of Elasticsearch, the 8.13 client version -is required for that. Elasticsearch language clients are only backwards -compatible with default distributions and without guarantees made. - -+-----------------------+-------------------------+-----------+ -| Elasticsearch version | elasticsearch-py branch | Supported | -+=======================+=========================+===========+ -| main | main | | -+-----------------------+-------------------------+-----------+ -| 8.x | 8.x | 8.x | -+-----------------------+-------------------------+-----------+ -| 7.x | 7.x | 7.17 | -+-----------------------+-------------------------+-----------+ - -If you need multiple versions installed at the same time, versions are -also released, such as ``elasticsearch7`` and ``elasticsearch8``. - - -Example Usage -------------- - -.. code-block:: python - - from datetime import datetime - from elasticsearch import Elasticsearch - - client = Elasticsearch("http://localhost:9200/", api_key="YOUR_API_KEY") - - doc = { - "author": "kimchy", - "text": "Elasticsearch: cool. bonsai cool.", - "timestamp": datetime.now(), - } - resp = client.index(index="test-index", id=1, document=doc) - print(resp["result"]) - - resp = client.get(index="test-index", id=1) - print(resp["_source"]) - - client.indices.refresh(index="test-index") - - resp = client.search(index="test-index", query={"match_all": {}}) - print("Got {} hits:".format(resp["hits"]["total"]["value"])) - for hit in resp["hits"]["hits"]: - print("{timestamp} {author} {text}".format(**hit["_source"])) - -See more examples in the :ref:`quickstart` page. - - - -Features --------- - -This client was designed as very thin wrapper around Elasticsearch's REST API to -allow for maximum flexibility. This means that there are no opinions in this -client; it also means that some of the APIs are a little cumbersome to use from -Python. We have created some :ref:`helpers` to help with this issue as well as -a more high level library (`elasticsearch-dsl`_) on top of this one to provide -a more convenient way of working with Elasticsearch. - - - -Elasticsearch-DSL ------------------ - -For a more high level client library with more limited scope, have a look at -`elasticsearch-dsl`_ - a more pythonic library sitting on top of -``elasticsearch-py``. - -`elasticsearch-dsl`_ provides a more convenient and idiomatic way to write and manipulate -`queries`_ by mirroring the terminology and structure of Elasticsearch JSON DSL -while exposing the whole range of the DSL from Python -either directly using defined classes or a queryset-like expressions. - -It also provides an optional `persistence layer`_ for working with documents as -Python objects in an ORM-like fashion: defining mappings, retrieving and saving -documents, wrapping the document data in user-defined classes. - -.. _elasticsearch-dsl: https://elasticsearch-dsl.readthedocs.io/ -.. _queries: https://elasticsearch-dsl.readthedocs.io/en/latest/search_dsl.html -.. _persistence layer: https://elasticsearch-dsl.readthedocs.io/en/latest/persistence.html#doctype - +.. toctree:: + :maxdepth: 2 -Contents --------- + es_api + dsl + api_helpers + exceptions .. toctree:: - :maxdepth: 3 + :caption: Async + :maxdepth: 2 + + async_es_api + async_dsl + async_api_helpers - quickstart - interactive - api - exceptions - async - helpers - Release Notes License ------- diff --git a/docs/sphinx/interactive.rst b/docs/sphinx/interactive.rst deleted file mode 100644 index 257d2aad1..000000000 --- a/docs/sphinx/interactive.rst +++ /dev/null @@ -1,107 +0,0 @@ -.. _interactive: - -Interactive examples -==================== - -The `elasticsearch-labs `_ repo contains interactive and executable `Python notebooks `_, sample apps, and resources for testing out Elasticsearch, using the Python client. -These examples are mainly focused on vector search, hybrid search and generative AI use cases, but you'll also find examples of basic operations like creating index mappings and performing lexical search. - -Search notebooks ----------------- - -The `Search `_ folder is a good place to start if you're new to Elasticsearch. -This folder contains a number of notebooks that demonstrate the fundamentals of Elasticsearch, like indexing vectors, running lexical, semantic and *hybrid* searches, and more. - -The following notebooks are available: - -0. `Quick start `_ -1. `Keyword, querying, filtering `_ -2. `Hybrid search `_ -3. `Semantic search with ELSER `_ -4. `Multilingual semantic search `_ -5. `Query rules `_ -6. `Synonyms API quick start `_ - -Here's a brief overview of what you'll learn in each notebook. - -Quick start -^^^^^^^^^^^ - -In the `00-quick-start.ipynb `_ notebook you'll learn how to: - -- Use the Elasticsearch Python client for various operations. -- Create and define an index for a sample dataset with ``dense_vector`` fields. -- Transform book titles into embeddings using `Sentence Transformers `_ and index them into Elasticsearch. -- Perform k-nearest neighbors (knn) semantic searches. -- Integrate traditional text-based search with semantic search, for a hybrid search system. -- Use reciprocal rank fusion (RRF) to intelligently combine search results from different retrieval systems. - -Keyword, querying, filtering -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -In the `01-keyword-querying-filtering.ipynb `_ notebook, you'll learn how to: - -- Use `query and filter contexts `_ to search and filter documents in Elasticsearch. -- Execute full-text searches with ``match`` and ``multi-match`` queries. -- Query and filter documents based on ``text``, ``number``, ``date``, or ``boolean`` values. -- Run multi-field searches using the ``multi-match`` query. -- Prioritize specific fields in the ``multi-match`` query for tailored results. - -Hybrid search -^^^^^^^^^^^^^ - -In the `02-hybrid-search.ipynb `_ notebook, you'll learn how to: - -- Combine results of traditional text-based search with semantic search, for a hybrid search system. -- Transform fields in the sample dataset into embeddings using the Sentence Transformer model and index them into Elasticsearch. -- Use the `RRF API `_ to combine the results of a ``match`` query and a ``kNN`` semantic search. -- Walk through a super simple toy example that demonstrates, step by step, how RRF ranking works. - -Semantic search with ELSER -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -In the `03-ELSER.ipynb `_ notebook, you'll learn how to: - -- Use the Elastic Learned Sparse Encoder (ELSER) for text expansion-powered semantic search, out of the box — without training, fine-tuning, or embeddings generation. -- Download and deploy the ELSER model in your Elastic environment. -- Create an Elasticsearch index named `search-movies` with specific mappings and index a dataset of movie descriptions. -- Create an ingest pipeline containing an inference processor for ELSER model execution. -- Reindex the data from `search-movies` into another index, `elser-movies`, using the ELSER pipeline for text expansion. -- Observe the results of running the documents through the model by inspecting the additional terms it adds to documents, which enhance searchability. -- Perform simple keyword searches on the `elser-movies` index to assess the impact of ELSER's text expansion. -- Execute ELSER-powered semantic searches using the ``text_expansion`` query. - -Multilingual semantic search -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -In the `04-multilingual.ipynb `_ notebook, you'll learn how to: - -- Use a multilingual embedding model for semantic search across languages. -- Transform fields in the sample dataset into embeddings using the Sentence Transformer model and index them into Elasticsearch. -- Use filtering with a ``kNN`` semantic search. -- Walk through a super simple toy example that demonstrates, step by step, how multilingual search works across languages, and within non-English languages. - -Query rules -^^^^^^^^^^^ - -In the `05-query-rules.ipynb `_ notebook, you'll learn how to: - -- Use the query rules management APIs to create and edit promotional rules based on contextual queries. -- Apply these query rules by using the ``rule_query`` in Query DSL. - -Synonyms API quick start -^^^^^^^^^^^^^^^^^^^^^^^^ - -In the `06-synonyms-api.ipynb `_ notebook, you'll learn how to: - -- Use the synonyms management API to create a synonyms set to enhance your search recall. -- Configure an index to use search-time synonyms. -- Update synonyms in real time. -- Run queries that are enhanced by synonyms. - -Other notebooks ---------------- - -- `Generative AI `_. Notebooks that demonstrate various use cases for Elasticsearch as the retrieval engine and vector store for LLM-powered applications. -- `Integrations `_. Notebooks that demonstrate how to integrate popular services and projects with Elasticsearch, including OpenAI, Hugging Face, and LlamaIndex -- `Langchain `_. Notebooks that demonstrate how to integrate Elastic with LangChain, a framework for developing applications powered by language models. diff --git a/docs/sphinx/quickstart.rst b/docs/sphinx/quickstart.rst deleted file mode 100644 index f7e527858..000000000 --- a/docs/sphinx/quickstart.rst +++ /dev/null @@ -1,167 +0,0 @@ -.. _quickstart: - -Quickstart -========== - -This guide shows you how to install the Elasticsearch Python client and perform basic -operations like indexing or searching documents. - -Requirements ------------- - -- `Python `_ 3.8 or newer -- `pip `_ - - -Installation ------------- - -To install the client, run the following command: - -.. code-block:: console - - $ python -m pip install elasticsearch - - -Connecting ----------- - -You can connect to Elastic Cloud using an API key and the Cloud ID. - -.. code-block:: python - - from elasticsearch import Elasticsearch - - client = Elasticsearch(cloud_id="YOUR_CLOUD_ID", api_key="YOUR_API_KEY") - -Your Cloud ID can be found on the **My deployment** page of your deployment -under **Cloud ID**. - -You can generate an API key on the **Management** page under Security. - -.. image:: _static/images/create-api-key.png - -Confirm that the connection was successful. - -.. code-block:: python - - print(client.info()) - -Using the client ----------------- - -Time to use Elasticsearch! This section walks you through the most important -operations of Elasticsearch. The following examples assume that the Python -client was instantiated as above. - -Create an index with mappings -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -This is how you create the `my_index` index. -Optionally, you can first define the expected types of your features with a custom mapping. - -.. code-block:: python - - mappings = { - "properties": { - "foo": {"type": "text"}, - "bar": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256, - } - }, - }, - } - } - - client.indices.create(index="my_index", mappings=mappings) - -Indexing documents -^^^^^^^^^^^^^^^^^^ - -This indexes a document with the index API: - -.. code-block:: python - - client.index( - index="my_index", - id="my_document_id", - document={ - "foo": "foo", - "bar": "bar", - }, - ) - -You can also index multiple documents at once with the bulk helper function: - -.. code-block:: python - - from elasticsearch import helpers - - def generate_docs(): - for i in range(10): - yield { - "_index": "my_index", - "foo": f"foo {i}", - "bar": "bar", - } - - helpers.bulk(client, generate_docs()) - -These helpers are the recommended way to perform bulk ingestion. While it is also possible to perform bulk ingestion using ``client.bulk`` directly, the helpers handle retries, ingesting chunk by chunk and more. See the :ref:`helpers` page for more details. - -Getting documents -^^^^^^^^^^^^^^^^^ - -You can get documents by using the following code: - -.. code-block:: python - - client.get(index="my_index", id="my_document_id") - - -Searching documents -^^^^^^^^^^^^^^^^^^^ - -This is how you can create a single match query with the Python client: - - -.. code-block:: python - - client.search(index="my_index", query={"match": {"foo": {"query": "foo"}}}) - - -Updating documents -^^^^^^^^^^^^^^^^^^ - -This is how you can update a document, for example to add a new field: - -.. code-block:: python - - client.update( - index="my_index", - id="my_document_id", - doc={ - "foo": "bar", - "new_field": "new value", - }, - ) - - -Deleting documents -^^^^^^^^^^^^^^^^^^ - -.. code-block:: python - - client.delete(index="my_index", id="my_document_id") - - -Deleting an index -^^^^^^^^^^^^^^^^^ - -.. code-block:: python - - client.indices.delete(index="my_index") From d89f3bb1947df2660c1dc645c0ced25f46d5ebee Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Apr 2025 14:59:07 +0400 Subject: [PATCH 32/57] Clarify Elasticsearch 9.x compatibility (#2928) (#2931) Co-authored-by: Quentin Pradet Co-authored-by: Marci W <333176+marciw@users.noreply.github.com> (cherry picked from commit bd612f3ee46b736e0af519b4c9f0abaaa9c10dfc) Co-authored-by: Zach Brisson <162374237+ZachBrisson-Elastic@users.noreply.github.com> --- README.md | 35 +++++++++++++++++------------------ docs/reference/index.md | 23 ++++++++++++++++------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 20b72407d..11d1b8259 100644 --- a/README.md +++ b/README.md @@ -63,24 +63,23 @@ of the getting started documentation. ## Compatibility -Language clients are forward compatible; meaning that the clients support -communicating with greater or equal minor versions of Elasticsearch without -breaking. It does not mean that the clients automatically support new features -of newer Elasticsearch versions; it is only possible after a release of a new -client version. For example, a 8.12 client version won't automatically support -the new features of the 8.13 version of Elasticsearch, the 8.13 client version -is required for that. Elasticsearch language clients are only backwards -compatible with default distributions and without guarantees made. - -| Elasticsearch Version | Elasticsearch-Python Branch | Supported | -| --------------------- | ------------------------ | --------- | -| main | main | | -| 8.x | 8.x | 8.x | -| 7.x | 7.x | 7.17 | - - -If you have a need to have multiple versions installed at the same time older -versions are also released as ``elasticsearch7`` and ``elasticsearch8``. +Language clients are _forward compatible:_ each client version works with equivalent and later minor versions of Elasticsearch without breaking. + +Compatibility does not imply full feature parity. New Elasticsearch features are supported only in equivalent client versions. For example, an 8.12 client fully supports Elasticsearch 8.12 features and works with 8.13 without breaking; however, it does not support new Elasticsearch 8.13 features. An 8.13 client fully supports Elasticsearch 8.13 features. + +| Elasticsearch version | elasticsearch-py branch | +| --- | --- | +| main | main | +| 9.x | 9.x | +| 9.x | 8.x | +| 8.x | 8.x | + +Elasticsearch language clients are also _backward compatible_ across minor versions — with default distributions and without guarantees. + +> [!TIP] +> To upgrade to a new major version, first upgrade Elasticsearch, then upgrade the Python Elasticsearch client. + +If you need to work with multiple client versions, note that older versions are also released as `elasticsearch7` and `elasticsearch8`. ## Documentation diff --git a/docs/reference/index.md b/docs/reference/index.md index 99282dec2..709a45366 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -56,12 +56,21 @@ For a higher level access with more limited scope, have a look at the DSL module ## Compatibility [_compatibility] -Language clients are forward compatible; meaning that the clients support communicating with greater or equal minor versions of {{es}} without breaking. It does not mean that the clients automatically support new features of newer {{es}} versions; it is only possible after a release of a new client version. For example, a 8.12 client version won’t automatically support the new features of the 8.13 version of {{es}}, the 8.13 client version is required for that. {{es}} language clients are only backwards compatible with default distributions and without guarantees made. +Language clients are _forward compatible:_ each client version works with equivalent and later minor versions of {{es}} without breaking. -| Elasticsearch version | elasticsearch-py branch | Supported | -| --- | --- | --- | -| main | main | | -| 8.x | 8.x | 8.x | -| 7.x | 7.x | 7.17 | +Compatibility does not imply full feature parity. New {{es}} features are supported only in equivalent client versions. For example, an 8.12 client fully supports {{es}} 8.12 features and works with 8.13 without breaking; however, it does not support new {{es}} 8.13 features. An 8.13 client fully supports {{es}} 8.13 features. -If you have a need to have multiple versions installed at the same time older versions are also released as `elasticsearch7` and `elasticsearch8`. +| Elasticsearch version | elasticsearch-py branch | +| --- | --- | +| main | main | +| 9.x | 9.x | +| 9.x | 8.x | +| 8.x | 8.x | + +{{es}} language clients are also _backward compatible_ across minor versions — with default distributions and without guarantees. + +:::{tip} +To upgrade to a new major version, first upgrade {{es}}, then upgrade the Python {{es}} client. +::: + +If you need to work with multiple client versions, note that older versions are also released as `elasticsearch7` and `elasticsearch8`. From 13dce23332241dcc58ce2d50c119ef080e596ba8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Apr 2025 18:46:31 +0400 Subject: [PATCH 33/57] fix image paths for docs-assembler (#2929) (#2930) (cherry picked from commit 3f10e9748506b84d6978597ea4b5c19563986064) Co-authored-by: Colleen McGinnis --- docs/reference/getting-started.md | 8 ++------ docs/reference/opentelemetry.md | 18 ++++++------------ 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/docs/reference/getting-started.md b/docs/reference/getting-started.md index 5ded3f138..54fce4ec3 100644 --- a/docs/reference/getting-started.md +++ b/docs/reference/getting-started.md @@ -41,15 +41,11 @@ client = Elasticsearch( Your Elasticsearch endpoint can be found on the **My deployment** page of your deployment: -:::{image} images/es-endpoint.jpg -:alt: Finding Elasticsearch endpoint -::: +![Finding Elasticsearch endpoint](images/es-endpoint.jpg) You can generate an API key on the **Management** page under Security. -:::{image} images/create-api-key.png -:alt: Create API key -::: +![Create API key](images/create-api-key.png) For other connection options, refer to the [*Connecting*](/reference/connecting.md) section. diff --git a/docs/reference/opentelemetry.md b/docs/reference/opentelemetry.md index 0521665f3..d2dbb5482 100644 --- a/docs/reference/opentelemetry.md +++ b/docs/reference/opentelemetry.md @@ -9,24 +9,18 @@ You can use [OpenTelemetry](https://opentelemetry.io/) to monitor the performanc The native instrumentation in the Python client follows the [OpenTelemetry Semantic Conventions for {{es}}](https://opentelemetry.io/docs/specs/semconv/database/elasticsearch/). In particular, the instrumentation in the client covers the logical layer of {{es}} requests. A single span per request is created that is processed by the service through the Python client. The following image shows a trace that records the handling of two different {{es}} requests: an `info` request and a `search` request. -:::{image} images/otel-waterfall-without-http.png -:alt: Distributed trace with Elasticsearch spans -:class: screenshot -::: +% TO DO: Use `:class: screenshot` +![Distributed trace with Elasticsearch spans](images/otel-waterfall-without-http.png) Usually, OpenTelemetry auto-instrumentation modules come with instrumentation support for HTTP-level communication. In this case, in addition to the logical {{es}} client requests, spans will be captured for the physical HTTP requests emitted by the client. The following image shows a trace with both, {{es}} spans (in blue) and the corresponding HTTP-level spans (in red) after having installed the ``opentelemetry-instrumentation-urllib3`` package: -:::{image} images/otel-waterfall-with-http.png -:alt: Distributed trace with Elasticsearch spans -:class: screenshot -::: +% TO DO: Use `:class: screenshot` +![Distributed trace with Elasticsearch spans](images/otel-waterfall-with-http.png) Advanced Python client behavior such as nodes round-robin and request retries are revealed through the combination of logical {{es}} spans and the physical HTTP spans. The following example shows a `search` request in a scenario with two nodes: -:::{image} images/otel-waterfall-retry.png -:alt: Distributed trace with Elasticsearch spans -:class: screenshot -::: +% TO DO: Use `:class: screenshot` +![Distributed trace with Elasticsearch spans](images/otel-waterfall-retry.png) The first node is unavailable and results in an HTTP error, while the retry to the second node succeeds. Both HTTP requests are subsumed by the logical {{es}} request span (in blue). From 826ec1bde2ec92672d1ebff3500df4f96a8022fb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 18 Apr 2025 14:23:39 +0400 Subject: [PATCH 34/57] Surface caused_by in ApiError (#2932) (#2935) In particular, this will give a clear error when using elasticsearch-py 9.0.0 on an 8.x cluster. (cherry picked from commit 72efd52628e889acd8b77147efaf901ebf4b9db7) Co-authored-by: Quentin Pradet --- elasticsearch/exceptions.py | 2 ++ test_elasticsearch/test_exceptions.py | 30 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/elasticsearch/exceptions.py b/elasticsearch/exceptions.py index dc410ae30..70738d5af 100644 --- a/elasticsearch/exceptions.py +++ b/elasticsearch/exceptions.py @@ -61,6 +61,7 @@ def __str__(self) -> str: if self.body and isinstance(self.body, dict) and "error" in self.body: if isinstance(self.body["error"], dict): root_cause = self.body["error"]["root_cause"][0] + caused_by = self.body["error"].get("caused_by", {}) cause = ", ".join( filter( None, @@ -68,6 +69,7 @@ def __str__(self) -> str: repr(root_cause["reason"]), root_cause.get("resource.id"), root_cause.get("resource.type"), + caused_by.get("reason"), ], ) ) diff --git a/test_elasticsearch/test_exceptions.py b/test_elasticsearch/test_exceptions.py index 00e8015c7..938aded3d 100644 --- a/test_elasticsearch/test_exceptions.py +++ b/test_elasticsearch/test_exceptions.py @@ -46,3 +46,33 @@ def test_transform_error_parse_with_error_string(self): assert ( str(e) == "ApiError(500, 'InternalServerError', 'something error message')" ) + + def test_transform_invalid_media_type_error(self): + e = ApiError( + message="InvalidMediaType", + meta=error_meta, + body={ + "error": { + "root_cause": [ + { + "type": "media_type_header_exception", + "reason": "Invalid media-type value on headers [Accept, Content-Type]", + } + ], + "type": "media_type_header_exception", + "reason": "Invalid media-type value on headers [Accept, Content-Type]", + "caused_by": { + "type": "status_exception", + "reason": "Accept version must be either version 8 or 7, but found 9. Accept=application/vnd.elasticsearch+json; compatible-with=9", + }, + }, + "status": 400, + }, + ) + + assert str(e) == ( + "ApiError(500, 'InvalidMediaType', " + "'Invalid media-type value on headers [Accept, Content-Type]', " + "Accept version must be either version 8 or 7, but found 9. " + "Accept=application/vnd.elasticsearch+json; compatible-with=9)" + ) From 17535796719af2a6eb546525cdc585b251113d12 Mon Sep 17 00:00:00 2001 From: Elastic Machine Date: Tue, 22 Apr 2025 07:31:26 +0200 Subject: [PATCH 35/57] Auto-generated API code (#2938) --- elasticsearch/_async/client/indices.py | 6 +++--- elasticsearch/_sync/client/indices.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/elasticsearch/_async/client/indices.py b/elasticsearch/_async/client/indices.py index c2472f314..07e7c58c2 100644 --- a/elasticsearch/_async/client/indices.py +++ b/elasticsearch/_async/client/indices.py @@ -265,7 +265,7 @@ async def cancel_migrate_reindex(

Cancel a migration reindex attempt for a data stream or index.

- ``_ + ``_ :param index: The index or data stream name """ @@ -794,7 +794,7 @@ async def create_from(

Copy the mappings and settings from the source index to a destination index while allowing request settings and mappings to override the source values.

- ``_ + ``_ :param source: The source index or data stream name :param dest: The destination index or data stream name @@ -2952,7 +2952,7 @@ async def migrate_reindex( The persistent task ID is returned immediately and the reindexing work is completed in that task.

- ``_ + ``_ :param reindex: """ diff --git a/elasticsearch/_sync/client/indices.py b/elasticsearch/_sync/client/indices.py index 131e4a06a..6cb3cb8d6 100644 --- a/elasticsearch/_sync/client/indices.py +++ b/elasticsearch/_sync/client/indices.py @@ -265,7 +265,7 @@ def cancel_migrate_reindex(

Cancel a migration reindex attempt for a data stream or index.

- ``_ + ``_ :param index: The index or data stream name """ @@ -794,7 +794,7 @@ def create_from(

Copy the mappings and settings from the source index to a destination index while allowing request settings and mappings to override the source values.

- ``_ + ``_ :param source: The source index or data stream name :param dest: The destination index or data stream name @@ -2952,7 +2952,7 @@ def migrate_reindex( The persistent task ID is returned immediately and the reindexing work is completed in that task.

- ``_ + ``_ :param reindex: """ From 051cdc79e49729f668ddd76648c065e4747a324c Mon Sep 17 00:00:00 2001 From: Elastic Machine Date: Mon, 28 Apr 2025 14:13:58 +0200 Subject: [PATCH 36/57] Auto-generated API code (#2943) --- elasticsearch/_async/client/ml.py | 6 +++--- elasticsearch/_sync/client/ml.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/elasticsearch/_async/client/ml.py b/elasticsearch/_async/client/ml.py index 517cb0b74..594dd8f09 100644 --- a/elasticsearch/_async/client/ml.py +++ b/elasticsearch/_async/client/ml.py @@ -1676,7 +1676,7 @@ async def get_data_frame_analytics_stats( """ .. raw:: html -

Get data frame analytics jobs usage info.

+

Get data frame analytics job stats.

``_ @@ -1744,7 +1744,7 @@ async def get_datafeed_stats( """ .. raw:: html -

Get datafeeds usage info. +

Get datafeed stats. You can get statistics for multiple datafeeds in a single API request by using a comma-separated list of datafeeds or a wildcard expression. You can get statistics for all datafeeds by using _all, by specifying * as the @@ -2033,7 +2033,7 @@ async def get_job_stats( """ .. raw:: html -

Get anomaly detection jobs usage info.

+

Get anomaly detection job stats.

``_ diff --git a/elasticsearch/_sync/client/ml.py b/elasticsearch/_sync/client/ml.py index 0b21fb264..7d2a632a9 100644 --- a/elasticsearch/_sync/client/ml.py +++ b/elasticsearch/_sync/client/ml.py @@ -1676,7 +1676,7 @@ def get_data_frame_analytics_stats( """ .. raw:: html -

Get data frame analytics jobs usage info.

+

Get data frame analytics job stats.

``_ @@ -1744,7 +1744,7 @@ def get_datafeed_stats( """ .. raw:: html -

Get datafeeds usage info. +

Get datafeed stats. You can get statistics for multiple datafeeds in a single API request by using a comma-separated list of datafeeds or a wildcard expression. You can get statistics for all datafeeds by using _all, by specifying * as the @@ -2033,7 +2033,7 @@ def get_job_stats( """ .. raw:: html -

Get anomaly detection jobs usage info.

+

Get anomaly detection job stats.

``_ From 022beb4aa88788e12b49c6a3e28858cc4e696b5f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 28 Apr 2025 16:36:59 +0400 Subject: [PATCH 37/57] [docs] Fix various syntax and rendering errors (#2940) (#2944) * fix various syntax and rendering issues * fix image (cherry picked from commit 631956d262bc8e9faee7b1b09ab564e23aedf321) Co-authored-by: Colleen McGinnis --- docs/reference/client-helpers.md | 2 +- docs/{ => reference}/images/python-example.png | Bin docs/reference/querying.md | 8 +++----- 3 files changed, 4 insertions(+), 6 deletions(-) rename docs/{ => reference}/images/python-example.png (100%) diff --git a/docs/reference/client-helpers.md b/docs/reference/client-helpers.md index 904d61815..38cea019d 100644 --- a/docs/reference/client-helpers.md +++ b/docs/reference/client-helpers.md @@ -12,7 +12,7 @@ You can find here a collection of simple helper functions that abstract some spe There are several helpers for the bulk API since its requirement for specific formatting and other considerations can make it cumbersome if used directly. -All bulk helpers accept an instance of `{{es}}` class and an iterable `action` (any iterable, can also be a generator, which is ideal in most cases since it allows you to index large datasets without the need of loading them into memory). +All bulk helpers accept an instance of `Elasticsearch` class and an iterable `action` (any iterable, can also be a generator, which is ideal in most cases since it allows you to index large datasets without the need of loading them into memory). The items in the iterable `action` should be the documents we wish to index in several formats. The most common one is the same as returned by `search()`, for example: diff --git a/docs/images/python-example.png b/docs/reference/images/python-example.png similarity index 100% rename from docs/images/python-example.png rename to docs/reference/images/python-example.png diff --git a/docs/reference/querying.md b/docs/reference/querying.md index 5d701280d..a4946d340 100644 --- a/docs/reference/querying.md +++ b/docs/reference/querying.md @@ -6,7 +6,7 @@ The Python Elasticsearch client provides several ways to send queries to Elastic Elasticsearch APIs are grouped by namespaces. - * There's the global namespace, with APIs like the Search API (`GET _search`) or the Index API (`PUT //_doc/<_id>` and related endpoints). + * There's the global namespace, with APIs like the Search API (`GET _search`) or the Index API (`PUT //_doc/<_id>` and related endpoints). * Then there are all the other namespaces, such as: * Indices with APIs like the Create index API (`PUT /my-index`), * ES|QL with the Run an ES|QL query API (`POST /_async`), @@ -28,10 +28,8 @@ How can you figure out the namespace? * Finally, for Elasticsearch 8.x, most examples in the [Elasticsearch guide](https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html) are also available in Python. (This is still a work in progress for Elasticsearch 9.x.) In the example below, `client.ingest.put_pipeline(...)` is the function that calls the "Create or update a pipeline" API. -:::{image} ../images/python-example.png -:alt: Python code example in the Elasticsearch guide -::: - +![Python code example in the Elasticsearch guide](images/python-example.png) + ## Parameters Now that you know which functions to call, the next step is parameters. To avoid ambiguity, the Python Elasticsearch client mandates keyword arguments. To give an example, let's look at the ["Create an index" API](https://elasticsearch-py.readthedocs.io/en/stable/api/indices.html#elasticsearch.client.IndicesClient.create). There's only one required parameter, `index`, so the minimal form looks like this: From 2955a813431d72b3cecbafd841a7acbf7ca793ff Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 28 Apr 2025 16:59:03 +0400 Subject: [PATCH 38/57] Add breaking changes to release notes (#2936) (#2945) * Add breaking changes to release notes * Add upgrade tip * Update docs/release-notes/index.md * Fix impact/action formatting * Fix links * Apply suggestions from code review * Apply suggestions from code review * Update docs/release-notes/breaking-changes.md * Remove empty sections --------- (cherry picked from commit 185d90a67a361960c58ab81ed65f869d56e7806e) Co-authored-by: Quentin Pradet Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Marci W <333176+marciw@users.noreply.github.com> --- docs/release-notes/breaking-changes.md | 43 ++++++++++-- docs/release-notes/index.md | 95 ++++++++++++++------------ 2 files changed, 89 insertions(+), 49 deletions(-) diff --git a/docs/release-notes/breaking-changes.md b/docs/release-notes/breaking-changes.md index 1d90c89dc..640a57036 100644 --- a/docs/release-notes/breaking-changes.md +++ b/docs/release-notes/breaking-changes.md @@ -14,11 +14,40 @@ Breaking changes can impact your Elastic applications, potentially disrupting no % **Action**
Steps for mitigating deprecation impact. % :::: -% ## 9.0.0 [elasticsearch-python-client-900-breaking-changes] +## 9.0.0 [elasticsearch-python-client-900-breaking-changes] -% ::::{dropdown} Title of breaking change -% Description of the breaking change. -% For more information, check [PR #](PR link). -% **Impact**
Impact of the breaking change. -% **Action**
Steps for mitigating deprecation impact. -% :::: \ No newline at end of file +::::{dropdown} Remove deprecated Elasticsearch() options +The `timeout`, `randomize_hosts`, `host_info_callback`, `sniffer_timeout`, `sniff_on_connection_fail` and `maxsize` parameters were deprecated in elasticsearch-py 8.0 and are now removed from `Elasticsearch.__init__()`. +For more information, check [PR #2840](https://github.com/elastic/elasticsearch-py/pull/2840). + +**Impact**
These parameters were removed in favor of more descriptive versions. Using any of these parameters will prevent instantiating the Elasticsearch client. + +**Action**
These parameters can be replaced as follows: + * `timeout` is now `request_timeout` + * `randomize_hosts` is now `randomize_nodes_in_pool` + * `host_info_callback` is now `sniffed_node_callback` + * `sniffer_timeout` is now `min_delay_between_sniffing` + * `sniff_on_connection_fail` is now `sniff_on_node_failure` + * `maxsize` is now `connection_per_node` +:::: + +::::{dropdown} Remove deprecated url_prefix and use_ssl host keys +When instantiating a new client, `hosts` can be specified as a dictionary. The `url_prefix` and `use_ssl` keys are no longer allowed. +For more information, check [PR #2797](https://github.com/elastic/elasticsearch-py/pull/2797). + +**Impact**
+Using any of these parameters will prevent instantiating the Elasticsearch client. + +**Action**
+The parameters can be replaced as follows: + * `use_ssl` isn't needed, as a scheme is required since elasticsearch-py 8.0 (`http` or `https`) + * `url_prefix` should be replaced with `path_prefix`, which is more descriptive. This functionality allows you to deploy Elasticsearch under a specific path, such as `http://host:port/path/to/elasticsearch`, instead of the default root path (`http://host:port/`) +:::: + +::::{dropdown} Remove APIs +Elasticsearch 9 removed the kNN search and Unfreeze index APIs. + +**Action**
+ * The kNN search API has been replaced by the `knn` option in the search API since Elasticsearch 8.4. + * The Unfreeze index API was deprecated in Elasticsearch 7.14 and has been removed in Elasticsearch 9. + :::: \ No newline at end of file diff --git a/docs/release-notes/index.md b/docs/release-notes/index.md index 5d47dd45b..fc0847d11 100644 --- a/docs/release-notes/index.md +++ b/docs/release-notes/index.md @@ -21,54 +21,65 @@ To check for security updates, go to [Security announcements for the Elastic sta ## 9.0.0 (2025-04-15) [elasticsearch-python-client-900-release-notes] +:::{tip} +Upgrade to Elasticsearch 9 before using elasticsearch-py 9.0.0 or later. Using elasticsearch-py 9.0.0 on an Elasticsearch 8 server will fail. +Since language clients are forward-compatible, you should first upgrade Elasticsearch, then the Elasticsearch client. See the [compatibility documentation](/reference/index.md#_compatibility) for more details. +::: + +### Breaking changes + * Remove deprecated `Elasticsearch()` options ([#2840](https://github.com/elastic/elasticsearch-py/pull/2840)) * Remove deprecated `url_prefix` and `use_ssl` options ([#2797](https://github.com/elastic/elasticsearch-py/pull/2797)) -* Merge `Elasticsearch-DSL `_ package ([#2736](https://github.com/elastic/elasticsearch-py/pull/2736)) + +See the [breaking changes page](breaking-changes.md) for more details. + +### Enhancements + +* Merge [`elasticsearch-dsl-py`](https://github.com/elastic/elasticsearch-dsl-py/) _ package ([#2736](https://github.com/elastic/elasticsearch-py/pull/2736)) * Add Python DSL documentation ([#2761](https://github.com/elastic/elasticsearch-py/pull/2761)) * Autogenerate DSL field classes from schema ([#2780](https://github.com/elastic/elasticsearch-py/pull/2780)) * Improve DSL documentation examples with class-based queries and type hints ([#2857](https://github.com/elastic/elasticsearch-py/pull/2857)) * Document the use of `param()` in Python DSL methods ([#2861](https://github.com/elastic/elasticsearch-py/pull/2861)) * Migrate documentation from AsciiDoc to Markdown format ([#2806](https://github.com/elastic/elasticsearch-py/pull/2806)) * Document use of sub-clients ([#2798](https://github.com/elastic/elasticsearch-py/pull/2798)) -* Document how to making API calls ([#2843](https://github.com/elastic/elasticsearch-py/pull/2843)) +* Document how to make API calls ([#2843](https://github.com/elastic/elasticsearch-py/pull/2843)) * Fix `simulate` sub-client documentation ([#2749](https://github.com/elastic/elasticsearch-py/pull/2749)) -* Update APIs - * Remove deprecated `/_knn_search` API - * Remove Unfreeze an index API - * Remove min_compatible_shard_node from Search and Async Search Submit APIs - * Remove local parameter from cat alias, Alias exists, and Get alias APIs - * Remove `verbose` from Index segments API - * Remove `include_model_definition` from Get trained model configuration info API - * Remove `wait_for_active_shards` from experimental Get field usage stats API - * Support soft-deletes in connectors: - * Add `hard` to Delete connector API - * Add `include_deleted` to Get and List Connector APIs - * Add `master_timeout` to Migrate to data tiers routing APIs - * Add `master_timeout` to the Alias exists and Get alias APIs. - * Add `expand_wildcards` to Create snapshot API - * Rename incorrect `access_token` to `token` in Logout of OpenID Connect API - * Add inference APIs: Alibaba Cloud AI Search, Amazon Bedrock, Anthropic, Azure AI Studio, Azure OpenAI, Cohere, Elastic Inference Service (EIS), Elasticsearch, ELSER, Google AI Studio, Google Vertex AI, Hugging Face, Jina AI, Mistral, OpenAI, and Voyage AI - * Add Elastic Inference Service (EIS) chat completion API - * Add Reindex legacy backing indices APIs - * Add Create an index from a source index API - * Add `include_source_on_error` to Create, Index, Update and Bulk APIs - * Add Stop async ES|QL query API - * Add `timeout` to Resolve Cluster API - * Add `adaptive_allocations` body field to Start and Update a trained model deployment API - * Rename `index_template_subtitutions` to `index_template_substitutions` in Simulate data ingestion API* Add `if_primary_term`, `if_seq_no`, `op_type`, `require_alias` and `require_data_stream` to Create API - * Add `max_concurrent_shard_requests` to Open point in time API - * Add `local` and `flat_settings` to Check index templates API - * Add `reopen` to Update index settings API - * Add `resource` to Reload search analyzer API - * Add `lazy` to Roll over to a new index API - * Add `cause` and `create` to Simulate index template APIs - * Add Elastic Inference Service (EIS) chat completion - * Add inference APIs: Alibaba Cloud AI Search, Amazon Bedrock, Anthropic, Azure AI Studio, Azure OpenAI, Cohere, Elastic Inference Service (EIS), Elasticsearch, ELSER, Google AI Studio, Google Vertex AI, Hugging Face, Jina AI, Mistral, OpenAI, and Voyage AI -* Update DSL - * Add `ignore_malformed`, `script`, `on_script_error` and `time_series_dimension` to Boolean field - * Add `index` to GeoShape field - * Add `search_inference_id` to SemanticText field - -### Features and enhancements [elasticsearch-python-client-900-features-enhancements] - -### Fixes [elasticsearch-python-client-900-fixes] + +### APIs + +* Remove deprecated `/_knn_search` API +* Remove Unfreeze an index API +* Remove `min_compatible_shard_node` from Search and Async Search Submit APIs +* Remove local parameter from cat alias, Alias exists, and Get alias APIs +* Remove `verbose` from Index segments API +* Remove `include_model_definition` from Get trained model configuration info API +* Remove `wait_for_active_shards` from experimental Get field usage stats API +* Support soft-deletes in connectors: + * Add `hard` to Delete connector API + * Add `include_deleted` to Get and List Connector APIs +* Add `master_timeout` to Migrate to data tiers routing APIs +* Add `master_timeout` to the Alias exists and Get alias APIs. +* Add `expand_wildcards` to Create snapshot API +* Rename incorrect `access_token` to `token` in Logout of OpenID Connect API +* Add inference APIs: Alibaba Cloud AI Search, Amazon Bedrock, Anthropic, Azure AI Studio, Azure OpenAI, Cohere, Elastic Inference Service (EIS), Elasticsearch, ELSER, Google AI Studio, Google Vertex AI, Hugging Face, Jina AI, Mistral, OpenAI, and Voyage AI +* Add Elastic Inference Service (EIS) chat completion API +* Add Reindex legacy backing indices APIs +* Add Create an index from a source index API +* Add `include_source_on_error` to Create, Index, Update and Bulk APIs +* Add Stop async ES|QL query API +* Add `timeout` to Resolve Cluster API +* Add `adaptive_allocations` body field to Start and Update a trained model deployment API +* Rename `index_template_subtitutions` to `index_template_substitutions` in Simulate data ingestion API +* Add `if_primary_term`, `if_seq_no`, `op_type`, `require_alias` and `require_data_stream` to Create API +* Add `max_concurrent_shard_requests` to Open point in time API +* Add `local` and `flat_settings` to Check index templates API +* Add `reopen` to Update index settings API +* Add `resource` to Reload search analyzer API +* Add `lazy` to Roll over to a new index API +* Add `cause` and `create` to Simulate index template APIs +* Add inference APIs: Alibaba Cloud AI Search, Amazon Bedrock, Anthropic, Azure AI Studio, Azure OpenAI, Cohere, Elasticsearch, ELSER, Google AI Studio, Google Vertex AI, Hugging Face, Jina AI, Mistral, OpenAI, and Voyage AI + +### DSL + * Add `ignore_malformed`, `script`, `on_script_error` and `time_series_dimension` to Boolean field + * Add `index` to GeoShape field + * Add `search_inference_id` to SemanticText field From e774026fd02f711c2409163f7321f2f6b07f6afe Mon Sep 17 00:00:00 2001 From: Quentin Pradet Date: Mon, 28 Apr 2025 17:41:07 +0400 Subject: [PATCH 39/57] Release 9.0.1 (#2946) --- docs/release-notes/index.md | 11 ++++++++++- elasticsearch/_version.py | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/release-notes/index.md b/docs/release-notes/index.md index fc0847d11..4146d076d 100644 --- a/docs/release-notes/index.md +++ b/docs/release-notes/index.md @@ -12,13 +12,22 @@ To check for security updates, go to [Security announcements for the Elastic sta % Release notes include only features, enhancements, and fixes. Add breaking changes, deprecations, and known issues to the applicable release notes sections. -% ## version.next [felasticsearch-python-client-next-release-notes] +% ## version.next [elasticsearch-python-client-next-release-notes] % ### Features and enhancements [elasticsearch-python-client-next-features-enhancements] % * % ### Fixes [elasticsearch-python-client-next-fixes] +## 9.0.1 (2025-04-28) [elasticsearch-python-client-901-release-notes] + +### Features and enhancements [elasticsearch-python-client-901-features-enhancements] + +* Surface caused_by in ApiError ([#2932](https://github.com/elastic/elasticsearch-py/pull/2932)) +* Clarify Elasticsearch 9.x compatibility ([#2928](https://github.com/elastic/elasticsearch-py/pull/2928)) +* Reorganize Sphinx docs to only include reference pages ([#2776](https://github.com/elastic/elasticsearch-py/pull/2776)) + + ## 9.0.0 (2025-04-15) [elasticsearch-python-client-900-release-notes] :::{tip} diff --git a/elasticsearch/_version.py b/elasticsearch/_version.py index f0ae401fc..fafa33a2b 100644 --- a/elasticsearch/_version.py +++ b/elasticsearch/_version.py @@ -15,4 +15,4 @@ # specific language governing permissions and limitations # under the License. -__versionstr__ = "9.0.0" +__versionstr__ = "9.0.1" From 1cb68489a79178cdc0bce92b217acd76f0b1ee1a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 1 May 2025 10:17:07 +0100 Subject: [PATCH 40/57] Update intro paragraphs in the documentation (#2952) (#2954) (cherry picked from commit 5b610f695182360f2d81954cb07750337427a387) Co-authored-by: Miguel Grinberg --- docs/reference/index.md | 2 +- docs/sphinx/index.rst | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/reference/index.md b/docs/reference/index.md index 709a45366..41c7883f2 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -6,7 +6,7 @@ mapped_pages: # Python [overview] -This is the official low-level Python client for {{es}}. Its goal is to provide common ground for all {{es}}-related code in Python. For this reason, the client is designed to be unopinionated and extendable. An API reference is available on [Read the Docs](https://elasticsearch-py.readthedocs.io). +This is the official Python client for {{es}}. Its goal is to provide common ground for all {{es}}-related code in Python. For this reason, the client is designed to be unopinionated and extendable. API reference documentation for this client is available on [Read the Docs](https://elasticsearch-py.readthedocs.io). ## Example use [_example_use] diff --git a/docs/sphinx/index.rst b/docs/sphinx/index.rst index 7c7b5d6fa..4cf5f92cc 100644 --- a/docs/sphinx/index.rst +++ b/docs/sphinx/index.rst @@ -1,6 +1,12 @@ Python Elasticsearch Client =========================== +Welcome to the API documentation of the official Python client for Elasticsearch! +The goal of this client is to provide common ground for all Elasticsearch-related +code in Python; because of this it tries to be opinion-free and very extendable. + +High-level documentation for this client is `also available `_. + .. toctree:: :maxdepth: 2 From cf4ceffd13250eeddeae741249afb1317e3acee4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 15:04:27 +0400 Subject: [PATCH 41/57] [Docs] Fix broken link to RTD helpers page (#2958) (#2959) * Fix broken link to RTD helpers page * Update index.md * remove circular redirect (cherry picked from commit 67d186b782238ef799716b87ca5f4dba48e2bab0) Co-authored-by: Marci W <333176+marciw@users.noreply.github.com> --- docs/reference/client-helpers.md | 2 +- docs/reference/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reference/client-helpers.md b/docs/reference/client-helpers.md index 38cea019d..08f480e23 100644 --- a/docs/reference/client-helpers.md +++ b/docs/reference/client-helpers.md @@ -5,7 +5,7 @@ mapped_pages: # Client helpers [client-helpers] -You can find here a collection of simple helper functions that abstract some specifics of the raw API. For detailed examples, refer to [this page](https://elasticsearch-py.readthedocs.io/en/stable/helpers.html). +You can find here a collection of simple helper functions that abstract some specifics of the raw API. ## Bulk helpers [bulk-helpers] diff --git a/docs/reference/index.md b/docs/reference/index.md index 41c7883f2..6046d7801 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -46,7 +46,7 @@ The client’s features include: * Thread safety * Pluggable architecture -The client also contains a convenient set of [helpers](https://elasticsearch-py.readthedocs.org/en/master/helpers.md) for some of the more engaging tasks like bulk indexing and reindexing. +The client also contains a convenient set of [helpers](client-helpers.md) for some of the more engaging tasks like bulk indexing and reindexing. ## Elasticsearch Python DSL [_elasticsearch_python_dsl] From 47e75f225f876c9e8aba0bfb9ad012eb8515b1e2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 30 May 2025 12:00:47 +0400 Subject: [PATCH 42/57] Stop using event_loop fixture (#2969) (#2970) It was removed in pytest-asyncio 1.0. (cherry picked from commit 3c9680a5cf0b67a56356bf73173a7d5eabb2e552) Co-authored-by: Quentin Pradet --- docs/reference/async.md | 3 +-- test_elasticsearch/test_async/test_transport.py | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/reference/async.md b/docs/reference/async.md index f205d3807..70e8949d5 100644 --- a/docs/reference/async.md +++ b/docs/reference/async.md @@ -34,8 +34,7 @@ async def main(): ) print(resp) -loop = asyncio.get_event_loop() -loop.run_until_complete(main()) +asyncio.run(main()) ``` All APIs that are available under the sync client are also available under the async client. diff --git a/test_elasticsearch/test_async/test_transport.py b/test_elasticsearch/test_async/test_transport.py index ef52ca85c..cf9b8600a 100644 --- a/test_elasticsearch/test_async/test_transport.py +++ b/test_elasticsearch/test_async/test_transport.py @@ -527,7 +527,8 @@ async def test_sniff_on_node_failure_triggers(self, extra_key, extra_value): assert request_failed_in_error assert len(client.transport.node_pool) == 3 - async def test_sniff_after_n_seconds(self, event_loop): + async def test_sniff_after_n_seconds(self): + event_loop = asyncio.get_running_loop() client = AsyncElasticsearch( # noqa: F821 [NodeConfig("http", "localhost", 9200, _extras={"data": CLUSTER_NODES})], node_class=DummyNode, @@ -579,7 +580,8 @@ async def test_sniffing_disabled_on_elastic_cloud(self, kwargs): == "Sniffing should not be enabled when connecting to Elastic Cloud" ) - async def test_sniff_on_start_close_unlocks_async_calls(self, event_loop): + async def test_sniff_on_start_close_unlocks_async_calls(self): + event_loop = asyncio.get_running_loop() client = AsyncElasticsearch( # noqa: F821 [ NodeConfig( From 2577d7dc01b3f0036b1bb48e4f610c2385b79388 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 30 May 2025 12:27:38 +0100 Subject: [PATCH 43/57] Fix some new type warnings from mypy (#2974) (#2976) (cherry picked from commit 63efa48aabc353f806ef0a0b07add5130136fc5d) Co-authored-by: Miguel Grinberg --- elasticsearch/dsl/_async/document.py | 2 +- elasticsearch/dsl/_sync/document.py | 2 +- elasticsearch/dsl/field.py | 12 ++++++- elasticsearch/dsl/query.py | 44 ++++++++++++++++++++++- elasticsearch/dsl/types.py | 54 ++++++++++++++++++++++------ 5 files changed, 100 insertions(+), 14 deletions(-) diff --git a/elasticsearch/dsl/_async/document.py b/elasticsearch/dsl/_async/document.py index 4b7654761..de6e9eecc 100644 --- a/elasticsearch/dsl/_async/document.py +++ b/elasticsearch/dsl/_async/document.py @@ -96,7 +96,7 @@ class AsyncDocument(DocumentBase, metaclass=AsyncIndexMeta): @classmethod def _get_using(cls, using: Optional[AsyncUsingType] = None) -> AsyncUsingType: - return cast(AsyncUsingType, using or cls._index._using) + return using or cls._index._using @classmethod def _get_connection( diff --git a/elasticsearch/dsl/_sync/document.py b/elasticsearch/dsl/_sync/document.py index 316ece5cb..f68be4aae 100644 --- a/elasticsearch/dsl/_sync/document.py +++ b/elasticsearch/dsl/_sync/document.py @@ -92,7 +92,7 @@ class Document(DocumentBase, metaclass=IndexMeta): @classmethod def _get_using(cls, using: Optional[UsingType] = None) -> UsingType: - return cast(UsingType, using or cls._index._using) + return using or cls._index._using @classmethod def _get_connection(cls, using: Optional[UsingType] = None) -> "Elasticsearch": diff --git a/elasticsearch/dsl/field.py b/elasticsearch/dsl/field.py index 726fbe358..e3ed5dfcd 100644 --- a/elasticsearch/dsl/field.py +++ b/elasticsearch/dsl/field.py @@ -1290,7 +1290,7 @@ def _deserialize(self, data: Any) -> Union[datetime, date]: if isinstance(data, datetime): if self._default_timezone and data.tzinfo is None: data = data.replace(tzinfo=self._default_timezone) - return data + return cast(datetime, data) if isinstance(data, date): return data if isinstance(data, int): @@ -3689,6 +3689,11 @@ class SemanticText(Field): by using the Update mapping API. Use the Create inference API to create the endpoint. If not specified, the inference endpoint defined by inference_id will be used at both index and query time. + :arg chunking_settings: Settings for chunking text into smaller + passages. If specified, these will override the chunking settings + sent in the inference endpoint associated with inference_id. If + chunking settings are updated, they will not be applied to + existing documents until they are reindexed. """ name = "semantic_text" @@ -3699,6 +3704,9 @@ def __init__( meta: Union[Mapping[str, str], "DefaultType"] = DEFAULT, inference_id: Union[str, "DefaultType"] = DEFAULT, search_inference_id: Union[str, "DefaultType"] = DEFAULT, + chunking_settings: Union[ + "types.ChunkingSettings", Dict[str, Any], "DefaultType" + ] = DEFAULT, **kwargs: Any, ): if meta is not DEFAULT: @@ -3707,6 +3715,8 @@ def __init__( kwargs["inference_id"] = inference_id if search_inference_id is not DEFAULT: kwargs["search_inference_id"] = search_inference_id + if chunking_settings is not DEFAULT: + kwargs["chunking_settings"] = chunking_settings super().__init__(*args, **kwargs) diff --git a/elasticsearch/dsl/query.py b/elasticsearch/dsl/query.py index 1282d3b02..06be2f7fb 100644 --- a/elasticsearch/dsl/query.py +++ b/elasticsearch/dsl/query.py @@ -1382,7 +1382,49 @@ def __init__( min_term_freq: Union[int, "DefaultType"] = DEFAULT, min_word_length: Union[int, "DefaultType"] = DEFAULT, routing: Union[str, "DefaultType"] = DEFAULT, - stop_words: Union[str, Sequence[str], "DefaultType"] = DEFAULT, + stop_words: Union[ + Literal[ + "_arabic_", + "_armenian_", + "_basque_", + "_bengali_", + "_brazilian_", + "_bulgarian_", + "_catalan_", + "_cjk_", + "_czech_", + "_danish_", + "_dutch_", + "_english_", + "_estonian_", + "_finnish_", + "_french_", + "_galician_", + "_german_", + "_greek_", + "_hindi_", + "_hungarian_", + "_indonesian_", + "_irish_", + "_italian_", + "_latvian_", + "_lithuanian_", + "_norwegian_", + "_persian_", + "_portuguese_", + "_romanian_", + "_russian_", + "_serbian_", + "_sorani_", + "_spanish_", + "_swedish_", + "_thai_", + "_turkish_", + "_none_", + ], + Sequence[str], + "DefaultType", + ] = DEFAULT, unlike: Union[ Union[str, "types.LikeDocument"], Sequence[Union[str, "types.LikeDocument"]], diff --git a/elasticsearch/dsl/types.py b/elasticsearch/dsl/types.py index 6dc9f09df..e6e19e410 100644 --- a/elasticsearch/dsl/types.py +++ b/elasticsearch/dsl/types.py @@ -142,6 +142,48 @@ def __init__( super().__init__(kwargs) +class ChunkingSettings(AttrDict[Any]): + """ + :arg strategy: (required) The chunking strategy: `sentence` or `word`. + Defaults to `sentence` if omitted. + :arg max_chunk_size: (required) The maximum size of a chunk in words. + This value cannot be higher than `300` or lower than `20` (for + `sentence` strategy) or `10` (for `word` strategy). Defaults to + `250` if omitted. + :arg overlap: The number of overlapping words for chunks. It is + applicable only to a `word` chunking strategy. This value cannot + be higher than half the `max_chunk_size` value. Defaults to `100` + if omitted. + :arg sentence_overlap: The number of overlapping sentences for chunks. + It is applicable only for a `sentence` chunking strategy. It can + be either `1` or `0`. Defaults to `1` if omitted. + """ + + strategy: Union[str, DefaultType] + max_chunk_size: Union[int, DefaultType] + overlap: Union[int, DefaultType] + sentence_overlap: Union[int, DefaultType] + + def __init__( + self, + *, + strategy: Union[str, DefaultType] = DEFAULT, + max_chunk_size: Union[int, DefaultType] = DEFAULT, + overlap: Union[int, DefaultType] = DEFAULT, + sentence_overlap: Union[int, DefaultType] = DEFAULT, + **kwargs: Any, + ): + if strategy is not DEFAULT: + kwargs["strategy"] = strategy + if max_chunk_size is not DEFAULT: + kwargs["max_chunk_size"] = max_chunk_size + if overlap is not DEFAULT: + kwargs["overlap"] = overlap + if sentence_overlap is not DEFAULT: + kwargs["sentence_overlap"] = sentence_overlap + super().__init__(kwargs) + + class ClassificationInferenceOptions(AttrDict[Any]): """ :arg num_top_classes: Specifies the number of top class predictions to @@ -1561,11 +1603,7 @@ class InnerHits(AttrDict[Any]): DefaultType, ] seq_no_primary_term: Union[bool, DefaultType] - fields: Union[ - Union[str, InstrumentedField], - Sequence[Union[str, InstrumentedField]], - DefaultType, - ] + fields: Union[Sequence[Union[str, InstrumentedField]], DefaultType] sort: Union[ Union[Union[str, InstrumentedField], "SortOptions"], Sequence[Union[Union[str, InstrumentedField], "SortOptions"]], @@ -1600,11 +1638,7 @@ def __init__( DefaultType, ] = DEFAULT, seq_no_primary_term: Union[bool, DefaultType] = DEFAULT, - fields: Union[ - Union[str, InstrumentedField], - Sequence[Union[str, InstrumentedField]], - DefaultType, - ] = DEFAULT, + fields: Union[Sequence[Union[str, InstrumentedField]], DefaultType] = DEFAULT, sort: Union[ Union[Union[str, InstrumentedField], "SortOptions"], Sequence[Union[Union[str, InstrumentedField], "SortOptions"]], From 4d37fea18b9e68d017cfb56d08204cc2dbb760e2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 4 Jun 2025 12:58:59 +0100 Subject: [PATCH 44/57] Add the recent mypy fix to field.py to the template for this file (#2979) (#2982) (cherry picked from commit e616da96335f59849e193716132de8769acc9813) Co-authored-by: Miguel Grinberg --- utils/templates/field.py.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/templates/field.py.tpl b/utils/templates/field.py.tpl index 95ee2f391..030060d23 100644 --- a/utils/templates/field.py.tpl +++ b/utils/templates/field.py.tpl @@ -367,7 +367,7 @@ class {{ k.name }}({{ k.parent }}): if isinstance(data, datetime): if self._default_timezone and data.tzinfo is None: data = data.replace(tzinfo=self._default_timezone) - return data + return cast(datetime, data) if isinstance(data, date): return data if isinstance(data, int): From f1c34ba3450c6322c36925d331690ff008a4c7a4 Mon Sep 17 00:00:00 2001 From: Elastic Machine Date: Thu, 5 Jun 2025 06:32:06 -0400 Subject: [PATCH 45/57] Auto-generated code for 9.0 (#2955) * Auto-generated API code * ran the format task again on this branch --------- Co-authored-by: Miguel Grinberg --- elasticsearch/_async/client/__init__.py | 10 +- elasticsearch/_async/client/cat.py | 208 ++++++++++++++++++++++- elasticsearch/_async/client/indices.py | 17 +- elasticsearch/_async/client/inference.py | 74 +------- elasticsearch/_sync/client/__init__.py | 10 +- elasticsearch/_sync/client/cat.py | 208 ++++++++++++++++++++++- elasticsearch/_sync/client/indices.py | 17 +- elasticsearch/_sync/client/inference.py | 74 +------- elasticsearch/dsl/query.py | 2 +- elasticsearch/dsl/types.py | 32 ++++ 10 files changed, 475 insertions(+), 177 deletions(-) diff --git a/elasticsearch/_async/client/__init__.py b/elasticsearch/_async/client/__init__.py index 97765ed16..dd10aca31 100644 --- a/elasticsearch/_async/client/__init__.py +++ b/elasticsearch/_async/client/__init__.py @@ -4652,11 +4652,11 @@ async def search( of the specified nodes are available, select shards from any available node using the default method. * `_prefer_nodes:,` to if possible, run the search on the specified nodes IDs. If not, select shards using the - default method. `_shards:,` to run the search only on the specified - shards. You can combine this value with other `preference` values. However, - the `_shards` value must come first. For example: `_shards:2,3|_local`. `` - (any string that does not start with `_`) to route searches with the same - `` to the same shards in the same order. + default method. * `_shards:,` to run the search only on the + specified shards. You can combine this value with other `preference` values. + However, the `_shards` value must come first. For example: `_shards:2,3|_local`. + * `` (any string that does not start with `_`) to route searches + with the same `` to the same shards in the same order. :param profile: Set to `true` to return detailed timing information about the execution of individual components in a search request. NOTE: This is a debugging tool and adds significant overhead to search execution. diff --git a/elasticsearch/_async/client/cat.py b/elasticsearch/_async/client/cat.py index bb289c12d..1736c4b35 100644 --- a/elasticsearch/_async/client/cat.py +++ b/elasticsearch/_async/client/cat.py @@ -1767,7 +1767,200 @@ async def nodes( filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, format: t.Optional[str] = None, full_id: t.Optional[t.Union[bool, str]] = None, - h: t.Optional[t.Union[str, t.Sequence[str]]] = None, + h: t.Optional[ + t.Union[ + t.Sequence[ + t.Union[ + str, + t.Literal[ + "build", + "completion.size", + "cpu", + "disk.avail", + "disk.total", + "disk.used", + "disk.used_percent", + "fielddata.evictions", + "fielddata.memory_size", + "file_desc.current", + "file_desc.max", + "file_desc.percent", + "flush.total", + "flush.total_time", + "get.current", + "get.exists_time", + "get.exists_total", + "get.missing_time", + "get.missing_total", + "get.time", + "get.total", + "heap.current", + "heap.max", + "heap.percent", + "http_address", + "id", + "indexing.delete_current", + "indexing.delete_time", + "indexing.delete_total", + "indexing.index_current", + "indexing.index_failed", + "indexing.index_failed_due_to_version_conflict", + "indexing.index_time", + "indexing.index_total", + "ip", + "jdk", + "load_15m", + "load_1m", + "load_5m", + "mappings.total_count", + "mappings.total_estimated_overhead_in_bytes", + "master", + "merges.current", + "merges.current_docs", + "merges.current_size", + "merges.total", + "merges.total_docs", + "merges.total_size", + "merges.total_time", + "name", + "node.role", + "pid", + "port", + "query_cache.evictions", + "query_cache.hit_count", + "query_cache.memory_size", + "query_cache.miss_count", + "ram.current", + "ram.max", + "ram.percent", + "refresh.time", + "refresh.total", + "request_cache.evictions", + "request_cache.hit_count", + "request_cache.memory_size", + "request_cache.miss_count", + "script.cache_evictions", + "script.compilations", + "search.fetch_current", + "search.fetch_time", + "search.fetch_total", + "search.open_contexts", + "search.query_current", + "search.query_time", + "search.query_total", + "search.scroll_current", + "search.scroll_time", + "search.scroll_total", + "segments.count", + "segments.fixed_bitset_memory", + "segments.index_writer_memory", + "segments.memory", + "segments.version_map_memory", + "shard_stats.total_count", + "suggest.current", + "suggest.time", + "suggest.total", + "uptime", + "version", + ], + ] + ], + t.Union[ + str, + t.Literal[ + "build", + "completion.size", + "cpu", + "disk.avail", + "disk.total", + "disk.used", + "disk.used_percent", + "fielddata.evictions", + "fielddata.memory_size", + "file_desc.current", + "file_desc.max", + "file_desc.percent", + "flush.total", + "flush.total_time", + "get.current", + "get.exists_time", + "get.exists_total", + "get.missing_time", + "get.missing_total", + "get.time", + "get.total", + "heap.current", + "heap.max", + "heap.percent", + "http_address", + "id", + "indexing.delete_current", + "indexing.delete_time", + "indexing.delete_total", + "indexing.index_current", + "indexing.index_failed", + "indexing.index_failed_due_to_version_conflict", + "indexing.index_time", + "indexing.index_total", + "ip", + "jdk", + "load_15m", + "load_1m", + "load_5m", + "mappings.total_count", + "mappings.total_estimated_overhead_in_bytes", + "master", + "merges.current", + "merges.current_docs", + "merges.current_size", + "merges.total", + "merges.total_docs", + "merges.total_size", + "merges.total_time", + "name", + "node.role", + "pid", + "port", + "query_cache.evictions", + "query_cache.hit_count", + "query_cache.memory_size", + "query_cache.miss_count", + "ram.current", + "ram.max", + "ram.percent", + "refresh.time", + "refresh.total", + "request_cache.evictions", + "request_cache.hit_count", + "request_cache.memory_size", + "request_cache.miss_count", + "script.cache_evictions", + "script.compilations", + "search.fetch_current", + "search.fetch_time", + "search.fetch_total", + "search.open_contexts", + "search.query_current", + "search.query_time", + "search.query_total", + "search.scroll_current", + "search.scroll_time", + "search.scroll_total", + "segments.count", + "segments.fixed_bitset_memory", + "segments.index_writer_memory", + "segments.memory", + "segments.version_map_memory", + "shard_stats.total_count", + "suggest.current", + "suggest.time", + "suggest.total", + "uptime", + "version", + ], + ], + ] + ] = None, help: t.Optional[bool] = None, human: t.Optional[bool] = None, include_unloaded_segments: t.Optional[bool] = None, @@ -1794,16 +1987,17 @@ async def nodes( to `text`, `json`, `cbor`, `yaml`, or `smile`. :param full_id: If `true`, return the full node ID. If `false`, return the shortened node ID. - :param h: List of columns to appear in the response. Supports simple wildcards. + :param h: A comma-separated list of columns names to display. It supports simple + wildcards. :param help: When set to `true` will output available columns. This option can't be combined with any other query string option. :param include_unloaded_segments: If true, the response includes information from segments that are not loaded into memory. - :param master_timeout: Period to wait for a connection to the master node. - :param s: List of columns that determine how the table should be sorted. Sorting - defaults to ascending and can be changed by setting `:asc` or `:desc` as - a suffix to the column name. - :param time: Unit used to display time values. + :param master_timeout: The period to wait for a connection to the master node. + :param s: A comma-separated list of column names or aliases that determines the + sort order. Sorting defaults to ascending and can be changed by setting `:asc` + or `:desc` as a suffix to the column name. + :param time: The unit used to display time values. :param v: When set to `true` will enable verbose output. """ __path_parts: t.Dict[str, str] = {} diff --git a/elasticsearch/_async/client/indices.py b/elasticsearch/_async/client/indices.py index 07e7c58c2..0b5c9fde2 100644 --- a/elasticsearch/_async/client/indices.py +++ b/elasticsearch/_async/client/indices.py @@ -656,7 +656,15 @@ async def create( ``_ - :param index: Name of the index you wish to create. + :param index: Name of the index you wish to create. Index names must meet the + following criteria: * Lowercase only * Cannot include `\\`, `/`, `*`, `?`, + `"`, `<`, `>`, `|`, ` ` (space character), `,`, or `#` * Indices prior to + 7.0 could contain a colon (`:`), but that has been deprecated and will not + be supported in later versions * Cannot start with `-`, `_`, or `+` * Cannot + be `.` or `..` * Cannot be longer than 255 bytes (note thtat it is bytes, + so multi-byte characters will reach the limit faster) * Names starting with + `.` are deprecated, except for hidden indices and internal indices managed + by plugins :param aliases: Aliases for the index. :param mappings: Mapping for fields in the index. If specified, this mapping can include: - Field names - Field data types - Mapping parameters @@ -1246,7 +1254,8 @@ async def delete_template( """ .. raw:: html -

Delete a legacy index template.

+

Delete a legacy index template. + IMPORTANT: This documentation is about legacy index templates, which are deprecated and will be replaced by the composable templates introduced in Elasticsearch 7.8.

``_ @@ -2880,7 +2889,7 @@ async def get_template( """ .. raw:: html -

Get index templates. +

Get legacy index templates. Get information about one or more index templates.

IMPORTANT: This documentation is about legacy index templates, which are deprecated and will be replaced by the composable templates introduced in Elasticsearch 7.8.

@@ -3973,7 +3982,7 @@ async def put_template( """ .. raw:: html -

Create or update an index template. +

Create or update a legacy index template. Index templates define settings, mappings, and aliases that can be applied automatically to new indices. Elasticsearch applies templates to new indices based on an index pattern that matches the index name.

IMPORTANT: This documentation is about legacy index templates, which are deprecated and will be replaced by the composable templates introduced in Elasticsearch 7.8.

diff --git a/elasticsearch/_async/client/inference.py b/elasticsearch/_async/client/inference.py index 71318b954..8437a8b89 100644 --- a/elasticsearch/_async/client/inference.py +++ b/elasticsearch/_async/client/inference.py @@ -370,12 +370,7 @@ async def put( """ .. raw:: html -

Create an inference endpoint. - When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

+

Create an inference endpoint.

IMPORTANT: The inference APIs enable you to use certain services, such as built-in machine learning models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Mistral, Azure OpenAI, Google AI Studio, Google Vertex AI, Anthropic, Watsonx.ai, or Hugging Face. For built-in models and models uploaded through Eland, the inference APIs offer an alternative way to use and manage trained models. However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.

@@ -458,11 +453,6 @@ async def put_alibabacloud(

Create an AlibabaCloud AI Search inference endpoint.

Create an inference endpoint to perform an inference task with the alibabacloud-ai-search service.

-

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

``_ @@ -558,11 +548,6 @@ async def put_amazonbedrock(

info You need to provide the access and secret keys only once, during the inference model creation. The get inference API does not retrieve your access or secret keys. After creating the inference model, you cannot change the associated key pairs. If you want to use a different access and secret key pair, delete the inference model and recreate it with the same name and the updated keys.

-

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

``_ @@ -654,11 +639,6 @@ async def put_anthropic(

Create an Anthropic inference endpoint.

Create an inference endpoint to perform an inference task with the anthropic service.

-

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

``_ @@ -751,11 +731,6 @@ async def put_azureaistudio(

Create an Azure AI studio inference endpoint.

Create an inference endpoint to perform an inference task with the azureaistudio service.

-

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

``_ @@ -853,11 +828,6 @@ async def put_azureopenai(

The list of embeddings models that you can choose from in your deployment can be found in the Azure models documentation.

-

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

``_ @@ -951,11 +921,6 @@ async def put_cohere(

Create a Cohere inference endpoint.

Create an inference endpoint to perform an inference task with the cohere service.

-

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

``_ @@ -1239,11 +1204,6 @@ async def put_googleaistudio(

Create an Google AI Studio inference endpoint.

Create an inference endpoint to perform an inference task with the googleaistudio service.

-

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

``_ @@ -1331,11 +1291,6 @@ async def put_googlevertexai(

Create a Google Vertex AI inference endpoint.

Create an inference endpoint to perform an inference task with the googlevertexai service.

-

When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

``_ @@ -1434,11 +1389,6 @@ async def put_hugging_face(
  • multilingual-e5-base
  • multilingual-e5-small
  • -

    When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

    ``_ @@ -1528,11 +1478,6 @@ async def put_jinaai(

    Create an inference endpoint to perform an inference task with the jinaai service.

    To review the available rerank models, refer to https://jina.ai/reranker. To review the available text_embedding models, refer to the https://jina.ai/embeddings/.

    -

    When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

    ``_ @@ -1616,11 +1561,6 @@ async def put_mistral(

    Create a Mistral inference endpoint.

    Creates an inference endpoint to perform an inference task with the mistral service.

    -

    When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

    ``_ @@ -1708,12 +1648,7 @@ async def put_openai( .. raw:: html

    Create an OpenAI inference endpoint.

    -

    Create an inference endpoint to perform an inference task with the openai service.

    -

    When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

    +

    Create an inference endpoint to perform an inference task with the openai service or openai compatible APIs.

    ``_ @@ -1890,11 +1825,6 @@ async def put_watsonx(

    Create an inference endpoint to perform an inference task with the watsonxai service. You need an IBM Cloud Databases for Elasticsearch deployment to use the watsonxai inference service. You can provision one through the IBM catalog, the Cloud Databases CLI plug-in, the Cloud Databases API, or Terraform.

    -

    When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

    ``_ diff --git a/elasticsearch/_sync/client/__init__.py b/elasticsearch/_sync/client/__init__.py index 56ecd4f2f..a6230144c 100644 --- a/elasticsearch/_sync/client/__init__.py +++ b/elasticsearch/_sync/client/__init__.py @@ -4650,11 +4650,11 @@ def search( of the specified nodes are available, select shards from any available node using the default method. * `_prefer_nodes:,` to if possible, run the search on the specified nodes IDs. If not, select shards using the - default method. `_shards:,` to run the search only on the specified - shards. You can combine this value with other `preference` values. However, - the `_shards` value must come first. For example: `_shards:2,3|_local`. `` - (any string that does not start with `_`) to route searches with the same - `` to the same shards in the same order. + default method. * `_shards:,` to run the search only on the + specified shards. You can combine this value with other `preference` values. + However, the `_shards` value must come first. For example: `_shards:2,3|_local`. + * `` (any string that does not start with `_`) to route searches + with the same `` to the same shards in the same order. :param profile: Set to `true` to return detailed timing information about the execution of individual components in a search request. NOTE: This is a debugging tool and adds significant overhead to search execution. diff --git a/elasticsearch/_sync/client/cat.py b/elasticsearch/_sync/client/cat.py index 2a218a36c..d71571c57 100644 --- a/elasticsearch/_sync/client/cat.py +++ b/elasticsearch/_sync/client/cat.py @@ -1767,7 +1767,200 @@ def nodes( filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, format: t.Optional[str] = None, full_id: t.Optional[t.Union[bool, str]] = None, - h: t.Optional[t.Union[str, t.Sequence[str]]] = None, + h: t.Optional[ + t.Union[ + t.Sequence[ + t.Union[ + str, + t.Literal[ + "build", + "completion.size", + "cpu", + "disk.avail", + "disk.total", + "disk.used", + "disk.used_percent", + "fielddata.evictions", + "fielddata.memory_size", + "file_desc.current", + "file_desc.max", + "file_desc.percent", + "flush.total", + "flush.total_time", + "get.current", + "get.exists_time", + "get.exists_total", + "get.missing_time", + "get.missing_total", + "get.time", + "get.total", + "heap.current", + "heap.max", + "heap.percent", + "http_address", + "id", + "indexing.delete_current", + "indexing.delete_time", + "indexing.delete_total", + "indexing.index_current", + "indexing.index_failed", + "indexing.index_failed_due_to_version_conflict", + "indexing.index_time", + "indexing.index_total", + "ip", + "jdk", + "load_15m", + "load_1m", + "load_5m", + "mappings.total_count", + "mappings.total_estimated_overhead_in_bytes", + "master", + "merges.current", + "merges.current_docs", + "merges.current_size", + "merges.total", + "merges.total_docs", + "merges.total_size", + "merges.total_time", + "name", + "node.role", + "pid", + "port", + "query_cache.evictions", + "query_cache.hit_count", + "query_cache.memory_size", + "query_cache.miss_count", + "ram.current", + "ram.max", + "ram.percent", + "refresh.time", + "refresh.total", + "request_cache.evictions", + "request_cache.hit_count", + "request_cache.memory_size", + "request_cache.miss_count", + "script.cache_evictions", + "script.compilations", + "search.fetch_current", + "search.fetch_time", + "search.fetch_total", + "search.open_contexts", + "search.query_current", + "search.query_time", + "search.query_total", + "search.scroll_current", + "search.scroll_time", + "search.scroll_total", + "segments.count", + "segments.fixed_bitset_memory", + "segments.index_writer_memory", + "segments.memory", + "segments.version_map_memory", + "shard_stats.total_count", + "suggest.current", + "suggest.time", + "suggest.total", + "uptime", + "version", + ], + ] + ], + t.Union[ + str, + t.Literal[ + "build", + "completion.size", + "cpu", + "disk.avail", + "disk.total", + "disk.used", + "disk.used_percent", + "fielddata.evictions", + "fielddata.memory_size", + "file_desc.current", + "file_desc.max", + "file_desc.percent", + "flush.total", + "flush.total_time", + "get.current", + "get.exists_time", + "get.exists_total", + "get.missing_time", + "get.missing_total", + "get.time", + "get.total", + "heap.current", + "heap.max", + "heap.percent", + "http_address", + "id", + "indexing.delete_current", + "indexing.delete_time", + "indexing.delete_total", + "indexing.index_current", + "indexing.index_failed", + "indexing.index_failed_due_to_version_conflict", + "indexing.index_time", + "indexing.index_total", + "ip", + "jdk", + "load_15m", + "load_1m", + "load_5m", + "mappings.total_count", + "mappings.total_estimated_overhead_in_bytes", + "master", + "merges.current", + "merges.current_docs", + "merges.current_size", + "merges.total", + "merges.total_docs", + "merges.total_size", + "merges.total_time", + "name", + "node.role", + "pid", + "port", + "query_cache.evictions", + "query_cache.hit_count", + "query_cache.memory_size", + "query_cache.miss_count", + "ram.current", + "ram.max", + "ram.percent", + "refresh.time", + "refresh.total", + "request_cache.evictions", + "request_cache.hit_count", + "request_cache.memory_size", + "request_cache.miss_count", + "script.cache_evictions", + "script.compilations", + "search.fetch_current", + "search.fetch_time", + "search.fetch_total", + "search.open_contexts", + "search.query_current", + "search.query_time", + "search.query_total", + "search.scroll_current", + "search.scroll_time", + "search.scroll_total", + "segments.count", + "segments.fixed_bitset_memory", + "segments.index_writer_memory", + "segments.memory", + "segments.version_map_memory", + "shard_stats.total_count", + "suggest.current", + "suggest.time", + "suggest.total", + "uptime", + "version", + ], + ], + ] + ] = None, help: t.Optional[bool] = None, human: t.Optional[bool] = None, include_unloaded_segments: t.Optional[bool] = None, @@ -1794,16 +1987,17 @@ def nodes( to `text`, `json`, `cbor`, `yaml`, or `smile`. :param full_id: If `true`, return the full node ID. If `false`, return the shortened node ID. - :param h: List of columns to appear in the response. Supports simple wildcards. + :param h: A comma-separated list of columns names to display. It supports simple + wildcards. :param help: When set to `true` will output available columns. This option can't be combined with any other query string option. :param include_unloaded_segments: If true, the response includes information from segments that are not loaded into memory. - :param master_timeout: Period to wait for a connection to the master node. - :param s: List of columns that determine how the table should be sorted. Sorting - defaults to ascending and can be changed by setting `:asc` or `:desc` as - a suffix to the column name. - :param time: Unit used to display time values. + :param master_timeout: The period to wait for a connection to the master node. + :param s: A comma-separated list of column names or aliases that determines the + sort order. Sorting defaults to ascending and can be changed by setting `:asc` + or `:desc` as a suffix to the column name. + :param time: The unit used to display time values. :param v: When set to `true` will enable verbose output. """ __path_parts: t.Dict[str, str] = {} diff --git a/elasticsearch/_sync/client/indices.py b/elasticsearch/_sync/client/indices.py index 6cb3cb8d6..08913867b 100644 --- a/elasticsearch/_sync/client/indices.py +++ b/elasticsearch/_sync/client/indices.py @@ -656,7 +656,15 @@ def create( ``_ - :param index: Name of the index you wish to create. + :param index: Name of the index you wish to create. Index names must meet the + following criteria: * Lowercase only * Cannot include `\\`, `/`, `*`, `?`, + `"`, `<`, `>`, `|`, ` ` (space character), `,`, or `#` * Indices prior to + 7.0 could contain a colon (`:`), but that has been deprecated and will not + be supported in later versions * Cannot start with `-`, `_`, or `+` * Cannot + be `.` or `..` * Cannot be longer than 255 bytes (note thtat it is bytes, + so multi-byte characters will reach the limit faster) * Names starting with + `.` are deprecated, except for hidden indices and internal indices managed + by plugins :param aliases: Aliases for the index. :param mappings: Mapping for fields in the index. If specified, this mapping can include: - Field names - Field data types - Mapping parameters @@ -1246,7 +1254,8 @@ def delete_template( """ .. raw:: html -

    Delete a legacy index template.

    +

    Delete a legacy index template. + IMPORTANT: This documentation is about legacy index templates, which are deprecated and will be replaced by the composable templates introduced in Elasticsearch 7.8.

    ``_ @@ -2880,7 +2889,7 @@ def get_template( """ .. raw:: html -

    Get index templates. +

    Get legacy index templates. Get information about one or more index templates.

    IMPORTANT: This documentation is about legacy index templates, which are deprecated and will be replaced by the composable templates introduced in Elasticsearch 7.8.

    @@ -3973,7 +3982,7 @@ def put_template( """ .. raw:: html -

    Create or update an index template. +

    Create or update a legacy index template. Index templates define settings, mappings, and aliases that can be applied automatically to new indices. Elasticsearch applies templates to new indices based on an index pattern that matches the index name.

    IMPORTANT: This documentation is about legacy index templates, which are deprecated and will be replaced by the composable templates introduced in Elasticsearch 7.8.

    diff --git a/elasticsearch/_sync/client/inference.py b/elasticsearch/_sync/client/inference.py index 2dfcfd671..fa679f6e3 100644 --- a/elasticsearch/_sync/client/inference.py +++ b/elasticsearch/_sync/client/inference.py @@ -370,12 +370,7 @@ def put( """ .. raw:: html -

    Create an inference endpoint. - When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

    +

    Create an inference endpoint.

    IMPORTANT: The inference APIs enable you to use certain services, such as built-in machine learning models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Mistral, Azure OpenAI, Google AI Studio, Google Vertex AI, Anthropic, Watsonx.ai, or Hugging Face. For built-in models and models uploaded through Eland, the inference APIs offer an alternative way to use and manage trained models. However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.

    @@ -458,11 +453,6 @@ def put_alibabacloud(

    Create an AlibabaCloud AI Search inference endpoint.

    Create an inference endpoint to perform an inference task with the alibabacloud-ai-search service.

    -

    When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

    ``_ @@ -558,11 +548,6 @@ def put_amazonbedrock(

    info You need to provide the access and secret keys only once, during the inference model creation. The get inference API does not retrieve your access or secret keys. After creating the inference model, you cannot change the associated key pairs. If you want to use a different access and secret key pair, delete the inference model and recreate it with the same name and the updated keys.

    -

    When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

    ``_ @@ -654,11 +639,6 @@ def put_anthropic(

    Create an Anthropic inference endpoint.

    Create an inference endpoint to perform an inference task with the anthropic service.

    -

    When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

    ``_ @@ -751,11 +731,6 @@ def put_azureaistudio(

    Create an Azure AI studio inference endpoint.

    Create an inference endpoint to perform an inference task with the azureaistudio service.

    -

    When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

    ``_ @@ -853,11 +828,6 @@ def put_azureopenai(
  • GPT-3.5
  • The list of embeddings models that you can choose from in your deployment can be found in the Azure models documentation.

    -

    When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

    ``_ @@ -951,11 +921,6 @@ def put_cohere(

    Create a Cohere inference endpoint.

    Create an inference endpoint to perform an inference task with the cohere service.

    -

    When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

    ``_ @@ -1239,11 +1204,6 @@ def put_googleaistudio(

    Create an Google AI Studio inference endpoint.

    Create an inference endpoint to perform an inference task with the googleaistudio service.

    -

    When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

    ``_ @@ -1331,11 +1291,6 @@ def put_googlevertexai(

    Create a Google Vertex AI inference endpoint.

    Create an inference endpoint to perform an inference task with the googlevertexai service.

    -

    When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

    ``_ @@ -1434,11 +1389,6 @@ def put_hugging_face(
  • multilingual-e5-base
  • multilingual-e5-small
  • -

    When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

    ``_ @@ -1528,11 +1478,6 @@ def put_jinaai(

    Create an inference endpoint to perform an inference task with the jinaai service.

    To review the available rerank models, refer to https://jina.ai/reranker. To review the available text_embedding models, refer to the https://jina.ai/embeddings/.

    -

    When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

    ``_ @@ -1616,11 +1561,6 @@ def put_mistral(

    Create a Mistral inference endpoint.

    Creates an inference endpoint to perform an inference task with the mistral service.

    -

    When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

    ``_ @@ -1708,12 +1648,7 @@ def put_openai( .. raw:: html

    Create an OpenAI inference endpoint.

    -

    Create an inference endpoint to perform an inference task with the openai service.

    -

    When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

    +

    Create an inference endpoint to perform an inference task with the openai service or openai compatible APIs.

    ``_ @@ -1890,11 +1825,6 @@ def put_watsonx(

    Create an inference endpoint to perform an inference task with the watsonxai service. You need an IBM Cloud Databases for Elasticsearch deployment to use the watsonxai inference service. You can provision one through the IBM catalog, the Cloud Databases CLI plug-in, the Cloud Databases API, or Terraform.

    -

    When you create an inference endpoint, the associated machine learning model is automatically deployed if it is not already running. - After creating the endpoint, wait for the model deployment to complete before using it. - To verify the deployment status, use the get trained model statistics API. - Look for "state": "fully_allocated" in the response and ensure that the "allocation_count" matches the "target_allocation_count". - Avoid creating multiple endpoints for the same model unless required, as each endpoint consumes significant resources.

    ``_ diff --git a/elasticsearch/dsl/query.py b/elasticsearch/dsl/query.py index 06be2f7fb..03f50b951 100644 --- a/elasticsearch/dsl/query.py +++ b/elasticsearch/dsl/query.py @@ -1084,7 +1084,7 @@ class Knn(Query): :arg similarity: The minimum similarity for a vector to be considered a match :arg rescore_vector: Apply oversampling and rescoring to quantized - vectors * + vectors :arg boost: Floating point number used to decrease or increase the relevance scores of the query. Boost values are relative to the default value of 1.0. A boost value between 0 and 1.0 decreases diff --git a/elasticsearch/dsl/types.py b/elasticsearch/dsl/types.py index e6e19e410..1b75e1fa9 100644 --- a/elasticsearch/dsl/types.py +++ b/elasticsearch/dsl/types.py @@ -371,6 +371,9 @@ class DenseVectorIndexOptions(AttrDict[Any]): :arg m: The number of neighbors each node will be connected to in the HNSW graph. Only applicable to `hnsw`, `int8_hnsw`, `bbq_hnsw`, and `int4_hnsw` index types. Defaults to `16` if omitted. + :arg rescore_vector: The rescore vector options. This is only + applicable to `bbq_hnsw`, `int4_hnsw`, `int8_hnsw`, `bbq_flat`, + `int4_flat`, and `int8_flat` index types. """ type: Union[ @@ -389,6 +392,9 @@ class DenseVectorIndexOptions(AttrDict[Any]): confidence_interval: Union[float, DefaultType] ef_construction: Union[int, DefaultType] m: Union[int, DefaultType] + rescore_vector: Union[ + "DenseVectorIndexOptionsRescoreVector", Dict[str, Any], DefaultType + ] def __init__( self, @@ -409,6 +415,9 @@ def __init__( confidence_interval: Union[float, DefaultType] = DEFAULT, ef_construction: Union[int, DefaultType] = DEFAULT, m: Union[int, DefaultType] = DEFAULT, + rescore_vector: Union[ + "DenseVectorIndexOptionsRescoreVector", Dict[str, Any], DefaultType + ] = DEFAULT, **kwargs: Any, ): if type is not DEFAULT: @@ -419,6 +428,29 @@ def __init__( kwargs["ef_construction"] = ef_construction if m is not DEFAULT: kwargs["m"] = m + if rescore_vector is not DEFAULT: + kwargs["rescore_vector"] = rescore_vector + super().__init__(kwargs) + + +class DenseVectorIndexOptionsRescoreVector(AttrDict[Any]): + """ + :arg oversample: (required) The oversampling factor to use when + searching for the nearest neighbor. This is only applicable to the + quantized formats: `bbq_*`, `int4_*`, and `int8_*`. When provided, + `oversample * k` vectors will be gathered and then their scores + will be re-computed with the original vectors. valid values are + between `1.0` and `10.0` (inclusive), or `0` exactly to disable + oversampling. + """ + + oversample: Union[float, DefaultType] + + def __init__( + self, *, oversample: Union[float, DefaultType] = DEFAULT, **kwargs: Any + ): + if oversample is not DEFAULT: + kwargs["oversample"] = oversample super().__init__(kwargs) From 6a2dbcdbb6808acf09e6c6ea2a236efc78ec8c4d Mon Sep 17 00:00:00 2001 From: Miguel Grinberg Date: Thu, 5 Jun 2025 12:33:19 +0100 Subject: [PATCH 46/57] Release 9.0.2 --- docs/release-notes/index.md | 7 +++++++ elasticsearch/_version.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/index.md b/docs/release-notes/index.md index 4146d076d..314030cdd 100644 --- a/docs/release-notes/index.md +++ b/docs/release-notes/index.md @@ -19,6 +19,13 @@ To check for security updates, go to [Security announcements for the Elastic sta % ### Fixes [elasticsearch-python-client-next-fixes] +## 9.0.2 (2025-06-05) [elasticsearch-python-client-902-release-notes] + +### DSL + +* Add `rescore_vector` to `DenseVectorIndexOptions` + + ## 9.0.1 (2025-04-28) [elasticsearch-python-client-901-release-notes] ### Features and enhancements [elasticsearch-python-client-901-features-enhancements] diff --git a/elasticsearch/_version.py b/elasticsearch/_version.py index fafa33a2b..0624a7ff1 100644 --- a/elasticsearch/_version.py +++ b/elasticsearch/_version.py @@ -15,4 +15,4 @@ # specific language governing permissions and limitations # under the License. -__versionstr__ = "9.0.1" +__versionstr__ = "9.0.2" From e66c39cc20f168654870eed9de2f6498cf46a308 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 17:19:38 +0100 Subject: [PATCH 47/57] Handle lists in `copy_to` field option correctly (Fixes #2992) (#2993) (#2996) * Handle lists in `copy_to` field option correctly (Fixes #2992) * add integration test (cherry picked from commit 44cbf67bf9cfc29bf4253cff3e48fb0286e471ff) Co-authored-by: Miguel Grinberg --- elasticsearch/dsl/aggs.py | 20 ++ elasticsearch/dsl/field.py | 267 +++++++++++++++--- elasticsearch/dsl/query.py | 9 +- elasticsearch/dsl/response/__init__.py | 2 +- elasticsearch/dsl/types.py | 166 ++++++++++- .../test_integration/_async/test_document.py | 53 +++- .../test_integration/_sync/test_document.py | 49 +++- utils/templates/field.py.tpl | 7 + 8 files changed, 519 insertions(+), 54 deletions(-) diff --git a/elasticsearch/dsl/aggs.py b/elasticsearch/dsl/aggs.py index 97ef48d59..802d6eca0 100644 --- a/elasticsearch/dsl/aggs.py +++ b/elasticsearch/dsl/aggs.py @@ -373,6 +373,12 @@ class Boxplot(Agg[_R]): :arg compression: Limits the maximum number of nodes used by the underlying TDigest algorithm to `20 * compression`, enabling control of memory usage and approximation error. + :arg execution_hint: The default implementation of TDigest is + optimized for performance, scaling to millions or even billions of + sample values while maintaining acceptable accuracy levels (close + to 1% relative error for millions of samples in some cases). To + use an implementation optimized for accuracy, set this parameter + to high_accuracy instead. Defaults to `default` if omitted. :arg field: The field on which to run the aggregation. :arg missing: The value to apply to documents that do not have a value. By default, documents without a value are ignored. @@ -385,6 +391,9 @@ def __init__( self, *, compression: Union[float, "DefaultType"] = DEFAULT, + execution_hint: Union[ + Literal["default", "high_accuracy"], "DefaultType" + ] = DEFAULT, field: Union[str, "InstrumentedField", "DefaultType"] = DEFAULT, missing: Union[str, int, float, bool, "DefaultType"] = DEFAULT, script: Union["types.Script", Dict[str, Any], "DefaultType"] = DEFAULT, @@ -392,6 +401,7 @@ def __init__( ): super().__init__( compression=compression, + execution_hint=execution_hint, field=field, missing=missing, script=script, @@ -1900,6 +1910,12 @@ class MedianAbsoluteDeviation(Agg[_R]): underlying TDigest algorithm to `20 * compression`, enabling control of memory usage and approximation error. Defaults to `1000` if omitted. + :arg execution_hint: The default implementation of TDigest is + optimized for performance, scaling to millions or even billions of + sample values while maintaining acceptable accuracy levels (close + to 1% relative error for millions of samples in some cases). To + use an implementation optimized for accuracy, set this parameter + to high_accuracy instead. Defaults to `default` if omitted. :arg format: :arg field: The field on which to run the aggregation. :arg missing: The value to apply to documents that do not have a @@ -1913,6 +1929,9 @@ def __init__( self, *, compression: Union[float, "DefaultType"] = DEFAULT, + execution_hint: Union[ + Literal["default", "high_accuracy"], "DefaultType" + ] = DEFAULT, format: Union[str, "DefaultType"] = DEFAULT, field: Union[str, "InstrumentedField", "DefaultType"] = DEFAULT, missing: Union[str, int, float, bool, "DefaultType"] = DEFAULT, @@ -1921,6 +1940,7 @@ def __init__( ): super().__init__( compression=compression, + execution_hint=execution_hint, format=format, field=field, missing=missing, diff --git a/elasticsearch/dsl/field.py b/elasticsearch/dsl/field.py index e3ed5dfcd..73108bf3f 100644 --- a/elasticsearch/dsl/field.py +++ b/elasticsearch/dsl/field.py @@ -280,7 +280,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -387,7 +390,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -463,7 +469,10 @@ def __init__( if subobjects is not DEFAULT: kwargs["subobjects"] = subobjects if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -575,6 +584,7 @@ class AggregateMetricDouble(Field): """ :arg default_metric: (required) :arg metrics: (required) + :arg ignore_malformed: :arg time_series_metric: :arg meta: Metadata about the field. :arg properties: @@ -595,6 +605,7 @@ def __init__( *args: Any, default_metric: Union[str, "DefaultType"] = DEFAULT, metrics: Union[Sequence[str], "DefaultType"] = DEFAULT, + ignore_malformed: Union[bool, "DefaultType"] = DEFAULT, time_series_metric: Union[ Literal["gauge", "counter", "summary", "histogram", "position"], "DefaultType", @@ -615,6 +626,8 @@ def __init__( kwargs["default_metric"] = default_metric if metrics is not DEFAULT: kwargs["metrics"] = metrics + if ignore_malformed is not DEFAULT: + kwargs["ignore_malformed"] = ignore_malformed if time_series_metric is not DEFAULT: kwargs["time_series_metric"] = time_series_metric if meta is not DEFAULT: @@ -727,7 +740,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -838,7 +854,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -953,7 +972,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -1043,7 +1065,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -1251,7 +1276,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -1376,7 +1404,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -1455,7 +1486,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -1658,7 +1692,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -1733,7 +1770,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -1762,6 +1802,7 @@ class Flattened(Field): :arg null_value: :arg similarity: :arg split_queries_on_whitespace: + :arg time_series_dimensions: :arg meta: Metadata about the field. :arg properties: :arg ignore_above: @@ -1790,6 +1831,7 @@ def __init__( null_value: Union[str, "DefaultType"] = DEFAULT, similarity: Union[str, "DefaultType"] = DEFAULT, split_queries_on_whitespace: Union[bool, "DefaultType"] = DEFAULT, + time_series_dimensions: Union[Sequence[str], "DefaultType"] = DEFAULT, meta: Union[Mapping[str, str], "DefaultType"] = DEFAULT, properties: Union[Mapping[str, Field], "DefaultType"] = DEFAULT, ignore_above: Union[int, "DefaultType"] = DEFAULT, @@ -1820,6 +1862,8 @@ def __init__( kwargs["similarity"] = similarity if split_queries_on_whitespace is not DEFAULT: kwargs["split_queries_on_whitespace"] = split_queries_on_whitespace + if time_series_dimensions is not DEFAULT: + kwargs["time_series_dimensions"] = time_series_dimensions if meta is not DEFAULT: kwargs["meta"] = meta if properties is not DEFAULT: @@ -1892,7 +1936,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -1918,6 +1965,7 @@ class GeoPoint(Field): :arg index: :arg on_script_error: :arg script: + :arg time_series_metric: :arg doc_values: :arg copy_to: :arg store: @@ -1951,6 +1999,9 @@ def __init__( index: Union[bool, "DefaultType"] = DEFAULT, on_script_error: Union[Literal["fail", "continue"], "DefaultType"] = DEFAULT, script: Union["types.Script", Dict[str, Any], "DefaultType"] = DEFAULT, + time_series_metric: Union[ + Literal["gauge", "counter", "position"], "DefaultType" + ] = DEFAULT, doc_values: Union[bool, "DefaultType"] = DEFAULT, copy_to: Union[ Union[str, "InstrumentedField"], @@ -1982,10 +2033,15 @@ def __init__( kwargs["on_script_error"] = on_script_error if script is not DEFAULT: kwargs["script"] = script + if time_series_metric is not DEFAULT: + kwargs["time_series_metric"] = time_series_metric if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -2074,7 +2130,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -2177,7 +2236,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -2360,7 +2422,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -2435,7 +2500,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -2527,7 +2595,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -2611,7 +2682,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -2781,7 +2855,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -2884,7 +2961,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -2959,7 +3039,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -3016,7 +3099,10 @@ def __init__( if meta is not DEFAULT: kwargs["meta"] = meta if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) super().__init__(*args, **kwargs) @@ -3064,7 +3150,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -3134,7 +3223,10 @@ def __init__( if include_in_root is not DEFAULT: kwargs["include_in_root"] = include_in_root if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -3205,7 +3297,10 @@ def __init__( if time_series_dimension is not DEFAULT: kwargs["time_series_dimension"] = time_series_dimension if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -3334,7 +3429,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -3452,6 +3550,62 @@ def __init__( super().__init__(*args, **kwargs) +class RankVectors(Field): + """ + Technical preview + + :arg element_type: + :arg dims: + :arg meta: Metadata about the field. + :arg properties: + :arg ignore_above: + :arg dynamic: + :arg fields: + :arg synthetic_source_keep: + """ + + name = "rank_vectors" + _param_defs = { + "properties": {"type": "field", "hash": True}, + "fields": {"type": "field", "hash": True}, + } + + def __init__( + self, + *args: Any, + element_type: Union[Literal["byte", "float", "bit"], "DefaultType"] = DEFAULT, + dims: Union[int, "DefaultType"] = DEFAULT, + meta: Union[Mapping[str, str], "DefaultType"] = DEFAULT, + properties: Union[Mapping[str, Field], "DefaultType"] = DEFAULT, + ignore_above: Union[int, "DefaultType"] = DEFAULT, + dynamic: Union[ + Literal["strict", "runtime", "true", "false"], bool, "DefaultType" + ] = DEFAULT, + fields: Union[Mapping[str, Field], "DefaultType"] = DEFAULT, + synthetic_source_keep: Union[ + Literal["none", "arrays", "all"], "DefaultType" + ] = DEFAULT, + **kwargs: Any, + ): + if element_type is not DEFAULT: + kwargs["element_type"] = element_type + if dims is not DEFAULT: + kwargs["dims"] = dims + if meta is not DEFAULT: + kwargs["meta"] = meta + if properties is not DEFAULT: + kwargs["properties"] = properties + if ignore_above is not DEFAULT: + kwargs["ignore_above"] = ignore_above + if dynamic is not DEFAULT: + kwargs["dynamic"] = dynamic + if fields is not DEFAULT: + kwargs["fields"] = fields + if synthetic_source_keep is not DEFAULT: + kwargs["synthetic_source_keep"] = synthetic_source_keep + super().__init__(*args, **kwargs) + + class ScaledFloat(Float): """ :arg null_value: @@ -3541,7 +3695,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -3657,7 +3814,10 @@ def __init__( if term_vector is not DEFAULT: kwargs["term_vector"] = term_vector if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -3689,6 +3849,9 @@ class SemanticText(Field): by using the Update mapping API. Use the Create inference API to create the endpoint. If not specified, the inference endpoint defined by inference_id will be used at both index and query time. + :arg index_options: Settings for index_options that override any + defaults used by semantic_text, for example specific quantization + settings. :arg chunking_settings: Settings for chunking text into smaller passages. If specified, these will override the chunking settings sent in the inference endpoint associated with inference_id. If @@ -3704,6 +3867,9 @@ def __init__( meta: Union[Mapping[str, str], "DefaultType"] = DEFAULT, inference_id: Union[str, "DefaultType"] = DEFAULT, search_inference_id: Union[str, "DefaultType"] = DEFAULT, + index_options: Union[ + "types.SemanticTextIndexOptions", Dict[str, Any], "DefaultType" + ] = DEFAULT, chunking_settings: Union[ "types.ChunkingSettings", Dict[str, Any], "DefaultType" ] = DEFAULT, @@ -3715,6 +3881,8 @@ def __init__( kwargs["inference_id"] = inference_id if search_inference_id is not DEFAULT: kwargs["search_inference_id"] = search_inference_id + if index_options is not DEFAULT: + kwargs["index_options"] = index_options if chunking_settings is not DEFAULT: kwargs["chunking_settings"] = chunking_settings super().__init__(*args, **kwargs) @@ -3783,7 +3951,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -3886,7 +4057,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -3906,6 +4080,7 @@ def __init__( class SparseVector(Field): """ + :arg store: :arg meta: Metadata about the field. :arg properties: :arg ignore_above: @@ -3923,6 +4098,7 @@ class SparseVector(Field): def __init__( self, *args: Any, + store: Union[bool, "DefaultType"] = DEFAULT, meta: Union[Mapping[str, str], "DefaultType"] = DEFAULT, properties: Union[Mapping[str, Field], "DefaultType"] = DEFAULT, ignore_above: Union[int, "DefaultType"] = DEFAULT, @@ -3935,6 +4111,8 @@ def __init__( ] = DEFAULT, **kwargs: Any, ): + if store is not DEFAULT: + kwargs["store"] = store if meta is not DEFAULT: kwargs["meta"] = meta if properties is not DEFAULT: @@ -4070,7 +4248,10 @@ def __init__( if term_vector is not DEFAULT: kwargs["term_vector"] = term_vector if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -4153,7 +4334,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -4256,7 +4440,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -4318,7 +4505,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: @@ -4384,7 +4574,10 @@ def __init__( if doc_values is not DEFAULT: kwargs["doc_values"] = doc_values if copy_to is not DEFAULT: - kwargs["copy_to"] = str(copy_to) + if isinstance(copy_to, list): + kwargs["copy_to"] = [str(field) for field in copy_to] + else: + kwargs["copy_to"] = str(copy_to) if store is not DEFAULT: kwargs["store"] = store if meta is not DEFAULT: diff --git a/elasticsearch/dsl/query.py b/elasticsearch/dsl/query.py index 03f50b951..0a2cef032 100644 --- a/elasticsearch/dsl/query.py +++ b/elasticsearch/dsl/query.py @@ -2034,8 +2034,9 @@ def __init__( class Rule(Query): """ :arg organic: (required) - :arg ruleset_ids: (required) :arg match_criteria: (required) + :arg ruleset_ids: + :arg ruleset_id: :arg boost: Floating point number used to decrease or increase the relevance scores of the query. Boost values are relative to the default value of 1.0. A boost value between 0 and 1.0 decreases @@ -2053,16 +2054,18 @@ def __init__( self, *, organic: Union[Query, "DefaultType"] = DEFAULT, - ruleset_ids: Union[Sequence[str], "DefaultType"] = DEFAULT, match_criteria: Any = DEFAULT, + ruleset_ids: Union[str, Sequence[str], "DefaultType"] = DEFAULT, + ruleset_id: Union[str, "DefaultType"] = DEFAULT, boost: Union[float, "DefaultType"] = DEFAULT, _name: Union[str, "DefaultType"] = DEFAULT, **kwargs: Any, ): super().__init__( organic=organic, - ruleset_ids=ruleset_ids, match_criteria=match_criteria, + ruleset_ids=ruleset_ids, + ruleset_id=ruleset_id, boost=boost, _name=_name, **kwargs, diff --git a/elasticsearch/dsl/response/__init__.py b/elasticsearch/dsl/response/__init__.py index 2ae863fff..712cda27b 100644 --- a/elasticsearch/dsl/response/__init__.py +++ b/elasticsearch/dsl/response/__init__.py @@ -363,7 +363,7 @@ class UpdateByQueryResponse(AttrDict[Any], Generic[_R]): deleted: int requests_per_second: float retries: "types.Retries" - task: Union[str, int] + task: str timed_out: bool took: Any total: int diff --git a/elasticsearch/dsl/types.py b/elasticsearch/dsl/types.py index 1b75e1fa9..7aaf52da6 100644 --- a/elasticsearch/dsl/types.py +++ b/elasticsearch/dsl/types.py @@ -945,7 +945,7 @@ def __init__( class GeoGridQuery(AttrDict[Any]): """ - :arg geogrid: + :arg geotile: :arg geohash: :arg geohex: :arg boost: Floating point number used to decrease or increase the @@ -956,7 +956,7 @@ class GeoGridQuery(AttrDict[Any]): :arg _name: """ - geogrid: Union[str, DefaultType] + geotile: Union[str, DefaultType] geohash: Union[str, DefaultType] geohex: Union[str, DefaultType] boost: Union[float, DefaultType] @@ -965,15 +965,15 @@ class GeoGridQuery(AttrDict[Any]): def __init__( self, *, - geogrid: Union[str, DefaultType] = DEFAULT, + geotile: Union[str, DefaultType] = DEFAULT, geohash: Union[str, DefaultType] = DEFAULT, geohex: Union[str, DefaultType] = DEFAULT, boost: Union[float, DefaultType] = DEFAULT, _name: Union[str, DefaultType] = DEFAULT, **kwargs: Any, ): - if geogrid is not DEFAULT: - kwargs["geogrid"] = geogrid + if geotile is not DEFAULT: + kwargs["geotile"] = geotile if geohash is not DEFAULT: kwargs["geohash"] = geohash if geohex is not DEFAULT: @@ -1211,6 +1211,7 @@ class Highlight(AttrDict[Any]): fields: Union[ Mapping[Union[str, InstrumentedField], "HighlightField"], + Sequence[Mapping[Union[str, InstrumentedField], "HighlightField"]], Dict[str, Any], DefaultType, ] @@ -1242,6 +1243,7 @@ def __init__( *, fields: Union[ Mapping[Union[str, InstrumentedField], "HighlightField"], + Sequence[Mapping[Union[str, InstrumentedField], "HighlightField"]], Dict[str, Any], DefaultType, ] = DEFAULT, @@ -1799,6 +1801,8 @@ class IntervalsContainer(AttrDict[Any]): :arg match: Matches analyzed text. :arg prefix: Matches terms that start with a specified set of characters. + :arg range: + :arg regexp: :arg wildcard: Matches terms using a wildcard pattern. """ @@ -1807,6 +1811,8 @@ class IntervalsContainer(AttrDict[Any]): fuzzy: Union["IntervalsFuzzy", Dict[str, Any], DefaultType] match: Union["IntervalsMatch", Dict[str, Any], DefaultType] prefix: Union["IntervalsPrefix", Dict[str, Any], DefaultType] + range: Union["IntervalsRange", Dict[str, Any], DefaultType] + regexp: Union["IntervalsRegexp", Dict[str, Any], DefaultType] wildcard: Union["IntervalsWildcard", Dict[str, Any], DefaultType] def __init__( @@ -1817,6 +1823,8 @@ def __init__( fuzzy: Union["IntervalsFuzzy", Dict[str, Any], DefaultType] = DEFAULT, match: Union["IntervalsMatch", Dict[str, Any], DefaultType] = DEFAULT, prefix: Union["IntervalsPrefix", Dict[str, Any], DefaultType] = DEFAULT, + range: Union["IntervalsRange", Dict[str, Any], DefaultType] = DEFAULT, + regexp: Union["IntervalsRegexp", Dict[str, Any], DefaultType] = DEFAULT, wildcard: Union["IntervalsWildcard", Dict[str, Any], DefaultType] = DEFAULT, **kwargs: Any, ): @@ -1830,6 +1838,10 @@ def __init__( kwargs["match"] = match if prefix is not DEFAULT: kwargs["prefix"] = prefix + if range is not DEFAULT: + kwargs["range"] = range + if regexp is not DEFAULT: + kwargs["regexp"] = regexp if wildcard is not DEFAULT: kwargs["wildcard"] = wildcard super().__init__(kwargs) @@ -2050,6 +2062,8 @@ class IntervalsQuery(AttrDict[Any]): :arg match: Matches analyzed text. :arg prefix: Matches terms that start with a specified set of characters. + :arg range: + :arg regexp: :arg wildcard: Matches terms using a wildcard pattern. :arg boost: Floating point number used to decrease or increase the relevance scores of the query. Boost values are relative to the @@ -2064,6 +2078,8 @@ class IntervalsQuery(AttrDict[Any]): fuzzy: Union["IntervalsFuzzy", Dict[str, Any], DefaultType] match: Union["IntervalsMatch", Dict[str, Any], DefaultType] prefix: Union["IntervalsPrefix", Dict[str, Any], DefaultType] + range: Union["IntervalsRange", Dict[str, Any], DefaultType] + regexp: Union["IntervalsRegexp", Dict[str, Any], DefaultType] wildcard: Union["IntervalsWildcard", Dict[str, Any], DefaultType] boost: Union[float, DefaultType] _name: Union[str, DefaultType] @@ -2076,6 +2092,8 @@ def __init__( fuzzy: Union["IntervalsFuzzy", Dict[str, Any], DefaultType] = DEFAULT, match: Union["IntervalsMatch", Dict[str, Any], DefaultType] = DEFAULT, prefix: Union["IntervalsPrefix", Dict[str, Any], DefaultType] = DEFAULT, + range: Union["IntervalsRange", Dict[str, Any], DefaultType] = DEFAULT, + regexp: Union["IntervalsRegexp", Dict[str, Any], DefaultType] = DEFAULT, wildcard: Union["IntervalsWildcard", Dict[str, Any], DefaultType] = DEFAULT, boost: Union[float, DefaultType] = DEFAULT, _name: Union[str, DefaultType] = DEFAULT, @@ -2091,6 +2109,10 @@ def __init__( kwargs["match"] = match if prefix is not DEFAULT: kwargs["prefix"] = prefix + if range is not DEFAULT: + kwargs["range"] = range + if regexp is not DEFAULT: + kwargs["regexp"] = regexp if wildcard is not DEFAULT: kwargs["wildcard"] = wildcard if boost is not DEFAULT: @@ -2100,6 +2122,83 @@ def __init__( super().__init__(kwargs) +class IntervalsRange(AttrDict[Any]): + """ + :arg analyzer: Analyzer used to analyze the `prefix`. + :arg gte: Lower term, either gte or gt must be provided. + :arg gt: Lower term, either gte or gt must be provided. + :arg lte: Upper term, either lte or lt must be provided. + :arg lt: Upper term, either lte or lt must be provided. + :arg use_field: If specified, match intervals from this field rather + than the top-level field. The `prefix` is normalized using the + search analyzer from this field, unless `analyzer` is specified + separately. + """ + + analyzer: Union[str, DefaultType] + gte: Union[str, DefaultType] + gt: Union[str, DefaultType] + lte: Union[str, DefaultType] + lt: Union[str, DefaultType] + use_field: Union[str, InstrumentedField, DefaultType] + + def __init__( + self, + *, + analyzer: Union[str, DefaultType] = DEFAULT, + gte: Union[str, DefaultType] = DEFAULT, + gt: Union[str, DefaultType] = DEFAULT, + lte: Union[str, DefaultType] = DEFAULT, + lt: Union[str, DefaultType] = DEFAULT, + use_field: Union[str, InstrumentedField, DefaultType] = DEFAULT, + **kwargs: Any, + ): + if analyzer is not DEFAULT: + kwargs["analyzer"] = analyzer + if gte is not DEFAULT: + kwargs["gte"] = gte + if gt is not DEFAULT: + kwargs["gt"] = gt + if lte is not DEFAULT: + kwargs["lte"] = lte + if lt is not DEFAULT: + kwargs["lt"] = lt + if use_field is not DEFAULT: + kwargs["use_field"] = str(use_field) + super().__init__(kwargs) + + +class IntervalsRegexp(AttrDict[Any]): + """ + :arg pattern: (required) Regex pattern. + :arg analyzer: Analyzer used to analyze the `prefix`. + :arg use_field: If specified, match intervals from this field rather + than the top-level field. The `prefix` is normalized using the + search analyzer from this field, unless `analyzer` is specified + separately. + """ + + pattern: Union[str, DefaultType] + analyzer: Union[str, DefaultType] + use_field: Union[str, InstrumentedField, DefaultType] + + def __init__( + self, + *, + pattern: Union[str, DefaultType] = DEFAULT, + analyzer: Union[str, DefaultType] = DEFAULT, + use_field: Union[str, InstrumentedField, DefaultType] = DEFAULT, + **kwargs: Any, + ): + if pattern is not DEFAULT: + kwargs["pattern"] = pattern + if analyzer is not DEFAULT: + kwargs["analyzer"] = analyzer + if use_field is not DEFAULT: + kwargs["use_field"] = str(use_field) + super().__init__(kwargs) + + class IntervalsWildcard(AttrDict[Any]): """ :arg pattern: (required) Wildcard pattern used to find matching terms. @@ -3040,6 +3139,26 @@ def __init__( super().__init__(kwargs) +class SemanticTextIndexOptions(AttrDict[Any]): + """ + :arg dense_vector: + """ + + dense_vector: Union["DenseVectorIndexOptions", Dict[str, Any], DefaultType] + + def __init__( + self, + *, + dense_vector: Union[ + "DenseVectorIndexOptions", Dict[str, Any], DefaultType + ] = DEFAULT, + **kwargs: Any, + ): + if dense_vector is not DEFAULT: + kwargs["dense_vector"] = dense_vector + super().__init__(kwargs) + + class ShapeFieldQuery(AttrDict[Any]): """ :arg indexed_shape: Queries using a pre-indexed shape. @@ -3117,10 +3236,15 @@ def __init__( class SourceFilter(AttrDict[Any]): """ - :arg excludes: - :arg includes: + :arg exclude_vectors: If `true`, vector fields are excluded from the + returned source. This option takes precedence over `includes`: + any vector field will remain excluded even if it matches an + `includes` rule. + :arg excludes: A list of fields to exclude from the returned source. + :arg includes: A list of fields to include in the returned source. """ + exclude_vectors: Union[bool, DefaultType] excludes: Union[ Union[str, InstrumentedField], Sequence[Union[str, InstrumentedField]], @@ -3135,6 +3259,7 @@ class SourceFilter(AttrDict[Any]): def __init__( self, *, + exclude_vectors: Union[bool, DefaultType] = DEFAULT, excludes: Union[ Union[str, InstrumentedField], Sequence[Union[str, InstrumentedField]], @@ -3147,6 +3272,8 @@ def __init__( ] = DEFAULT, **kwargs: Any, ): + if exclude_vectors is not DEFAULT: + kwargs["exclude_vectors"] = exclude_vectors if excludes is not DEFAULT: kwargs["excludes"] = str(excludes) if includes is not DEFAULT: @@ -3634,15 +3761,30 @@ class TDigest(AttrDict[Any]): :arg compression: Limits the maximum number of nodes used by the underlying TDigest algorithm to `20 * compression`, enabling control of memory usage and approximation error. + :arg execution_hint: The default implementation of TDigest is + optimized for performance, scaling to millions or even billions of + sample values while maintaining acceptable accuracy levels (close + to 1% relative error for millions of samples in some cases). To + use an implementation optimized for accuracy, set this parameter + to high_accuracy instead. Defaults to `default` if omitted. """ compression: Union[int, DefaultType] + execution_hint: Union[Literal["default", "high_accuracy"], DefaultType] def __init__( - self, *, compression: Union[int, DefaultType] = DEFAULT, **kwargs: Any + self, + *, + compression: Union[int, DefaultType] = DEFAULT, + execution_hint: Union[ + Literal["default", "high_accuracy"], DefaultType + ] = DEFAULT, + **kwargs: Any, ): if compression is not DEFAULT: kwargs["compression"] = compression + if execution_hint is not DEFAULT: + kwargs["execution_hint"] = execution_hint super().__init__(kwargs) @@ -4112,7 +4254,7 @@ class WeightedTokensQuery(AttrDict[Any]): :arg _name: """ - tokens: Union[Mapping[str, float], DefaultType] + tokens: Union[Mapping[str, float], Sequence[Mapping[str, float]], DefaultType] pruning_config: Union["TokenPruningConfig", Dict[str, Any], DefaultType] boost: Union[float, DefaultType] _name: Union[str, DefaultType] @@ -4120,7 +4262,9 @@ class WeightedTokensQuery(AttrDict[Any]): def __init__( self, *, - tokens: Union[Mapping[str, float], DefaultType] = DEFAULT, + tokens: Union[ + Mapping[str, float], Sequence[Mapping[str, float]], DefaultType + ] = DEFAULT, pruning_config: Union[ "TokenPruningConfig", Dict[str, Any], DefaultType ] = DEFAULT, @@ -4806,7 +4950,7 @@ class ErrorCause(AttrDict[Any]): """ type: str - reason: str + reason: Union[str, None] stack_trace: str caused_by: "ErrorCause" root_cause: Sequence["ErrorCause"] diff --git a/test_elasticsearch/test_dsl/test_integration/_async/test_document.py b/test_elasticsearch/test_dsl/test_integration/_async/test_document.py index e72955a0a..99f475cf1 100644 --- a/test_elasticsearch/test_dsl/test_integration/_async/test_document.py +++ b/test_elasticsearch/test_dsl/test_integration/_async/test_document.py @@ -23,7 +23,7 @@ from datetime import datetime from ipaddress import ip_address -from typing import TYPE_CHECKING, Any, AsyncIterator, Dict, List, Tuple, Union +from typing import TYPE_CHECKING, Any, AsyncIterator, Dict, List, Optional, Tuple, Union import pytest from pytest import raises @@ -42,6 +42,7 @@ Ip, Keyword, Long, + M, Mapping, MetaField, Nested, @@ -52,6 +53,8 @@ analyzer, mapped_field, ) +from elasticsearch.dsl.query import Match +from elasticsearch.dsl.types import MatchQuery from elasticsearch.dsl.utils import AttrList from elasticsearch.helpers.errors import BulkIndexError @@ -850,3 +853,51 @@ class Index: assert docs[0].float_vector == doc.float_vector assert docs[0].byte_vector == doc.byte_vector assert docs[0].bit_vector == doc.bit_vector + + +@pytest.mark.asyncio +async def test_copy_to(async_client: AsyncElasticsearch) -> None: + class Person(AsyncDocument): + first_name: M[str] = mapped_field(Text(copy_to=["full_name", "all"])) + last_name: M[str] = mapped_field(Text(copy_to=["full_name", "all"])) + birth_place: M[str] = mapped_field(Text(copy_to="all")) + full_name: M[Optional[str]] = mapped_field(init=False) + all: M[Optional[str]] = mapped_field(init=False) + + class Index: + name = "people" + + await Person._index.delete(ignore_unavailable=True) + await Person.init() + + person = Person(first_name="Jane", last_name="Doe", birth_place="Springfield") + await person.save() + await Person._index.refresh() + + match = ( + await Person.search() + .query(Match(Person.full_name, MatchQuery(query="Jane"))) + .execute() + ) + assert len(match) == 1 + + match = ( + await Person.search() + .query(Match(Person.all, MatchQuery(query="Doe"))) + .execute() + ) + assert len(match) == 1 + + match = ( + await Person.search() + .query(Match(Person.full_name, MatchQuery(query="Springfield"))) + .execute() + ) + assert len(match) == 0 + + match = ( + await Person.search() + .query(Match(Person.all, MatchQuery(query="Springfield"))) + .execute() + ) + assert len(match) == 1 diff --git a/test_elasticsearch/test_dsl/test_integration/_sync/test_document.py b/test_elasticsearch/test_dsl/test_integration/_sync/test_document.py index 13b60f71b..05dd05fd9 100644 --- a/test_elasticsearch/test_dsl/test_integration/_sync/test_document.py +++ b/test_elasticsearch/test_dsl/test_integration/_sync/test_document.py @@ -23,7 +23,7 @@ from datetime import datetime from ipaddress import ip_address -from typing import TYPE_CHECKING, Any, Dict, Iterator, List, Tuple, Union +from typing import TYPE_CHECKING, Any, Dict, Iterator, List, Optional, Tuple, Union import pytest from pytest import raises @@ -41,6 +41,7 @@ Ip, Keyword, Long, + M, Mapping, MetaField, Nested, @@ -52,6 +53,8 @@ analyzer, mapped_field, ) +from elasticsearch.dsl.query import Match +from elasticsearch.dsl.types import MatchQuery from elasticsearch.dsl.utils import AttrList from elasticsearch.helpers.errors import BulkIndexError @@ -842,3 +845,47 @@ class Index: assert docs[0].float_vector == doc.float_vector assert docs[0].byte_vector == doc.byte_vector assert docs[0].bit_vector == doc.bit_vector + + +@pytest.mark.sync +def test_copy_to(client: Elasticsearch) -> None: + class Person(Document): + first_name: M[str] = mapped_field(Text(copy_to=["full_name", "all"])) + last_name: M[str] = mapped_field(Text(copy_to=["full_name", "all"])) + birth_place: M[str] = mapped_field(Text(copy_to="all")) + full_name: M[Optional[str]] = mapped_field(init=False) + all: M[Optional[str]] = mapped_field(init=False) + + class Index: + name = "people" + + Person._index.delete(ignore_unavailable=True) + Person.init() + + person = Person(first_name="Jane", last_name="Doe", birth_place="Springfield") + person.save() + Person._index.refresh() + + match = ( + Person.search() + .query(Match(Person.full_name, MatchQuery(query="Jane"))) + .execute() + ) + assert len(match) == 1 + + match = Person.search().query(Match(Person.all, MatchQuery(query="Doe"))).execute() + assert len(match) == 1 + + match = ( + Person.search() + .query(Match(Person.full_name, MatchQuery(query="Springfield"))) + .execute() + ) + assert len(match) == 0 + + match = ( + Person.search() + .query(Match(Person.all, MatchQuery(query="Springfield"))) + .execute() + ) + assert len(match) == 1 diff --git a/utils/templates/field.py.tpl b/utils/templates/field.py.tpl index 030060d23..8a4c73f33 100644 --- a/utils/templates/field.py.tpl +++ b/utils/templates/field.py.tpl @@ -245,7 +245,14 @@ class {{ k.name }}({{ k.parent }}): {% if not arg.positional %} if {{ arg.name }} is not DEFAULT: {% if "InstrumentedField" in arg.type %} + {% if "Sequence" in arg.type %} + if isinstance({{ arg.name }}, list): + kwargs["{{ arg.name }}"] = [str(field) for field in {{ arg.name }}] + else: + kwargs["{{ arg.name }}"] = str({{ arg.name }}) + {% else %} kwargs["{{ arg.name }}"] = str({{ arg.name }}) + {% endif %} {% else %} kwargs["{{ arg.name }}"] = {{ arg.name }} {% endif %} From d244d3eb889db2e3b9ee1d8817895ad8c75c8de3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 25 Jul 2025 17:32:38 +0100 Subject: [PATCH 48/57] Remove U+200B character from Pandas docs (#3004) (#3005) (cherry picked from commit fe5c43775adc30f4a292c9359df665e9c3d9f8fb) Co-authored-by: Quentin Pradet --- docs/reference/esql-pandas.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/esql-pandas.md b/docs/reference/esql-pandas.md index 6c0b1f96a..5e7e0c886 100644 --- a/docs/reference/esql-pandas.md +++ b/docs/reference/esql-pandas.md @@ -355,7 +355,7 @@ You can now analyze the data with Pandas or you can also continue transforming t ## Analyze the data with Pandas [analyze-data] -In the next example, the [STATS …​ BY](elasticsearch://reference/query-languages/esql/commands/processing-commands.md#esql-stats-by) command is utilized to count how many employees are speaking a given language. The results are sorted with the `languages` column using [SORT](elasticsearch://reference/query-languages/esql/commands/processing-commands.md#esql-sort): +In the next example, the [STATS … BY](elasticsearch://reference/query-languages/esql/commands/processing-commands.md#esql-stats-by) command is utilized to count how many employees are speaking a given language. The results are sorted with the `languages` column using [SORT](elasticsearch://reference/query-languages/esql/commands/processing-commands.md#esql-sort): ```python response = client.esql.query( From 33eb66a83eeb4ff22bc93e21cf7d9b61ad8011eb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 17:14:00 +0100 Subject: [PATCH 49/57] Add option to disable accurate reporting of file and line location in warnings (Fixes #3003) (#3006) (#3008) (cherry picked from commit ee3f2d9b5262273da425048ca01cfc7ea0c5c8c4) Co-authored-by: Miguel Grinberg --- elasticsearch/compat.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/elasticsearch/compat.py b/elasticsearch/compat.py index 7639fd2bd..007971306 100644 --- a/elasticsearch/compat.py +++ b/elasticsearch/compat.py @@ -16,12 +16,15 @@ # under the License. import inspect +import os import sys from pathlib import Path from typing import Tuple, Type, Union string_types: Tuple[Type[str], Type[bytes]] = (str, bytes) +DISABLE_WARN_STACKLEVEL_ENV_VAR = "DISABLE_WARN_STACKLEVEL" + def to_str(x: Union[str, bytes], encoding: str = "ascii") -> str: if not isinstance(x, str): @@ -37,6 +40,8 @@ def to_bytes(x: Union[str, bytes], encoding: str = "ascii") -> bytes: def warn_stacklevel() -> int: """Dynamically determine warning stacklevel for warnings based on the call stack""" + if os.environ.get(DISABLE_WARN_STACKLEVEL_ENV_VAR) in ["1", "true", "True"]: + return 0 try: # Grab the root module from the current module '__name__' module_name = __name__.partition(".")[0] From 491adbe66dd660f10637d0531b37c60ca227b48d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 18:46:39 +0100 Subject: [PATCH 50/57] ES|QL query builder (#2997) (#3009) * ES|QL query builder * add missing esql api documentation * add FORK command * initial attempt at generating all functions * unit tests * more operators * documentation * integration tests * add new COMPLETION command * show ES|QL in all docs examples * Docstring fixes * add technical preview warning (cherry picked from commit 9eadabb0486f92bdc37312f56acfd40e62ec6fcf) Co-authored-by: Miguel Grinberg --- docs/reference/esql-query-builder.md | 240 +++ docs/reference/toc.yml | 1 + docs/sphinx/esql.rst | 100 + docs/sphinx/index.rst | 1 + elasticsearch/dsl/__init__.py | 3 +- elasticsearch/dsl/document_base.py | 192 +- elasticsearch/dsl/utils.py | 2 +- elasticsearch/esql/__init__.py | 18 + elasticsearch/esql/esql.py | 1105 +++++++++++ elasticsearch/esql/functions.py | 1738 +++++++++++++++++ .../test_dsl/_async/test_esql.py | 93 + .../test_dsl/_sync/test_esql.py | 93 + test_elasticsearch/test_esql.py | 715 +++++++ 13 files changed, 4283 insertions(+), 18 deletions(-) create mode 100644 docs/reference/esql-query-builder.md create mode 100644 docs/sphinx/esql.rst create mode 100644 elasticsearch/esql/__init__.py create mode 100644 elasticsearch/esql/esql.py create mode 100644 elasticsearch/esql/functions.py create mode 100644 test_elasticsearch/test_dsl/_async/test_esql.py create mode 100644 test_elasticsearch/test_dsl/_sync/test_esql.py create mode 100644 test_elasticsearch/test_esql.py diff --git a/docs/reference/esql-query-builder.md b/docs/reference/esql-query-builder.md new file mode 100644 index 000000000..1cdc0c5b3 --- /dev/null +++ b/docs/reference/esql-query-builder.md @@ -0,0 +1,240 @@ +# ES|QL Query Builder + +::::{warning} +This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. +:::: + +The ES|QL Query Builder allows you to construct ES|QL queries using Python syntax. Consider the following example: + +```python +>>> from elasticsearch.esql import ESQL +>>> query = ( + ESQL.from_("employees") + .sort("emp_no") + .keep("first_name", "last_name", "height") + .eval(height_feet="height * 3.281", height_cm="height * 100") + .limit(3) +) +``` + +You can then see the assembled ES|QL query by printing the resulting query object: + +```python +>>> query +FROM employees +| SORT emp_no +| KEEP first_name, last_name, height +| EVAL height_feet = height * 3.281, height_cm = height * 100 +| LIMIT 3 +``` + +To execute this query, you can cast it to a string and pass the string to the `client.esql.query()` endpoint: + +```python +>>> from elasticsearch import Elasticsearch +>>> client = Elasticsearch(hosts=[os.environ['ELASTICSEARCH_URL']]) +>>> response = client.esql.query(query=str(query)) +``` + +The response body contains a `columns` attribute with the list of columns included in the results, and a `values` attribute with the list of results for the query, each given as a list of column values. Here is a possible response body returned by the example query given above: + +```python +>>> from pprint import pprint +>>> pprint(response.body) +{'columns': [{'name': 'first_name', 'type': 'text'}, + {'name': 'last_name', 'type': 'text'}, + {'name': 'height', 'type': 'double'}, + {'name': 'height_feet', 'type': 'double'}, + {'name': 'height_cm', 'type': 'double'}], + 'is_partial': False, + 'took': 11, + 'values': [['Adrian', 'Wells', 2.424, 7.953144, 242.4], + ['Aaron', 'Gonzalez', 1.584, 5.1971, 158.4], + ['Miranda', 'Kramer', 1.55, 5.08555, 155]]} +``` + +## Creating an ES|QL query + +To construct an ES|QL query you start from one of the ES|QL source commands: + +### `ESQL.from_` + +The `FROM` command selects the indices, data streams or aliases to be queried. + +Examples: + +```python +from elasticsearch.esql import ESQL + +# FROM employees +query1 = ESQL.from_("employees") + +# FROM +query2 = ESQL.from_("") + +# FROM employees-00001, other-employees-* +query3 = ESQL.from_("employees-00001", "other-employees-*") + +# FROM cluster_one:employees-00001, cluster_two:other-employees-* +query4 = ESQL.from_("cluster_one:employees-00001", "cluster_two:other-employees-*") + +# FROM employees METADATA _id +query5 = ESQL.from_("employees").metadata("_id") +``` + +Note how in the last example the optional `METADATA` clause of the `FROM` command is added as a chained method. + +### `ESQL.row` + +The `ROW` command produces a row with one or more columns, with the values that you specify. + +Examples: + +```python +from elasticsearch.esql import ESQL, functions + +# ROW a = 1, b = "two", c = null +query1 = ESQL.row(a=1, b="two", c=None) + +# ROW a = [1, 2] +query2 = ESQL.row(a=[1, 2]) + +# ROW a = ROUND(1.23, 0) +query3 = ESQL.row(a=functions.round(1.23, 0)) +``` + +### `ESQL.show` + +The `SHOW` command returns information about the deployment and its capabilities. + +Example: + +```python +from elasticsearch.esql import ESQL + +# SHOW INFO +query = ESQL.show("INFO") +``` + +## Adding processing commands + +Once you have a query object, you can add one or more processing commands to it. The following +example shows how to create a query that uses the `WHERE` and `LIMIT` commands to filter the +results: + +```python +from elasticsearch.esql import ESQL + +# FROM employees +# | WHERE still_hired == true +# | LIMIT 10 +query = ESQL.from_("employees").where("still_hired == true").limit(10) +``` + +For a complete list of available commands, review the methods of the [`ESQLBase` class](https://elasticsearch-py.readthedocs.io/en/stable/esql.html) in the Elasticsearch Python API documentation. + +## Creating ES|QL Expressions and Conditions + +The ES|QL query builder for Python provides two ways to create expressions and conditions in ES|QL queries. + +The simplest option is to provide all ES|QL expressions and conditionals as strings. The following example uses this approach to add two calculated columns to the results using the `EVAL` command: + +```python +from elasticsearch.esql import ESQL + +# FROM employees +# | SORT emp_no +# | KEEP first_name, last_name, height +# | EVAL height_feet = height * 3.281, height_cm = height * 100 +query = ( + ESQL.from_("employees") + .sort("emp_no") + .keep("first_name", "last_name", "height") + .eval(height_feet="height * 3.281", height_cm="height * 100") +) +``` + +A more advanced alternative is to replace the strings with Python expressions, which are automatically translated to ES|QL when the query object is rendered to a string. The following example is functionally equivalent to the one above: + +```python +from elasticsearch.esql import ESQL, E + +# FROM employees +# | SORT emp_no +# | KEEP first_name, last_name, height +# | EVAL height_feet = height * 3.281, height_cm = height * 100 +query = ( + ESQL.from_("employees") + .sort("emp_no") + .keep("first_name", "last_name", "height") + .eval(height_feet=E("height") * 3.281, height_cm=E("height") * 100) +) +``` + +Here the `E()` helper function is used as a wrapper to the column name that initiates an ES|QL expression. The `E()` function transforms the given column into an ES|QL expression that can be modified with Python operators. + +Here is a second example, which uses a conditional expression in the `WHERE` command: + +```python +from elasticsearch.esql import ESQL + +# FROM employees +# | KEEP first_name, last_name, height +# | WHERE first_name == "Larry" +query = ( + ESQL.from_("employees") + .keep("first_name", "last_name", "height") + .where('first_name == "Larry"') +) +``` + +Using Python syntax, the condition can be rewritten as follows: + +```python +from elasticsearch.esql import ESQL, E + +# FROM employees +# | KEEP first_name, last_name, height +# | WHERE first_name == "Larry" +query = ( + ESQL.from_("employees") + .keep("first_name", "last_name", "height") + .where(E("first_name") == "Larry") +) +``` + +## Using ES|QL functions + +The ES|QL language includes a rich set of functions that can be used in expressions and conditionals. These can be included in expressions given as strings, as shown in the example below: + +```python +from elasticsearch.esql import ESQL + +# FROM employees +# | KEEP first_name, last_name, height +# | WHERE LENGTH(first_name) < 4" +query = ( + ESQL.from_("employees") + .keep("first_name", "last_name", "height") + .where("LENGTH(first_name) < 4") +) +``` + +All available ES|QL functions have Python wrappers in the `elasticsearch.esql.functions` module, which can be used when building expressions using Python syntax. Below is the example above coded using Python syntax: + +```python +from elasticsearch.esql import ESQL, functions + +# FROM employees +# | KEEP first_name, last_name, height +# | WHERE LENGTH(first_name) < 4" +query = ( + ESQL.from_("employees") + .keep("first_name", "last_name", "height") + .where(functions.length(E("first_name")) < 4) +) +``` + +Note that arguments passed to functions are assumed to be literals. When passing field names, it is necessary to wrap them with the `E()` helper function so that they are interpreted correctly. + +You can find the complete list of available functions in the Python client's [ES|QL API reference documentation](https://elasticsearch-py.readthedocs.io/en/stable/esql.html#module-elasticsearch.esql.functions). diff --git a/docs/reference/toc.yml b/docs/reference/toc.yml index 015027e4d..7e26b7274 100644 --- a/docs/reference/toc.yml +++ b/docs/reference/toc.yml @@ -5,6 +5,7 @@ toc: - file: connecting.md - file: configuration.md - file: querying.md + - file: esql-query-builder.md - file: async.md - file: integrations.md children: diff --git a/docs/sphinx/esql.rst b/docs/sphinx/esql.rst new file mode 100644 index 000000000..1104b5b97 --- /dev/null +++ b/docs/sphinx/esql.rst @@ -0,0 +1,100 @@ +ES|QL Query Builder +=================== + +Commands +-------- + +.. autoclass:: elasticsearch.esql.ESQL + :inherited-members: + :members: + +.. autoclass:: elasticsearch.esql.esql.ESQLBase + :inherited-members: + :members: + :exclude-members: __init__ + +.. autoclass:: elasticsearch.esql.esql.From + :members: + :exclude-members: __init__ + +.. autoclass:: elasticsearch.esql.esql.Row + :members: + :exclude-members: __init__ + +.. autoclass:: elasticsearch.esql.esql.Show + :members: + :exclude-members: __init__ + +.. autoclass:: elasticsearch.esql.esql.ChangePoint + :members: + :exclude-members: __init__ + +.. autoclass:: elasticsearch.esql.esql.Completion + :members: + :exclude-members: __init__ + +.. autoclass:: elasticsearch.esql.esql.Dissect + :members: + :exclude-members: __init__ + +.. autoclass:: elasticsearch.esql.esql.Drop + :members: + :exclude-members: __init__ + +.. autoclass:: elasticsearch.esql.esql.Enrich + :members: + :exclude-members: __init__ + +.. autoclass:: elasticsearch.esql.esql.Eval + :members: + :exclude-members: __init__ + +.. autoclass:: elasticsearch.esql.esql.Fork + :members: + :exclude-members: __init__ + +.. autoclass:: elasticsearch.esql.esql.Grok + :members: + :exclude-members: __init__ + +.. autoclass:: elasticsearch.esql.esql.Keep + :members: + :exclude-members: __init__ + +.. autoclass:: elasticsearch.esql.esql.Limit + :members: + :exclude-members: __init__ + +.. autoclass:: elasticsearch.esql.esql.LookupJoin + :members: + :exclude-members: __init__ + +.. autoclass:: elasticsearch.esql.esql.MvExpand + :members: + :exclude-members: __init__ + +.. autoclass:: elasticsearch.esql.esql.Rename + :members: + :exclude-members: __init__ + +.. autoclass:: elasticsearch.esql.esql.Sample + :members: + :exclude-members: __init__ + +.. autoclass:: elasticsearch.esql.esql.Sort + :members: + :exclude-members: __init__ + +.. autoclass:: elasticsearch.esql.esql.Stats + :members: + :exclude-members: __init__ + +.. autoclass:: elasticsearch.esql.esql.Where + :members: + :exclude-members: __init__ + +Functions +--------- + +.. automodule:: elasticsearch.esql.functions + :members: diff --git a/docs/sphinx/index.rst b/docs/sphinx/index.rst index 4cf5f92cc..afbdf0aef 100644 --- a/docs/sphinx/index.rst +++ b/docs/sphinx/index.rst @@ -11,6 +11,7 @@ High-level documentation for this client is `also available str: + if isinstance(value, InstrumentedExpression): + return str(value) + return json.dumps(value) + + def __str__(self) -> str: + return self._expr + + def __repr__(self) -> str: + return f"InstrumentedExpression[{self._expr}]" + + def __pos__(self) -> "InstrumentedExpression": + return self + + def __neg__(self) -> "InstrumentedExpression": + return InstrumentedExpression(f"-({self._expr})") + + def __eq__(self, value: Any) -> "InstrumentedExpression": # type: ignore[override] + return InstrumentedExpression(f"{self._expr} == {self._render_value(value)}") + + def __ne__(self, value: Any) -> "InstrumentedExpression": # type: ignore[override] + return InstrumentedExpression(f"{self._expr} != {self._render_value(value)}") + + def __lt__(self, value: Any) -> "InstrumentedExpression": + return InstrumentedExpression(f"{self._expr} < {self._render_value(value)}") + + def __gt__(self, value: Any) -> "InstrumentedExpression": + return InstrumentedExpression(f"{self._expr} > {self._render_value(value)}") + + def __le__(self, value: Any) -> "InstrumentedExpression": + return InstrumentedExpression(f"{self._expr} <= {self._render_value(value)}") + + def __ge__(self, value: Any) -> "InstrumentedExpression": + return InstrumentedExpression(f"{self._expr} >= {self._render_value(value)}") + + def __add__(self, value: Any) -> "InstrumentedExpression": + return InstrumentedExpression(f"{self._expr} + {self._render_value(value)}") + + def __radd__(self, value: Any) -> "InstrumentedExpression": + return InstrumentedExpression(f"{self._render_value(value)} + {self._expr}") + + def __sub__(self, value: Any) -> "InstrumentedExpression": + return InstrumentedExpression(f"{self._expr} - {self._render_value(value)}") + + def __rsub__(self, value: Any) -> "InstrumentedExpression": + return InstrumentedExpression(f"{self._render_value(value)} - {self._expr}") + + def __mul__(self, value: Any) -> "InstrumentedExpression": + return InstrumentedExpression(f"{self._expr} * {self._render_value(value)}") + + def __rmul__(self, value: Any) -> "InstrumentedExpression": + return InstrumentedExpression(f"{self._render_value(value)} * {self._expr}") + + def __truediv__(self, value: Any) -> "InstrumentedExpression": + return InstrumentedExpression(f"{self._expr} / {self._render_value(value)}") + + def __rtruediv__(self, value: Any) -> "InstrumentedExpression": + return InstrumentedExpression(f"{self._render_value(value)} / {self._expr}") + + def __mod__(self, value: Any) -> "InstrumentedExpression": + return InstrumentedExpression(f"{self._expr} % {self._render_value(value)}") + + def __rmod__(self, value: Any) -> "InstrumentedExpression": + return InstrumentedExpression(f"{self._render_value(value)} % {self._expr}") + + def is_null(self) -> "InstrumentedExpression": + """Compare the expression against NULL.""" + return InstrumentedExpression(f"{self._expr} IS NULL") + + def is_not_null(self) -> "InstrumentedExpression": + """Compare the expression against NOT NULL.""" + return InstrumentedExpression(f"{self._expr} IS NOT NULL") + + def in_(self, *values: Any) -> "InstrumentedExpression": + """Test if the expression equals one of the given values.""" + rendered_values = ", ".join([f"{value}" for value in values]) + return InstrumentedExpression(f"{self._expr} IN ({rendered_values})") + + def like(self, *patterns: str) -> "InstrumentedExpression": + """Filter the expression using a string pattern.""" + if len(patterns) == 1: + return InstrumentedExpression( + f"{self._expr} LIKE {self._render_value(patterns[0])}" + ) + else: + return InstrumentedExpression( + f'{self._expr} LIKE ({", ".join([self._render_value(p) for p in patterns])})' + ) + + def rlike(self, *patterns: str) -> "InstrumentedExpression": + """Filter the expression using a regular expression.""" + if len(patterns) == 1: + return InstrumentedExpression( + f"{self._expr} RLIKE {self._render_value(patterns[0])}" + ) + else: + return InstrumentedExpression( + f'{self._expr} RLIKE ({", ".join([self._render_value(p) for p in patterns])})' + ) + + def match(self, query: str) -> "InstrumentedExpression": + """Perform a match query on the field.""" + return InstrumentedExpression(f"{self._expr}:{self._render_value(query)}") + + def asc(self) -> "InstrumentedExpression": + """Return the field name representation for ascending sort order. + + For use in ES|QL queries only. + """ + return InstrumentedExpression(f"{self._expr} ASC") + + def desc(self) -> "InstrumentedExpression": + """Return the field name representation for descending sort order. + + For use in ES|QL queries only. + """ + return InstrumentedExpression(f"{self._expr} DESC") + + def nulls_first(self) -> "InstrumentedExpression": + """Return the field name representation for nulls first sort order. + + For use in ES|QL queries only. + """ + return InstrumentedExpression(f"{self._expr} NULLS FIRST") + + def nulls_last(self) -> "InstrumentedExpression": + """Return the field name representation for nulls last sort order. + + For use in ES|QL queries only. + """ + return InstrumentedExpression(f"{self._expr} NULLS LAST") + + def where( + self, *expressions: Union[str, "InstrumentedExpression"] + ) -> "InstrumentedExpression": + """Add a condition to be met for the row to be included. + + Use only in expressions given in the ``STATS`` command. + """ + if len(expressions) == 1: + return InstrumentedExpression(f"{self._expr} WHERE {expressions[0]}") + else: + return InstrumentedExpression( + f'{self._expr} WHERE {" AND ".join([f"({expr})" for expr in expressions])}' + ) + + +E = InstrumentedExpression + + +class InstrumentedField(InstrumentedExpression): """Proxy object for a mapped document field. An object of this instance is returned when a field is accessed as a class @@ -71,8 +228,8 @@ class MyDocument(Document): s = s.sort(-MyDocument.name) # sort by name in descending order """ - def __init__(self, name: str, field: Field): - self._name = name + def __init__(self, name: str, field: Optional[Field]): + super().__init__(name) self._field = field # note that the return value type here assumes classes will only be used to @@ -83,26 +240,29 @@ def __getattr__(self, attr: str) -> "InstrumentedField": # first let's see if this is an attribute of this object return super().__getattribute__(attr) # type: ignore[no-any-return] except AttributeError: - try: - # next we see if we have a sub-field with this name - return InstrumentedField(f"{self._name}.{attr}", self._field[attr]) - except KeyError: - # lastly we let the wrapped field resolve this attribute - return getattr(self._field, attr) # type: ignore[no-any-return] - - def __pos__(self) -> str: + if self._field: + try: + # next we see if we have a sub-field with this name + return InstrumentedField(f"{self._expr}.{attr}", self._field[attr]) + except KeyError: + # lastly we let the wrapped field resolve this attribute + return getattr(self._field, attr) # type: ignore[no-any-return] + else: + raise + + def __pos__(self) -> str: # type: ignore[override] """Return the field name representation for ascending sort order""" - return f"{self._name}" + return f"{self._expr}" - def __neg__(self) -> str: + def __neg__(self) -> str: # type: ignore[override] """Return the field name representation for descending sort order""" - return f"-{self._name}" + return f"-{self._expr}" def __str__(self) -> str: - return self._name + return self._expr def __repr__(self) -> str: - return f"InstrumentedField[{self._name}]" + return f"InstrumentedField[{self._expr}]" class DocumentMeta(type): diff --git a/elasticsearch/dsl/utils.py b/elasticsearch/dsl/utils.py index b52ec63a0..127a48cc2 100644 --- a/elasticsearch/dsl/utils.py +++ b/elasticsearch/dsl/utils.py @@ -333,7 +333,7 @@ def __init__(self, _expand__to_dot: Optional[bool] = None, **params: Any) -> Non _expand__to_dot = EXPAND__TO_DOT self._params: Dict[str, Any] = {} for pname, pvalue in params.items(): - if pvalue == DEFAULT: + if pvalue is DEFAULT: continue # expand "__" to dots if "__" in pname and _expand__to_dot: diff --git a/elasticsearch/esql/__init__.py b/elasticsearch/esql/__init__.py new file mode 100644 index 000000000..d872c329a --- /dev/null +++ b/elasticsearch/esql/__init__.py @@ -0,0 +1,18 @@ +# Licensed to Elasticsearch B.V. under one or more contributor +# license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright +# ownership. Elasticsearch B.V. 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. + +from .esql import ESQL, and_, not_, or_ # noqa: F401 diff --git a/elasticsearch/esql/esql.py b/elasticsearch/esql/esql.py new file mode 100644 index 000000000..07ccdf839 --- /dev/null +++ b/elasticsearch/esql/esql.py @@ -0,0 +1,1105 @@ +# Licensed to Elasticsearch B.V. under one or more contributor +# license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright +# ownership. Elasticsearch B.V. 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. + +import json +from abc import ABC, abstractmethod +from typing import Any, Dict, Optional, Tuple, Type, Union + +from ..dsl.document_base import DocumentBase, InstrumentedExpression, InstrumentedField + +FieldType = Union[InstrumentedField, str] +IndexType = Union[Type[DocumentBase], str] +ExpressionType = Any + + +class ESQL(ABC): + """The static methods of the ``ESQL`` class provide access to the ES|QL source + commands, used to create ES|QL queries. + + These methods return an instance of class ``ESQLBase``, which provides access to + the ES|QL processing commands. + """ + + @staticmethod + def from_(*indices: IndexType) -> "From": + """The ``FROM`` source command returns a table with data from a data stream, index, or alias. + + :param indices: A list of indices, data streams or aliases. Supports wildcards and date math. + + Examples:: + + query1 = ESQL.from_("employees") + query2 = ESQL.from_("") + query3 = ESQL.from_("employees-00001", "other-employees-*") + query4 = ESQL.from_("cluster_one:employees-00001", "cluster_two:other-employees-*") + query5 = ESQL.from_("employees").metadata("_id") + """ + return From(*indices) + + @staticmethod + def row(**params: ExpressionType) -> "Row": + """The ``ROW`` source command produces a row with one or more columns with values that you specify. + This can be useful for testing. + + :param params: the column values to produce, given as keyword arguments. + + Examples:: + + query1 = ESQL.row(a=1, b="two", c=None) + query2 = ESQL.row(a=[1, 2]) + query3 = ESQL.row(a=functions.round(1.23, 0)) + """ + return Row(**params) + + @staticmethod + def show(item: str) -> "Show": + """The ``SHOW`` source command returns information about the deployment and its capabilities. + + :param item: Can only be ``INFO``. + + Examples:: + + query = ESQL.show("INFO") + """ + return Show(item) + + @staticmethod + def branch() -> "Branch": + """This method can only be used inside a ``FORK`` command to create each branch. + + Examples:: + + query = ESQL.from_("employees").fork( + ESQL.branch().where("emp_no == 10001"), + ESQL.branch().where("emp_no == 10002"), + ) + """ + return Branch() + + +class ESQLBase(ABC): + """The methods of the ``ESQLBase`` class provide access to the ES|QL processing + commands, used to build ES|QL queries. + """ + + def __init__(self, parent: Optional["ESQLBase"] = None): + self._parent = parent + + def __repr__(self) -> str: + return self.render() + + def render(self) -> str: + return ( + self._parent.render() + "\n| " if self._parent else "" + ) + self._render_internal() + + @abstractmethod + def _render_internal(self) -> str: + pass + + def _is_forked(self) -> bool: + if self.__class__.__name__ == "Fork": + return True + if self._parent: + return self._parent._is_forked() + return False + + def change_point(self, value: FieldType) -> "ChangePoint": + """`CHANGE_POINT` detects spikes, dips, and change points in a metric. + + :param value: The column with the metric in which you want to detect a change point. + + Examples:: + + query = ( + ESQL.row(key=list(range(1, 26))) + .mv_expand("key") + .eval(value=functions.case("key<13", 0, 42)) + .change_point("value") + .on("key") + .where("type IS NOT NULL") + ) + """ + return ChangePoint(self, value) + + def completion( + self, *prompt: ExpressionType, **named_prompt: ExpressionType + ) -> "Completion": + """The `COMPLETION` command allows you to send prompts and context to a Large + Language Model (LLM) directly within your ES|QL queries, to perform text + generation tasks. + + :param prompt: The input text or expression used to prompt the LLM. This can + be a string literal or a reference to a column containing text. + :param named_prompt: The input text or expresion, given as a keyword argument. + The argument name is used for the column name. If not + specified, the results will be stored in a column named + `completion`. If the specified column already exists, it + will be overwritten with the new results. + + Examples:: + + query1 = ( + ESQL.row(question="What is Elasticsearch?") + .completion("question").with_("test_completion_model") + .keep("question", "completion") + ) + query2 = ( + ESQL.row(question="What is Elasticsearch?") + .completion(answer="question").with_("test_completion_model") + .keep("question", "answer") + ) + query3 = ( + ESQL.from_("movies") + .sort("rating DESC") + .limit(10) + .eval(prompt=\"\"\"CONCAT( + "Summarize this movie using the following information: \\n", + "Title: ", title, "\\n", + "Synopsis: ", synopsis, "\\n", + "Actors: ", MV_CONCAT(actors, ", "), "\\n", + )\"\"\") + .completion(summary="prompt").with_("test_completion_model") + .keep("title", "summary", "rating") + ) + """ + return Completion(self, *prompt, **named_prompt) + + def dissect(self, input: FieldType, pattern: str) -> "Dissect": + """``DISSECT`` enables you to extract structured data out of a string. + + :param input: The column that contains the string you want to structure. If + the column has multiple values, ``DISSECT`` will process each value. + :param pattern: A dissect pattern. If a field name conflicts with an existing + column, the existing column is dropped. If a field name is used + more than once, only the rightmost duplicate creates a column. + + Examples:: + + query = ( + ESQL.row(a="2023-01-23T12:15:00.000Z - some text - 127.0.0.1") + .dissect("a", "%{date} - %{msg} - %{ip}") + .keep("date", "msg", "ip") + .eval(date="TO_DATETIME(date)") + ) + """ + return Dissect(self, input, pattern) + + def drop(self, *columns: FieldType) -> "Drop": + """The ``DROP`` processing command removes one or more columns. + + :param columns: The columns to drop, given as positional arguments. Supports wildcards. + + Examples:: + + query1 = ESQL.from_("employees").drop("height") + query2 = ESQL.from_("employees").drop("height*") + """ + return Drop(self, *columns) + + def enrich(self, policy: str) -> "Enrich": + """``ENRICH`` enables you to add data from existing indices as new columns using an + enrich policy. + + :param policy: The name of the enrich policy. You need to create and execute the + enrich policy first. + + Examples:: + + query1 = ( + ESQL.row(a="1") + .enrich("languages_policy").on("a").with_("language_name") + ) + query2 = ( + ESQL.row(a="1") + .enrich("languages_policy").on("a").with_(name="language_name") + ) + """ + return Enrich(self, policy) + + def eval(self, *columns: ExpressionType, **named_columns: ExpressionType) -> "Eval": + """The ``EVAL`` processing command enables you to append new columns with calculated values. + + :param columns: The values for the columns, given as positional arguments. Can be literals, + expressions, or functions. Can use columns defined left of this one. + :param named_columns: The values for the new columns, given as keyword arguments. The name + of the arguments is used as column name. If a column with the same + name already exists, the existing column is dropped. If a column name + is used more than once, only the rightmost duplicate creates a column. + + Examples:: + + query1 = ( + ESQL.from_("employees") + .sort("emp_no") + .keep("first_name", "last_name", "height") + .eval(height_feet="height * 3.281", height_cm="height * 100") + ) + query2 = ( + ESQL.from_("employees") + .eval("height * 3.281") + .stats(avg_height_feet=functions.avg("`height * 3.281`")) + ) + """ + return Eval(self, *columns, **named_columns) + + def fork( + self, + fork1: "ESQLBase", + fork2: Optional["ESQLBase"] = None, + fork3: Optional["ESQLBase"] = None, + fork4: Optional["ESQLBase"] = None, + fork5: Optional["ESQLBase"] = None, + fork6: Optional["ESQLBase"] = None, + fork7: Optional["ESQLBase"] = None, + fork8: Optional["ESQLBase"] = None, + ) -> "Fork": + """The ``FORK`` processing command creates multiple execution branches to operate on the + same input data and combines the results in a single output table. + + :param fork: Up to 8 execution branches, created with the ``ESQL.branch()`` method. + + Examples:: + + query = ( + ESQL.from_("employees") + .fork( + ESQL.branch().where("emp_no == 10001"), + ESQL.branch().where("emp_no == 10002"), + ) + .keep("emp_no", "_fork") + .sort("emp_no") + ) + """ + if self._is_forked(): + raise ValueError("a query can only have one fork") + return Fork(self, fork1, fork2, fork3, fork4, fork5, fork6, fork7, fork8) + + def grok(self, input: FieldType, pattern: str) -> "Grok": + """``GROK`` enables you to extract structured data out of a string. + + :param input: The column that contains the string you want to structure. If the + column has multiple values, ``GROK`` will process each value. + :param pattern: A grok pattern. If a field name conflicts with an existing column, + the existing column is discarded. If a field name is used more than + once, a multi-valued column will be created with one value per each + occurrence of the field name. + + Examples:: + + query1 = ( + ESQL.row(a="2023-01-23T12:15:00.000Z 127.0.0.1 some.email@foo.com 42") + .grok("a", "%{TIMESTAMP_ISO8601:date} %{IP:ip} %{EMAILADDRESS:email} %{NUMBER:num}") + .keep("date", "ip", "email", "num") + ) + query2 = ( + ESQL.row(a="2023-01-23T12:15:00.000Z 127.0.0.1 some.email@foo.com 42") + .grok( + "a", + "%{TIMESTAMP_ISO8601:date} %{IP:ip} %{EMAILADDRESS:email} %{NUMBER:num:int}", + ) + .keep("date", "ip", "email", "num") + .eval(date=functions.to_datetime("date")) + ) + query3 = ( + ESQL.from_("addresses") + .keep("city.name", "zip_code") + .grok("zip_code", "%{WORD:zip_parts} %{WORD:zip_parts}") + ) + """ + return Grok(self, input, pattern) + + def keep(self, *columns: FieldType) -> "Keep": + """The ``KEEP`` processing command enables you to specify what columns are returned + and the order in which they are returned. + + :param columns: The columns to keep, given as positional arguments. Supports + wildcards. + + Examples:: + + query1 = ESQL.from_("employees").keep("emp_no", "first_name", "last_name", "height") + query2 = ESQL.from_("employees").keep("h*") + query3 = ESQL.from_("employees").keep("h*", "*") + """ + return Keep(self, *columns) + + def limit(self, max_number_of_rows: int) -> "Limit": + """The ``LIMIT`` processing command enables you to limit the number of rows that are + returned. + + :param max_number_of_rows: The maximum number of rows to return. + + Examples:: + + query1 = ESQL.from_("employees").sort("emp_no ASC").limit(5) + query2 = ESQL.from_("index").stats(functions.avg("field1")).by("field2").limit(20000) + """ + return Limit(self, max_number_of_rows) + + def lookup_join(self, lookup_index: IndexType) -> "LookupJoin": + """`LOOKUP JOIN` enables you to add data from another index, AKA a 'lookup' index, + to your ES|QL query results, simplifying data enrichment and analysis workflows. + + :param lookup_index: The name of the lookup index. This must be a specific index + name - wildcards, aliases, and remote cluster references are + not supported. Indices used for lookups must be configured + with the lookup index mode. + + Examples:: + + query1 = ( + ESQL.from_("firewall_logs") + .lookup_join("threat_list").on("source.IP") + .where("threat_level IS NOT NULL") + ) + query2 = ( + ESQL.from_("system_metrics") + .lookup_join("host_inventory").on("host.name") + .lookup_join("ownerships").on("host.name") + ) + query3 = ( + ESQL.from_("app_logs") + .lookup_join("service_owners").on("service_id") + ) + query4 = ( + ESQL.from_("employees") + .eval(language_code="languages") + .where("emp_no >= 10091 AND emp_no < 10094") + .lookup_join("languages_lookup").on("language_code") + ) + """ + return LookupJoin(self, lookup_index) + + def mv_expand(self, column: FieldType) -> "MvExpand": + """The `MV_EXPAND` processing command expands multivalued columns into one row per + value, duplicating other columns. + + :param column: The multivalued column to expand. + + Examples:: + + query = ESQL.row(a=[1, 2, 3], b="b", j=["a", "b"]).mv_expand("a") + """ + return MvExpand(self, column) + + def rename(self, **columns: FieldType) -> "Rename": + """The ``RENAME`` processing command renames one or more columns. + + :param columns: The old and new column name pairs, given as keyword arguments. + If a name conflicts with an existing column name, the existing column + is dropped. If multiple columns are renamed to the same name, all but + the rightmost column with the same new name are dropped. + + Examples:: + + query = ( + ESQL.from_("employees") + .keep("first_name", "last_name", "still_hired") + .rename(still_hired="employed") + ) + """ + return Rename(self, **columns) + + def sample(self, probability: float) -> "Sample": + """The ``SAMPLE`` command samples a fraction of the table rows. + + :param probability: The probability that a row is included in the sample. The value + must be between 0 and 1, exclusive. + + Examples:: + + query = ESQL.from_("employees").keep("emp_no").sample(0.05) + """ + return Sample(self, probability) + + def sort(self, *columns: FieldType) -> "Sort": + """The ``SORT`` processing command sorts a table on one or more columns. + + :param columns: The columns to sort on. + + Examples:: + + query1 = ( + ESQL.from_("employees") + .keep("first_name", "last_name", "height") + .sort("height") + ) + query2 = ( + ESQL.from_("employees") + .keep("first_name", "last_name", "height") + .sort("height DESC") + ) + query3 = ( + ESQL.from_("employees") + .keep("first_name", "last_name", "height") + .sort("height DESC", "first_name ASC") + ) + query4 = ( + ESQL.from_("employees") + .keep("first_name", "last_name", "height") + .sort("first_name ASC NULLS FIRST") + ) + """ + return Sort(self, *columns) + + def stats( + self, *expressions: ExpressionType, **named_expressions: ExpressionType + ) -> "Stats": + """The ``STATS`` processing command groups rows according to a common value and + calculates one or more aggregated values over the grouped rows. + + :param expressions: A list of expressions, given as positional arguments. + :param named_expressions: A list of expressions, given as keyword arguments. The + argument names are used for the returned aggregated values. + + Note that only one of `expressions` and `named_expressions` must be provided. + + Examples:: + + query1 = ( + ESQL.from_("employees") + .stats(count=functions.count("emp_no")).by("languages") + .sort("languages") + ) + query2 = ( + ESQL.from_("employees") + .stats(avg_lang=functions.avg("languages")) + ) + query3 = ( + ESQL.from_("employees") + .stats( + avg_lang=functions.avg("languages"), + max_lang=functions.max("languages") + ) + ) + query4 = ( + ESQL.from_("employees") + .stats( + avg50s=functions.avg("salary").where('birth_date < "1960-01-01"'), + avg60s=functions.avg("salary").where('birth_date >= "1960-01-01"'), + ).by("gender") + .sort("gender") + ) + query5 = ( + ESQL.from_("employees") + .eval(Ks="salary / 1000") + .stats( + under_40K=functions.count("*").where("Ks < 40"), + inbetween=functions.count("*").where("40 <= Ks AND Ks < 60"), + over_60K=functions.count("*").where("60 <= Ks"), + total=f.count("*") + ) + ) + query6 = ( + ESQL.row(i=1, a=["a", "b"]) + .stats(functions.min("i")).by("a") + .sort("a ASC") + ) + query7 = ( + ESQL.from_("employees") + .eval(hired=functions.date_format("hire_date", "yyyy")) + .stats(avg_salary=functions.avg("salary")).by("hired", "languages.long") + .eval(avg_salary=functions.round("avg_salary")) + .sort("hired", "languages.long") + + ) + """ + return Stats(self, *expressions, **named_expressions) + + def where(self, *expressions: ExpressionType) -> "Where": + """The ``WHERE`` processing command produces a table that contains all the rows + from the input table for which the provided condition evaluates to `true`. + + :param expressions: A list of boolean expressions, given as positional arguments. + These expressions are combined with an ``AND`` logical operator. + + Examples:: + + query1 = ( + ESQL.from_("employees") + .keep("first_name", "last_name", "still_hired") + .where("still_hired == true") + ) + query2 = ( + ESQL.from_("sample_data") + .where("@timestamp > NOW() - 1 hour") + ) + query3 = ( + ESQL.from_("employees") + .keep("first_name", "last_name", "height") + .where("LENGTH(first_name) < 4") + ) + """ + return Where(self, *expressions) + + +class From(ESQLBase): + """Implementation of the ``FROM`` source command. + + This class inherits from :class:`ESQLBase `, + to make it possible to chain all the commands that belong to an ES|QL query + in a single expression. + """ + + def __init__(self, *indices: IndexType): + super().__init__() + self._indices = indices + self._metadata_fields: Tuple[FieldType, ...] = tuple() + + def metadata(self, *fields: FieldType) -> "From": + """Continuation of the ``FROM`` source command. + + :param fields: metadata fields to retrieve, given as positional arguments. + """ + self._metadata_fields = fields + return self + + def _render_internal(self) -> str: + indices = [ + index if isinstance(index, str) else index._index._name + for index in self._indices + ] + s = f'{self.__class__.__name__.upper()} {", ".join(indices)}' + if self._metadata_fields: + s = ( + s + + f' METADATA {", ".join([str(field) for field in self._metadata_fields])}' + ) + return s + + +class Row(ESQLBase): + """Implementation of the ``ROW`` source command. + + This class inherits from :class:`ESQLBase `, + to make it possible to chain all the commands that belong to an ES|QL query + in a single expression. + """ + + def __init__(self, **params: ExpressionType): + super().__init__() + self._params = { + k: json.dumps(v) if not isinstance(v, InstrumentedExpression) else v + for k, v in params.items() + } + + def _render_internal(self) -> str: + return "ROW " + ", ".join([f"{k} = {v}" for k, v in self._params.items()]) + + +class Show(ESQLBase): + """Implementation of the ``SHOW`` source command. + + This class inherits from :class:`ESQLBase `, + which makes it possible to chain all the commands that belong to an ES|QL query + in a single expression. + """ + + def __init__(self, item: str): + super().__init__() + self._item = item + + def _render_internal(self) -> str: + return f"SHOW {self._item}" + + +class Branch(ESQLBase): + """Implementation of a branch inside a ``FORK`` processing command. + + This class inherits from :class:`ESQLBase `, + which makes it possible to chain all the commands that belong to the branch + in a single expression. + """ + + def _render_internal(self) -> str: + return "" + + +class ChangePoint(ESQLBase): + """Implementation of the ``CHANGE POINT`` processing command. + + This class inherits from :class:`ESQLBase `, + to make it possible to chain all the commands that belong to an ES|QL query + in a single expression. + """ + + def __init__(self, parent: ESQLBase, value: FieldType): + super().__init__(parent) + self._value = value + self._key: Optional[FieldType] = None + self._type_name: Optional[str] = None + self._pvalue_name: Optional[str] = None + + def on(self, key: FieldType) -> "ChangePoint": + """Continuation of the `CHANGE_POINT` command. + + :param key: The column with the key to order the values by. If not specified, + `@timestamp` is used. + """ + self._key = key + return self + + def as_(self, type_name: str, pvalue_name: str) -> "ChangePoint": + """Continuation of the `CHANGE_POINT` command. + + :param type_name: The name of the output column with the change point type. + If not specified, `type` is used. + :param pvalue_name: The name of the output column with the p-value that indicates + how extreme the change point is. If not specified, `pvalue` is used. + """ + self._type_name = type_name + self._pvalue_name = pvalue_name + return self + + def _render_internal(self) -> str: + key = "" if not self._key else f" ON {self._key}" + names = ( + "" + if not self._type_name and not self._pvalue_name + else f' AS {self._type_name or "type"}, {self._pvalue_name or "pvalue"}' + ) + return f"CHANGE_POINT {self._value}{key}{names}" + + +class Completion(ESQLBase): + """Implementation of the ``COMPLETION`` processing command. + + This class inherits from :class:`ESQLBase `, + to make it possible to chain all the commands that belong to an ES|QL query + in a single expression. + """ + + def __init__( + self, parent: ESQLBase, *prompt: ExpressionType, **named_prompt: ExpressionType + ): + if len(prompt) + len(named_prompt) > 1: + raise ValueError( + "this method requires either one positional or one keyword argument only" + ) + super().__init__(parent) + self._prompt = prompt + self._named_prompt = named_prompt + self._inference_id: Optional[str] = None + + def with_(self, inference_id: str) -> "Completion": + """Continuation of the `COMPLETION` command. + + :param inference_id: The ID of the inference endpoint to use for the task. The + inference endpoint must be configured with the completion + task type. + """ + self._inference_id = inference_id + return self + + def _render_internal(self) -> str: + if self._inference_id is None: + raise ValueError("The completion command requires an inference ID") + if self._named_prompt: + column = list(self._named_prompt.keys())[0] + prompt = list(self._named_prompt.values())[0] + return f"COMPLETION {column} = {prompt} WITH {self._inference_id}" + else: + return f"COMPLETION {self._prompt[0]} WITH {self._inference_id}" + + +class Dissect(ESQLBase): + """Implementation of the ``DISSECT`` processing command. + + This class inherits from :class:`ESQLBase `, + to make it possible to chain all the commands that belong to an ES|QL query + in a single expression. + """ + + def __init__(self, parent: ESQLBase, input: FieldType, pattern: str): + super().__init__(parent) + self._input = input + self._pattern = pattern + self._separator: Optional[str] = None + + def append_separator(self, separator: str) -> "Dissect": + """Continuation of the ``DISSECT`` command. + + :param separator: A string used as the separator between appended values, + when using the append modifier. + """ + self._separator = separator + return self + + def _render_internal(self) -> str: + sep = ( + "" if self._separator is None else f' APPEND_SEPARATOR="{self._separator}"' + ) + return f"DISSECT {self._input} {json.dumps(self._pattern)}{sep}" + + +class Drop(ESQLBase): + """Implementation of the ``DROP`` processing command. + + This class inherits from :class:`ESQLBase `, + to make it possible to chain all the commands that belong to an ES|QL query + in a single expression. + """ + + def __init__(self, parent: ESQLBase, *columns: FieldType): + super().__init__(parent) + self._columns = columns + + def _render_internal(self) -> str: + return f'DROP {", ".join([str(col) for col in self._columns])}' + + +class Enrich(ESQLBase): + """Implementation of the ``ENRICH`` processing command. + + This class inherits from :class:`ESQLBase `, + to make it possible to chain all the commands that belong to an ES|QL query + in a single expression. + """ + + def __init__(self, parent: ESQLBase, policy: str): + super().__init__(parent) + self._policy = policy + self._match_field: Optional[FieldType] = None + self._fields: Optional[Tuple[FieldType, ...]] = None + self._named_fields: Optional[Dict[str, FieldType]] = None + + def on(self, match_field: FieldType) -> "Enrich": + """Continuation of the ``ENRICH`` command. + + :param match_field: The match field. ``ENRICH`` uses its value to look for records + in the enrich index. If not specified, the match will be + performed on the column with the same name as the + `match_field` defined in the enrich policy. + """ + self._match_field = match_field + return self + + def with_(self, *fields: FieldType, **named_fields: FieldType) -> "Enrich": + """Continuation of the ``ENRICH`` command. + + :param fields: The enrich fields from the enrich index that are added to the result + as new columns, given as positional arguments. If a column with the + same name as the enrich field already exists, the existing column will + be replaced by the new column. If not specified, each of the enrich + fields defined in the policy is added. A column with the same name as + the enrich field will be dropped unless the enrich field is renamed. + :param named_fields: The enrich fields from the enrich index that are added to the + result as new columns, given as keyword arguments. The name of + the keyword arguments are used as column names. If a column has + the same name as the new name, it will be discarded. If a name + (new or original) occurs more than once, only the rightmost + duplicate creates a new column. + """ + if fields and named_fields: + raise ValueError( + "this method supports positional or keyword arguments but not both" + ) + self._fields = fields + self._named_fields = named_fields + return self + + def _render_internal(self) -> str: + on = "" if self._match_field is None else f" ON {self._match_field}" + with_ = "" + if self._named_fields: + with_ = f' WITH {", ".join([f"{name} = {field}" for name, field in self._named_fields.items()])}' + elif self._fields is not None: + with_ = f' WITH {", ".join([str(field) for field in self._fields])}' + return f"ENRICH {self._policy}{on}{with_}" + + +class Eval(ESQLBase): + """Implementation of the ``EVAL`` processing command. + + This class inherits from :class:`ESQLBase `, + to make it possible to chain all the commands that belong to an ES|QL query + in a single expression. + """ + + def __init__( + self, parent: ESQLBase, *columns: FieldType, **named_columns: FieldType + ): + if columns and named_columns: + raise ValueError( + "this method supports positional or keyword arguments but not both" + ) + super().__init__(parent) + self._columns = columns or named_columns + + def _render_internal(self) -> str: + if isinstance(self._columns, dict): + cols = ", ".join( + [f"{name} = {value}" for name, value in self._columns.items()] + ) + else: + cols = ", ".join([f"{col}" for col in self._columns]) + return f"EVAL {cols}" + + +class Fork(ESQLBase): + """Implementation of the ``FORK`` processing command. + + This class inherits from :class:`ESQLBase `, + to make it possible to chain all the commands that belong to an ES|QL query + in a single expression. + """ + + def __init__( + self, + parent: ESQLBase, + fork1: ESQLBase, + fork2: Optional[ESQLBase] = None, + fork3: Optional[ESQLBase] = None, + fork4: Optional[ESQLBase] = None, + fork5: Optional[ESQLBase] = None, + fork6: Optional[ESQLBase] = None, + fork7: Optional[ESQLBase] = None, + fork8: Optional[ESQLBase] = None, + ): + super().__init__(parent) + self._branches = [fork1, fork2, fork3, fork4, fork5, fork6, fork7, fork8] + + def _render_internal(self) -> str: + cmds = "" + for branch in self._branches: + if branch: + cmd = branch.render()[3:].replace("\n", " ") + if cmds == "": + cmds = f"( {cmd} )" + else: + cmds += f"\n ( {cmd} )" + return f"FORK {cmds}" + + +class Grok(ESQLBase): + """Implementation of the ``GROK`` processing command. + + This class inherits from :class:`ESQLBase `, + to make it possible to chain all the commands that belong to an ES|QL query + in a single expression. + """ + + def __init__(self, parent: ESQLBase, input: FieldType, pattern: str): + super().__init__(parent) + self._input = input + self._pattern = pattern + + def _render_internal(self) -> str: + return f"GROK {self._input} {json.dumps(self._pattern)}" + + +class Keep(ESQLBase): + """Implementation of the ``KEEP`` processing command. + + This class inherits from :class:`ESQLBase `, + to make it possible to chain all the commands that belong to an ES|QL query + in a single expression. + """ + + def __init__(self, parent: ESQLBase, *columns: FieldType): + super().__init__(parent) + self._columns = columns + + def _render_internal(self) -> str: + return f'KEEP {", ".join([f"{col}" for col in self._columns])}' + + +class Limit(ESQLBase): + """Implementation of the ``LIMIT`` processing command. + + This class inherits from :class:`ESQLBase `, + to make it possible to chain all the commands that belong to an ES|QL query + in a single expression. + """ + + def __init__(self, parent: ESQLBase, max_number_of_rows: int): + super().__init__(parent) + self._max_number_of_rows = max_number_of_rows + + def _render_internal(self) -> str: + return f"LIMIT {self._max_number_of_rows}" + + +class LookupJoin(ESQLBase): + """Implementation of the ``LOOKUP JOIN`` processing command. + + This class inherits from :class:`ESQLBase `, + to make it possible to chain all the commands that belong to an ES|QL query + in a single expression. + """ + + def __init__(self, parent: ESQLBase, lookup_index: IndexType): + super().__init__(parent) + self._lookup_index = lookup_index + self._field: Optional[FieldType] = None + + def on(self, field: FieldType) -> "LookupJoin": + """Continuation of the `LOOKUP_JOIN` command. + + :param field: The field to join on. This field must exist in both your current query + results and in the lookup index. If the field contains multi-valued + entries, those entries will not match anything (the added fields will + contain null for those rows). + """ + self._field = field + return self + + def _render_internal(self) -> str: + if self._field is None: + raise ValueError("Joins require a field to join on.") + index = ( + self._lookup_index + if isinstance(self._lookup_index, str) + else self._lookup_index._index._name + ) + return f"LOOKUP JOIN {index} ON {self._field}" + + +class MvExpand(ESQLBase): + """Implementation of the ``MV_EXPAND`` processing command. + + This class inherits from :class:`ESQLBase `, + to make it possible to chain all the commands that belong to an ES|QL query + in a single expression. + """ + + def __init__(self, parent: ESQLBase, column: FieldType): + super().__init__(parent) + self._column = column + + def _render_internal(self) -> str: + return f"MV_EXPAND {self._column}" + + +class Rename(ESQLBase): + """Implementation of the ``RENAME`` processing command. + + This class inherits from :class:`ESQLBase `, + to make it possible to chain all the commands that belong to an ES|QL query + in a single expression. + """ + + def __init__(self, parent: ESQLBase, **columns: FieldType): + super().__init__(parent) + self._columns = columns + + def _render_internal(self) -> str: + return f'RENAME {", ".join([f"{old_name} AS {new_name}" for old_name, new_name in self._columns.items()])}' + + +class Sample(ESQLBase): + """Implementation of the ``SAMPLE`` processing command. + + This class inherits from :class:`ESQLBase `, + to make it possible to chain all the commands that belong to an ES|QL query + in a single expression. + """ + + def __init__(self, parent: ESQLBase, probability: float): + super().__init__(parent) + self._probability = probability + + def _render_internal(self) -> str: + return f"SAMPLE {self._probability}" + + +class Sort(ESQLBase): + """Implementation of the ``SORT`` processing command. + + This class inherits from :class:`ESQLBase `, + to make it possible to chain all the commands that belong to an ES|QL query + in a single expression. + """ + + def __init__(self, parent: ESQLBase, *columns: FieldType): + super().__init__(parent) + self._columns = columns + + def _render_internal(self) -> str: + return f'SORT {", ".join([f"{col}" for col in self._columns])}' + + +class Stats(ESQLBase): + """Implementation of the ``STATS`` processing command. + + This class inherits from :class:`ESQLBase `, + to make it possible to chain all the commands that belong to an ES|QL query + in a single expression. + """ + + def __init__( + self, + parent: ESQLBase, + *expressions: ExpressionType, + **named_expressions: ExpressionType, + ): + if expressions and named_expressions: + raise ValueError( + "this method supports positional or keyword arguments but not both" + ) + super().__init__(parent) + self._expressions = expressions or named_expressions + self._grouping_expressions: Optional[Tuple[ExpressionType, ...]] = None + + def by(self, *grouping_expressions: ExpressionType) -> "Stats": + self._grouping_expressions = grouping_expressions + return self + + def _render_internal(self) -> str: + if isinstance(self._expressions, dict): + exprs = [f"{key} = {value}" for key, value in self._expressions.items()] + else: + exprs = [f"{expr}" for expr in self._expressions] + expression_separator = ",\n " + by = ( + "" + if self._grouping_expressions is None + else f'\n BY {", ".join([f"{expr}" for expr in self._grouping_expressions])}' + ) + return f'STATS {expression_separator.join([f"{expr}" for expr in exprs])}{by}' + + +class Where(ESQLBase): + """Implementation of the ``WHERE`` processing command. + + This class inherits from :class:`ESQLBase `, + to make it possible to chain all the commands that belong to an ES|QL query + in a single expression. + """ + + def __init__(self, parent: ESQLBase, *expressions: ExpressionType): + super().__init__(parent) + self._expressions = expressions + + def _render_internal(self) -> str: + return f'WHERE {" AND ".join([f"{expr}" for expr in self._expressions])}' + + +def and_(*expressions: InstrumentedExpression) -> "InstrumentedExpression": + """Combine two or more expressions with the AND operator.""" + return InstrumentedExpression(" AND ".join([f"({expr})" for expr in expressions])) + + +def or_(*expressions: InstrumentedExpression) -> "InstrumentedExpression": + """Combine two or more expressions with the OR operator.""" + return InstrumentedExpression(" OR ".join([f"({expr})" for expr in expressions])) + + +def not_(expression: InstrumentedExpression) -> "InstrumentedExpression": + """Negate an expression.""" + return InstrumentedExpression(f"NOT ({expression})") diff --git a/elasticsearch/esql/functions.py b/elasticsearch/esql/functions.py new file mode 100644 index 000000000..515e3ddfc --- /dev/null +++ b/elasticsearch/esql/functions.py @@ -0,0 +1,1738 @@ +# Licensed to Elasticsearch B.V. under one or more contributor +# license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright +# ownership. Elasticsearch B.V. 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. + +import json +from typing import Any + +from elasticsearch.dsl.document_base import InstrumentedExpression +from elasticsearch.esql.esql import ExpressionType + + +def _render(v: Any) -> str: + return json.dumps(v) if not isinstance(v, InstrumentedExpression) else str(v) + + +def abs(number: ExpressionType) -> InstrumentedExpression: + """Returns the absolute value. + + :param number: Numeric expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"ABS({_render(number)})") + + +def acos(number: ExpressionType) -> InstrumentedExpression: + """Returns the arccosine of `n` as an angle, expressed in radians. + + :param number: Number between -1 and 1. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"ACOS({_render(number)})") + + +def asin(number: ExpressionType) -> InstrumentedExpression: + """Returns the arcsine of the input numeric expression as an angle, + expressed in radians. + + :param number: Number between -1 and 1. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"ASIN({_render(number)})") + + +def atan(number: ExpressionType) -> InstrumentedExpression: + """Returns the arctangent of the input numeric expression as an angle, + expressed in radians. + + :param number: Numeric expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"ATAN({_render(number)})") + + +def atan2( + y_coordinate: ExpressionType, x_coordinate: ExpressionType +) -> InstrumentedExpression: + """The angle between the positive x-axis and the ray from the origin to the + point (x , y) in the Cartesian plane, expressed in radians. + + :param y_coordinate: y coordinate. If `null`, the function returns `null`. + :param x_coordinate: x coordinate. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"ATAN2({y_coordinate}, {x_coordinate})") + + +def avg(number: ExpressionType) -> InstrumentedExpression: + """The average of a numeric field. + + :param number: Expression that outputs values to average. + """ + return InstrumentedExpression(f"AVG({_render(number)})") + + +def avg_over_time(number: ExpressionType) -> InstrumentedExpression: + """The average over time of a numeric field. + + :param number: Expression that outputs values to average. + """ + return InstrumentedExpression(f"AVG_OVER_TIME({_render(number)})") + + +def bit_length(string: ExpressionType) -> InstrumentedExpression: + """Returns the bit length of a string. + + :param string: String expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"BIT_LENGTH({_render(string)})") + + +def bucket( + field: ExpressionType, + buckets: ExpressionType, + from_: ExpressionType, + to: ExpressionType, +) -> InstrumentedExpression: + """Creates groups of values - buckets - out of a datetime or numeric input. + The size of the buckets can either be provided directly, or chosen based on + a recommended count and values range. + + :param field: Numeric or date expression from which to derive buckets. + :param buckets: Target number of buckets, or desired bucket size if `from` + and `to` parameters are omitted. + :param from_: Start of the range. Can be a number, a date or a date expressed + as a string. + :param to: End of the range. Can be a number, a date or a date expressed as a string. + """ + return InstrumentedExpression( + f"BUCKET({_render(field)}, {_render(buckets)}, {from_}, {_render(to)})" + ) + + +def byte_length(string: ExpressionType) -> InstrumentedExpression: + """Returns the byte length of a string. + + :param string: String expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"BYTE_LENGTH({_render(string)})") + + +def case(*conditions: ExpressionType) -> InstrumentedExpression: + """Accepts pairs of conditions and values. The function returns the value + that belongs to the first condition that evaluates to `true`. If the + number of arguments is odd, the last argument is the default value which is + returned when no condition matches. If the number of arguments is even, and + no condition matches, the function returns `null`. + """ + return InstrumentedExpression( + f'CASE({", ".join([_render(c) for c in conditions])})' + ) + + +def categorize(field: ExpressionType) -> InstrumentedExpression: + """Groups text messages into categories of similarly formatted text values. + + :param field: Expression to categorize + """ + return InstrumentedExpression(f"CATEGORIZE({_render(field)})") + + +def cbrt(number: ExpressionType) -> InstrumentedExpression: + """Returns the cube root of a number. The input can be any numeric value, + the return value is always a double. Cube roots of infinities are null. + + :param number: Numeric expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"CBRT({_render(number)})") + + +def ceil(number: ExpressionType) -> InstrumentedExpression: + """Round a number up to the nearest integer. + + :param number: Numeric expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"CEIL({_render(number)})") + + +def cidr_match(ip: ExpressionType, block_x: ExpressionType) -> InstrumentedExpression: + """Returns true if the provided IP is contained in one of the provided CIDR blocks. + + :param ip: IP address of type `ip` (both IPv4 and IPv6 are supported). + :param block_x: CIDR block to test the IP against. + """ + return InstrumentedExpression(f"CIDR_MATCH({_render(ip)}, {block_x})") + + +def coalesce(first: ExpressionType, rest: ExpressionType) -> InstrumentedExpression: + """Returns the first of its arguments that is not null. If all arguments + are null, it returns `null`. + + :param first: Expression to evaluate. + :param rest: Other expression to evaluate. + """ + return InstrumentedExpression(f"COALESCE({_render(first)}, {_render(rest)})") + + +def concat(*strings: ExpressionType) -> InstrumentedExpression: + """Concatenates two or more strings.""" + return InstrumentedExpression( + f'CONCAT({", ".join([f"{_render(s)}" for s in strings])})' + ) + + +def cos(angle: ExpressionType) -> InstrumentedExpression: + """Returns the cosine of an angle. + + :param angle: An angle, in radians. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"COS({_render(angle)})") + + +def cosh(number: ExpressionType) -> InstrumentedExpression: + """Returns the hyperbolic cosine of a number. + + :param number: Numeric expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"COSH({_render(number)})") + + +def count(field: ExpressionType) -> InstrumentedExpression: + """Returns the total number (count) of input values. + + :param field: Expression that outputs values to be counted. If omitted, + equivalent to `COUNT(*)` (the number of rows). + """ + return InstrumentedExpression(f"COUNT({_render(field)})") + + +def count_distinct( + field: ExpressionType, precision: ExpressionType +) -> InstrumentedExpression: + """Returns the approximate number of distinct values. + + :param field: Column or literal for which to count the number of distinct values. + :param precision: Precision threshold. The maximum supported value is 40000. Thresholds + above this number will have the same effect as a threshold of 40000. + The default value is 3000. + """ + return InstrumentedExpression( + f"COUNT_DISTINCT({_render(field)}, {_render(precision)})" + ) + + +def count_distinct_over_time( + field: ExpressionType, precision: ExpressionType +) -> InstrumentedExpression: + """The count of distinct values over time for a field. + + :param field: + :param precision: Precision threshold. The maximum supported value is 40000. Thresholds + above this number will have the same effect as a threshold of 40000. The + default value is 3000. + """ + return InstrumentedExpression( + f"COUNT_DISTINCT_OVER_TIME({_render(field)}, {_render(precision)})" + ) + + +def count_over_time(field: ExpressionType) -> InstrumentedExpression: + """The count over time value of a field. + + :param field: + """ + return InstrumentedExpression(f"COUNT_OVER_TIME({_render(field)})") + + +def date_diff( + unit: ExpressionType, start_timestamp: ExpressionType, end_timestamp: ExpressionType +) -> InstrumentedExpression: + """Subtracts the `startTimestamp` from the `endTimestamp` and returns the + difference in multiples of `unit`. If `startTimestamp` is later than the + `endTimestamp`, negative values are returned. + + :param unit: Time difference unit + :param start_timestamp: A string representing a start timestamp + :param end_timestamp: A string representing an end timestamp + """ + return InstrumentedExpression( + f"DATE_DIFF({_render(unit)}, {start_timestamp}, {end_timestamp})" + ) + + +def date_extract( + date_part: ExpressionType, date: ExpressionType +) -> InstrumentedExpression: + """Extracts parts of a date, like year, month, day, hour. + + :param date_part: Part of the date to extract. Can be: + `aligned_day_of_week_in_month`, `aligned_day_of_week_in_year`, + `aligned_week_of_month`, `aligned_week_of_year`, `ampm_of_day`, + `clock_hour_of_ampm`, `clock_hour_of_day`, `day_of_month`, `day_of_week`, + `day_of_year`, `epoch_day`, `era`, `hour_of_ampm`, `hour_of_day`, + `instant_seconds`, `micro_of_day`, `micro_of_second`, `milli_of_day`, + `milli_of_second`, `minute_of_day`, `minute_of_hour`, `month_of_year`, + `nano_of_day`, `nano_of_second`, `offset_seconds`, `proleptic_month`, + `second_of_day`, `second_of_minute`, `year`, or `year_of_era`. If `null`, + the function returns `null`. + :param date: Date expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"DATE_EXTRACT({date_part}, {_render(date)})") + + +def date_format( + date: ExpressionType, + date_format: ExpressionType = None, +) -> InstrumentedExpression: + """Returns a string representation of a date, in the provided format. + + :param date_format: Date format (optional). If no format is specified, the + `yyyy-MM-dd'T'HH:mm:ss.SSSZ` format is used. If `null`, the + function returns `null`. + :param date: Date expression. If `null`, the function returns `null`. + """ + if date_format is not None: + return InstrumentedExpression( + f"DATE_FORMAT({json.dumps(date_format)}, {_render(date)})" + ) + else: + return InstrumentedExpression(f"DATE_FORMAT({_render(date)})") + + +def date_parse( + date_pattern: ExpressionType, date_string: ExpressionType +) -> InstrumentedExpression: + """Returns a date by parsing the second argument using the format specified + in the first argument. + + :param date_pattern: The date format. If `null`, the function returns `null`. + :param date_string: Date expression as a string. If `null` or an empty + string, the function returns `null`. + """ + return InstrumentedExpression(f"DATE_PARSE({date_pattern}, {date_string})") + + +def date_trunc( + interval: ExpressionType, date: ExpressionType +) -> InstrumentedExpression: + """Rounds down a date to the closest interval since epoch, which starts at `0001-01-01T00:00:00Z`. + + :param interval: Interval; expressed using the timespan literal syntax. + :param date: Date expression + """ + return InstrumentedExpression(f"DATE_TRUNC({_render(interval)}, {_render(date)})") + + +def e() -> InstrumentedExpression: + """Returns Euler’s number).""" + return InstrumentedExpression("E()") + + +def ends_with(str: ExpressionType, suffix: ExpressionType) -> InstrumentedExpression: + """Returns a boolean that indicates whether a keyword string ends with + another string. + + :param str: String expression. If `null`, the function returns `null`. + :param suffix: String expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"ENDS_WITH({_render(str)}, {_render(suffix)})") + + +def exp(number: ExpressionType) -> InstrumentedExpression: + """Returns the value of e raised to the power of the given number. + + :param number: Numeric expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"EXP({_render(number)})") + + +def first_over_time(field: ExpressionType) -> InstrumentedExpression: + """The earliest value of a field, where recency determined by the + `@timestamp` field. + + :param field: + """ + return InstrumentedExpression(f"FIRST_OVER_TIME({_render(field)})") + + +def floor(number: ExpressionType) -> InstrumentedExpression: + """Round a number down to the nearest integer. + + :param number: Numeric expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"FLOOR({_render(number)})") + + +def from_base64(string: ExpressionType) -> InstrumentedExpression: + """Decode a base64 string. + + :param string: A base64 string. + """ + return InstrumentedExpression(f"FROM_BASE64({_render(string)})") + + +def greatest(first: ExpressionType, rest: ExpressionType) -> InstrumentedExpression: + """Returns the maximum value from multiple columns. This is similar to + `MV_MAX` except it is intended to run on multiple columns at once. + + :param first: First of the columns to evaluate. + :param rest: The rest of the columns to evaluate. + """ + return InstrumentedExpression(f"GREATEST({_render(first)}, {_render(rest)})") + + +def hash(algorithm: ExpressionType, input: ExpressionType) -> InstrumentedExpression: + """Computes the hash of the input using various algorithms such as MD5, + SHA, SHA-224, SHA-256, SHA-384, SHA-512. + + :param algorithm: Hash algorithm to use. + :param input: Input to hash. + """ + return InstrumentedExpression(f"HASH({_render(algorithm)}, {_render(input)})") + + +def hypot(number1: ExpressionType, number2: ExpressionType) -> InstrumentedExpression: + """Returns the hypotenuse of two numbers. The input can be any numeric + values, the return value is always a double. Hypotenuses of infinities are null. + + :param number1: Numeric expression. If `null`, the function returns `null`. + :param number2: Numeric expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"HYPOT({number1}, {number2})") + + +def ip_prefix( + ip: ExpressionType, + prefix_length_v4: ExpressionType, + prefix_length_v6: ExpressionType, +) -> InstrumentedExpression: + """Truncates an IP to a given prefix length. + + :param ip: IP address of type `ip` (both IPv4 and IPv6 are supported). + :param prefix_length_v4: Prefix length for IPv4 addresses. + :param prefix_length_v6: Prefix length for IPv6 addresses. + """ + return InstrumentedExpression( + f"IP_PREFIX({_render(ip)}, {prefix_length_v4}, {prefix_length_v6})" + ) + + +def knn( + field: ExpressionType, query: ExpressionType, options: ExpressionType = None +) -> InstrumentedExpression: + """Finds the k nearest vectors to a query vector, as measured by a + similarity metric. knn function finds nearest vectors through approximate + search on indexed dense_vectors. + + :param field: Field that the query will target. + :param query: Vector value to find top nearest neighbours for. + :param options: (Optional) kNN additional options as function named parameters. + """ + if options is not None: + return InstrumentedExpression( + f"KNN({_render(field)}, {_render(query)}, {_render(options)})" + ) + else: + return InstrumentedExpression(f"KNN({_render(field)}, {_render(query)})") + + +def kql(query: ExpressionType) -> InstrumentedExpression: + """Performs a KQL query. Returns true if the provided KQL query string + matches the row. + + :param query: Query string in KQL query string format. + """ + return InstrumentedExpression(f"KQL({_render(query)})") + + +def last_over_time(field: ExpressionType) -> InstrumentedExpression: + """The latest value of a field, where recency determined by the + `@timestamp` field. + + :param field: + """ + return InstrumentedExpression(f"LAST_OVER_TIME({_render(field)})") + + +def least(first: ExpressionType, rest: ExpressionType) -> InstrumentedExpression: + """Returns the minimum value from multiple columns. This is similar to + `MV_MIN` except it is intended to run on multiple columns at once. + + :param first: First of the columns to evaluate. + :param rest: The rest of the columns to evaluate. + """ + return InstrumentedExpression(f"LEAST({_render(first)}, {_render(rest)})") + + +def left(string: ExpressionType, length: ExpressionType) -> InstrumentedExpression: + """Returns the substring that extracts *length* chars from *string* + starting from the left. + + :param string: The string from which to return a substring. + :param length: The number of characters to return. + """ + return InstrumentedExpression(f"LEFT({_render(string)}, {_render(length)})") + + +def length(string: ExpressionType) -> InstrumentedExpression: + """Returns the character length of a string. + + :param string: String expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"LENGTH({_render(string)})") + + +def locate( + string: ExpressionType, substring: ExpressionType, start: ExpressionType +) -> InstrumentedExpression: + """Returns an integer that indicates the position of a keyword substring + within another string. Returns `0` if the substring cannot be found. Note + that string positions start from `1`. + + :param string: An input string + :param substring: A substring to locate in the input string + :param start: The start index + """ + return InstrumentedExpression( + f"LOCATE({_render(string)}, {_render(substring)}, {_render(start)})" + ) + + +def log(base: ExpressionType, number: ExpressionType) -> InstrumentedExpression: + """Returns the logarithm of a value to a base. The input can be any numeric + value, the return value is always a double. Logs of zero, negative + numbers, and base of one return `null` as well as a warning. + + :param base: Base of logarithm. If `null`, the function returns `null`. If + not provided, this function returns the natural logarithm (base e) of a value. + :param number: Numeric expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"LOG({_render(base)}, {_render(number)})") + + +def log10(number: ExpressionType) -> InstrumentedExpression: + """Returns the logarithm of a value to base 10. The input can be any + numeric value, the return value is always a double. Logs of 0 and negative + numbers return `null` as well as a warning. + + :param number: Numeric expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"LOG10({_render(number)})") + + +def ltrim(string: ExpressionType) -> InstrumentedExpression: + """Removes leading whitespaces from a string. + + :param string: String expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"LTRIM({_render(string)})") + + +def match( + field: ExpressionType, query: ExpressionType, options: ExpressionType = None +) -> InstrumentedExpression: + """Use `MATCH` to perform a match query on the specified field. Using + `MATCH` is equivalent to using the `match` query in the Elasticsearch Query DSL. + + :param field: Field that the query will target. + :param query: Value to find in the provided field. + :param options: (Optional) Match additional options as function named parameters. + """ + if options is not None: + return InstrumentedExpression( + f"MATCH({_render(field)}, {_render(query)}, {_render(options)})" + ) + else: + return InstrumentedExpression(f"MATCH({_render(field)}, {_render(query)})") + + +def match_phrase( + field: ExpressionType, query: ExpressionType, options: ExpressionType = None +) -> InstrumentedExpression: + """Use `MATCH_PHRASE` to perform a `match_phrase` on the specified field. + Using `MATCH_PHRASE` is equivalent to using the `match_phrase` query in the + Elasticsearch Query DSL. + + :param field: Field that the query will target. + :param query: Value to find in the provided field. + :param options: (Optional) MatchPhrase additional options as function named parameters. + """ + if options is not None: + return InstrumentedExpression( + f"MATCH_PHRASE({_render(field)}, {_render(query)}, {_render(options)})" + ) + else: + return InstrumentedExpression( + f"MATCH_PHRASE({_render(field)}, {_render(query)})" + ) + + +def max(field: ExpressionType) -> InstrumentedExpression: + """The maximum value of a field. + + :param field: + """ + return InstrumentedExpression(f"MAX({_render(field)})") + + +def max_over_time(field: ExpressionType) -> InstrumentedExpression: + """The maximum over time value of a field. + + :param field: + """ + return InstrumentedExpression(f"MAX_OVER_TIME({_render(field)})") + + +def md5(input: ExpressionType) -> InstrumentedExpression: + """Computes the MD5 hash of the input. + + :param input: Input to hash. + """ + return InstrumentedExpression(f"MD5({_render(input)})") + + +def median(number: ExpressionType) -> InstrumentedExpression: + """The value that is greater than half of all values and less than half of + all values, also known as the 50% `PERCENTILE`. + + :param number: Expression that outputs values to calculate the median of. + """ + return InstrumentedExpression(f"MEDIAN({_render(number)})") + + +def median_absolute_deviation(number: ExpressionType) -> InstrumentedExpression: + """Returns the median absolute deviation, a measure of variability. It is a + robust statistic, meaning that it is useful for describing data that may + have outliers, or may not be normally distributed. For such data it can be + more descriptive than standard deviation. It is calculated as the median + of each data point’s deviation from the median of the entire sample. That + is, for a random variable `X`, the median absolute deviation is + `median(|median(X) - X|)`. + + :param number: + """ + return InstrumentedExpression(f"MEDIAN_ABSOLUTE_DEVIATION({_render(number)})") + + +def min(field: ExpressionType) -> InstrumentedExpression: + """The minimum value of a field. + + :param field: + """ + return InstrumentedExpression(f"MIN({_render(field)})") + + +def min_over_time(field: ExpressionType) -> InstrumentedExpression: + """The minimum over time value of a field. + + :param field: + """ + return InstrumentedExpression(f"MIN_OVER_TIME({_render(field)})") + + +def multi_match( + query: ExpressionType, fields: ExpressionType, options: ExpressionType = None +) -> InstrumentedExpression: + """Use `MULTI_MATCH` to perform a multi-match query on the specified field. + The multi_match query builds on the match query to allow multi-field queries. + + :param query: Value to find in the provided fields. + :param fields: Fields to use for matching + :param options: (Optional) Additional options for MultiMatch, passed as function + named parameters + """ + if options is not None: + return InstrumentedExpression( + f"MULTI_MATCH({_render(query)}, {_render(fields)}, {_render(options)})" + ) + else: + return InstrumentedExpression( + f"MULTI_MATCH({_render(query)}, {_render(fields)})" + ) + + +def mv_append(field1: ExpressionType, field2: ExpressionType) -> InstrumentedExpression: + """Concatenates values of two multi-value fields. + + :param field1: + :param field2: + """ + return InstrumentedExpression(f"MV_APPEND({field1}, {field2})") + + +def mv_avg(number: ExpressionType) -> InstrumentedExpression: + """Converts a multivalued field into a single valued field containing the + average of all of the values. + + :param number: Multivalue expression. + """ + return InstrumentedExpression(f"MV_AVG({_render(number)})") + + +def mv_concat(string: ExpressionType, delim: ExpressionType) -> InstrumentedExpression: + """Converts a multivalued string expression into a single valued column + containing the concatenation of all values separated by a delimiter. + + :param string: Multivalue expression. + :param delim: Delimiter. + """ + return InstrumentedExpression(f"MV_CONCAT({_render(string)}, {_render(delim)})") + + +def mv_count(field: ExpressionType) -> InstrumentedExpression: + """Converts a multivalued expression into a single valued column containing + a count of the number of values. + + :param field: Multivalue expression. + """ + return InstrumentedExpression(f"MV_COUNT({_render(field)})") + + +def mv_dedupe(field: ExpressionType) -> InstrumentedExpression: + """Remove duplicate values from a multivalued field. + + :param field: Multivalue expression. + """ + return InstrumentedExpression(f"MV_DEDUPE({_render(field)})") + + +def mv_first(field: ExpressionType) -> InstrumentedExpression: + """Converts a multivalued expression into a single valued column containing + the first value. This is most useful when reading from a function that + emits multivalued columns in a known order like `SPLIT`. + + :param field: Multivalue expression. + """ + return InstrumentedExpression(f"MV_FIRST({_render(field)})") + + +def mv_last(field: ExpressionType) -> InstrumentedExpression: + """Converts a multivalue expression into a single valued column containing + the last value. This is most useful when reading from a function that emits + multivalued columns in a known order like `SPLIT`. + + :param field: Multivalue expression. + """ + return InstrumentedExpression(f"MV_LAST({_render(field)})") + + +def mv_max(field: ExpressionType) -> InstrumentedExpression: + """Converts a multivalued expression into a single valued column containing + the maximum value. + + :param field: Multivalue expression. + """ + return InstrumentedExpression(f"MV_MAX({_render(field)})") + + +def mv_median(number: ExpressionType) -> InstrumentedExpression: + """Converts a multivalued field into a single valued field containing the + median value. + + :param number: Multivalue expression. + """ + return InstrumentedExpression(f"MV_MEDIAN({_render(number)})") + + +def mv_median_absolute_deviation(number: ExpressionType) -> InstrumentedExpression: + """Converts a multivalued field into a single valued field containing the + median absolute deviation. It is calculated as the median of each data + point’s deviation from the median of the entire sample. That is, for a + random variable `X`, the median absolute deviation is `median(|median(X) - X|)`. + + :param number: Multivalue expression. + """ + return InstrumentedExpression(f"MV_MEDIAN_ABSOLUTE_DEVIATION({_render(number)})") + + +def mv_min(field: ExpressionType) -> InstrumentedExpression: + """Converts a multivalued expression into a single valued column containing + the minimum value. + + :param field: Multivalue expression. + """ + return InstrumentedExpression(f"MV_MIN({_render(field)})") + + +def mv_percentile( + number: ExpressionType, percentile: ExpressionType +) -> InstrumentedExpression: + """Converts a multivalued field into a single valued field containing the + value at which a certain percentage of observed values occur. + + :param number: Multivalue expression. + :param percentile: The percentile to calculate. Must be a number between 0 + and 100. Numbers out of range will return a null instead. + """ + return InstrumentedExpression( + f"MV_PERCENTILE({_render(number)}, {_render(percentile)})" + ) + + +def mv_pseries_weighted_sum( + number: ExpressionType, p: ExpressionType +) -> InstrumentedExpression: + """Converts a multivalued expression into a single-valued column by + multiplying every element on the input list by its corresponding term in + P-Series and computing the sum. + + :param number: Multivalue expression. + :param p: It is a constant number that represents the *p* parameter in the + P-Series. It impacts every element’s contribution to the weighted sum. + """ + return InstrumentedExpression( + f"MV_PSERIES_WEIGHTED_SUM({_render(number)}, {_render(p)})" + ) + + +def mv_slice( + field: ExpressionType, start: ExpressionType, end: ExpressionType = None +) -> InstrumentedExpression: + """Returns a subset of the multivalued field using the start and end index + values. This is most useful when reading from a function that emits + multivalued columns in a known order like `SPLIT` or `MV_SORT`. + + :param field: Multivalue expression. If `null`, the function returns `null`. + :param start: Start position. If `null`, the function returns `null`. The + start argument can be negative. An index of -1 is used to specify + the last value in the list. + :param end: End position(included). Optional; if omitted, the position at + `start` is returned. The end argument can be negative. An index of -1 + is used to specify the last value in the list. + """ + if end is not None: + return InstrumentedExpression( + f"MV_SLICE({_render(field)}, {_render(start)}, {_render(end)})" + ) + else: + return InstrumentedExpression(f"MV_SLICE({_render(field)}, {_render(start)})") + + +def mv_sort(field: ExpressionType, order: ExpressionType) -> InstrumentedExpression: + """Sorts a multivalued field in lexicographical order. + + :param field: Multivalue expression. If `null`, the function returns `null`. + :param order: Sort order. The valid options are ASC and DESC, the default is ASC. + """ + return InstrumentedExpression(f"MV_SORT({_render(field)}, {_render(order)})") + + +def mv_sum(number: ExpressionType) -> InstrumentedExpression: + """Converts a multivalued field into a single valued field containing the + sum of all of the values. + + :param number: Multivalue expression. + """ + return InstrumentedExpression(f"MV_SUM({_render(number)})") + + +def mv_zip( + string1: ExpressionType, string2: ExpressionType, delim: ExpressionType = None +) -> InstrumentedExpression: + """Combines the values from two multivalued fields with a delimiter that + joins them together. + + :param string1: Multivalue expression. + :param string2: Multivalue expression. + :param delim: Delimiter. Optional; if omitted, `,` is used as a default delimiter. + """ + if delim is not None: + return InstrumentedExpression(f"MV_ZIP({string1}, {string2}, {_render(delim)})") + else: + return InstrumentedExpression(f"MV_ZIP({string1}, {string2})") + + +def now() -> InstrumentedExpression: + """Returns current date and time.""" + return InstrumentedExpression("NOW()") + + +def percentile( + number: ExpressionType, percentile: ExpressionType +) -> InstrumentedExpression: + """Returns the value at which a certain percentage of observed values + occur. For example, the 95th percentile is the value which is greater than + 95% of the observed values and the 50th percentile is the `MEDIAN`. + + :param number: + :param percentile: + """ + return InstrumentedExpression( + f"PERCENTILE({_render(number)}, {_render(percentile)})" + ) + + +def pi() -> InstrumentedExpression: + """Returns Pi, the ratio of a circle’s circumference to its diameter.""" + return InstrumentedExpression("PI()") + + +def pow(base: ExpressionType, exponent: ExpressionType) -> InstrumentedExpression: + """Returns the value of `base` raised to the power of `exponent`. + + :param base: Numeric expression for the base. If `null`, the function returns `null`. + :param exponent: Numeric expression for the exponent. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"POW({_render(base)}, {_render(exponent)})") + + +def qstr( + query: ExpressionType, options: ExpressionType = None +) -> InstrumentedExpression: + """Performs a query string query. Returns true if the provided query string + matches the row. + + :param query: Query string in Lucene query string format. + :param options: (Optional) Additional options for Query String as function named + parameters. + """ + if options is not None: + return InstrumentedExpression(f"QSTR({_render(query)}, {_render(options)})") + else: + return InstrumentedExpression(f"QSTR({_render(query)})") + + +def rate(field: ExpressionType) -> InstrumentedExpression: + """The rate of a counter field. + + :param field: + """ + return InstrumentedExpression(f"RATE({_render(field)})") + + +def repeat(string: ExpressionType, number: ExpressionType) -> InstrumentedExpression: + """Returns a string constructed by concatenating `string` with itself the + specified `number` of times. + + :param string: String expression. + :param number: Number times to repeat. + """ + return InstrumentedExpression(f"REPEAT({_render(string)}, {_render(number)})") + + +def replace( + string: ExpressionType, regex: ExpressionType, new_string: ExpressionType +) -> InstrumentedExpression: + """The function substitutes in the string `str` any match of the regular + expression `regex` with the replacement string `newStr`. + + :param string: String expression. + :param regex: Regular expression. + :param new_string: Replacement string. + """ + return InstrumentedExpression( + f"REPLACE({_render(string)}, {_render(regex)}, {new_string})" + ) + + +def reverse(str: ExpressionType) -> InstrumentedExpression: + """Returns a new string representing the input string in reverse order. + + :param str: String expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"REVERSE({_render(str)})") + + +def right(string: ExpressionType, length: ExpressionType) -> InstrumentedExpression: + """Return the substring that extracts *length* chars from *str* starting + from the right. + + :param string: The string from which to returns a substring. + :param length: The number of characters to return. + """ + return InstrumentedExpression(f"RIGHT({_render(string)}, {_render(length)})") + + +def round( + number: ExpressionType, decimals: ExpressionType = None +) -> InstrumentedExpression: + """Rounds a number to the specified number of decimal places. Defaults to + 0, which returns the nearest integer. If the precision is a negative + number, rounds to the number of digits left of the decimal point. + + :param number: The numeric value to round. If `null`, the function returns `null`. + :param decimals: The number of decimal places to round to. Defaults to 0. If + `null`, the function returns `null`. + """ + if decimals is not None: + return InstrumentedExpression(f"ROUND({_render(number)}, {_render(decimals)})") + else: + return InstrumentedExpression(f"ROUND({_render(number)})") + + +def round_to(field: ExpressionType, points: ExpressionType) -> InstrumentedExpression: + """Rounds down to one of a list of fixed points. + + :param field: The numeric value to round. If `null`, the function returns `null`. + :param points: Remaining rounding points. Must be constants. + """ + return InstrumentedExpression(f"ROUND_TO({_render(field)}, {_render(points)})") + + +def rtrim(string: ExpressionType) -> InstrumentedExpression: + """Removes trailing whitespaces from a string. + + :param string: String expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"RTRIM({_render(string)})") + + +def sample(field: ExpressionType, limit: ExpressionType) -> InstrumentedExpression: + """Collects sample values for a field. + + :param field: The field to collect sample values for. + :param limit: The maximum number of values to collect. + """ + return InstrumentedExpression(f"SAMPLE({_render(field)}, {_render(limit)})") + + +def scalb(d: ExpressionType, scale_factor: ExpressionType) -> InstrumentedExpression: + """Returns the result of `d * 2 ^ scaleFactor`, Similar to Java's `scalb` + function. Result is rounded as if performed by a single correctly rounded + floating-point multiply to a member of the double value set. + + :param d: Numeric expression for the multiplier. If `null`, the function + returns `null`. + :param scale_factor: Numeric expression for the scale factor. If `null`, the + function returns `null`. + """ + return InstrumentedExpression(f"SCALB({_render(d)}, {scale_factor})") + + +def sha1(input: ExpressionType) -> InstrumentedExpression: + """Computes the SHA1 hash of the input. + + :param input: Input to hash. + """ + return InstrumentedExpression(f"SHA1({_render(input)})") + + +def sha256(input: ExpressionType) -> InstrumentedExpression: + """Computes the SHA256 hash of the input. + + :param input: Input to hash. + """ + return InstrumentedExpression(f"SHA256({_render(input)})") + + +def signum(number: ExpressionType) -> InstrumentedExpression: + """Returns the sign of the given number. It returns `-1` for negative + numbers, `0` for `0` and `1` for positive numbers. + + :param number: Numeric expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"SIGNUM({_render(number)})") + + +def sin(angle: ExpressionType) -> InstrumentedExpression: + """Returns the sine of an angle. + + :param angle: An angle, in radians. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"SIN({_render(angle)})") + + +def sinh(number: ExpressionType) -> InstrumentedExpression: + """Returns the hyperbolic sine of a number. + + :param number: Numeric expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"SINH({_render(number)})") + + +def space(number: ExpressionType) -> InstrumentedExpression: + """Returns a string made of `number` spaces. + + :param number: Number of spaces in result. + """ + return InstrumentedExpression(f"SPACE({_render(number)})") + + +def split(string: ExpressionType, delim: ExpressionType) -> InstrumentedExpression: + """Split a single valued string into multiple strings. + + :param string: String expression. If `null`, the function returns `null`. + :param delim: Delimiter. Only single byte delimiters are currently supported. + """ + return InstrumentedExpression(f"SPLIT({_render(string)}, {_render(delim)})") + + +def sqrt(number: ExpressionType) -> InstrumentedExpression: + """Returns the square root of a number. The input can be any numeric value, + the return value is always a double. Square roots of negative numbers and + infinities are null. + + :param number: Numeric expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"SQRT({_render(number)})") + + +def starts_with(str: ExpressionType, prefix: ExpressionType) -> InstrumentedExpression: + """Returns a boolean that indicates whether a keyword string starts with + another string. + + :param str: String expression. If `null`, the function returns `null`. + :param prefix: String expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"STARTS_WITH({_render(str)}, {_render(prefix)})") + + +def std_dev(number: ExpressionType) -> InstrumentedExpression: + """The population standard deviation of a numeric field. + + :param number: + """ + return InstrumentedExpression(f"STD_DEV({_render(number)})") + + +def st_centroid_agg(field: ExpressionType) -> InstrumentedExpression: + """Calculate the spatial centroid over a field with spatial point geometry type. + + :param field: + """ + return InstrumentedExpression(f"ST_CENTROID_AGG({_render(field)})") + + +def st_contains( + geom_a: ExpressionType, geom_b: ExpressionType +) -> InstrumentedExpression: + """Returns whether the first geometry contains the second geometry. This is + the inverse of the ST_WITHIN function. + + :param geom_a: Expression of type `geo_point`, `cartesian_point`, + `geo_shape` or `cartesian_shape`. If `null`, the function returns + `null`. + :param geom_b: Expression of type `geo_point`, `cartesian_point`, `geo_shape` + or `cartesian_shape`. If `null`, the function returns `null`. The + second parameter must also have the same coordinate system as the + first. This means it is not possible to combine `geo_*` and + `cartesian_*` parameters. + """ + return InstrumentedExpression(f"ST_CONTAINS({geom_a}, {geom_b})") + + +def st_disjoint( + geom_a: ExpressionType, geom_b: ExpressionType +) -> InstrumentedExpression: + """Returns whether the two geometries or geometry columns are disjoint. + This is the inverse of the ST_INTERSECTS function. In mathematical terms: + ST_Disjoint(A, B) ⇔ A ⋂ B = ∅ + + :param geom_a: Expression of type `geo_point`, `cartesian_point`, + `geo_shape` or `cartesian_shape`. If `null`, the function returns + `null`. + :param geom_b: Expression of type `geo_point`, `cartesian_point`, `geo_shape` + or `cartesian_shape`. If `null`, the function returns `null`. The + second parameter must also have the same coordinate system as the + first. This means it is not possible to combine `geo_*` and + `cartesian_*` parameters. + """ + return InstrumentedExpression(f"ST_DISJOINT({geom_a}, {geom_b})") + + +def st_distance( + geom_a: ExpressionType, geom_b: ExpressionType +) -> InstrumentedExpression: + """Computes the distance between two points. For cartesian geometries, this + is the pythagorean distance in the same units as the original coordinates. + For geographic geometries, this is the circular distance along the great + circle in meters. + + :param geom_a: Expression of type `geo_point` or `cartesian_point`. If + `null`, the function returns `null`. + :param geom_b: Expression of type `geo_point` or `cartesian_point`. If + `null`, the function returns `null`. The second parameter must + also have the same coordinate system as the first. This means it + is not possible to combine `geo_point` and `cartesian_point` parameters. + """ + return InstrumentedExpression(f"ST_DISTANCE({geom_a}, {geom_b})") + + +def st_envelope(geometry: ExpressionType) -> InstrumentedExpression: + """Determines the minimum bounding box of the supplied geometry. + + :param geometry: Expression of type `geo_point`, `geo_shape`, + `cartesian_point` or `cartesian_shape`. If `null`, the function + returns `null`. + """ + return InstrumentedExpression(f"ST_ENVELOPE({_render(geometry)})") + + +def st_extent_agg(field: ExpressionType) -> InstrumentedExpression: + """Calculate the spatial extent over a field with geometry type. Returns a + bounding box for all values of the field. + + :param field: + """ + return InstrumentedExpression(f"ST_EXTENT_AGG({_render(field)})") + + +def st_geohash( + geometry: ExpressionType, precision: ExpressionType, bounds: ExpressionType = None +) -> InstrumentedExpression: + """Calculates the `geohash` of the supplied geo_point at the specified + precision. The result is long encoded. Use ST_GEOHASH_TO_STRING to convert + the result to a string. These functions are related to the `geo_grid` + query and the `geohash_grid` aggregation. + + :param geometry: Expression of type `geo_point`. If `null`, the function + returns `null`. + :param precision: Expression of type `integer`. If `null`, the function + returns `null`. Valid values are between 1 and 12. + :param bounds: Optional bounds to filter the grid tiles, a `geo_shape` of + type `BBOX`. Use `ST_ENVELOPE` if the `geo_shape` is of any + other type. + """ + if bounds is not None: + return InstrumentedExpression( + f"ST_GEOHASH({_render(geometry)}, {_render(precision)}, {_render(bounds)})" + ) + else: + return InstrumentedExpression( + f"ST_GEOHASH({_render(geometry)}, {_render(precision)})" + ) + + +def st_geohash_to_long(grid_id: ExpressionType) -> InstrumentedExpression: + """Converts an input value representing a geohash grid-ID in string format + into a long. + + :param grid_id: Input geohash grid-id. The input can be a single- or + multi-valued column or an expression. + """ + return InstrumentedExpression(f"ST_GEOHASH_TO_LONG({grid_id})") + + +def st_geohash_to_string(grid_id: ExpressionType) -> InstrumentedExpression: + """Converts an input value representing a geohash grid-ID in long format + into a string. + + :param grid_id: Input geohash grid-id. The input can be a single- or + multi-valued column or an expression. + """ + return InstrumentedExpression(f"ST_GEOHASH_TO_STRING({grid_id})") + + +def st_geohex( + geometry: ExpressionType, precision: ExpressionType, bounds: ExpressionType = None +) -> InstrumentedExpression: + """Calculates the `geohex`, the H3 cell-id, of the supplied geo_point at + the specified precision. The result is long encoded. Use + ST_GEOHEX_TO_STRING to convert the result to a string. These functions are + related to the `geo_grid` query and the `geohex_grid` aggregation. + + :param geometry: Expression of type `geo_point`. If `null`, the function + returns `null`. + :param precision: Expression of type `integer`. If `null`, the function + returns `null`. Valid values are between 0 and 15. + :param bounds: Optional bounds to filter the grid tiles, a `geo_shape` of + type `BBOX`. Use `ST_ENVELOPE` if the `geo_shape` + is of any other type. + """ + if bounds is not None: + return InstrumentedExpression( + f"ST_GEOHEX({_render(geometry)}, {_render(precision)}, {_render(bounds)})" + ) + else: + return InstrumentedExpression( + f"ST_GEOHEX({_render(geometry)}, {_render(precision)})" + ) + + +def st_geohex_to_long(grid_id: ExpressionType) -> InstrumentedExpression: + """Converts an input value representing a geohex grid-ID in string format + into a long. + + :param grid_id: Input geohex grid-id. The input can be a single- or + multi-valued column or an expression. + """ + return InstrumentedExpression(f"ST_GEOHEX_TO_LONG({grid_id})") + + +def st_geohex_to_string(grid_id: ExpressionType) -> InstrumentedExpression: + """Converts an input value representing a Geohex grid-ID in long format + into a string. + + :param grid_id: Input Geohex grid-id. The input can be a single- or + multi-valued column or an expression. + """ + return InstrumentedExpression(f"ST_GEOHEX_TO_STRING({grid_id})") + + +def st_geotile( + geometry: ExpressionType, precision: ExpressionType, bounds: ExpressionType = None +) -> InstrumentedExpression: + """Calculates the `geotile` of the supplied geo_point at the specified + precision. The result is long encoded. Use ST_GEOTILE_TO_STRING to convert + the result to a string. These functions are related to the `geo_grid` + query and the `geotile_grid` aggregation. + + :param geometry: Expression of type `geo_point`. If `null`, the function + returns `null`. + :param precision: Expression of type `integer`. If `null`, the function + returns `null`. Valid values are between 0 and 29. + :param bounds: Optional bounds to filter the grid tiles, a `geo_shape` of + type `BBOX`. Use `ST_ENVELOPE` if the `geo_shape` is of any + other type. + """ + if bounds is not None: + return InstrumentedExpression( + f"ST_GEOTILE({_render(geometry)}, {_render(precision)}, {_render(bounds)})" + ) + else: + return InstrumentedExpression( + f"ST_GEOTILE({_render(geometry)}, {_render(precision)})" + ) + + +def st_geotile_to_long(grid_id: ExpressionType) -> InstrumentedExpression: + """Converts an input value representing a geotile grid-ID in string format + into a long. + + :param grid_id: Input geotile grid-id. The input can be a single- or + multi-valued column or an expression. + """ + return InstrumentedExpression(f"ST_GEOTILE_TO_LONG({grid_id})") + + +def st_geotile_to_string(grid_id: ExpressionType) -> InstrumentedExpression: + """Converts an input value representing a geotile grid-ID in long format + into a string. + + :param grid_id: Input geotile grid-id. The input can be a single- or + multi-valued column or an expression. + """ + return InstrumentedExpression(f"ST_GEOTILE_TO_STRING({grid_id})") + + +def st_intersects( + geom_a: ExpressionType, geom_b: ExpressionType +) -> InstrumentedExpression: + """Returns true if two geometries intersect. They intersect if they have + any point in common, including their interior points (points along lines or + within polygons). This is the inverse of the ST_DISJOINT function. In + mathematical terms: ST_Intersects(A, B) ⇔ A ⋂ B ≠ ∅ + + :param geom_a: Expression of type `geo_point`, `cartesian_point`, + `geo_shape` or `cartesian_shape`. If `null`, the function returns + `null`. + :param geom_b: Expression of type `geo_point`, `cartesian_point`, `geo_shape` + or `cartesian_shape`. If `null`, the function returns `null`. The + second parameter must also have the same coordinate system as the + first. This means it is not possible to combine `geo_*` and + `cartesian_*` parameters. + """ + return InstrumentedExpression(f"ST_INTERSECTS({geom_a}, {geom_b})") + + +def st_within(geom_a: ExpressionType, geom_b: ExpressionType) -> InstrumentedExpression: + """Returns whether the first geometry is within the second geometry. This + is the inverse of the ST_CONTAINS function. + + :param geom_a: Expression of type `geo_point`, `cartesian_point`, + `geo_shape` or `cartesian_shape`. If `null`, the function returns + `null`. + :param geom_b: Expression of type `geo_point`, `cartesian_point`, `geo_shape` + or `cartesian_shape`. If `null`, the function returns `null`. The + second parameter must also have the same coordinate system as the + first. This means it is not possible to combine `geo_*` and + `cartesian_*` parameters. + """ + return InstrumentedExpression(f"ST_WITHIN({geom_a}, {geom_b})") + + +def st_x(point: ExpressionType) -> InstrumentedExpression: + """Extracts the `x` coordinate from the supplied point. If the points is of + type `geo_point` this is equivalent to extracting the `longitude` value. + + :param point: Expression of type `geo_point` or `cartesian_point`. If + `null`, the function returns `null`. + """ + return InstrumentedExpression(f"ST_X({_render(point)})") + + +def st_xmax(point: ExpressionType) -> InstrumentedExpression: + """Extracts the maximum value of the `x` coordinates from the supplied + geometry. If the geometry is of type `geo_point` or `geo_shape` this is + equivalent to extracting the maximum `longitude` value. + + :param point: Expression of type `geo_point`, `geo_shape`, `cartesian_point` + or `cartesian_shape`. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"ST_XMAX({_render(point)})") + + +def st_xmin(point: ExpressionType) -> InstrumentedExpression: + """Extracts the minimum value of the `x` coordinates from the supplied + geometry. If the geometry is of type `geo_point` or `geo_shape` this is + equivalent to extracting the minimum `longitude` value. + + :param point: Expression of type `geo_point`, `geo_shape`, `cartesian_point` + or `cartesian_shape`. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"ST_XMIN({_render(point)})") + + +def st_y(point: ExpressionType) -> InstrumentedExpression: + """Extracts the `y` coordinate from the supplied point. If the points is of + type `geo_point` this is equivalent to extracting the `latitude` value. + + :param point: Expression of type `geo_point` or `cartesian_point`. If + `null`, the function returns `null`. + """ + return InstrumentedExpression(f"ST_Y({_render(point)})") + + +def st_ymax(point: ExpressionType) -> InstrumentedExpression: + """Extracts the maximum value of the `y` coordinates from the supplied + geometry. If the geometry is of type `geo_point` or `geo_shape` this is + equivalent to extracting the maximum `latitude` value. + + :param point: Expression of type `geo_point`, `geo_shape`, `cartesian_point` + or `cartesian_shape`. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"ST_YMAX({_render(point)})") + + +def st_ymin(point: ExpressionType) -> InstrumentedExpression: + """Extracts the minimum value of the `y` coordinates from the supplied + geometry. If the geometry is of type `geo_point` or `geo_shape` this is + equivalent to extracting the minimum `latitude` value. + + :param point: Expression of type `geo_point`, `geo_shape`, `cartesian_point` + or `cartesian_shape`. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"ST_YMIN({_render(point)})") + + +def substring( + string: ExpressionType, start: ExpressionType, length: ExpressionType = None +) -> InstrumentedExpression: + """Returns a substring of a string, specified by a start position and an + optional length. + + :param string: String expression. If `null`, the function returns `null`. + :param start: Start position. + :param length: Length of the substring from the start position. Optional; if + omitted, all positions after `start` are returned. + """ + if length is not None: + return InstrumentedExpression( + f"SUBSTRING({_render(string)}, {_render(start)}, {_render(length)})" + ) + else: + return InstrumentedExpression(f"SUBSTRING({_render(string)}, {_render(start)})") + + +def sum(number: ExpressionType) -> InstrumentedExpression: + """The sum of a numeric expression. + + :param number: + """ + return InstrumentedExpression(f"SUM({_render(number)})") + + +def tan(angle: ExpressionType) -> InstrumentedExpression: + """Returns the tangent of an angle. + + :param angle: An angle, in radians. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"TAN({_render(angle)})") + + +def tanh(number: ExpressionType) -> InstrumentedExpression: + """Returns the hyperbolic tangent of a number. + + :param number: Numeric expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"TANH({_render(number)})") + + +def tau() -> InstrumentedExpression: + """Returns the ratio of a circle’s circumference to its radius.""" + return InstrumentedExpression("TAU()") + + +def term(field: ExpressionType, query: ExpressionType) -> InstrumentedExpression: + """Performs a Term query on the specified field. Returns true if the + provided term matches the row. + + :param field: Field that the query will target. + :param query: Term you wish to find in the provided field. + """ + return InstrumentedExpression(f"TERM({_render(field)}, {_render(query)})") + + +def top( + field: ExpressionType, limit: ExpressionType, order: ExpressionType +) -> InstrumentedExpression: + """Collects the top values for a field. Includes repeated values. + + :param field: The field to collect the top values for. + :param limit: The maximum number of values to collect. + :param order: The order to calculate the top values. Either `asc` or `desc`. + """ + return InstrumentedExpression( + f"TOP({_render(field)}, {_render(limit)}, {_render(order)})" + ) + + +def to_aggregate_metric_double(number: ExpressionType) -> InstrumentedExpression: + """Encode a numeric to an aggregate_metric_double. + + :param number: Input value. The input can be a single- or multi-valued + column or an expression. + """ + return InstrumentedExpression(f"TO_AGGREGATE_METRIC_DOUBLE({_render(number)})") + + +def to_base64(string: ExpressionType) -> InstrumentedExpression: + """Encode a string to a base64 string. + + :param string: A string. + """ + return InstrumentedExpression(f"TO_BASE64({_render(string)})") + + +def to_boolean(field: ExpressionType) -> InstrumentedExpression: + """Converts an input value to a boolean value. A string value of `true` + will be case-insensitive converted to the Boolean `true`. For anything + else, including the empty string, the function will return `false`. The + numerical value of `0` will be converted to `false`, anything else will be + converted to `true`. + + :param field: Input value. The input can be a single- or multi-valued column + or an expression. + """ + return InstrumentedExpression(f"TO_BOOLEAN({_render(field)})") + + +def to_cartesianpoint(field: ExpressionType) -> InstrumentedExpression: + """Converts an input value to a `cartesian_point` value. A string will only + be successfully converted if it respects the WKT Point format. + + :param field: Input value. The input can be a single- or multi-valued column + or an expression. + """ + return InstrumentedExpression(f"TO_CARTESIANPOINT({_render(field)})") + + +def to_cartesianshape(field: ExpressionType) -> InstrumentedExpression: + """Converts an input value to a `cartesian_shape` value. A string will only + be successfully converted if it respects the WKT format. + + :param field: Input value. The input can be a single- or multi-valued column + or an expression. + """ + return InstrumentedExpression(f"TO_CARTESIANSHAPE({_render(field)})") + + +def to_dateperiod(field: ExpressionType) -> InstrumentedExpression: + """Converts an input value into a `date_period` value. + + :param field: Input value. The input is a valid constant date period expression. + """ + return InstrumentedExpression(f"TO_DATEPERIOD({_render(field)})") + + +def to_datetime(field: ExpressionType) -> InstrumentedExpression: + """Converts an input value to a date value. A string will only be + successfully converted if it’s respecting the format + `yyyy-MM-dd'T'HH:mm:ss.SSS'Z'`. To convert dates in other formats, use `DATE_PARSE`. + + :param field: Input value. The input can be a single- or multi-valued column + or an expression. + """ + return InstrumentedExpression(f"TO_DATETIME({_render(field)})") + + +def to_date_nanos(field: ExpressionType) -> InstrumentedExpression: + """Converts an input to a nanosecond-resolution date value (aka date_nanos). + + :param field: Input value. The input can be a single- or multi-valued column + or an expression. + """ + return InstrumentedExpression(f"TO_DATE_NANOS({_render(field)})") + + +def to_degrees(number: ExpressionType) -> InstrumentedExpression: + """Converts a number in radians to degrees). + + :param number: Input value. The input can be a single- or multi-valued + column or an expression. + """ + return InstrumentedExpression(f"TO_DEGREES({_render(number)})") + + +def to_double(field: ExpressionType) -> InstrumentedExpression: + """Converts an input value to a double value. If the input parameter is of + a date type, its value will be interpreted as milliseconds since the Unix + epoch, converted to double. Boolean `true` will be converted to double + `1.0`, `false` to `0.0`. + + :param field: Input value. The input can be a single- or multi-valued column + or an expression. + """ + return InstrumentedExpression(f"TO_DOUBLE({_render(field)})") + + +def to_geopoint(field: ExpressionType) -> InstrumentedExpression: + """Converts an input value to a `geo_point` value. A string will only be + successfully converted if it respects the WKT Point format. + + :param field: Input value. The input can be a single- or multi-valued column + or an expression. + """ + return InstrumentedExpression(f"TO_GEOPOINT({_render(field)})") + + +def to_geoshape(field: ExpressionType) -> InstrumentedExpression: + """Converts an input value to a `geo_shape` value. A string will only be + successfully converted if it respects the WKT format. + + :param field: Input value. The input can be a single- or multi-valued column + or an expression. + """ + return InstrumentedExpression(f"TO_GEOSHAPE({_render(field)})") + + +def to_integer(field: ExpressionType) -> InstrumentedExpression: + """Converts an input value to an integer value. If the input parameter is + of a date type, its value will be interpreted as milliseconds since the + Unix epoch, converted to integer. Boolean `true` will be converted to + integer `1`, `false` to `0`. + + :param field: Input value. The input can be a single- or multi-valued column + or an expression. + """ + return InstrumentedExpression(f"TO_INTEGER({_render(field)})") + + +def to_ip( + field: ExpressionType, options: ExpressionType = None +) -> InstrumentedExpression: + """Converts an input string to an IP value. + + :param field: Input value. The input can be a single- or multi-valued column + or an expression. + :param options: (Optional) Additional options. + """ + if options is not None: + return InstrumentedExpression(f"TO_IP({_render(field)}, {_render(options)})") + else: + return InstrumentedExpression(f"TO_IP({_render(field)})") + + +def to_long(field: ExpressionType) -> InstrumentedExpression: + """Converts an input value to a long value. If the input parameter is of a + date type, its value will be interpreted as milliseconds since the Unix + epoch, converted to long. Boolean `true` will be converted to long `1`, + `false` to `0`. + + :param field: Input value. The input can be a single- or multi-valued column + or an expression. + """ + return InstrumentedExpression(f"TO_LONG({_render(field)})") + + +def to_lower(str: ExpressionType) -> InstrumentedExpression: + """Returns a new string representing the input string converted to lower case. + + :param str: String expression. If `null`, the function returns `null`. The + input can be a single-valued column or expression, or a multi-valued + column or expression. + """ + return InstrumentedExpression(f"TO_LOWER({_render(str)})") + + +def to_radians(number: ExpressionType) -> InstrumentedExpression: + """Converts a number in degrees) to radians. + + :param number: Input value. The input can be a single- or multi-valued + column or an expression. + """ + return InstrumentedExpression(f"TO_RADIANS({_render(number)})") + + +def to_string(field: ExpressionType) -> InstrumentedExpression: + """Converts an input value into a string. + + :param field: Input value. The input can be a single- or multi-valued column + or an expression. + """ + return InstrumentedExpression(f"TO_STRING({_render(field)})") + + +def to_timeduration(field: ExpressionType) -> InstrumentedExpression: + """Converts an input value into a `time_duration` value. + + :param field: Input value. The input is a valid constant time duration expression. + """ + return InstrumentedExpression(f"TO_TIMEDURATION({_render(field)})") + + +def to_unsigned_long(field: ExpressionType) -> InstrumentedExpression: + """Converts an input value to an unsigned long value. If the input + parameter is of a date type, its value will be interpreted as milliseconds + since the Unix epoch, converted to unsigned long. Boolean `true` will be + converted to unsigned long `1`, `false` to `0`. + + :param field: Input value. The input can be a single- or multi-valued column + or an expression. + """ + return InstrumentedExpression(f"TO_UNSIGNED_LONG({_render(field)})") + + +def to_upper(str: ExpressionType) -> InstrumentedExpression: + """Returns a new string representing the input string converted to upper case. + + :param str: String expression. If `null`, the function returns `null`. The + input can be a single-valued column or expression, or a multi-valued + column or expression. + """ + return InstrumentedExpression(f"TO_UPPER({_render(str)})") + + +def to_version(field: ExpressionType) -> InstrumentedExpression: + """Converts an input string to a version value. + + :param field: Input value. The input can be a single- or multi-valued column + or an expression. + """ + return InstrumentedExpression(f"TO_VERSION({_render(field)})") + + +def trim(string: ExpressionType) -> InstrumentedExpression: + """Removes leading and trailing whitespaces from a string. + + :param string: String expression. If `null`, the function returns `null`. + """ + return InstrumentedExpression(f"TRIM({_render(string)})") + + +def values(field: ExpressionType) -> InstrumentedExpression: + """Returns unique values as a multivalued field. The order of the returned + values isn’t guaranteed. If you need the values returned in order use `MV_SORT`. + + :param field: + """ + return InstrumentedExpression(f"VALUES({_render(field)})") + + +def weighted_avg( + number: ExpressionType, weight: ExpressionType +) -> InstrumentedExpression: + """The weighted average of a numeric expression. + + :param number: A numeric value. + :param weight: A numeric weight. + """ + return InstrumentedExpression(f"WEIGHTED_AVG({_render(number)}, {_render(weight)})") diff --git a/test_elasticsearch/test_dsl/_async/test_esql.py b/test_elasticsearch/test_dsl/_async/test_esql.py new file mode 100644 index 000000000..7aacb833c --- /dev/null +++ b/test_elasticsearch/test_dsl/_async/test_esql.py @@ -0,0 +1,93 @@ +# Licensed to Elasticsearch B.V. under one or more contributor +# license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright +# ownership. Elasticsearch B.V. 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. + +import pytest + +from elasticsearch.dsl import AsyncDocument, M +from elasticsearch.esql import ESQL, functions + + +class Employee(AsyncDocument): + emp_no: M[int] + first_name: M[str] + last_name: M[str] + height: M[float] + still_hired: M[bool] + + class Index: + name = "employees" + + +async def load_db(): + data = [ + [10000, "Joseph", "Wall", 2.2, True], + [10001, "Stephanie", "Ward", 1.749, True], + [10002, "David", "Keller", 1.872, True], + [10003, "Roger", "Hinton", 1.694, False], + [10004, "Joshua", "Garcia", 1.661, False], + [10005, "Matthew", "Richards", 1.633, False], + [10006, "Maria", "Luna", 1.893, True], + [10007, "Angela", "Navarro", 1.604, False], + [10008, "Maria", "Cannon", 2.079, False], + [10009, "Joseph", "Sutton", 2.025, True], + ] + if await Employee._index.exists(): + await Employee._index.delete() + await Employee.init() + + for e in data: + employee = Employee( + emp_no=e[0], first_name=e[1], last_name=e[2], height=e[3], still_hired=e[4] + ) + await employee.save() + await Employee._index.refresh() + + +@pytest.mark.asyncio +async def test_esql(async_client): + await load_db() + + # get the full names of the employees + query = ( + ESQL.from_(Employee) + .eval(name=functions.concat(Employee.first_name, " ", Employee.last_name)) + .keep("name") + .sort("name") + .limit(10) + ) + r = await async_client.esql.query(query=str(query)) + assert r.body["values"] == [ + ["Angela Navarro"], + ["David Keller"], + ["Joseph Sutton"], + ["Joseph Wall"], + ["Joshua Garcia"], + ["Maria Cannon"], + ["Maria Luna"], + ["Matthew Richards"], + ["Roger Hinton"], + ["Stephanie Ward"], + ] + + # get the average height of all hired employees + query = ESQL.from_(Employee).stats( + avg_height=functions.round(functions.avg(Employee.height), 2).where( + Employee.still_hired == True # noqa: E712 + ) + ) + r = await async_client.esql.query(query=str(query)) + assert r.body["values"] == [[1.95]] diff --git a/test_elasticsearch/test_dsl/_sync/test_esql.py b/test_elasticsearch/test_dsl/_sync/test_esql.py new file mode 100644 index 000000000..1c4084fc7 --- /dev/null +++ b/test_elasticsearch/test_dsl/_sync/test_esql.py @@ -0,0 +1,93 @@ +# Licensed to Elasticsearch B.V. under one or more contributor +# license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright +# ownership. Elasticsearch B.V. 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. + +import pytest + +from elasticsearch.dsl import Document, M +from elasticsearch.esql import ESQL, functions + + +class Employee(Document): + emp_no: M[int] + first_name: M[str] + last_name: M[str] + height: M[float] + still_hired: M[bool] + + class Index: + name = "employees" + + +def load_db(): + data = [ + [10000, "Joseph", "Wall", 2.2, True], + [10001, "Stephanie", "Ward", 1.749, True], + [10002, "David", "Keller", 1.872, True], + [10003, "Roger", "Hinton", 1.694, False], + [10004, "Joshua", "Garcia", 1.661, False], + [10005, "Matthew", "Richards", 1.633, False], + [10006, "Maria", "Luna", 1.893, True], + [10007, "Angela", "Navarro", 1.604, False], + [10008, "Maria", "Cannon", 2.079, False], + [10009, "Joseph", "Sutton", 2.025, True], + ] + if Employee._index.exists(): + Employee._index.delete() + Employee.init() + + for e in data: + employee = Employee( + emp_no=e[0], first_name=e[1], last_name=e[2], height=e[3], still_hired=e[4] + ) + employee.save() + Employee._index.refresh() + + +@pytest.mark.sync +def test_esql(client): + load_db() + + # get the full names of the employees + query = ( + ESQL.from_(Employee) + .eval(name=functions.concat(Employee.first_name, " ", Employee.last_name)) + .keep("name") + .sort("name") + .limit(10) + ) + r = client.esql.query(query=str(query)) + assert r.body["values"] == [ + ["Angela Navarro"], + ["David Keller"], + ["Joseph Sutton"], + ["Joseph Wall"], + ["Joshua Garcia"], + ["Maria Cannon"], + ["Maria Luna"], + ["Matthew Richards"], + ["Roger Hinton"], + ["Stephanie Ward"], + ] + + # get the average height of all hired employees + query = ESQL.from_(Employee).stats( + avg_height=functions.round(functions.avg(Employee.height), 2).where( + Employee.still_hired == True # noqa: E712 + ) + ) + r = client.esql.query(query=str(query)) + assert r.body["values"] == [[1.95]] diff --git a/test_elasticsearch/test_esql.py b/test_elasticsearch/test_esql.py new file mode 100644 index 000000000..70c9ec679 --- /dev/null +++ b/test_elasticsearch/test_esql.py @@ -0,0 +1,715 @@ +# Licensed to Elasticsearch B.V. under one or more contributor +# license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright +# ownership. Elasticsearch B.V. 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. + +from elasticsearch.dsl import E +from elasticsearch.esql import ESQL, and_, functions, not_, or_ + + +def test_from(): + query = ESQL.from_("employees") + assert query.render() == "FROM employees" + + query = ESQL.from_("") + assert query.render() == "FROM " + + query = ESQL.from_("employees-00001", "other-employees-*") + assert query.render() == "FROM employees-00001, other-employees-*" + + query = ESQL.from_("cluster_one:employees-00001", "cluster_two:other-employees-*") + assert ( + query.render() + == "FROM cluster_one:employees-00001, cluster_two:other-employees-*" + ) + + query = ESQL.from_("employees").metadata("_id") + assert query.render() == "FROM employees METADATA _id" + + +def test_row(): + query = ESQL.row(a=1, b="two", c=None) + assert query.render() == 'ROW a = 1, b = "two", c = null' + + query = ESQL.row(a=[2, 1]) + assert query.render() == "ROW a = [2, 1]" + + query = ESQL.row(a=functions.round(1.23, 0)) + assert query.render() == "ROW a = ROUND(1.23, 0)" + + +def test_show(): + query = ESQL.show("INFO") + assert query.render() == "SHOW INFO" + + +def test_change_point(): + query = ( + ESQL.row(key=list(range(1, 26))) + .mv_expand("key") + .eval(value=functions.case(E("key") < 13, 0, 42)) + .change_point("value") + .on("key") + .where("type IS NOT NULL") + ) + assert ( + query.render() + == """ROW key = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25] +| MV_EXPAND key +| EVAL value = CASE(key < 13, 0, 42) +| CHANGE_POINT value ON key +| WHERE type IS NOT NULL""" + ) + + +def test_completion(): + query = ( + ESQL.row(question="What is Elasticsearch?") + .completion("question") + .with_("test_completion_model") + .keep("question", "completion") + ) + assert ( + query.render() + == """ROW question = "What is Elasticsearch?" +| COMPLETION question WITH test_completion_model +| KEEP question, completion""" + ) + + query = ( + ESQL.row(question="What is Elasticsearch?") + .completion(answer=E("question")) + .with_("test_completion_model") + .keep("question", "answer") + ) + assert ( + query.render() + == """ROW question = "What is Elasticsearch?" +| COMPLETION answer = question WITH test_completion_model +| KEEP question, answer""" + ) + + query = ( + ESQL.from_("movies") + .sort("rating DESC") + .limit(10) + .eval( + prompt="""CONCAT( + "Summarize this movie using the following information: \\n", + "Title: ", title, "\\n", + "Synopsis: ", synopsis, "\\n", + "Actors: ", MV_CONCAT(actors, ", "), "\\n", + )""" + ) + .completion(summary="prompt") + .with_("test_completion_model") + .keep("title", "summary", "rating") + ) + assert ( + query.render() + == """FROM movies +| SORT rating DESC +| LIMIT 10 +| EVAL prompt = CONCAT( + "Summarize this movie using the following information: \\n", + "Title: ", title, "\\n", + "Synopsis: ", synopsis, "\\n", + "Actors: ", MV_CONCAT(actors, ", "), "\\n", + ) +| COMPLETION summary = prompt WITH test_completion_model +| KEEP title, summary, rating""" + ) + + query = ( + ESQL.from_("movies") + .sort("rating DESC") + .limit(10) + .eval( + prompt=functions.concat( + "Summarize this movie using the following information: \n", + "Title: ", + E("title"), + "\n", + "Synopsis: ", + E("synopsis"), + "\n", + "Actors: ", + functions.mv_concat(E("actors"), ", "), + "\n", + ) + ) + .completion(summary="prompt") + .with_("test_completion_model") + .keep("title", "summary", "rating") + ) + assert ( + query.render() + == """FROM movies +| SORT rating DESC +| LIMIT 10 +| EVAL prompt = CONCAT("Summarize this movie using the following information: \\n", "Title: ", title, "\\n", "Synopsis: ", synopsis, "\\n", "Actors: ", MV_CONCAT(actors, ", "), "\\n") +| COMPLETION summary = prompt WITH test_completion_model +| KEEP title, summary, rating""" + ) + + +def test_dissect(): + query = ( + ESQL.row(a="2023-01-23T12:15:00.000Z - some text - 127.0.0.1") + .dissect("a", "%{date} - %{msg} - %{ip}") + .keep("date", "msg", "ip") + ) + assert ( + query.render() + == """ROW a = "2023-01-23T12:15:00.000Z - some text - 127.0.0.1" +| DISSECT a "%{date} - %{msg} - %{ip}" +| KEEP date, msg, ip""" + ) + + +def test_drop(): + query = ESQL.from_("employees").drop("height") + assert query.render() == "FROM employees\n| DROP height" + query = ESQL.from_("employees").drop("height*") + assert query.render() == "FROM employees\n| DROP height*" + + +def test_enrich(): + query = ESQL.row(language_code="1").enrich("languages_policy") + assert ( + query.render() + == """ROW language_code = "1" +| ENRICH languages_policy""" + ) + + query = ESQL.row(language_code="1").enrich("languages_policy").on("a") + assert ( + query.render() + == """ROW language_code = "1" +| ENRICH languages_policy ON a""" + ) + + query = ( + ESQL.row(language_code="1") + .enrich("languages_policy") + .on("a") + .with_(name="language_name") + ) + assert ( + query.render() + == """ROW language_code = "1" +| ENRICH languages_policy ON a WITH name = language_name""" + ) + + +def test_eval(): + query = ( + ESQL.from_("employees") + .sort("emp_no") + .keep("first_name", "last_name", "height") + .eval(height_feet=E("height") * 3.281, height_cm=E("height") * 100) + ) + assert ( + query.render() + == """FROM employees +| SORT emp_no +| KEEP first_name, last_name, height +| EVAL height_feet = height * 3.281, height_cm = height * 100""" + ) + + query = ( + ESQL.from_("employees") + .sort("emp_no") + .keep("first_name", "last_name", "height") + .eval(E("height") * 3.281) + ) + assert ( + query.render() + == """FROM employees +| SORT emp_no +| KEEP first_name, last_name, height +| EVAL height * 3.281""" + ) + + query = ( + ESQL.from_("employees") + .eval("height * 3.281") + .stats(avg_height_feet=functions.avg(E("`height * 3.281`"))) + ) + assert ( + query.render() + == """FROM employees +| EVAL height * 3.281 +| STATS avg_height_feet = AVG(`height * 3.281`)""" + ) + + +def test_fork(): + query = ( + ESQL.from_("employees") + .fork( + ESQL.branch().where(E("emp_no") == 10001), + ESQL.branch().where("emp_no == 10002"), + ) + .keep("emp_no", "_fork") + .sort("emp_no") + ) + assert ( + query.render() + == """FROM employees +| FORK ( WHERE emp_no == 10001 ) + ( WHERE emp_no == 10002 ) +| KEEP emp_no, _fork +| SORT emp_no""" + ) + + +def test_grok(): + query = ( + ESQL.row(a="2023-01-23T12:15:00.000Z 127.0.0.1 some.email@foo.com 42") + .grok( + "a", + "%{TIMESTAMP_ISO8601:date} %{IP:ip} %{EMAILADDRESS:email} %{NUMBER:num}", + ) + .keep("date", "ip", "email", "num") + ) + assert ( + query.render() + == """ROW a = "2023-01-23T12:15:00.000Z 127.0.0.1 some.email@foo.com 42" +| GROK a "%{TIMESTAMP_ISO8601:date} %{IP:ip} %{EMAILADDRESS:email} %{NUMBER:num}" +| KEEP date, ip, email, num""" + ) + + query = ( + ESQL.row(a="2023-01-23T12:15:00.000Z 127.0.0.1 some.email@foo.com 42") + .grok( + "a", + "%{TIMESTAMP_ISO8601:date} %{IP:ip} %{EMAILADDRESS:email} %{NUMBER:num:int}", + ) + .keep("date", "ip", "email", "num") + .eval(date=functions.to_datetime(E("date"))) + ) + assert ( + query.render() + == """ROW a = "2023-01-23T12:15:00.000Z 127.0.0.1 some.email@foo.com 42" +| GROK a "%{TIMESTAMP_ISO8601:date} %{IP:ip} %{EMAILADDRESS:email} %{NUMBER:num:int}" +| KEEP date, ip, email, num +| EVAL date = TO_DATETIME(date)""" + ) + + query = ( + ESQL.from_("addresses") + .keep("city.name", "zip_code") + .grok("zip_code", "%{WORD:zip_parts} %{WORD:zip_parts}") + ) + assert ( + query.render() + == """FROM addresses +| KEEP city.name, zip_code +| GROK zip_code "%{WORD:zip_parts} %{WORD:zip_parts}\"""" + ) + + +def test_keep(): + query = ESQL.from_("employees").keep("emp_no", "first_name", "last_name", "height") + assert ( + query.render() == "FROM employees\n| KEEP emp_no, first_name, last_name, height" + ) + + query = ESQL.from_("employees").keep("h*") + assert query.render() == "FROM employees\n| KEEP h*" + + query = ESQL.from_("employees").keep("*", "first_name") + assert query.render() == "FROM employees\n| KEEP *, first_name" + + +def test_limit(): + query = ESQL.from_("index").where(E("field") == "value").limit(1000) + assert query.render() == 'FROM index\n| WHERE field == "value"\n| LIMIT 1000' + + query = ( + ESQL.from_("index").stats(functions.avg(E("field1"))).by("field2").limit(20000) + ) + assert ( + query.render() + == "FROM index\n| STATS AVG(field1)\n BY field2\n| LIMIT 20000" + ) + + +def test_lookup_join(): + query = ( + ESQL.from_("firewall_logs") + .lookup_join("threat_list") + .on("source.IP") + .where("threat_level IS NOT NULL") + ) + assert ( + query.render() + == """FROM firewall_logs +| LOOKUP JOIN threat_list ON source.IP +| WHERE threat_level IS NOT NULL""" + ) + + query = ( + ESQL.from_("system_metrics") + .lookup_join("host_inventory") + .on("host.name") + .lookup_join("ownerships") + .on("host.name") + ) + assert ( + query.render() + == """FROM system_metrics +| LOOKUP JOIN host_inventory ON host.name +| LOOKUP JOIN ownerships ON host.name""" + ) + + query = ESQL.from_("app_logs").lookup_join("service_owners").on("service_id") + assert ( + query.render() + == """FROM app_logs +| LOOKUP JOIN service_owners ON service_id""" + ) + + query = ( + ESQL.from_("employees") + .eval(language_code="languages") + .where(E("emp_no") >= 10091, E("emp_no") < 10094) + .lookup_join("languages_lookup") + .on("language_code") + ) + assert ( + query.render() + == """FROM employees +| EVAL language_code = languages +| WHERE emp_no >= 10091 AND emp_no < 10094 +| LOOKUP JOIN languages_lookup ON language_code""" + ) + + +def test_mv_expand(): + query = ESQL.row(a=[1, 2, 3], b="b", j=["a", "b"]).mv_expand("a") + assert ( + query.render() + == """ROW a = [1, 2, 3], b = "b", j = ["a", "b"] +| MV_EXPAND a""" + ) + + +def test_rename(): + query = ( + ESQL.from_("employees") + .keep("first_name", "last_name", "still_hired") + .rename(still_hired="employed") + ) + assert ( + query.render() + == """FROM employees +| KEEP first_name, last_name, still_hired +| RENAME still_hired AS employed""" + ) + + +def test_sample(): + query = ESQL.from_("employees").keep("emp_no").sample(0.05) + assert ( + query.render() + == """FROM employees +| KEEP emp_no +| SAMPLE 0.05""" + ) + + +def test_sort(): + query = ( + ESQL.from_("employees").keep("first_name", "last_name", "height").sort("height") + ) + assert ( + query.render() + == """FROM employees +| KEEP first_name, last_name, height +| SORT height""" + ) + + query = ( + ESQL.from_("employees") + .keep("first_name", "last_name", "height") + .sort("height DESC") + ) + assert ( + query.render() + == """FROM employees +| KEEP first_name, last_name, height +| SORT height DESC""" + ) + + query = ( + ESQL.from_("employees") + .keep("first_name", "last_name", "height") + .sort("height DESC", "first_name ASC") + ) + assert ( + query.render() + == """FROM employees +| KEEP first_name, last_name, height +| SORT height DESC, first_name ASC""" + ) + + query = ( + ESQL.from_("employees") + .keep("first_name", "last_name", "height") + .sort("first_name ASC NULLS FIRST") + ) + assert ( + query.render() + == """FROM employees +| KEEP first_name, last_name, height +| SORT first_name ASC NULLS FIRST""" + ) + + +def test_stats(): + query = ( + ESQL.from_("employees") + .stats(count=functions.count(E("emp_no"))) + .by("languages") + .sort("languages") + ) + assert ( + query.render() + == """FROM employees +| STATS count = COUNT(emp_no) + BY languages +| SORT languages""" + ) + + query = ESQL.from_("employees").stats(avg_lang=functions.avg(E("languages"))) + assert ( + query.render() + == """FROM employees +| STATS avg_lang = AVG(languages)""" + ) + + query = ESQL.from_("employees").stats( + avg_lang=functions.avg(E("languages")), max_lang=functions.max(E("languages")) + ) + assert ( + query.render() + == """FROM employees +| STATS avg_lang = AVG(languages), + max_lang = MAX(languages)""" + ) + + query = ( + ESQL.from_("employees") + .stats( + avg50s=functions.avg(E("salary")).where('birth_date < "1960-01-01"'), + avg60s=functions.avg(E("salary")).where('birth_date >= "1960-01-01"'), + ) + .by("gender") + .sort("gender") + ) + assert ( + query.render() + == """FROM employees +| STATS avg50s = AVG(salary) WHERE birth_date < "1960-01-01", + avg60s = AVG(salary) WHERE birth_date >= "1960-01-01" + BY gender +| SORT gender""" + ) + + query = ( + ESQL.from_("employees") + .eval(Ks="salary / 1000") + .stats( + under_40K=functions.count(E("*")).where("Ks < 40"), + inbetween=functions.count(E("*")).where("40 <= Ks", "Ks < 60"), + over_60K=functions.count(E("*")).where("60 <= Ks"), + total=functions.count(E("*")), + ) + ) + assert ( + query.render() + == """FROM employees +| EVAL Ks = salary / 1000 +| STATS under_40K = COUNT(*) WHERE Ks < 40, + inbetween = COUNT(*) WHERE (40 <= Ks) AND (Ks < 60), + over_60K = COUNT(*) WHERE 60 <= Ks, + total = COUNT(*)""" + ) + + query = ( + ESQL.row(i=1, a=["a", "b"]).stats(functions.min(E("i"))).by("a").sort("a ASC") + ) + assert ( + query.render() + == 'ROW i = 1, a = ["a", "b"]\n| STATS MIN(i)\n BY a\n| SORT a ASC' + ) + + query = ( + ESQL.from_("employees") + .eval(hired=functions.date_format(E("hire_date"), "yyyy")) + .stats(avg_salary=functions.avg(E("salary"))) + .by("hired", "languages.long") + .eval(avg_salary=functions.round(E("avg_salary"))) + .sort("hired", "languages.long") + ) + assert ( + query.render() + == """FROM employees +| EVAL hired = DATE_FORMAT("yyyy", hire_date) +| STATS avg_salary = AVG(salary) + BY hired, languages.long +| EVAL avg_salary = ROUND(avg_salary) +| SORT hired, languages.long""" + ) + + +def test_where(): + query = ( + ESQL.from_("employees") + .keep("first_name", "last_name", "still_hired") + .where("still_hired == true") + ) + assert ( + query.render() + == """FROM employees +| KEEP first_name, last_name, still_hired +| WHERE still_hired == true""" + ) + + query = ESQL.from_("sample_data").where("@timestamp > NOW() - 1 hour") + assert ( + query.render() + == """FROM sample_data +| WHERE @timestamp > NOW() - 1 hour""" + ) + + query = ( + ESQL.from_("employees") + .keep("first_name", "last_name", "height") + .where("LENGTH(first_name) < 4") + ) + assert ( + query.render() + == """FROM employees +| KEEP first_name, last_name, height +| WHERE LENGTH(first_name) < 4""" + ) + + +def test_and_operator(): + query = ESQL.from_("index").where( + and_(E("age") > 30, E("age") < 40, E("name").is_not_null()) + ) + assert ( + query.render() + == """FROM index +| WHERE (age > 30) AND (age < 40) AND (name IS NOT NULL)""" + ) + + +def test_or_operator(): + query = ESQL.from_("index").where( + or_(E("age") < 30, E("age") > 40, E("name").is_null()) + ) + assert ( + query.render() + == """FROM index +| WHERE (age < 30) OR (age > 40) OR (name IS NULL)""" + ) + + +def test_not_operator(): + query = ESQL.from_("index").where(not_(E("age") > 40)) + assert ( + query.render() + == """FROM index +| WHERE NOT (age > 40)""" + ) + + +def test_in_operator(): + query = ESQL.row(a=1, b=4, c=3).where((E("c") - E("a")).in_(3, E("b") / 2, "a")) + assert ( + query.render() + == """ROW a = 1, b = 4, c = 3 +| WHERE c - a IN (3, b / 2, a)""" + ) + + +def test_like_operator(): + query = ( + ESQL.from_("employees") + .where(E("first_name").like("?b*")) + .keep("first_name", "last_name") + ) + assert ( + query.render() + == """FROM employees +| WHERE first_name LIKE "?b*" +| KEEP first_name, last_name""" + ) + + query = ESQL.row(message="foo * bar").where(E("message").like("foo \\* bar")) + assert ( + query.render() + == """ROW message = "foo * bar" +| WHERE message LIKE "foo \\\\* bar\"""" + ) + + query = ESQL.row(message="foobar").where(E("message").like("foo*", "bar?")) + assert ( + query.render() + == """ROW message = "foobar" +| WHERE message LIKE ("foo*", "bar?")""" + ) + + +def test_rlike_operator(): + query = ( + ESQL.from_("employees") + .where(E("first_name").rlike(".leja*")) + .keep("first_name", "last_name") + ) + assert ( + query.render() + == """FROM employees +| WHERE first_name RLIKE ".leja*" +| KEEP first_name, last_name""" + ) + + query = ESQL.row(message="foo ( bar").where(E("message").rlike("foo \\( bar")) + assert ( + query.render() + == """ROW message = "foo ( bar" +| WHERE message RLIKE "foo \\\\( bar\"""" + ) + + query = ESQL.row(message="foobar").where(E("message").rlike("foo.*", "bar.")) + assert ( + query.render() + == """ROW message = "foobar" +| WHERE message RLIKE ("foo.*", "bar.")""" + ) + + +def test_match_operator(): + query = ESQL.from_("books").where(E("author").match("Faulkner")) + assert ( + query.render() + == """FROM books +| WHERE author:"Faulkner\"""" + ) From 6a5f451a98d4528bd866d0654d93f993c7fde229 Mon Sep 17 00:00:00 2001 From: Elastic Machine Date: Tue, 29 Jul 2025 13:28:23 +0200 Subject: [PATCH 51/57] Auto-generated API code (#2985) Co-authored-by: Miguel Grinberg --- elasticsearch/_async/client/__init__.py | 240 +++---------- elasticsearch/_async/client/cat.py | 418 ++++++++++++++++++++-- elasticsearch/_async/client/cluster.py | 18 +- elasticsearch/_async/client/eql.py | 12 +- elasticsearch/_async/client/esql.py | 21 +- elasticsearch/_async/client/indices.py | 130 ++++--- elasticsearch/_async/client/inference.py | 111 +++++- elasticsearch/_async/client/ingest.py | 7 - elasticsearch/_async/client/license.py | 8 +- elasticsearch/_async/client/ml.py | 23 +- elasticsearch/_async/client/monitoring.py | 2 +- elasticsearch/_async/client/rollup.py | 23 +- elasticsearch/_async/client/security.py | 28 +- elasticsearch/_async/client/snapshot.py | 6 + elasticsearch/_async/client/synonyms.py | 1 + elasticsearch/_async/client/watcher.py | 6 +- elasticsearch/_sync/client/__init__.py | 240 +++---------- elasticsearch/_sync/client/cat.py | 418 ++++++++++++++++++++-- elasticsearch/_sync/client/cluster.py | 18 +- elasticsearch/_sync/client/eql.py | 12 +- elasticsearch/_sync/client/esql.py | 21 +- elasticsearch/_sync/client/indices.py | 130 ++++--- elasticsearch/_sync/client/inference.py | 111 +++++- elasticsearch/_sync/client/ingest.py | 7 - elasticsearch/_sync/client/license.py | 8 +- elasticsearch/_sync/client/ml.py | 23 +- elasticsearch/_sync/client/monitoring.py | 2 +- elasticsearch/_sync/client/rollup.py | 23 +- elasticsearch/_sync/client/security.py | 28 +- elasticsearch/_sync/client/snapshot.py | 6 + elasticsearch/_sync/client/synonyms.py | 1 + elasticsearch/_sync/client/watcher.py | 6 +- elasticsearch/dsl/aggs.py | 20 -- elasticsearch/dsl/field.py | 18 - elasticsearch/dsl/query.py | 2 +- elasticsearch/dsl/response/__init__.py | 2 +- elasticsearch/dsl/types.py | 133 +------ 37 files changed, 1419 insertions(+), 864 deletions(-) diff --git a/elasticsearch/_async/client/__init__.py b/elasticsearch/_async/client/__init__.py index dd10aca31..79d6efef1 100644 --- a/elasticsearch/_async/client/__init__.py +++ b/elasticsearch/_async/client/__init__.py @@ -637,6 +637,8 @@ async def bulk( Imagine a _bulk?refresh=wait_for request with three documents in it that happen to be routed to different shards in an index with five shards. The request will only wait for those three shards to refresh. The other two shards that make up the index do not participate in the _bulk request at all.

    +

    You might want to disable the refresh interval temporarily to improve indexing throughput for large bulk requests. + Refer to the linked documentation for step-by-step instructions using the index settings API.

    ``_ @@ -1029,10 +1031,7 @@ async def create( error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, - if_primary_term: t.Optional[int] = None, - if_seq_no: t.Optional[int] = None, include_source_on_error: t.Optional[bool] = None, - op_type: t.Optional[t.Union[str, t.Literal["create", "index"]]] = None, pipeline: t.Optional[str] = None, pretty: t.Optional[bool] = None, refresh: t.Optional[ @@ -1117,18 +1116,8 @@ async def create( :param id: A unique identifier for the document. To automatically generate a document ID, use the `POST //_doc/` request format. :param document: - :param if_primary_term: Only perform the operation if the document has this primary - term. - :param if_seq_no: Only perform the operation if the document has this sequence - number. :param include_source_on_error: True or false if to include the document source in the error message in case of parsing errors. - :param op_type: Set to `create` to only index the document if it does not already - exist (put if absent). If a document with the specified `_id` already exists, - the indexing operation will fail. The behavior is the same as using the `/_create` - endpoint. If a document ID is specified, this paramater defaults to `index`. - Otherwise, it defaults to `create`. If the request targets a data stream, - an `op_type` of `create` is required. :param pipeline: The ID of the pipeline to use to preprocess incoming documents. If the index has a default ingest pipeline specified, setting the value to `_none` turns off the default ingest pipeline for this request. If a final @@ -1180,14 +1169,8 @@ async def create( __query["filter_path"] = filter_path if human is not None: __query["human"] = human - if if_primary_term is not None: - __query["if_primary_term"] = if_primary_term - if if_seq_no is not None: - __query["if_seq_no"] = if_seq_no if include_source_on_error is not None: __query["include_source_on_error"] = include_source_on_error - if op_type is not None: - __query["op_type"] = op_type if pipeline is not None: __query["pipeline"] = pipeline if pretty is not None: @@ -2324,7 +2307,7 @@ async def get( :param index: The name of the index that contains the document. :param id: A unique document identifier. :param force_synthetic_source: Indicates whether the request forces synthetic - `_source`. Use this paramater to test if the mapping supports synthetic `_source` + `_source`. Use this parameter to test if the mapping supports synthetic `_source` and to get a sense of the worst case performance. Fetches with this parameter enabled will be slower than enabling synthetic source natively in the index. :param preference: The node or shard the operation should be performed on. By @@ -2355,8 +2338,8 @@ async def get( :param stored_fields: A comma-separated list of stored fields to return as part of a hit. If no fields are specified, no stored fields are included in the response. If this field is specified, the `_source` parameter defaults to - `false`. Only leaf fields can be retrieved with the `stored_field` option. - Object fields can't be returned;​if specified, the request fails. + `false`. Only leaf fields can be retrieved with the `stored_fields` option. + Object fields can't be returned; if specified, the request fails. :param version: The version number for concurrency control. It must match the current version of the document for the request to succeed. :param version_type: The version type. @@ -2560,7 +2543,6 @@ async def get_source( source: t.Optional[t.Union[bool, t.Union[str, t.Sequence[str]]]] = None, source_excludes: t.Optional[t.Union[str, t.Sequence[str]]] = None, source_includes: t.Optional[t.Union[str, t.Sequence[str]]] = None, - stored_fields: t.Optional[t.Union[str, t.Sequence[str]]] = None, version: t.Optional[int] = None, version_type: t.Optional[ t.Union[str, t.Literal["external", "external_gte", "force", "internal"]] @@ -2597,8 +2579,6 @@ async def get_source( the response. :param source_includes: A comma-separated list of source fields to include in the response. - :param stored_fields: A comma-separated list of stored fields to return as part - of a hit. :param version: The version number for concurrency control. It must match the current version of the document for the request to succeed. :param version_type: The version type. @@ -2632,8 +2612,6 @@ async def get_source( __query["_source_excludes"] = source_excludes if source_includes is not None: __query["_source_includes"] = source_includes - if stored_fields is not None: - __query["stored_fields"] = stored_fields if version is not None: __query["version"] = version if version_type is not None: @@ -2742,6 +2720,7 @@ async def index( t.Union[bool, str, t.Literal["false", "true", "wait_for"]] ] = None, require_alias: t.Optional[bool] = None, + require_data_stream: t.Optional[bool] = None, routing: t.Optional[str] = None, timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, version: t.Optional[int] = None, @@ -2877,6 +2856,8 @@ async def index( this operation visible to search. If `wait_for`, it waits for a refresh to make this operation visible to search. If `false`, it does nothing with refreshes. :param require_alias: If `true`, the destination must be an index alias. + :param require_data_stream: If `true`, the request's actions must target a data + stream (existing or to be created). :param routing: A custom value that is used to route operations to a specific shard. :param timeout: The period the request waits for the following operations: automatic @@ -2938,6 +2919,8 @@ async def index( __query["refresh"] = refresh if require_alias is not None: __query["require_alias"] = require_alias + if require_data_stream is not None: + __query["require_data_stream"] = require_data_stream if routing is not None: __query["routing"] = routing if timeout is not None: @@ -2973,7 +2956,8 @@ async def info( .. raw:: html

    Get cluster info. - Get basic build, version, and cluster information.

    + Get basic build, version, and cluster information. + ::: In Serverless, this API is retained for backward compatibility only. Some response fields, such as the version number, should be ignored.

    ``_ @@ -3586,8 +3570,7 @@ async def open_point_in_time( :param expand_wildcards: The type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. It supports comma-separated - values, such as `open,hidden`. Valid values are: `all`, `open`, `closed`, - `hidden`, `none`. + values, such as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param index_filter: Filter indices if the provided query rewrites to `match_none` @@ -3887,110 +3870,7 @@ async def reindex( In this case, the response includes a count of the version conflicts that were encountered. Note that the handling of other error types is unaffected by the conflicts property. Additionally, if you opt to count version conflicts, the operation could attempt to reindex more documents from the source than max_docs until it has successfully indexed max_docs documents into the target or it has gone through every document in the source query.

    -

    NOTE: The reindex API makes no effort to handle ID collisions. - The last document written will "win" but the order isn't usually predictable so it is not a good idea to rely on this behavior. - Instead, make sure that IDs are unique by using a script.

    -

    Running reindex asynchronously

    -

    If the request contains wait_for_completion=false, Elasticsearch performs some preflight checks, launches the request, and returns a task you can use to cancel or get the status of the task. - Elasticsearch creates a record of this task as a document at _tasks/<task_id>.

    -

    Reindex from multiple sources

    -

    If you have many sources to reindex it is generally better to reindex them one at a time rather than using a glob pattern to pick up multiple sources. - That way you can resume the process if there are any errors by removing the partially completed source and starting over. - It also makes parallelizing the process fairly simple: split the list of sources to reindex and run each list in parallel.

    -

    For example, you can use a bash script like this:

    -
    for index in i1 i2 i3 i4 i5; do
    -            curl -HContent-Type:application/json -XPOST localhost:9200/_reindex?pretty -d'{
    -              "source": {
    -                "index": "'$index'"
    -              },
    -              "dest": {
    -                "index": "'$index'-reindexed"
    -              }
    -            }'
    -          done
    -          
    -

    Throttling

    -

    Set requests_per_second to any positive decimal number (1.4, 6, 1000, for example) to throttle the rate at which reindex issues batches of index operations. - Requests are throttled by padding each batch with a wait time. - To turn off throttling, set requests_per_second to -1.

    -

    The throttling is done by waiting between batches so that the scroll that reindex uses internally can be given a timeout that takes into account the padding. - The padding time is the difference between the batch size divided by the requests_per_second and the time spent writing. - By default the batch size is 1000, so if requests_per_second is set to 500:

    -
    target_time = 1000 / 500 per second = 2 seconds
    -          wait_time = target_time - write_time = 2 seconds - .5 seconds = 1.5 seconds
    -          
    -

    Since the batch is issued as a single bulk request, large batch sizes cause Elasticsearch to create many requests and then wait for a while before starting the next set. - This is "bursty" instead of "smooth".

    -

    Slicing

    -

    Reindex supports sliced scroll to parallelize the reindexing process. - This parallelization can improve efficiency and provide a convenient way to break the request down into smaller parts.

    -

    NOTE: Reindexing from remote clusters does not support manual or automatic slicing.

    -

    You can slice a reindex request manually by providing a slice ID and total number of slices to each request. - You can also let reindex automatically parallelize by using sliced scroll to slice on _id. - The slices parameter specifies the number of slices to use.

    -

    Adding slices to the reindex request just automates the manual process, creating sub-requests which means it has some quirks:

    -
      -
    • You can see these requests in the tasks API. These sub-requests are "child" tasks of the task for the request with slices.
    • -
    • Fetching the status of the task for the request with slices only contains the status of completed slices.
    • -
    • These sub-requests are individually addressable for things like cancellation and rethrottling.
    • -
    • Rethrottling the request with slices will rethrottle the unfinished sub-request proportionally.
    • -
    • Canceling the request with slices will cancel each sub-request.
    • -
    • Due to the nature of slices, each sub-request won't get a perfectly even portion of the documents. All documents will be addressed, but some slices may be larger than others. Expect larger slices to have a more even distribution.
    • -
    • Parameters like requests_per_second and max_docs on a request with slices are distributed proportionally to each sub-request. Combine that with the previous point about distribution being uneven and you should conclude that using max_docs with slices might not result in exactly max_docs documents being reindexed.
    • -
    • Each sub-request gets a slightly different snapshot of the source, though these are all taken at approximately the same time.
    • -
    -

    If slicing automatically, setting slices to auto will choose a reasonable number for most indices. - If slicing manually or otherwise tuning automatic slicing, use the following guidelines.

    -

    Query performance is most efficient when the number of slices is equal to the number of shards in the index. - If that number is large (for example, 500), choose a lower number as too many slices will hurt performance. - Setting slices higher than the number of shards generally does not improve efficiency and adds overhead.

    -

    Indexing performance scales linearly across available resources with the number of slices.

    -

    Whether query or indexing performance dominates the runtime depends on the documents being reindexed and cluster resources.

    -

    Modify documents during reindexing

    -

    Like _update_by_query, reindex operations support a script that modifies the document. - Unlike _update_by_query, the script is allowed to modify the document's metadata.

    -

    Just as in _update_by_query, you can set ctx.op to change the operation that is run on the destination. - For example, set ctx.op to noop if your script decides that the document doesn’t have to be indexed in the destination. This "no operation" will be reported in the noop counter in the response body. - Set ctx.op to delete if your script decides that the document must be deleted from the destination. - The deletion will be reported in the deleted counter in the response body. - Setting ctx.op to anything else will return an error, as will setting any other field in ctx.

    -

    Think of the possibilities! Just be careful; you are able to change:

    -
      -
    • _id
    • -
    • _index
    • -
    • _version
    • -
    • _routing
    • -
    -

    Setting _version to null or clearing it from the ctx map is just like not sending the version in an indexing request. - It will cause the document to be overwritten in the destination regardless of the version on the target or the version type you use in the reindex API.

    -

    Reindex from remote

    -

    Reindex supports reindexing from a remote Elasticsearch cluster. - The host parameter must contain a scheme, host, port, and optional path. - The username and password parameters are optional and when they are present the reindex operation will connect to the remote Elasticsearch node using basic authentication. - Be sure to use HTTPS when using basic authentication or the password will be sent in plain text. - There are a range of settings available to configure the behavior of the HTTPS connection.

    -

    When using Elastic Cloud, it is also possible to authenticate against the remote cluster through the use of a valid API key. - Remote hosts must be explicitly allowed with the reindex.remote.whitelist setting. - It can be set to a comma delimited list of allowed remote host and port combinations. - Scheme is ignored; only the host and port are used. - For example:

    -
    reindex.remote.whitelist: [otherhost:9200, another:9200, 127.0.10.*:9200, localhost:*"]
    -          
    -

    The list of allowed hosts must be configured on any nodes that will coordinate the reindex. - This feature should work with remote clusters of any version of Elasticsearch. - This should enable you to upgrade from any version of Elasticsearch to the current version by reindexing from a cluster of the old version.

    -

    WARNING: Elasticsearch does not support forward compatibility across major versions. - For example, you cannot reindex from a 7.x cluster into a 6.x cluster.

    -

    To enable queries sent to older versions of Elasticsearch, the query parameter is sent directly to the remote host without validation or modification.

    -

    NOTE: Reindexing from remote clusters does not support manual or automatic slicing.

    -

    Reindexing from a remote server uses an on-heap buffer that defaults to a maximum size of 100mb. - If the remote index includes very large documents you'll need to use a smaller batch size. - It is also possible to set the socket read timeout on the remote connection with the socket_timeout field and the connection timeout with the connect_timeout field. - Both default to 30 seconds.

    -

    Configuring SSL parameters

    -

    Reindex from remote supports configurable SSL settings. - These must be specified in the elasticsearch.yml file, with the exception of the secure settings, which you add in the Elasticsearch keystore. - It is not possible to configure SSL in the body of the reindex request.

    +

    Refer to the linked documentation for examples of how to reindex documents.

    ``_ @@ -4992,51 +4872,6 @@ async def search_mvt(
  • Optionally, a geo_bounds aggregation on the <field>. The search only includes this aggregation if the exact_bounds parameter is true.
  • If the optional parameter with_labels is true, the internal search will include a dynamic runtime field that calls the getLabelPosition function of the geometry doc value. This enables the generation of new point features containing suggested geometry labels, so that, for example, multi-polygons will have only one label.
  • -

    For example, Elasticsearch may translate a vector tile search API request with a grid_agg argument of geotile and an exact_bounds argument of true into the following search

    -
    GET my-index/_search
    -          {
    -            "size": 10000,
    -            "query": {
    -              "geo_bounding_box": {
    -                "my-geo-field": {
    -                  "top_left": {
    -                    "lat": -40.979898069620134,
    -                    "lon": -45
    -                  },
    -                  "bottom_right": {
    -                    "lat": -66.51326044311186,
    -                    "lon": 0
    -                  }
    -                }
    -              }
    -            },
    -            "aggregations": {
    -              "grid": {
    -                "geotile_grid": {
    -                  "field": "my-geo-field",
    -                  "precision": 11,
    -                  "size": 65536,
    -                  "bounds": {
    -                    "top_left": {
    -                      "lat": -40.979898069620134,
    -                      "lon": -45
    -                    },
    -                    "bottom_right": {
    -                      "lat": -66.51326044311186,
    -                      "lon": 0
    -                    }
    -                  }
    -                }
    -              },
    -              "bounds": {
    -                "geo_bounds": {
    -                  "field": "my-geo-field",
    -                  "wrap_longitude": false
    -                }
    -              }
    -            }
    -          }
    -          

    The API returns results as a binary Mapbox vector tile. Mapbox vector tiles are encoded as Google Protobufs (PBF). By default, the tile contains three layers:

      @@ -5291,6 +5126,7 @@ async def search_mvt( Some cells may intersect more than one vector tile. To compute the H3 resolution for each precision, Elasticsearch compares the average density of hexagonal bins at each resolution with the average density of tile bins at each zoom level. Elasticsearch uses the H3 resolution that is closest to the corresponding geotile density.

      +

      Learn how to use the vector tile search API with practical examples in the Vector tile search examples guide.

      ``_ @@ -5480,7 +5316,7 @@ async def search_shards( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param local: If `true`, the request retrieves information from the local node @@ -5592,8 +5428,7 @@ async def search_template( :param expand_wildcards: The type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated - values, such as `open,hidden`. Valid values are: `all`, `open`, `closed`, - `hidden`, `none`. + values, such as `open,hidden`. :param explain: If `true`, returns detailed information about score calculation as part of each hit. If you specify both this and the `explain` query parameter, the API uses only the query parameter. @@ -5867,7 +5702,8 @@ async def termvectors( The information is only retrieved for the shard the requested document resides in. The term and field statistics are therefore only useful as relative measures whereas the absolute numbers have no meaning in this context. By default, when requesting term vectors of artificial documents, a shard to get the statistics from is randomly selected. - Use routing only to hit a particular shard.

      + Use routing only to hit a particular shard. + Refer to the linked documentation for detailed examples of how to use this API.

      ``_ @@ -6038,7 +5874,8 @@ async def update(

    The document must still be reindexed, but using this API removes some network roundtrips and reduces chances of version conflicts between the GET and the index operation.

    The _source field must be enabled to use this API. - In addition to _source, you can access the following variables through the ctx map: _index, _type, _id, _version, _routing, and _now (the current timestamp).

    + In addition to _source, you can access the following variables through the ctx map: _index, _type, _id, _version, _routing, and _now (the current timestamp). + For usage examples such as partial updates, upserts, and scripted updates, see the External documentation.

    ``_ @@ -6231,6 +6068,24 @@ async def update_by_query( A bulk update request is performed for each batch of matching documents. Any query or update failures cause the update by query request to fail and the failures are shown in the response. Any update requests that completed successfully still stick, they are not rolled back.

    +

    Refreshing shards

    +

    Specifying the refresh parameter refreshes all shards once the request completes. + This is different to the update API's refresh parameter, which causes only the shard + that received the request to be refreshed. Unlike the update API, it does not support + wait_for.

    +

    Running update by query asynchronously

    +

    If the request contains wait_for_completion=false, Elasticsearch + performs some preflight checks, launches the request, and returns a + task you can use to cancel or get the status of the task. + Elasticsearch creates a record of this task as a document at .tasks/task/${taskId}.

    +

    Waiting for active shards

    +

    wait_for_active_shards controls how many copies of a shard must be active + before proceeding with the request. See wait_for_active_shards + for details. timeout controls how long each write request waits for unavailable + shards to become available. Both work exactly the way they work in the + Bulk API. Update by query uses scrolled searches, so you can also + specify the scroll parameter to control how long it keeps the search context + alive, for example ?scroll=10m. The default is 5 minutes.

    Throttling update requests

    To control the rate at which update by query issues batches of update operations, you can set requests_per_second to any positive decimal number. This pads each batch with a wait time to throttle the rate. @@ -6265,18 +6120,8 @@ async def update_by_query(

  • Query performance is most efficient when the number of slices is equal to the number of shards in the index or backing index. If that number is large (for example, 500), choose a lower number as too many slices hurts performance. Setting slices higher than the number of shards generally does not improve efficiency and adds overhead.
  • Update performance scales linearly across available resources with the number of slices.
  • -

    Whether query or update performance dominates the runtime depends on the documents being reindexed and cluster resources.

    -

    Update the document source

    -

    Update by query supports scripts to update the document source. - As with the update API, you can set ctx.op to change the operation that is performed.

    -

    Set ctx.op = "noop" if your script decides that it doesn't have to make any changes. - The update by query operation skips updating the document and increments the noop counter.

    -

    Set ctx.op = "delete" if your script decides that the document should be deleted. - The update by query operation deletes the document and increments the deleted counter.

    -

    Update by query supports only index, noop, and delete. - Setting ctx.op to anything else is an error. - Setting any other field in ctx is an error. - This API enables you to only modify the source of matching documents; you cannot move them.

    +

    Whether query or update performance dominates the runtime depends on the documents being reindexed and cluster resources. + Refer to the linked documentation for examples of how to update documents using the _update_by_query API:

    ``_ @@ -6304,8 +6149,7 @@ async def update_by_query( :param expand_wildcards: The type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. It supports comma-separated - values, such as `open,hidden`. Valid values are: `all`, `open`, `closed`, - `hidden`, `none`. + values, such as `open,hidden`. :param from_: Skips the specified number of documents. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. diff --git a/elasticsearch/_async/client/cat.py b/elasticsearch/_async/client/cat.py index 1736c4b35..55aaded74 100644 --- a/elasticsearch/_async/client/cat.py +++ b/elasticsearch/_async/client/cat.py @@ -584,7 +584,9 @@ async def indices( filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, format: t.Optional[str] = None, h: t.Optional[t.Union[str, t.Sequence[str]]] = None, - health: t.Optional[t.Union[str, t.Literal["green", "red", "yellow"]]] = None, + health: t.Optional[ + t.Union[str, t.Literal["green", "red", "unavailable", "unknown", "yellow"]] + ] = None, help: t.Optional[bool] = None, human: t.Optional[bool] = None, include_unloaded_segments: t.Optional[bool] = None, @@ -2216,7 +2218,74 @@ async def recovery( error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, format: t.Optional[str] = None, - h: t.Optional[t.Union[str, t.Sequence[str]]] = None, + h: t.Optional[ + t.Union[ + t.Sequence[ + t.Union[ + str, + t.Literal[ + "bytes", + "bytes_percent", + "bytes_recovered", + "bytes_total", + "files", + "files_percent", + "files_recovered", + "files_total", + "index", + "repository", + "shard", + "snapshot", + "source_host", + "source_node", + "stage", + "start_time", + "start_time_millis", + "stop_time", + "stop_time_millis", + "target_host", + "target_node", + "time", + "translog_ops", + "translog_ops_percent", + "translog_ops_recovered", + "type", + ], + ] + ], + t.Union[ + str, + t.Literal[ + "bytes", + "bytes_percent", + "bytes_recovered", + "bytes_total", + "files", + "files_percent", + "files_recovered", + "files_total", + "index", + "repository", + "shard", + "snapshot", + "source_host", + "source_node", + "stage", + "start_time", + "start_time_millis", + "stop_time", + "stop_time_millis", + "target_host", + "target_node", + "time", + "translog_ops", + "translog_ops_percent", + "translog_ops_recovered", + "type", + ], + ], + ] + ] = None, help: t.Optional[bool] = None, human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, @@ -2247,13 +2316,14 @@ async def recovery( shard recoveries. :param format: Specifies the format to return the columnar data in, can be set to `text`, `json`, `cbor`, `yaml`, or `smile`. - :param h: List of columns to appear in the response. Supports simple wildcards. + :param h: A comma-separated list of columns names to display. It supports simple + wildcards. :param help: When set to `true` will output available columns. This option can't be combined with any other query string option. - :param s: List of columns that determine how the table should be sorted. Sorting - defaults to ascending and can be changed by setting `:asc` or `:desc` as - a suffix to the column name. - :param time: Unit used to display time values. + :param s: A comma-separated list of column names or aliases that determines the + sort order. Sorting defaults to ascending and can be changed by setting `:asc` + or `:desc` as a suffix to the column name. + :param time: The unit used to display time values. :param v: When set to `true` will enable verbose output. """ __path_parts: t.Dict[str, str] @@ -2387,7 +2457,52 @@ async def segments( error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, format: t.Optional[str] = None, - h: t.Optional[t.Union[str, t.Sequence[str]]] = None, + h: t.Optional[ + t.Union[ + t.Sequence[ + t.Union[ + str, + t.Literal[ + "committed", + "compound", + "docs.count", + "docs.deleted", + "generation", + "id", + "index", + "ip", + "prirep", + "searchable", + "segment", + "shard", + "size", + "size.memory", + "version", + ], + ] + ], + t.Union[ + str, + t.Literal[ + "committed", + "compound", + "docs.count", + "docs.deleted", + "generation", + "id", + "index", + "ip", + "prirep", + "searchable", + "segment", + "shard", + "size", + "size.memory", + "version", + ], + ], + ] + ] = None, help: t.Optional[bool] = None, human: t.Optional[bool] = None, local: t.Optional[bool] = None, @@ -2413,7 +2528,8 @@ async def segments( :param bytes: The unit used to display byte values. :param format: Specifies the format to return the columnar data in, can be set to `text`, `json`, `cbor`, `yaml`, or `smile`. - :param h: List of columns to appear in the response. Supports simple wildcards. + :param h: A comma-separated list of columns names to display. It supports simple + wildcards. :param help: When set to `true` will output available columns. This option can't be combined with any other query string option. :param local: If `true`, the request computes the list of selected nodes from @@ -2421,9 +2537,9 @@ async def segments( from the cluster state of the master node. In both cases the coordinating node will send requests for further information to each selected node. :param master_timeout: Period to wait for a connection to the master node. - :param s: List of columns that determine how the table should be sorted. Sorting - defaults to ascending and can be changed by setting `:asc` or `:desc` as - a suffix to the column name. + :param s: A comma-separated list of column names or aliases that determines the + sort order. Sorting defaults to ascending and can be changed by setting `:asc` + or `:desc` as a suffix to the column name. :param v: When set to `true` will enable verbose output. """ __path_parts: t.Dict[str, str] @@ -2479,7 +2595,162 @@ async def shards( error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, format: t.Optional[str] = None, - h: t.Optional[t.Union[str, t.Sequence[str]]] = None, + h: t.Optional[ + t.Union[ + t.Sequence[ + t.Union[ + str, + t.Literal[ + "completion.size", + "dataset.size", + "dense_vector.value_count", + "docs", + "dsparse_vector.value_count", + "fielddata.evictions", + "fielddata.memory_size", + "flush.total", + "flush.total_time", + "get.current", + "get.exists_time", + "get.exists_total", + "get.missing_time", + "get.missing_total", + "get.time", + "get.total", + "id", + "index", + "indexing.delete_current", + "indexing.delete_time", + "indexing.delete_total", + "indexing.index_current", + "indexing.index_failed", + "indexing.index_failed_due_to_version_conflict", + "indexing.index_time", + "indexing.index_total", + "ip", + "merges.current", + "merges.current_docs", + "merges.current_size", + "merges.total", + "merges.total_docs", + "merges.total_size", + "merges.total_time", + "node", + "prirep", + "query_cache.evictions", + "query_cache.memory_size", + "recoverysource.type", + "refresh.time", + "refresh.total", + "search.fetch_current", + "search.fetch_time", + "search.fetch_total", + "search.open_contexts", + "search.query_current", + "search.query_time", + "search.query_total", + "search.scroll_current", + "search.scroll_time", + "search.scroll_total", + "segments.count", + "segments.fixed_bitset_memory", + "segments.index_writer_memory", + "segments.memory", + "segments.version_map_memory", + "seq_no.global_checkpoint", + "seq_no.local_checkpoint", + "seq_no.max", + "shard", + "state", + "store", + "suggest.current", + "suggest.time", + "suggest.total", + "sync_id", + "unassigned.at", + "unassigned.details", + "unassigned.for", + "unassigned.reason", + ], + ] + ], + t.Union[ + str, + t.Literal[ + "completion.size", + "dataset.size", + "dense_vector.value_count", + "docs", + "dsparse_vector.value_count", + "fielddata.evictions", + "fielddata.memory_size", + "flush.total", + "flush.total_time", + "get.current", + "get.exists_time", + "get.exists_total", + "get.missing_time", + "get.missing_total", + "get.time", + "get.total", + "id", + "index", + "indexing.delete_current", + "indexing.delete_time", + "indexing.delete_total", + "indexing.index_current", + "indexing.index_failed", + "indexing.index_failed_due_to_version_conflict", + "indexing.index_time", + "indexing.index_total", + "ip", + "merges.current", + "merges.current_docs", + "merges.current_size", + "merges.total", + "merges.total_docs", + "merges.total_size", + "merges.total_time", + "node", + "prirep", + "query_cache.evictions", + "query_cache.memory_size", + "recoverysource.type", + "refresh.time", + "refresh.total", + "search.fetch_current", + "search.fetch_time", + "search.fetch_total", + "search.open_contexts", + "search.query_current", + "search.query_time", + "search.query_total", + "search.scroll_current", + "search.scroll_time", + "search.scroll_total", + "segments.count", + "segments.fixed_bitset_memory", + "segments.index_writer_memory", + "segments.memory", + "segments.version_map_memory", + "seq_no.global_checkpoint", + "seq_no.local_checkpoint", + "seq_no.max", + "shard", + "state", + "store", + "suggest.current", + "suggest.time", + "suggest.total", + "sync_id", + "unassigned.at", + "unassigned.details", + "unassigned.for", + "unassigned.reason", + ], + ], + ] + ] = None, help: t.Optional[bool] = None, human: t.Optional[bool] = None, master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, @@ -2510,11 +2781,11 @@ async def shards( :param h: List of columns to appear in the response. Supports simple wildcards. :param help: When set to `true` will output available columns. This option can't be combined with any other query string option. - :param master_timeout: Period to wait for a connection to the master node. - :param s: List of columns that determine how the table should be sorted. Sorting - defaults to ascending and can be changed by setting `:asc` or `:desc` as - a suffix to the column name. - :param time: Unit used to display time values. + :param master_timeout: The period to wait for a connection to the master node. + :param s: A comma-separated list of column names or aliases that determines the + sort order. Sorting defaults to ascending and can be changed by setting `:asc` + or `:desc` as a suffix to the column name. + :param time: The unit used to display time values. :param v: When set to `true` will enable verbose output. """ __path_parts: t.Dict[str, str] @@ -2567,7 +2838,48 @@ async def snapshots( error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, format: t.Optional[str] = None, - h: t.Optional[t.Union[str, t.Sequence[str]]] = None, + h: t.Optional[ + t.Union[ + t.Sequence[ + t.Union[ + str, + t.Literal[ + "duration", + "end_epoch", + "end_time", + "failed_shards", + "id", + "indices", + "reason", + "repository", + "start_epoch", + "start_time", + "status", + "successful_shards", + "total_shards", + ], + ] + ], + t.Union[ + str, + t.Literal[ + "duration", + "end_epoch", + "end_time", + "failed_shards", + "id", + "indices", + "reason", + "repository", + "start_epoch", + "start_time", + "status", + "successful_shards", + "total_shards", + ], + ], + ] + ] = None, help: t.Optional[bool] = None, human: t.Optional[bool] = None, ignore_unavailable: t.Optional[bool] = None, @@ -2595,7 +2907,8 @@ async def snapshots( If any repository fails during the request, Elasticsearch returns an error. :param format: Specifies the format to return the columnar data in, can be set to `text`, `json`, `cbor`, `yaml`, or `smile`. - :param h: List of columns to appear in the response. Supports simple wildcards. + :param h: A comma-separated list of columns names to display. It supports simple + wildcards. :param help: When set to `true` will output available columns. This option can't be combined with any other query string option. :param ignore_unavailable: If `true`, the response does not include information @@ -2842,7 +3155,62 @@ async def thread_pool( error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, format: t.Optional[str] = None, - h: t.Optional[t.Union[str, t.Sequence[str]]] = None, + h: t.Optional[ + t.Union[ + t.Sequence[ + t.Union[ + str, + t.Literal[ + "active", + "completed", + "core", + "ephemeral_id", + "host", + "ip", + "keep_alive", + "largest", + "max", + "name", + "node_id", + "node_name", + "pid", + "pool_size", + "port", + "queue", + "queue_size", + "rejected", + "size", + "type", + ], + ] + ], + t.Union[ + str, + t.Literal[ + "active", + "completed", + "core", + "ephemeral_id", + "host", + "ip", + "keep_alive", + "largest", + "max", + "name", + "node_id", + "node_name", + "pid", + "pool_size", + "port", + "queue", + "queue_size", + "rejected", + "size", + "type", + ], + ], + ] + ] = None, help: t.Optional[bool] = None, human: t.Optional[bool] = None, local: t.Optional[bool] = None, @@ -2876,10 +3244,10 @@ async def thread_pool( the local cluster state. If `false` the list of selected nodes are computed from the cluster state of the master node. In both cases the coordinating node will send requests for further information to each selected node. - :param master_timeout: Period to wait for a connection to the master node. - :param s: List of columns that determine how the table should be sorted. Sorting - defaults to ascending and can be changed by setting `:asc` or `:desc` as - a suffix to the column name. + :param master_timeout: The period to wait for a connection to the master node. + :param s: A comma-separated list of column names or aliases that determines the + sort order. Sorting defaults to ascending and can be changed by setting `:asc` + or `:desc` as a suffix to the column name. :param time: The unit used to display time values. :param v: When set to `true` will enable verbose output. """ diff --git a/elasticsearch/_async/client/cluster.py b/elasticsearch/_async/client/cluster.py index 14a340a02..ee8036536 100644 --- a/elasticsearch/_async/client/cluster.py +++ b/elasticsearch/_async/client/cluster.py @@ -51,7 +51,8 @@ async def allocation_explain( Get explanations for shard allocations in the cluster. For unassigned shards, it provides an explanation for why the shard is unassigned. For assigned shards, it provides an explanation for why the shard is remaining on its current node and has not moved or rebalanced to another node. - This API can be very useful when attempting to diagnose why a shard is unassigned or why a shard continues to remain on its current node when you might expect otherwise.

    + This API can be very useful when attempting to diagnose why a shard is unassigned or why a shard continues to remain on its current node when you might expect otherwise. + Refer to the linked documentation for examples of how to troubleshoot allocation issues using this API.

    ``_ @@ -290,6 +291,7 @@ async def get_component_template( local: t.Optional[bool] = None, master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, pretty: t.Optional[bool] = None, + settings_filter: t.Optional[t.Union[str, t.Sequence[str]]] = None, ) -> ObjectApiResponse[t.Any]: """ .. raw:: html @@ -310,6 +312,8 @@ async def get_component_template( :param master_timeout: Period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails and returns an error. + :param settings_filter: Filter out results, for example to filter out sensitive + information. Supports wildcards or full settings keys """ __path_parts: t.Dict[str, str] if name not in SKIP_IN_PATH: @@ -335,6 +339,8 @@ async def get_component_template( __query["master_timeout"] = master_timeout if pretty is not None: __query["pretty"] = pretty + if settings_filter is not None: + __query["settings_filter"] = settings_filter __headers = {"accept": "application/json"} return await self.perform_request( # type: ignore[return-value] "GET", @@ -441,7 +447,7 @@ async def health( wait_for_no_relocating_shards: t.Optional[bool] = None, wait_for_nodes: t.Optional[t.Union[int, str]] = None, wait_for_status: t.Optional[ - t.Union[str, t.Literal["green", "red", "yellow"]] + t.Union[str, t.Literal["green", "red", "unavailable", "unknown", "yellow"]] ] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -731,6 +737,7 @@ async def put_component_template( *, name: str, template: t.Optional[t.Mapping[str, t.Any]] = None, + cause: t.Optional[str] = None, create: t.Optional[bool] = None, deprecated: t.Optional[bool] = None, error_trace: t.Optional[bool] = None, @@ -774,6 +781,7 @@ async def put_component_template( update settings API. :param template: The template to be applied which includes mappings, settings, or aliases configuration. + :param cause: User defined reason for create the component template. :param create: If `true`, this request cannot replace or update existing component templates. :param deprecated: Marks this index template as deprecated. When creating or @@ -798,6 +806,8 @@ async def put_component_template( __path = f'/_component_template/{__path_parts["name"]}' __query: t.Dict[str, t.Any] = {} __body: t.Dict[str, t.Any] = body if body is not None else {} + if cause is not None: + __query["cause"] = cause if create is not None: __query["create"] = create if error_trace is not None: @@ -870,9 +880,9 @@ async def put_settings( :param flat_settings: Return settings in flat format (default: false) :param master_timeout: Explicit operation timeout for connection to master node - :param persistent: + :param persistent: The settings that persist after the cluster restarts. :param timeout: Explicit operation timeout - :param transient: + :param transient: The settings that do not persist after the cluster restarts. """ __path_parts: t.Dict[str, str] = {} __path = "/_cluster/settings" diff --git a/elasticsearch/_async/client/eql.py b/elasticsearch/_async/client/eql.py index 61c282c1b..2e7a16dfa 100644 --- a/elasticsearch/_async/client/eql.py +++ b/elasticsearch/_async/client/eql.py @@ -204,6 +204,7 @@ async def search( allow_partial_search_results: t.Optional[bool] = None, allow_partial_sequence_results: t.Optional[bool] = None, case_sensitive: t.Optional[bool] = None, + ccs_minimize_roundtrips: t.Optional[bool] = None, error_trace: t.Optional[bool] = None, event_category_field: t.Optional[str] = None, expand_wildcards: t.Optional[ @@ -250,7 +251,9 @@ async def search( :param index: The name of the index to scope the operation :param query: EQL query you wish to run. - :param allow_no_indices: + :param allow_no_indices: Whether to ignore if a wildcard indices expression resolves + into no concrete indices. (This includes `_all` string or when no indices + have been specified) :param allow_partial_search_results: Allow query execution also in case of shard failures. If true, the query will keep running and will return results based on the available shards. For sequences, the behavior can be further refined @@ -261,9 +264,12 @@ async def search( If false, the sequence query will return successfully, but will always have empty results. :param case_sensitive: + :param ccs_minimize_roundtrips: Indicates whether network round-trips should + be minimized as part of cross-cluster search requests execution :param event_category_field: Field containing the event classification, such as process, file, or network. - :param expand_wildcards: + :param expand_wildcards: Whether to expand wildcard expression to concrete indices + that are open, closed or both. :param fetch_size: Maximum number of events to search at a time for sequence queries. :param fields: Array of wildcard (*) patterns. The response returns values for @@ -298,6 +304,8 @@ async def search( __body: t.Dict[str, t.Any] = body if body is not None else {} if allow_no_indices is not None: __query["allow_no_indices"] = allow_no_indices + if ccs_minimize_roundtrips is not None: + __query["ccs_minimize_roundtrips"] = ccs_minimize_roundtrips if error_trace is not None: __query["error_trace"] = error_trace if expand_wildcards is not None: diff --git a/elasticsearch/_async/client/esql.py b/elasticsearch/_async/client/esql.py index d84c1e438..78ce82a64 100644 --- a/elasticsearch/_async/client/esql.py +++ b/elasticsearch/_async/client/esql.py @@ -31,6 +31,8 @@ class EsqlClient(NamespacedClient): "columnar", "filter", "include_ccs_metadata", + "keep_alive", + "keep_on_completion", "locale", "params", "profile", @@ -145,10 +147,6 @@ async def async_query( __query["format"] = format if human is not None: __query["human"] = human - if keep_alive is not None: - __query["keep_alive"] = keep_alive - if keep_on_completion is not None: - __query["keep_on_completion"] = keep_on_completion if pretty is not None: __query["pretty"] = pretty if not __body: @@ -160,6 +158,10 @@ async def async_query( __body["filter"] = filter if include_ccs_metadata is not None: __body["include_ccs_metadata"] = include_ccs_metadata + if keep_alive is not None: + __body["keep_alive"] = keep_alive + if keep_on_completion is not None: + __body["keep_on_completion"] = keep_on_completion if locale is not None: __body["locale"] = locale if params is not None: @@ -242,6 +244,14 @@ async def async_query_get( drop_null_columns: t.Optional[bool] = None, error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + format: t.Optional[ + t.Union[ + str, + t.Literal[ + "arrow", "cbor", "csv", "json", "smile", "tsv", "txt", "yaml" + ], + ] + ] = None, human: t.Optional[bool] = None, keep_alive: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, pretty: t.Optional[bool] = None, @@ -267,6 +277,7 @@ async def async_query_get( will be removed from the `columns` and `values` portion of the results. If `true`, the response will include an extra section under the name `all_columns` which has the name of all the columns. + :param format: A short version of the Accept header, for example `json` or `yaml`. :param keep_alive: The period for which the query and its results are stored in the cluster. When this period expires, the query and its results are deleted, even if the query is still ongoing. @@ -287,6 +298,8 @@ async def async_query_get( __query["error_trace"] = error_trace if filter_path is not None: __query["filter_path"] = filter_path + if format is not None: + __query["format"] = format if human is not None: __query["human"] = human if keep_alive is not None: diff --git a/elasticsearch/_async/client/indices.py b/elasticsearch/_async/client/indices.py index 0b5c9fde2..285db75d6 100644 --- a/elasticsearch/_async/client/indices.py +++ b/elasticsearch/_async/client/indices.py @@ -338,7 +338,7 @@ async def clear_cache( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param fielddata: If `true`, clears the fields cache. Use the `fields` parameter to clear the cache of specific fields only. :param fields: Comma-separated list of field names used to limit the `fielddata` @@ -563,7 +563,7 @@ async def close( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param master_timeout: Period to wait for a connection to the master node. If @@ -950,7 +950,7 @@ async def delete( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param master_timeout: Period to wait for a connection to the master node. If @@ -1495,7 +1495,7 @@ async def exists( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param flat_settings: If `true`, returns settings in flat format. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. @@ -1579,7 +1579,7 @@ async def exists_alias( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, requests that include a missing data stream or index in the target indices or data streams return an error. :param master_timeout: Period to wait for a connection to the master node. If @@ -1928,7 +1928,7 @@ async def flush( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param force: If `true`, the request forces a flush even if there are no changes to commit to the index. :param ignore_unavailable: If `false`, the request returns an error if it targets @@ -2246,7 +2246,7 @@ async def get_alias( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param master_timeout: Period to wait for a connection to the master node. If @@ -2326,8 +2326,7 @@ async def get_data_lifecycle( wildcards (`*`). To target all data streams, omit this parameter or use `*` or `_all`. :param expand_wildcards: Type of data stream that wildcard patterns can match. - Supports comma-separated values, such as `open,hidden`. Valid values are: - `all`, `open`, `closed`, `hidden`, `none`. + Supports comma-separated values, such as `open,hidden`. :param include_defaults: If `true`, return all default settings in the response. :param master_timeout: Period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails and @@ -2523,7 +2522,7 @@ async def get_field_mapping( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param include_defaults: If `true`, return all default settings in the response. @@ -2679,7 +2678,7 @@ async def get_mapping( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param local: If `true`, the request retrieves information from the local node @@ -3171,7 +3170,7 @@ async def open( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param master_timeout: Period to wait for a connection to the master node. If @@ -3430,8 +3429,7 @@ async def put_data_lifecycle( for this data stream. A data stream lifecycle that's disabled (enabled: `false`) will have no effect on the data stream. :param expand_wildcards: Type of data stream that wildcard patterns can match. - Supports comma-separated values, such as `open,hidden`. Valid values are: - `all`, `hidden`, `open`, `closed`, `none`. + Supports comma-separated values, such as `open,hidden`. :param master_timeout: Period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails and returns an error. @@ -3707,24 +3705,17 @@ async def put_mapping(

    Update field mappings. Add new fields to an existing data stream or index. - You can also use this API to change the search settings of existing fields and add new properties to existing object fields. - For data streams, these changes are applied to all backing indices by default.

    -

    Add multi-fields to an existing field

    -

    Multi-fields let you index the same field in different ways. - You can use this API to update the fields mapping parameter and enable multi-fields for an existing field. - WARNING: If an index (or data stream) contains documents when you add a multi-field, those documents will not have values for the new multi-field. - You can populate the new multi-field with the update by query API.

    -

    Change supported mapping parameters for an existing field

    -

    The documentation for each mapping parameter indicates whether you can update it for an existing field using this API. - For example, you can use the update mapping API to update the ignore_above parameter.

    -

    Change the mapping of an existing field

    -

    Except for supported mapping parameters, you can't change the mapping or field type of an existing field. - Changing an existing field could invalidate data that's already indexed.

    -

    If you need to change the mapping of a field in a data stream's backing indices, refer to documentation about modifying data streams. - If you need to change the mapping of a field in other indices, create a new index with the correct mapping and reindex your data into that index.

    -

    Rename a field

    -

    Renaming a field would invalidate data already indexed under the old field name. - Instead, add an alias field to create an alternate field name.

    + You can use the update mapping API to:

    +
      +
    • Add a new field to an existing index
    • +
    • Update mappings for multiple indices in a single request
    • +
    • Add new properties to an object field
    • +
    • Enable multi-fields for an existing field
    • +
    • Update supported mapping parameters
    • +
    • Change a field's mapping using reindexing
    • +
    • Rename a field using a field alias
    • +
    +

    Learn how to use the update mapping API with practical examples in the Update mapping API examples guide.

    ``_ @@ -3743,7 +3734,7 @@ async def put_mapping( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param field_names: Control whether field names are enabled for the index. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. @@ -3861,8 +3852,36 @@ async def put_settings( Changes dynamic index settings in real time. For data streams, index setting changes are applied to all backing indices by default.

    To revert a setting to the default value, use a null value. - The list of per-index settings that can be updated dynamically on live indices can be found in index module documentation. + The list of per-index settings that can be updated dynamically on live indices can be found in index settings documentation. To preserve existing settings from being updated, set the preserve_existing parameter to true.

    +

    For performance optimization during bulk indexing, you can disable the refresh interval. + Refer to disable refresh interval for an example. + There are multiple valid ways to represent index settings in the request body. You can specify only the setting, for example:

    +
    {
    +            "number_of_replicas": 1
    +          }
    +          
    +

    Or you can use an index setting object:

    +
    {
    +            "index": {
    +              "number_of_replicas": 1
    +            }
    +          }
    +          
    +

    Or you can use dot annotation:

    +
    {
    +            "index.number_of_replicas": 1
    +          }
    +          
    +

    Or you can embed any of the aforementioned options in a settings object. For example:

    +
    {
    +            "settings": {
    +              "index": {
    +                "number_of_replicas": 1
    +              }
    +            }
    +          }
    +          

    NOTE: You can only define new analyzers on closed indices. To add an analyzer, you must close the index, define the analyzer, and reopen the index. You cannot close the write index of a data stream. @@ -3870,7 +3889,8 @@ async def put_settings( Then roll over the data stream to apply the new analyzer to the stream's write index and future backing indices. This affects searches and any new data added to the stream after the rollover. However, it does not affect the data stream's backing indices or their existing data. - To change the analyzer for existing backing indices, you must create a new data stream and reindex your data into it.

    + To change the analyzer for existing backing indices, you must create a new data stream and reindex your data into it. + Refer to updating analyzers on existing indices for step-by-step examples.

    ``_ @@ -4071,10 +4091,20 @@ async def recovery( *, index: t.Optional[t.Union[str, t.Sequence[str]]] = None, active_only: t.Optional[bool] = None, + allow_no_indices: t.Optional[bool] = None, detailed: t.Optional[bool] = None, error_trace: t.Optional[bool] = None, + expand_wildcards: t.Optional[ + t.Union[ + t.Sequence[ + t.Union[str, t.Literal["all", "closed", "hidden", "none", "open"]] + ], + t.Union[str, t.Literal["all", "closed", "hidden", "none", "open"]], + ] + ] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, + ignore_unavailable: t.Optional[bool] = None, pretty: t.Optional[bool] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -4107,8 +4137,17 @@ async def recovery( to limit the request. Supports wildcards (`*`). To target all data streams and indices, omit this parameter or use `*` or `_all`. :param active_only: If `true`, the response only includes ongoing shard recoveries. + :param allow_no_indices: If `false`, the request returns an error if any wildcard + expression, index alias, or `_all` value targets only missing or closed indices. + This behavior applies even if the request targets other open indices. :param detailed: If `true`, the response includes detailed information about shard recoveries. + :param expand_wildcards: Type of index that wildcard patterns can match. If the + request can target data streams, this argument determines whether wildcard + expressions match hidden data streams. Supports comma-separated values, such + as `open,hidden`. + :param ignore_unavailable: If `false`, the request returns an error if it targets + a missing or closed index. """ __path_parts: t.Dict[str, str] if index not in SKIP_IN_PATH: @@ -4120,14 +4159,20 @@ async def recovery( __query: t.Dict[str, t.Any] = {} if active_only is not None: __query["active_only"] = active_only + if allow_no_indices is not None: + __query["allow_no_indices"] = allow_no_indices if detailed is not None: __query["detailed"] = detailed if error_trace is not None: __query["error_trace"] = error_trace + if expand_wildcards is not None: + __query["expand_wildcards"] = expand_wildcards if filter_path is not None: __query["filter_path"] = filter_path if human is not None: __query["human"] = human + if ignore_unavailable is not None: + __query["ignore_unavailable"] = ignore_unavailable if pretty is not None: __query["pretty"] = pretty __headers = {"accept": "application/json"} @@ -4186,7 +4231,7 @@ async def refresh( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. """ @@ -4385,10 +4430,9 @@ async def resolve_cluster( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. - NOTE: This option is only supported when specifying an index expression. - You will get an error if you specify index options to the `_resolve/cluster` - API endpoint that takes no index expression. + as `open,hidden`. NOTE: This option is only supported when specifying an + index expression. You will get an error if you specify index options to the + `_resolve/cluster` API endpoint that takes no index expression. :param ignore_throttled: If true, concrete, expanded, or aliased indices are ignored when frozen. NOTE: This option is only supported when specifying an index expression. You will get an error if you specify index options to @@ -4481,7 +4525,7 @@ async def resolve_index( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. """ @@ -4695,7 +4739,7 @@ async def segments( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. """ @@ -5519,7 +5563,7 @@ async def validate_query( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param explain: If `true`, the response returns detailed information if an error has occurred. :param ignore_unavailable: If `false`, the request returns an error if it targets diff --git a/elasticsearch/_async/client/inference.py b/elasticsearch/_async/client/inference.py index 8437a8b89..22f51e29e 100644 --- a/elasticsearch/_async/client/inference.py +++ b/elasticsearch/_async/client/inference.py @@ -366,6 +366,7 @@ async def put( filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, ) -> ObjectApiResponse[t.Any]: """ .. raw:: html @@ -374,13 +375,35 @@ async def put(

    IMPORTANT: The inference APIs enable you to use certain services, such as built-in machine learning models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Mistral, Azure OpenAI, Google AI Studio, Google Vertex AI, Anthropic, Watsonx.ai, or Hugging Face. For built-in models and models uploaded through Eland, the inference APIs offer an alternative way to use and manage trained models. However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.

    +

    The following integrations are available through the inference API. You can find the available task types next to the integration name:

    +
      +
    • AlibabaCloud AI Search (completion, rerank, sparse_embedding, text_embedding)
    • +
    • Amazon Bedrock (completion, text_embedding)
    • +
    • Anthropic (completion)
    • +
    • Azure AI Studio (completion, text_embedding)
    • +
    • Azure OpenAI (completion, text_embedding)
    • +
    • Cohere (completion, rerank, text_embedding)
    • +
    • Elasticsearch (rerank, sparse_embedding, text_embedding - this service is for built-in models and models uploaded through Eland)
    • +
    • ELSER (sparse_embedding)
    • +
    • Google AI Studio (completion, text_embedding)
    • +
    • Google Vertex AI (rerank, text_embedding)
    • +
    • Hugging Face (text_embedding)
    • +
    • Mistral (text_embedding)
    • +
    • OpenAI (chat_completion, completion, text_embedding)
    • +
    • VoyageAI (text_embedding, rerank)
    • +
    • Watsonx inference integration (text_embedding)
    • +
    • JinaAI (text_embedding, rerank)
    • +
    ``_ :param inference_id: The inference Id :param inference_config: - :param task_type: The task type + :param task_type: The task type. Refer to the integration list in the API description + for the available task types. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if inference_id in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'inference_id'") @@ -411,6 +434,8 @@ async def put( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout __body = inference_config if inference_config is not None else body __headers = {"accept": "application/json", "content-type": "application/json"} return await self.perform_request( # type: ignore[return-value] @@ -446,6 +471,7 @@ async def put_alibabacloud( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -466,6 +492,8 @@ async def put_alibabacloud( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -492,6 +520,8 @@ async def put_alibabacloud( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -537,13 +567,14 @@ async def put_amazonbedrock( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ .. raw:: html

    Create an Amazon Bedrock inference endpoint.

    -

    Creates an inference endpoint to perform an inference task with the amazonbedrock service.

    +

    Create an inference endpoint to perform an inference task with the amazonbedrock service.

    info You need to provide the access and secret keys only once, during the inference model creation. The get inference API does not retrieve your access or secret keys. After creating the inference model, you cannot change the associated key pairs. If you want to use a different access and secret key pair, delete the inference model and recreate it with the same name and the updated keys.

    @@ -561,6 +592,8 @@ async def put_amazonbedrock( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -587,6 +620,8 @@ async def put_amazonbedrock( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -632,6 +667,7 @@ async def put_anthropic( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -653,6 +689,8 @@ async def put_anthropic( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -679,6 +717,8 @@ async def put_anthropic( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -724,6 +764,7 @@ async def put_azureaistudio( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -744,6 +785,8 @@ async def put_azureaistudio( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -770,6 +813,8 @@ async def put_azureaistudio( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -815,6 +860,7 @@ async def put_azureopenai( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -843,6 +889,8 @@ async def put_azureopenai( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -869,6 +917,8 @@ async def put_azureopenai( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -914,6 +964,7 @@ async def put_cohere( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -934,6 +985,8 @@ async def put_cohere( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -958,6 +1011,8 @@ async def put_cohere( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1005,6 +1060,7 @@ async def put_elasticsearch( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -1039,6 +1095,8 @@ async def put_elasticsearch( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -1065,6 +1123,8 @@ async def put_elasticsearch( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1104,6 +1164,7 @@ async def put_elser( filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -1136,6 +1197,8 @@ async def put_elser( :param service_settings: Settings used to install the inference model. These settings are specific to the `elser` service. :param chunking_settings: The chunking configuration object. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -1160,6 +1223,8 @@ async def put_elser( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1197,6 +1262,7 @@ async def put_googleaistudio( filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -1215,6 +1281,8 @@ async def put_googleaistudio( :param service_settings: Settings used to install the inference model. These settings are specific to the `googleaistudio` service. :param chunking_settings: The chunking configuration object. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -1241,6 +1309,8 @@ async def put_googleaistudio( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1284,6 +1354,7 @@ async def put_googlevertexai( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -1304,6 +1375,8 @@ async def put_googlevertexai( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -1330,6 +1403,8 @@ async def put_googlevertexai( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1369,6 +1444,7 @@ async def put_hugging_face( filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -1400,6 +1476,8 @@ async def put_hugging_face( :param service_settings: Settings used to install the inference model. These settings are specific to the `hugging_face` service. :param chunking_settings: The chunking configuration object. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -1426,6 +1504,8 @@ async def put_hugging_face( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1469,6 +1549,7 @@ async def put_jinaai( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -1491,6 +1572,8 @@ async def put_jinaai( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -1515,6 +1598,8 @@ async def put_jinaai( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1554,6 +1639,7 @@ async def put_mistral( filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -1573,6 +1659,8 @@ async def put_mistral( :param service_settings: Settings used to install the inference model. These settings are specific to the `mistral` service. :param chunking_settings: The chunking configuration object. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -1597,6 +1685,8 @@ async def put_mistral( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1642,6 +1732,7 @@ async def put_openai( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -1664,6 +1755,8 @@ async def put_openai( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -1688,6 +1781,8 @@ async def put_openai( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1733,6 +1828,7 @@ async def put_voyageai( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -1754,6 +1850,8 @@ async def put_voyageai( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -1778,6 +1876,8 @@ async def put_voyageai( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1816,6 +1916,7 @@ async def put_watsonx( filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -1836,6 +1937,8 @@ async def put_watsonx( this case, `watsonxai`. :param service_settings: Settings used to install the inference model. These settings are specific to the `watsonxai` service. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -1860,6 +1963,8 @@ async def put_watsonx( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1900,7 +2005,7 @@ async def rerank( """ .. raw:: html -

    Perform rereanking inference on the service

    +

    Perform reranking inference on the service

    ``_ diff --git a/elasticsearch/_async/client/ingest.py b/elasticsearch/_async/client/ingest.py index ebc47151a..d2fa0e4ae 100644 --- a/elasticsearch/_async/client/ingest.py +++ b/elasticsearch/_async/client/ingest.py @@ -288,7 +288,6 @@ async def get_ip_location_database( error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, - master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, pretty: t.Optional[bool] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -302,10 +301,6 @@ async def get_ip_location_database( :param id: Comma-separated list of database configuration IDs to retrieve. Wildcard (`*`) expressions are supported. To get all database configurations, omit this parameter or use `*`. - :param master_timeout: The period to wait for a connection to the master node. - If no response is received before the timeout expires, the request fails - and returns an error. A value of `-1` indicates that the request should never - time out. """ __path_parts: t.Dict[str, str] if id not in SKIP_IN_PATH: @@ -321,8 +316,6 @@ async def get_ip_location_database( __query["filter_path"] = filter_path if human is not None: __query["human"] = human - if master_timeout is not None: - __query["master_timeout"] = master_timeout if pretty is not None: __query["pretty"] = pretty __headers = {"accept": "application/json"} diff --git a/elasticsearch/_async/client/license.py b/elasticsearch/_async/client/license.py index 5f4976a81..05ebbd30b 100644 --- a/elasticsearch/_async/client/license.py +++ b/elasticsearch/_async/client/license.py @@ -353,7 +353,7 @@ async def post_start_trial( human: t.Optional[bool] = None, master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, pretty: t.Optional[bool] = None, - type_query_string: t.Optional[str] = None, + type: t.Optional[str] = None, ) -> ObjectApiResponse[t.Any]: """ .. raw:: html @@ -370,7 +370,7 @@ async def post_start_trial( :param acknowledge: whether the user has acknowledged acknowledge messages (default: false) :param master_timeout: Period to wait for a connection to the master node. - :param type_query_string: + :param type: The type of trial license to generate (default: "trial") """ __path_parts: t.Dict[str, str] = {} __path = "/_license/start_trial" @@ -387,8 +387,8 @@ async def post_start_trial( __query["master_timeout"] = master_timeout if pretty is not None: __query["pretty"] = pretty - if type_query_string is not None: - __query["type_query_string"] = type_query_string + if type is not None: + __query["type"] = type __headers = {"accept": "application/json"} return await self.perform_request( # type: ignore[return-value] "POST", diff --git a/elasticsearch/_async/client/ml.py b/elasticsearch/_async/client/ml.py index 594dd8f09..ed1dc3f82 100644 --- a/elasticsearch/_async/client/ml.py +++ b/elasticsearch/_async/client/ml.py @@ -3549,7 +3549,8 @@ async def put_datafeed( Datafeeds retrieve data from Elasticsearch for analysis by an anomaly detection job. You can associate only one datafeed with each anomaly detection job. The datafeed contains a query that runs at a defined interval (frequency). - If you are concerned about delayed data, you can add a delay (query_delay') at each interval. By default, the datafeed uses the following query: {"match_all": {"boost": 1}}`.

    + If you are concerned about delayed data, you can add a delay (query_delay) at each interval. + By default, the datafeed uses the following query: {"match_all": {"boost": 1}}.

    When Elasticsearch security features are enabled, your datafeed remembers which roles the user who created it had at the time of creation and runs the query using those same roles. If you provide secondary authorization headers, those credentials are used instead. @@ -3871,13 +3872,7 @@ async def put_job( :param description: A description of the job. :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard - expressions match hidden data streams. Supports comma-separated values. Valid - values are: * `all`: Match any data stream or index, including hidden ones. - * `closed`: Match closed, non-hidden indices. Also matches any non-hidden - data stream. Data streams cannot be closed. * `hidden`: Match hidden data - streams and hidden indices. Must be combined with `open`, `closed`, or both. - * `none`: Wildcard patterns are not accepted. * `open`: Match open, non-hidden - indices. Also matches any non-hidden data stream. + expressions match hidden data streams. Supports comma-separated values. :param groups: A list of job groups. A job can belong to no groups or many. :param ignore_throttled: If `true`, concrete, expanded or aliased indices are ignored when frozen. @@ -4999,7 +4994,7 @@ async def update_data_frame_analytics(

    Update a data frame analytics job.

    - ``_ + ``_ :param id: Identifier for the data frame analytics job. This identifier can contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and underscores. @@ -5140,13 +5135,7 @@ async def update_datafeed( check runs only on real-time datafeeds. :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard - expressions match hidden data streams. Supports comma-separated values. Valid - values are: * `all`: Match any data stream or index, including hidden ones. - * `closed`: Match closed, non-hidden indices. Also matches any non-hidden - data stream. Data streams cannot be closed. * `hidden`: Match hidden data - streams and hidden indices. Must be combined with `open`, `closed`, or both. - * `none`: Wildcard patterns are not accepted. * `open`: Match open, non-hidden - indices. Also matches any non-hidden data stream. + expressions match hidden data streams. Supports comma-separated values. :param frequency: The interval at which scheduled queries are made while the datafeed runs in real time. The default value is either the bucket span for short bucket spans, or, for longer bucket spans, a sensible fraction of the @@ -5801,7 +5790,7 @@ async def validate_detector(

    Validate an anomaly detection job.

    - ``_ + ``_ :param detector: """ diff --git a/elasticsearch/_async/client/monitoring.py b/elasticsearch/_async/client/monitoring.py index 4ab6dd02e..afc6406da 100644 --- a/elasticsearch/_async/client/monitoring.py +++ b/elasticsearch/_async/client/monitoring.py @@ -48,7 +48,7 @@ async def bulk( This API is used by the monitoring features to send monitoring data.

    - ``_ + ``_ :param interval: Collection interval (e.g., '10s' or '10000ms') of the payload :param operations: diff --git a/elasticsearch/_async/client/rollup.py b/elasticsearch/_async/client/rollup.py index 1324175e5..63a3955aa 100644 --- a/elasticsearch/_async/client/rollup.py +++ b/elasticsearch/_async/client/rollup.py @@ -419,28 +419,7 @@ async def rollup_search( The following functionality is not available:

    size: Because rollups work on pre-aggregated data, no search hits can be returned and so size must be set to zero or omitted entirely. highlighter, suggestors, post_filter, profile, explain: These are similarly disallowed.

    -

    Searching both historical rollup and non-rollup data

    -

    The rollup search API has the capability to search across both "live" non-rollup data and the aggregated rollup data. - This is done by simply adding the live indices to the URI. For example:

    -
    GET sensor-1,sensor_rollup/_rollup_search
    -          {
    -            "size": 0,
    -            "aggregations": {
    -               "max_temperature": {
    -                "max": {
    -                  "field": "temperature"
    -                }
    -              }
    -            }
    -          }
    -          
    -

    The rollup search endpoint does two things when the search runs:

    -
      -
    • The original request is sent to the non-rollup index unaltered.
    • -
    • A rewritten version of the original request is sent to the rollup index.
    • -
    -

    When the two responses are received, the endpoint rewrites the rollup response and merges the two together. - During the merging process, if there is any overlap in buckets between the two responses, the buckets from the non-rollup index are used.

    +

    For more detailed examples of using the rollup search API, including querying rolled-up data only or combining rolled-up and live data, refer to the External documentation.

    ``_ diff --git a/elasticsearch/_async/client/security.py b/elasticsearch/_async/client/security.py index cc6fa3ccb..f1b128f3d 100644 --- a/elasticsearch/_async/client/security.py +++ b/elasticsearch/_async/client/security.py @@ -2213,13 +2213,10 @@ async def get_user( async def get_user_privileges( self, *, - application: t.Optional[str] = None, error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, - priviledge: t.Optional[str] = None, - username: t.Optional[t.Union[None, str]] = None, ) -> ObjectApiResponse[t.Any]: """ .. raw:: html @@ -2232,19 +2229,10 @@ async def get_user_privileges( ``_ - - :param application: The name of the application. Application privileges are always - associated with exactly one application. If you do not specify this parameter, - the API returns information about all privileges for all applications. - :param priviledge: The name of the privilege. If you do not specify this parameter, - the API returns information about all privileges for the requested application. - :param username: """ __path_parts: t.Dict[str, str] = {} __path = "/_security/user/_privileges" __query: t.Dict[str, t.Any] = {} - if application is not None: - __query["application"] = application if error_trace is not None: __query["error_trace"] = error_trace if filter_path is not None: @@ -2253,10 +2241,6 @@ async def get_user_privileges( __query["human"] = human if pretty is not None: __query["pretty"] = pretty - if priviledge is not None: - __query["priviledge"] = priviledge - if username is not None: - __query["username"] = username __headers = {"accept": "application/json"} return await self.perform_request( # type: ignore[return-value] "GET", @@ -2345,6 +2329,9 @@ async def grant_api_key( human: t.Optional[bool] = None, password: t.Optional[str] = None, pretty: t.Optional[bool] = None, + refresh: t.Optional[ + t.Union[bool, str, t.Literal["false", "true", "wait_for"]] + ] = None, run_as: t.Optional[str] = None, username: t.Optional[str] = None, body: t.Optional[t.Dict[str, t.Any]] = None, @@ -2382,6 +2369,9 @@ async def grant_api_key( types. :param password: The user's password. If you specify the `password` grant type, this parameter is required. It is not valid with other grant types. + :param refresh: If 'true', Elasticsearch refreshes the affected shards to make + this operation visible to search. If 'wait_for', it waits for a refresh to + make this operation visible to search. If 'false', nothing is done with refreshes. :param run_as: The name of the user to be impersonated. :param username: The user name that identifies the user. If you specify the `password` grant type, this parameter is required. It is not valid with other grant @@ -2403,6 +2393,8 @@ async def grant_api_key( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if refresh is not None: + __query["refresh"] = refresh if not __body: if api_key is not None: __body["api_key"] = api_key @@ -3553,7 +3545,8 @@ async def query_api_keys( You can optionally filter the results with a query.

    To use this API, you must have at least the manage_own_api_key or the read_security cluster privileges. If you have only the manage_own_api_key privilege, this API returns only the API keys that you own. - If you have the read_security, manage_api_key, or greater privileges (including manage_security), this API returns all API keys regardless of ownership.

    + If you have the read_security, manage_api_key, or greater privileges (including manage_security), this API returns all API keys regardless of ownership. + Refer to the linked documentation for examples of how to find API keys:

    ``_ @@ -4466,6 +4459,7 @@ async def update_cross_cluster_api_key(

    This API supports updates to an API key's access scope, metadata, and expiration. The owner user's information, such as the username and realm, is also updated automatically on every call.

    NOTE: This API cannot update REST API keys, which should be updated by either the update API key or bulk update API keys API.

    +

    To learn more about how to use this API, refer to the Update cross cluter API key API examples page.

    ``_ diff --git a/elasticsearch/_async/client/snapshot.py b/elasticsearch/_async/client/snapshot.py index 0669c6971..02abc5ad6 100644 --- a/elasticsearch/_async/client/snapshot.py +++ b/elasticsearch/_async/client/snapshot.py @@ -403,6 +403,7 @@ async def delete( human: t.Optional[bool] = None, master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, pretty: t.Optional[bool] = None, + wait_for_completion: t.Optional[bool] = None, ) -> ObjectApiResponse[t.Any]: """ .. raw:: html @@ -418,6 +419,9 @@ async def delete( :param master_timeout: The period to wait for the master node. If the master node is not available before the timeout expires, the request fails and returns an error. To indicate that the request should never timeout, set it to `-1`. + :param wait_for_completion: If `true`, the request returns a response when the + matching snapshots are all deleted. If `false`, the request returns a response + as soon as the deletes are scheduled. """ if repository in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'repository'") @@ -439,6 +443,8 @@ async def delete( __query["master_timeout"] = master_timeout if pretty is not None: __query["pretty"] = pretty + if wait_for_completion is not None: + __query["wait_for_completion"] = wait_for_completion __headers = {"accept": "application/json"} return await self.perform_request( # type: ignore[return-value] "DELETE", diff --git a/elasticsearch/_async/client/synonyms.py b/elasticsearch/_async/client/synonyms.py index 5807a29c0..b1dbdb719 100644 --- a/elasticsearch/_async/client/synonyms.py +++ b/elasticsearch/_async/client/synonyms.py @@ -309,6 +309,7 @@ async def put_synonym( If you need to manage more synonym rules, you can create multiple synonym sets.

    When an existing synonyms set is updated, the search analyzers that use the synonyms set are reloaded automatically for all indices. This is equivalent to invoking the reload search analyzers API for all indices that use the synonyms set.

    +

    For practical examples of how to create or update a synonyms set, refer to the External documentation.

    ``_ diff --git a/elasticsearch/_async/client/watcher.py b/elasticsearch/_async/client/watcher.py index 5afde82bd..92c1aedc6 100644 --- a/elasticsearch/_async/client/watcher.py +++ b/elasticsearch/_async/client/watcher.py @@ -45,7 +45,8 @@ async def ack_watch(

    IMPORTANT: If the specified watch is currently being executed, this API will return an error The reason for this behavior is to prevent overwriting the watch status from a watch execution.

    Acknowledging an action throttles further executions of that action until its ack.state is reset to awaits_successful_execution. - This happens when the condition of the watch is not met (the condition evaluates to false).

    + This happens when the condition of the watch is not met (the condition evaluates to false). + To demonstrate how throttling works in practice and how it can be configured for individual actions within a watch, refer to External documentation.

    ``_ @@ -274,7 +275,8 @@ async def execute_watch( This serves as great tool for testing and debugging your watches prior to adding them to Watcher.

    When Elasticsearch security features are enabled on your cluster, watches are run with the privileges of the user that stored the watches. If your user is allowed to read index a, but not index b, then the exact same set of rules will apply during execution of a watch.

    -

    When using the run watch API, the authorization data of the user that called the API will be used as a base, instead of the information who stored the watch.

    +

    When using the run watch API, the authorization data of the user that called the API will be used as a base, instead of the information who stored the watch. + Refer to the external documentation for examples of watch execution requests, including existing, customized, and inline watches.

    ``_ diff --git a/elasticsearch/_sync/client/__init__.py b/elasticsearch/_sync/client/__init__.py index a6230144c..f174f4ecd 100644 --- a/elasticsearch/_sync/client/__init__.py +++ b/elasticsearch/_sync/client/__init__.py @@ -635,6 +635,8 @@ def bulk( Imagine a _bulk?refresh=wait_for request with three documents in it that happen to be routed to different shards in an index with five shards. The request will only wait for those three shards to refresh. The other two shards that make up the index do not participate in the _bulk request at all.

    +

    You might want to disable the refresh interval temporarily to improve indexing throughput for large bulk requests. + Refer to the linked documentation for step-by-step instructions using the index settings API.

    ``_ @@ -1027,10 +1029,7 @@ def create( error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, - if_primary_term: t.Optional[int] = None, - if_seq_no: t.Optional[int] = None, include_source_on_error: t.Optional[bool] = None, - op_type: t.Optional[t.Union[str, t.Literal["create", "index"]]] = None, pipeline: t.Optional[str] = None, pretty: t.Optional[bool] = None, refresh: t.Optional[ @@ -1115,18 +1114,8 @@ def create( :param id: A unique identifier for the document. To automatically generate a document ID, use the `POST //_doc/` request format. :param document: - :param if_primary_term: Only perform the operation if the document has this primary - term. - :param if_seq_no: Only perform the operation if the document has this sequence - number. :param include_source_on_error: True or false if to include the document source in the error message in case of parsing errors. - :param op_type: Set to `create` to only index the document if it does not already - exist (put if absent). If a document with the specified `_id` already exists, - the indexing operation will fail. The behavior is the same as using the `/_create` - endpoint. If a document ID is specified, this paramater defaults to `index`. - Otherwise, it defaults to `create`. If the request targets a data stream, - an `op_type` of `create` is required. :param pipeline: The ID of the pipeline to use to preprocess incoming documents. If the index has a default ingest pipeline specified, setting the value to `_none` turns off the default ingest pipeline for this request. If a final @@ -1178,14 +1167,8 @@ def create( __query["filter_path"] = filter_path if human is not None: __query["human"] = human - if if_primary_term is not None: - __query["if_primary_term"] = if_primary_term - if if_seq_no is not None: - __query["if_seq_no"] = if_seq_no if include_source_on_error is not None: __query["include_source_on_error"] = include_source_on_error - if op_type is not None: - __query["op_type"] = op_type if pipeline is not None: __query["pipeline"] = pipeline if pretty is not None: @@ -2322,7 +2305,7 @@ def get( :param index: The name of the index that contains the document. :param id: A unique document identifier. :param force_synthetic_source: Indicates whether the request forces synthetic - `_source`. Use this paramater to test if the mapping supports synthetic `_source` + `_source`. Use this parameter to test if the mapping supports synthetic `_source` and to get a sense of the worst case performance. Fetches with this parameter enabled will be slower than enabling synthetic source natively in the index. :param preference: The node or shard the operation should be performed on. By @@ -2353,8 +2336,8 @@ def get( :param stored_fields: A comma-separated list of stored fields to return as part of a hit. If no fields are specified, no stored fields are included in the response. If this field is specified, the `_source` parameter defaults to - `false`. Only leaf fields can be retrieved with the `stored_field` option. - Object fields can't be returned;​if specified, the request fails. + `false`. Only leaf fields can be retrieved with the `stored_fields` option. + Object fields can't be returned; if specified, the request fails. :param version: The version number for concurrency control. It must match the current version of the document for the request to succeed. :param version_type: The version type. @@ -2558,7 +2541,6 @@ def get_source( source: t.Optional[t.Union[bool, t.Union[str, t.Sequence[str]]]] = None, source_excludes: t.Optional[t.Union[str, t.Sequence[str]]] = None, source_includes: t.Optional[t.Union[str, t.Sequence[str]]] = None, - stored_fields: t.Optional[t.Union[str, t.Sequence[str]]] = None, version: t.Optional[int] = None, version_type: t.Optional[ t.Union[str, t.Literal["external", "external_gte", "force", "internal"]] @@ -2595,8 +2577,6 @@ def get_source( the response. :param source_includes: A comma-separated list of source fields to include in the response. - :param stored_fields: A comma-separated list of stored fields to return as part - of a hit. :param version: The version number for concurrency control. It must match the current version of the document for the request to succeed. :param version_type: The version type. @@ -2630,8 +2610,6 @@ def get_source( __query["_source_excludes"] = source_excludes if source_includes is not None: __query["_source_includes"] = source_includes - if stored_fields is not None: - __query["stored_fields"] = stored_fields if version is not None: __query["version"] = version if version_type is not None: @@ -2740,6 +2718,7 @@ def index( t.Union[bool, str, t.Literal["false", "true", "wait_for"]] ] = None, require_alias: t.Optional[bool] = None, + require_data_stream: t.Optional[bool] = None, routing: t.Optional[str] = None, timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, version: t.Optional[int] = None, @@ -2875,6 +2854,8 @@ def index( this operation visible to search. If `wait_for`, it waits for a refresh to make this operation visible to search. If `false`, it does nothing with refreshes. :param require_alias: If `true`, the destination must be an index alias. + :param require_data_stream: If `true`, the request's actions must target a data + stream (existing or to be created). :param routing: A custom value that is used to route operations to a specific shard. :param timeout: The period the request waits for the following operations: automatic @@ -2936,6 +2917,8 @@ def index( __query["refresh"] = refresh if require_alias is not None: __query["require_alias"] = require_alias + if require_data_stream is not None: + __query["require_data_stream"] = require_data_stream if routing is not None: __query["routing"] = routing if timeout is not None: @@ -2971,7 +2954,8 @@ def info( .. raw:: html

    Get cluster info. - Get basic build, version, and cluster information.

    + Get basic build, version, and cluster information. + ::: In Serverless, this API is retained for backward compatibility only. Some response fields, such as the version number, should be ignored.

    ``_ @@ -3584,8 +3568,7 @@ def open_point_in_time( :param expand_wildcards: The type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. It supports comma-separated - values, such as `open,hidden`. Valid values are: `all`, `open`, `closed`, - `hidden`, `none`. + values, such as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param index_filter: Filter indices if the provided query rewrites to `match_none` @@ -3885,110 +3868,7 @@ def reindex( In this case, the response includes a count of the version conflicts that were encountered. Note that the handling of other error types is unaffected by the conflicts property. Additionally, if you opt to count version conflicts, the operation could attempt to reindex more documents from the source than max_docs until it has successfully indexed max_docs documents into the target or it has gone through every document in the source query.

    -

    NOTE: The reindex API makes no effort to handle ID collisions. - The last document written will "win" but the order isn't usually predictable so it is not a good idea to rely on this behavior. - Instead, make sure that IDs are unique by using a script.

    -

    Running reindex asynchronously

    -

    If the request contains wait_for_completion=false, Elasticsearch performs some preflight checks, launches the request, and returns a task you can use to cancel or get the status of the task. - Elasticsearch creates a record of this task as a document at _tasks/<task_id>.

    -

    Reindex from multiple sources

    -

    If you have many sources to reindex it is generally better to reindex them one at a time rather than using a glob pattern to pick up multiple sources. - That way you can resume the process if there are any errors by removing the partially completed source and starting over. - It also makes parallelizing the process fairly simple: split the list of sources to reindex and run each list in parallel.

    -

    For example, you can use a bash script like this:

    -
    for index in i1 i2 i3 i4 i5; do
    -            curl -HContent-Type:application/json -XPOST localhost:9200/_reindex?pretty -d'{
    -              "source": {
    -                "index": "'$index'"
    -              },
    -              "dest": {
    -                "index": "'$index'-reindexed"
    -              }
    -            }'
    -          done
    -          
    -

    Throttling

    -

    Set requests_per_second to any positive decimal number (1.4, 6, 1000, for example) to throttle the rate at which reindex issues batches of index operations. - Requests are throttled by padding each batch with a wait time. - To turn off throttling, set requests_per_second to -1.

    -

    The throttling is done by waiting between batches so that the scroll that reindex uses internally can be given a timeout that takes into account the padding. - The padding time is the difference between the batch size divided by the requests_per_second and the time spent writing. - By default the batch size is 1000, so if requests_per_second is set to 500:

    -
    target_time = 1000 / 500 per second = 2 seconds
    -          wait_time = target_time - write_time = 2 seconds - .5 seconds = 1.5 seconds
    -          
    -

    Since the batch is issued as a single bulk request, large batch sizes cause Elasticsearch to create many requests and then wait for a while before starting the next set. - This is "bursty" instead of "smooth".

    -

    Slicing

    -

    Reindex supports sliced scroll to parallelize the reindexing process. - This parallelization can improve efficiency and provide a convenient way to break the request down into smaller parts.

    -

    NOTE: Reindexing from remote clusters does not support manual or automatic slicing.

    -

    You can slice a reindex request manually by providing a slice ID and total number of slices to each request. - You can also let reindex automatically parallelize by using sliced scroll to slice on _id. - The slices parameter specifies the number of slices to use.

    -

    Adding slices to the reindex request just automates the manual process, creating sub-requests which means it has some quirks:

    -
      -
    • You can see these requests in the tasks API. These sub-requests are "child" tasks of the task for the request with slices.
    • -
    • Fetching the status of the task for the request with slices only contains the status of completed slices.
    • -
    • These sub-requests are individually addressable for things like cancellation and rethrottling.
    • -
    • Rethrottling the request with slices will rethrottle the unfinished sub-request proportionally.
    • -
    • Canceling the request with slices will cancel each sub-request.
    • -
    • Due to the nature of slices, each sub-request won't get a perfectly even portion of the documents. All documents will be addressed, but some slices may be larger than others. Expect larger slices to have a more even distribution.
    • -
    • Parameters like requests_per_second and max_docs on a request with slices are distributed proportionally to each sub-request. Combine that with the previous point about distribution being uneven and you should conclude that using max_docs with slices might not result in exactly max_docs documents being reindexed.
    • -
    • Each sub-request gets a slightly different snapshot of the source, though these are all taken at approximately the same time.
    • -
    -

    If slicing automatically, setting slices to auto will choose a reasonable number for most indices. - If slicing manually or otherwise tuning automatic slicing, use the following guidelines.

    -

    Query performance is most efficient when the number of slices is equal to the number of shards in the index. - If that number is large (for example, 500), choose a lower number as too many slices will hurt performance. - Setting slices higher than the number of shards generally does not improve efficiency and adds overhead.

    -

    Indexing performance scales linearly across available resources with the number of slices.

    -

    Whether query or indexing performance dominates the runtime depends on the documents being reindexed and cluster resources.

    -

    Modify documents during reindexing

    -

    Like _update_by_query, reindex operations support a script that modifies the document. - Unlike _update_by_query, the script is allowed to modify the document's metadata.

    -

    Just as in _update_by_query, you can set ctx.op to change the operation that is run on the destination. - For example, set ctx.op to noop if your script decides that the document doesn’t have to be indexed in the destination. This "no operation" will be reported in the noop counter in the response body. - Set ctx.op to delete if your script decides that the document must be deleted from the destination. - The deletion will be reported in the deleted counter in the response body. - Setting ctx.op to anything else will return an error, as will setting any other field in ctx.

    -

    Think of the possibilities! Just be careful; you are able to change:

    -
      -
    • _id
    • -
    • _index
    • -
    • _version
    • -
    • _routing
    • -
    -

    Setting _version to null or clearing it from the ctx map is just like not sending the version in an indexing request. - It will cause the document to be overwritten in the destination regardless of the version on the target or the version type you use in the reindex API.

    -

    Reindex from remote

    -

    Reindex supports reindexing from a remote Elasticsearch cluster. - The host parameter must contain a scheme, host, port, and optional path. - The username and password parameters are optional and when they are present the reindex operation will connect to the remote Elasticsearch node using basic authentication. - Be sure to use HTTPS when using basic authentication or the password will be sent in plain text. - There are a range of settings available to configure the behavior of the HTTPS connection.

    -

    When using Elastic Cloud, it is also possible to authenticate against the remote cluster through the use of a valid API key. - Remote hosts must be explicitly allowed with the reindex.remote.whitelist setting. - It can be set to a comma delimited list of allowed remote host and port combinations. - Scheme is ignored; only the host and port are used. - For example:

    -
    reindex.remote.whitelist: [otherhost:9200, another:9200, 127.0.10.*:9200, localhost:*"]
    -          
    -

    The list of allowed hosts must be configured on any nodes that will coordinate the reindex. - This feature should work with remote clusters of any version of Elasticsearch. - This should enable you to upgrade from any version of Elasticsearch to the current version by reindexing from a cluster of the old version.

    -

    WARNING: Elasticsearch does not support forward compatibility across major versions. - For example, you cannot reindex from a 7.x cluster into a 6.x cluster.

    -

    To enable queries sent to older versions of Elasticsearch, the query parameter is sent directly to the remote host without validation or modification.

    -

    NOTE: Reindexing from remote clusters does not support manual or automatic slicing.

    -

    Reindexing from a remote server uses an on-heap buffer that defaults to a maximum size of 100mb. - If the remote index includes very large documents you'll need to use a smaller batch size. - It is also possible to set the socket read timeout on the remote connection with the socket_timeout field and the connection timeout with the connect_timeout field. - Both default to 30 seconds.

    -

    Configuring SSL parameters

    -

    Reindex from remote supports configurable SSL settings. - These must be specified in the elasticsearch.yml file, with the exception of the secure settings, which you add in the Elasticsearch keystore. - It is not possible to configure SSL in the body of the reindex request.

    +

    Refer to the linked documentation for examples of how to reindex documents.

    ``_ @@ -4990,51 +4870,6 @@ def search_mvt(
  • Optionally, a geo_bounds aggregation on the <field>. The search only includes this aggregation if the exact_bounds parameter is true.
  • If the optional parameter with_labels is true, the internal search will include a dynamic runtime field that calls the getLabelPosition function of the geometry doc value. This enables the generation of new point features containing suggested geometry labels, so that, for example, multi-polygons will have only one label.
  • -

    For example, Elasticsearch may translate a vector tile search API request with a grid_agg argument of geotile and an exact_bounds argument of true into the following search

    -
    GET my-index/_search
    -          {
    -            "size": 10000,
    -            "query": {
    -              "geo_bounding_box": {
    -                "my-geo-field": {
    -                  "top_left": {
    -                    "lat": -40.979898069620134,
    -                    "lon": -45
    -                  },
    -                  "bottom_right": {
    -                    "lat": -66.51326044311186,
    -                    "lon": 0
    -                  }
    -                }
    -              }
    -            },
    -            "aggregations": {
    -              "grid": {
    -                "geotile_grid": {
    -                  "field": "my-geo-field",
    -                  "precision": 11,
    -                  "size": 65536,
    -                  "bounds": {
    -                    "top_left": {
    -                      "lat": -40.979898069620134,
    -                      "lon": -45
    -                    },
    -                    "bottom_right": {
    -                      "lat": -66.51326044311186,
    -                      "lon": 0
    -                    }
    -                  }
    -                }
    -              },
    -              "bounds": {
    -                "geo_bounds": {
    -                  "field": "my-geo-field",
    -                  "wrap_longitude": false
    -                }
    -              }
    -            }
    -          }
    -          

    The API returns results as a binary Mapbox vector tile. Mapbox vector tiles are encoded as Google Protobufs (PBF). By default, the tile contains three layers:

      @@ -5289,6 +5124,7 @@ def search_mvt( Some cells may intersect more than one vector tile. To compute the H3 resolution for each precision, Elasticsearch compares the average density of hexagonal bins at each resolution with the average density of tile bins at each zoom level. Elasticsearch uses the H3 resolution that is closest to the corresponding geotile density.

      +

      Learn how to use the vector tile search API with practical examples in the Vector tile search examples guide.

      ``_ @@ -5478,7 +5314,7 @@ def search_shards( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param local: If `true`, the request retrieves information from the local node @@ -5590,8 +5426,7 @@ def search_template( :param expand_wildcards: The type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated - values, such as `open,hidden`. Valid values are: `all`, `open`, `closed`, - `hidden`, `none`. + values, such as `open,hidden`. :param explain: If `true`, returns detailed information about score calculation as part of each hit. If you specify both this and the `explain` query parameter, the API uses only the query parameter. @@ -5865,7 +5700,8 @@ def termvectors( The information is only retrieved for the shard the requested document resides in. The term and field statistics are therefore only useful as relative measures whereas the absolute numbers have no meaning in this context. By default, when requesting term vectors of artificial documents, a shard to get the statistics from is randomly selected. - Use routing only to hit a particular shard.

      + Use routing only to hit a particular shard. + Refer to the linked documentation for detailed examples of how to use this API.

      ``_ @@ -6036,7 +5872,8 @@ def update(

    The document must still be reindexed, but using this API removes some network roundtrips and reduces chances of version conflicts between the GET and the index operation.

    The _source field must be enabled to use this API. - In addition to _source, you can access the following variables through the ctx map: _index, _type, _id, _version, _routing, and _now (the current timestamp).

    + In addition to _source, you can access the following variables through the ctx map: _index, _type, _id, _version, _routing, and _now (the current timestamp). + For usage examples such as partial updates, upserts, and scripted updates, see the External documentation.

    ``_ @@ -6229,6 +6066,24 @@ def update_by_query( A bulk update request is performed for each batch of matching documents. Any query or update failures cause the update by query request to fail and the failures are shown in the response. Any update requests that completed successfully still stick, they are not rolled back.

    +

    Refreshing shards

    +

    Specifying the refresh parameter refreshes all shards once the request completes. + This is different to the update API's refresh parameter, which causes only the shard + that received the request to be refreshed. Unlike the update API, it does not support + wait_for.

    +

    Running update by query asynchronously

    +

    If the request contains wait_for_completion=false, Elasticsearch + performs some preflight checks, launches the request, and returns a + task you can use to cancel or get the status of the task. + Elasticsearch creates a record of this task as a document at .tasks/task/${taskId}.

    +

    Waiting for active shards

    +

    wait_for_active_shards controls how many copies of a shard must be active + before proceeding with the request. See wait_for_active_shards + for details. timeout controls how long each write request waits for unavailable + shards to become available. Both work exactly the way they work in the + Bulk API. Update by query uses scrolled searches, so you can also + specify the scroll parameter to control how long it keeps the search context + alive, for example ?scroll=10m. The default is 5 minutes.

    Throttling update requests

    To control the rate at which update by query issues batches of update operations, you can set requests_per_second to any positive decimal number. This pads each batch with a wait time to throttle the rate. @@ -6263,18 +6118,8 @@ def update_by_query(

  • Query performance is most efficient when the number of slices is equal to the number of shards in the index or backing index. If that number is large (for example, 500), choose a lower number as too many slices hurts performance. Setting slices higher than the number of shards generally does not improve efficiency and adds overhead.
  • Update performance scales linearly across available resources with the number of slices.
  • -

    Whether query or update performance dominates the runtime depends on the documents being reindexed and cluster resources.

    -

    Update the document source

    -

    Update by query supports scripts to update the document source. - As with the update API, you can set ctx.op to change the operation that is performed.

    -

    Set ctx.op = "noop" if your script decides that it doesn't have to make any changes. - The update by query operation skips updating the document and increments the noop counter.

    -

    Set ctx.op = "delete" if your script decides that the document should be deleted. - The update by query operation deletes the document and increments the deleted counter.

    -

    Update by query supports only index, noop, and delete. - Setting ctx.op to anything else is an error. - Setting any other field in ctx is an error. - This API enables you to only modify the source of matching documents; you cannot move them.

    +

    Whether query or update performance dominates the runtime depends on the documents being reindexed and cluster resources. + Refer to the linked documentation for examples of how to update documents using the _update_by_query API:

    ``_ @@ -6302,8 +6147,7 @@ def update_by_query( :param expand_wildcards: The type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. It supports comma-separated - values, such as `open,hidden`. Valid values are: `all`, `open`, `closed`, - `hidden`, `none`. + values, such as `open,hidden`. :param from_: Skips the specified number of documents. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. diff --git a/elasticsearch/_sync/client/cat.py b/elasticsearch/_sync/client/cat.py index d71571c57..bdfaf28ea 100644 --- a/elasticsearch/_sync/client/cat.py +++ b/elasticsearch/_sync/client/cat.py @@ -584,7 +584,9 @@ def indices( filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, format: t.Optional[str] = None, h: t.Optional[t.Union[str, t.Sequence[str]]] = None, - health: t.Optional[t.Union[str, t.Literal["green", "red", "yellow"]]] = None, + health: t.Optional[ + t.Union[str, t.Literal["green", "red", "unavailable", "unknown", "yellow"]] + ] = None, help: t.Optional[bool] = None, human: t.Optional[bool] = None, include_unloaded_segments: t.Optional[bool] = None, @@ -2216,7 +2218,74 @@ def recovery( error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, format: t.Optional[str] = None, - h: t.Optional[t.Union[str, t.Sequence[str]]] = None, + h: t.Optional[ + t.Union[ + t.Sequence[ + t.Union[ + str, + t.Literal[ + "bytes", + "bytes_percent", + "bytes_recovered", + "bytes_total", + "files", + "files_percent", + "files_recovered", + "files_total", + "index", + "repository", + "shard", + "snapshot", + "source_host", + "source_node", + "stage", + "start_time", + "start_time_millis", + "stop_time", + "stop_time_millis", + "target_host", + "target_node", + "time", + "translog_ops", + "translog_ops_percent", + "translog_ops_recovered", + "type", + ], + ] + ], + t.Union[ + str, + t.Literal[ + "bytes", + "bytes_percent", + "bytes_recovered", + "bytes_total", + "files", + "files_percent", + "files_recovered", + "files_total", + "index", + "repository", + "shard", + "snapshot", + "source_host", + "source_node", + "stage", + "start_time", + "start_time_millis", + "stop_time", + "stop_time_millis", + "target_host", + "target_node", + "time", + "translog_ops", + "translog_ops_percent", + "translog_ops_recovered", + "type", + ], + ], + ] + ] = None, help: t.Optional[bool] = None, human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, @@ -2247,13 +2316,14 @@ def recovery( shard recoveries. :param format: Specifies the format to return the columnar data in, can be set to `text`, `json`, `cbor`, `yaml`, or `smile`. - :param h: List of columns to appear in the response. Supports simple wildcards. + :param h: A comma-separated list of columns names to display. It supports simple + wildcards. :param help: When set to `true` will output available columns. This option can't be combined with any other query string option. - :param s: List of columns that determine how the table should be sorted. Sorting - defaults to ascending and can be changed by setting `:asc` or `:desc` as - a suffix to the column name. - :param time: Unit used to display time values. + :param s: A comma-separated list of column names or aliases that determines the + sort order. Sorting defaults to ascending and can be changed by setting `:asc` + or `:desc` as a suffix to the column name. + :param time: The unit used to display time values. :param v: When set to `true` will enable verbose output. """ __path_parts: t.Dict[str, str] @@ -2387,7 +2457,52 @@ def segments( error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, format: t.Optional[str] = None, - h: t.Optional[t.Union[str, t.Sequence[str]]] = None, + h: t.Optional[ + t.Union[ + t.Sequence[ + t.Union[ + str, + t.Literal[ + "committed", + "compound", + "docs.count", + "docs.deleted", + "generation", + "id", + "index", + "ip", + "prirep", + "searchable", + "segment", + "shard", + "size", + "size.memory", + "version", + ], + ] + ], + t.Union[ + str, + t.Literal[ + "committed", + "compound", + "docs.count", + "docs.deleted", + "generation", + "id", + "index", + "ip", + "prirep", + "searchable", + "segment", + "shard", + "size", + "size.memory", + "version", + ], + ], + ] + ] = None, help: t.Optional[bool] = None, human: t.Optional[bool] = None, local: t.Optional[bool] = None, @@ -2413,7 +2528,8 @@ def segments( :param bytes: The unit used to display byte values. :param format: Specifies the format to return the columnar data in, can be set to `text`, `json`, `cbor`, `yaml`, or `smile`. - :param h: List of columns to appear in the response. Supports simple wildcards. + :param h: A comma-separated list of columns names to display. It supports simple + wildcards. :param help: When set to `true` will output available columns. This option can't be combined with any other query string option. :param local: If `true`, the request computes the list of selected nodes from @@ -2421,9 +2537,9 @@ def segments( from the cluster state of the master node. In both cases the coordinating node will send requests for further information to each selected node. :param master_timeout: Period to wait for a connection to the master node. - :param s: List of columns that determine how the table should be sorted. Sorting - defaults to ascending and can be changed by setting `:asc` or `:desc` as - a suffix to the column name. + :param s: A comma-separated list of column names or aliases that determines the + sort order. Sorting defaults to ascending and can be changed by setting `:asc` + or `:desc` as a suffix to the column name. :param v: When set to `true` will enable verbose output. """ __path_parts: t.Dict[str, str] @@ -2479,7 +2595,162 @@ def shards( error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, format: t.Optional[str] = None, - h: t.Optional[t.Union[str, t.Sequence[str]]] = None, + h: t.Optional[ + t.Union[ + t.Sequence[ + t.Union[ + str, + t.Literal[ + "completion.size", + "dataset.size", + "dense_vector.value_count", + "docs", + "dsparse_vector.value_count", + "fielddata.evictions", + "fielddata.memory_size", + "flush.total", + "flush.total_time", + "get.current", + "get.exists_time", + "get.exists_total", + "get.missing_time", + "get.missing_total", + "get.time", + "get.total", + "id", + "index", + "indexing.delete_current", + "indexing.delete_time", + "indexing.delete_total", + "indexing.index_current", + "indexing.index_failed", + "indexing.index_failed_due_to_version_conflict", + "indexing.index_time", + "indexing.index_total", + "ip", + "merges.current", + "merges.current_docs", + "merges.current_size", + "merges.total", + "merges.total_docs", + "merges.total_size", + "merges.total_time", + "node", + "prirep", + "query_cache.evictions", + "query_cache.memory_size", + "recoverysource.type", + "refresh.time", + "refresh.total", + "search.fetch_current", + "search.fetch_time", + "search.fetch_total", + "search.open_contexts", + "search.query_current", + "search.query_time", + "search.query_total", + "search.scroll_current", + "search.scroll_time", + "search.scroll_total", + "segments.count", + "segments.fixed_bitset_memory", + "segments.index_writer_memory", + "segments.memory", + "segments.version_map_memory", + "seq_no.global_checkpoint", + "seq_no.local_checkpoint", + "seq_no.max", + "shard", + "state", + "store", + "suggest.current", + "suggest.time", + "suggest.total", + "sync_id", + "unassigned.at", + "unassigned.details", + "unassigned.for", + "unassigned.reason", + ], + ] + ], + t.Union[ + str, + t.Literal[ + "completion.size", + "dataset.size", + "dense_vector.value_count", + "docs", + "dsparse_vector.value_count", + "fielddata.evictions", + "fielddata.memory_size", + "flush.total", + "flush.total_time", + "get.current", + "get.exists_time", + "get.exists_total", + "get.missing_time", + "get.missing_total", + "get.time", + "get.total", + "id", + "index", + "indexing.delete_current", + "indexing.delete_time", + "indexing.delete_total", + "indexing.index_current", + "indexing.index_failed", + "indexing.index_failed_due_to_version_conflict", + "indexing.index_time", + "indexing.index_total", + "ip", + "merges.current", + "merges.current_docs", + "merges.current_size", + "merges.total", + "merges.total_docs", + "merges.total_size", + "merges.total_time", + "node", + "prirep", + "query_cache.evictions", + "query_cache.memory_size", + "recoverysource.type", + "refresh.time", + "refresh.total", + "search.fetch_current", + "search.fetch_time", + "search.fetch_total", + "search.open_contexts", + "search.query_current", + "search.query_time", + "search.query_total", + "search.scroll_current", + "search.scroll_time", + "search.scroll_total", + "segments.count", + "segments.fixed_bitset_memory", + "segments.index_writer_memory", + "segments.memory", + "segments.version_map_memory", + "seq_no.global_checkpoint", + "seq_no.local_checkpoint", + "seq_no.max", + "shard", + "state", + "store", + "suggest.current", + "suggest.time", + "suggest.total", + "sync_id", + "unassigned.at", + "unassigned.details", + "unassigned.for", + "unassigned.reason", + ], + ], + ] + ] = None, help: t.Optional[bool] = None, human: t.Optional[bool] = None, master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, @@ -2510,11 +2781,11 @@ def shards( :param h: List of columns to appear in the response. Supports simple wildcards. :param help: When set to `true` will output available columns. This option can't be combined with any other query string option. - :param master_timeout: Period to wait for a connection to the master node. - :param s: List of columns that determine how the table should be sorted. Sorting - defaults to ascending and can be changed by setting `:asc` or `:desc` as - a suffix to the column name. - :param time: Unit used to display time values. + :param master_timeout: The period to wait for a connection to the master node. + :param s: A comma-separated list of column names or aliases that determines the + sort order. Sorting defaults to ascending and can be changed by setting `:asc` + or `:desc` as a suffix to the column name. + :param time: The unit used to display time values. :param v: When set to `true` will enable verbose output. """ __path_parts: t.Dict[str, str] @@ -2567,7 +2838,48 @@ def snapshots( error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, format: t.Optional[str] = None, - h: t.Optional[t.Union[str, t.Sequence[str]]] = None, + h: t.Optional[ + t.Union[ + t.Sequence[ + t.Union[ + str, + t.Literal[ + "duration", + "end_epoch", + "end_time", + "failed_shards", + "id", + "indices", + "reason", + "repository", + "start_epoch", + "start_time", + "status", + "successful_shards", + "total_shards", + ], + ] + ], + t.Union[ + str, + t.Literal[ + "duration", + "end_epoch", + "end_time", + "failed_shards", + "id", + "indices", + "reason", + "repository", + "start_epoch", + "start_time", + "status", + "successful_shards", + "total_shards", + ], + ], + ] + ] = None, help: t.Optional[bool] = None, human: t.Optional[bool] = None, ignore_unavailable: t.Optional[bool] = None, @@ -2595,7 +2907,8 @@ def snapshots( If any repository fails during the request, Elasticsearch returns an error. :param format: Specifies the format to return the columnar data in, can be set to `text`, `json`, `cbor`, `yaml`, or `smile`. - :param h: List of columns to appear in the response. Supports simple wildcards. + :param h: A comma-separated list of columns names to display. It supports simple + wildcards. :param help: When set to `true` will output available columns. This option can't be combined with any other query string option. :param ignore_unavailable: If `true`, the response does not include information @@ -2842,7 +3155,62 @@ def thread_pool( error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, format: t.Optional[str] = None, - h: t.Optional[t.Union[str, t.Sequence[str]]] = None, + h: t.Optional[ + t.Union[ + t.Sequence[ + t.Union[ + str, + t.Literal[ + "active", + "completed", + "core", + "ephemeral_id", + "host", + "ip", + "keep_alive", + "largest", + "max", + "name", + "node_id", + "node_name", + "pid", + "pool_size", + "port", + "queue", + "queue_size", + "rejected", + "size", + "type", + ], + ] + ], + t.Union[ + str, + t.Literal[ + "active", + "completed", + "core", + "ephemeral_id", + "host", + "ip", + "keep_alive", + "largest", + "max", + "name", + "node_id", + "node_name", + "pid", + "pool_size", + "port", + "queue", + "queue_size", + "rejected", + "size", + "type", + ], + ], + ] + ] = None, help: t.Optional[bool] = None, human: t.Optional[bool] = None, local: t.Optional[bool] = None, @@ -2876,10 +3244,10 @@ def thread_pool( the local cluster state. If `false` the list of selected nodes are computed from the cluster state of the master node. In both cases the coordinating node will send requests for further information to each selected node. - :param master_timeout: Period to wait for a connection to the master node. - :param s: List of columns that determine how the table should be sorted. Sorting - defaults to ascending and can be changed by setting `:asc` or `:desc` as - a suffix to the column name. + :param master_timeout: The period to wait for a connection to the master node. + :param s: A comma-separated list of column names or aliases that determines the + sort order. Sorting defaults to ascending and can be changed by setting `:asc` + or `:desc` as a suffix to the column name. :param time: The unit used to display time values. :param v: When set to `true` will enable verbose output. """ diff --git a/elasticsearch/_sync/client/cluster.py b/elasticsearch/_sync/client/cluster.py index c8992f80d..a3829f224 100644 --- a/elasticsearch/_sync/client/cluster.py +++ b/elasticsearch/_sync/client/cluster.py @@ -51,7 +51,8 @@ def allocation_explain( Get explanations for shard allocations in the cluster. For unassigned shards, it provides an explanation for why the shard is unassigned. For assigned shards, it provides an explanation for why the shard is remaining on its current node and has not moved or rebalanced to another node. - This API can be very useful when attempting to diagnose why a shard is unassigned or why a shard continues to remain on its current node when you might expect otherwise.

    + This API can be very useful when attempting to diagnose why a shard is unassigned or why a shard continues to remain on its current node when you might expect otherwise. + Refer to the linked documentation for examples of how to troubleshoot allocation issues using this API.

    ``_ @@ -290,6 +291,7 @@ def get_component_template( local: t.Optional[bool] = None, master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, pretty: t.Optional[bool] = None, + settings_filter: t.Optional[t.Union[str, t.Sequence[str]]] = None, ) -> ObjectApiResponse[t.Any]: """ .. raw:: html @@ -310,6 +312,8 @@ def get_component_template( :param master_timeout: Period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails and returns an error. + :param settings_filter: Filter out results, for example to filter out sensitive + information. Supports wildcards or full settings keys """ __path_parts: t.Dict[str, str] if name not in SKIP_IN_PATH: @@ -335,6 +339,8 @@ def get_component_template( __query["master_timeout"] = master_timeout if pretty is not None: __query["pretty"] = pretty + if settings_filter is not None: + __query["settings_filter"] = settings_filter __headers = {"accept": "application/json"} return self.perform_request( # type: ignore[return-value] "GET", @@ -441,7 +447,7 @@ def health( wait_for_no_relocating_shards: t.Optional[bool] = None, wait_for_nodes: t.Optional[t.Union[int, str]] = None, wait_for_status: t.Optional[ - t.Union[str, t.Literal["green", "red", "yellow"]] + t.Union[str, t.Literal["green", "red", "unavailable", "unknown", "yellow"]] ] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -731,6 +737,7 @@ def put_component_template( *, name: str, template: t.Optional[t.Mapping[str, t.Any]] = None, + cause: t.Optional[str] = None, create: t.Optional[bool] = None, deprecated: t.Optional[bool] = None, error_trace: t.Optional[bool] = None, @@ -774,6 +781,7 @@ def put_component_template( update settings API. :param template: The template to be applied which includes mappings, settings, or aliases configuration. + :param cause: User defined reason for create the component template. :param create: If `true`, this request cannot replace or update existing component templates. :param deprecated: Marks this index template as deprecated. When creating or @@ -798,6 +806,8 @@ def put_component_template( __path = f'/_component_template/{__path_parts["name"]}' __query: t.Dict[str, t.Any] = {} __body: t.Dict[str, t.Any] = body if body is not None else {} + if cause is not None: + __query["cause"] = cause if create is not None: __query["create"] = create if error_trace is not None: @@ -870,9 +880,9 @@ def put_settings( :param flat_settings: Return settings in flat format (default: false) :param master_timeout: Explicit operation timeout for connection to master node - :param persistent: + :param persistent: The settings that persist after the cluster restarts. :param timeout: Explicit operation timeout - :param transient: + :param transient: The settings that do not persist after the cluster restarts. """ __path_parts: t.Dict[str, str] = {} __path = "/_cluster/settings" diff --git a/elasticsearch/_sync/client/eql.py b/elasticsearch/_sync/client/eql.py index 138169023..57cba8bf0 100644 --- a/elasticsearch/_sync/client/eql.py +++ b/elasticsearch/_sync/client/eql.py @@ -204,6 +204,7 @@ def search( allow_partial_search_results: t.Optional[bool] = None, allow_partial_sequence_results: t.Optional[bool] = None, case_sensitive: t.Optional[bool] = None, + ccs_minimize_roundtrips: t.Optional[bool] = None, error_trace: t.Optional[bool] = None, event_category_field: t.Optional[str] = None, expand_wildcards: t.Optional[ @@ -250,7 +251,9 @@ def search( :param index: The name of the index to scope the operation :param query: EQL query you wish to run. - :param allow_no_indices: + :param allow_no_indices: Whether to ignore if a wildcard indices expression resolves + into no concrete indices. (This includes `_all` string or when no indices + have been specified) :param allow_partial_search_results: Allow query execution also in case of shard failures. If true, the query will keep running and will return results based on the available shards. For sequences, the behavior can be further refined @@ -261,9 +264,12 @@ def search( If false, the sequence query will return successfully, but will always have empty results. :param case_sensitive: + :param ccs_minimize_roundtrips: Indicates whether network round-trips should + be minimized as part of cross-cluster search requests execution :param event_category_field: Field containing the event classification, such as process, file, or network. - :param expand_wildcards: + :param expand_wildcards: Whether to expand wildcard expression to concrete indices + that are open, closed or both. :param fetch_size: Maximum number of events to search at a time for sequence queries. :param fields: Array of wildcard (*) patterns. The response returns values for @@ -298,6 +304,8 @@ def search( __body: t.Dict[str, t.Any] = body if body is not None else {} if allow_no_indices is not None: __query["allow_no_indices"] = allow_no_indices + if ccs_minimize_roundtrips is not None: + __query["ccs_minimize_roundtrips"] = ccs_minimize_roundtrips if error_trace is not None: __query["error_trace"] = error_trace if expand_wildcards is not None: diff --git a/elasticsearch/_sync/client/esql.py b/elasticsearch/_sync/client/esql.py index 48e855fd0..ed6bc329e 100644 --- a/elasticsearch/_sync/client/esql.py +++ b/elasticsearch/_sync/client/esql.py @@ -31,6 +31,8 @@ class EsqlClient(NamespacedClient): "columnar", "filter", "include_ccs_metadata", + "keep_alive", + "keep_on_completion", "locale", "params", "profile", @@ -145,10 +147,6 @@ def async_query( __query["format"] = format if human is not None: __query["human"] = human - if keep_alive is not None: - __query["keep_alive"] = keep_alive - if keep_on_completion is not None: - __query["keep_on_completion"] = keep_on_completion if pretty is not None: __query["pretty"] = pretty if not __body: @@ -160,6 +158,10 @@ def async_query( __body["filter"] = filter if include_ccs_metadata is not None: __body["include_ccs_metadata"] = include_ccs_metadata + if keep_alive is not None: + __body["keep_alive"] = keep_alive + if keep_on_completion is not None: + __body["keep_on_completion"] = keep_on_completion if locale is not None: __body["locale"] = locale if params is not None: @@ -242,6 +244,14 @@ def async_query_get( drop_null_columns: t.Optional[bool] = None, error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, + format: t.Optional[ + t.Union[ + str, + t.Literal[ + "arrow", "cbor", "csv", "json", "smile", "tsv", "txt", "yaml" + ], + ] + ] = None, human: t.Optional[bool] = None, keep_alive: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, pretty: t.Optional[bool] = None, @@ -267,6 +277,7 @@ def async_query_get( will be removed from the `columns` and `values` portion of the results. If `true`, the response will include an extra section under the name `all_columns` which has the name of all the columns. + :param format: A short version of the Accept header, for example `json` or `yaml`. :param keep_alive: The period for which the query and its results are stored in the cluster. When this period expires, the query and its results are deleted, even if the query is still ongoing. @@ -287,6 +298,8 @@ def async_query_get( __query["error_trace"] = error_trace if filter_path is not None: __query["filter_path"] = filter_path + if format is not None: + __query["format"] = format if human is not None: __query["human"] = human if keep_alive is not None: diff --git a/elasticsearch/_sync/client/indices.py b/elasticsearch/_sync/client/indices.py index 08913867b..288239230 100644 --- a/elasticsearch/_sync/client/indices.py +++ b/elasticsearch/_sync/client/indices.py @@ -338,7 +338,7 @@ def clear_cache( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param fielddata: If `true`, clears the fields cache. Use the `fields` parameter to clear the cache of specific fields only. :param fields: Comma-separated list of field names used to limit the `fielddata` @@ -563,7 +563,7 @@ def close( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param master_timeout: Period to wait for a connection to the master node. If @@ -950,7 +950,7 @@ def delete( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param master_timeout: Period to wait for a connection to the master node. If @@ -1495,7 +1495,7 @@ def exists( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param flat_settings: If `true`, returns settings in flat format. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. @@ -1579,7 +1579,7 @@ def exists_alias( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, requests that include a missing data stream or index in the target indices or data streams return an error. :param master_timeout: Period to wait for a connection to the master node. If @@ -1928,7 +1928,7 @@ def flush( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param force: If `true`, the request forces a flush even if there are no changes to commit to the index. :param ignore_unavailable: If `false`, the request returns an error if it targets @@ -2246,7 +2246,7 @@ def get_alias( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param master_timeout: Period to wait for a connection to the master node. If @@ -2326,8 +2326,7 @@ def get_data_lifecycle( wildcards (`*`). To target all data streams, omit this parameter or use `*` or `_all`. :param expand_wildcards: Type of data stream that wildcard patterns can match. - Supports comma-separated values, such as `open,hidden`. Valid values are: - `all`, `open`, `closed`, `hidden`, `none`. + Supports comma-separated values, such as `open,hidden`. :param include_defaults: If `true`, return all default settings in the response. :param master_timeout: Period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails and @@ -2523,7 +2522,7 @@ def get_field_mapping( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param include_defaults: If `true`, return all default settings in the response. @@ -2679,7 +2678,7 @@ def get_mapping( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param local: If `true`, the request retrieves information from the local node @@ -3171,7 +3170,7 @@ def open( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. :param master_timeout: Period to wait for a connection to the master node. If @@ -3430,8 +3429,7 @@ def put_data_lifecycle( for this data stream. A data stream lifecycle that's disabled (enabled: `false`) will have no effect on the data stream. :param expand_wildcards: Type of data stream that wildcard patterns can match. - Supports comma-separated values, such as `open,hidden`. Valid values are: - `all`, `hidden`, `open`, `closed`, `none`. + Supports comma-separated values, such as `open,hidden`. :param master_timeout: Period to wait for a connection to the master node. If no response is received before the timeout expires, the request fails and returns an error. @@ -3707,24 +3705,17 @@ def put_mapping(

    Update field mappings. Add new fields to an existing data stream or index. - You can also use this API to change the search settings of existing fields and add new properties to existing object fields. - For data streams, these changes are applied to all backing indices by default.

    -

    Add multi-fields to an existing field

    -

    Multi-fields let you index the same field in different ways. - You can use this API to update the fields mapping parameter and enable multi-fields for an existing field. - WARNING: If an index (or data stream) contains documents when you add a multi-field, those documents will not have values for the new multi-field. - You can populate the new multi-field with the update by query API.

    -

    Change supported mapping parameters for an existing field

    -

    The documentation for each mapping parameter indicates whether you can update it for an existing field using this API. - For example, you can use the update mapping API to update the ignore_above parameter.

    -

    Change the mapping of an existing field

    -

    Except for supported mapping parameters, you can't change the mapping or field type of an existing field. - Changing an existing field could invalidate data that's already indexed.

    -

    If you need to change the mapping of a field in a data stream's backing indices, refer to documentation about modifying data streams. - If you need to change the mapping of a field in other indices, create a new index with the correct mapping and reindex your data into that index.

    -

    Rename a field

    -

    Renaming a field would invalidate data already indexed under the old field name. - Instead, add an alias field to create an alternate field name.

    + You can use the update mapping API to:

    +
      +
    • Add a new field to an existing index
    • +
    • Update mappings for multiple indices in a single request
    • +
    • Add new properties to an object field
    • +
    • Enable multi-fields for an existing field
    • +
    • Update supported mapping parameters
    • +
    • Change a field's mapping using reindexing
    • +
    • Rename a field using a field alias
    • +
    +

    Learn how to use the update mapping API with practical examples in the Update mapping API examples guide.

    ``_ @@ -3743,7 +3734,7 @@ def put_mapping( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param field_names: Control whether field names are enabled for the index. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. @@ -3861,8 +3852,36 @@ def put_settings( Changes dynamic index settings in real time. For data streams, index setting changes are applied to all backing indices by default.

    To revert a setting to the default value, use a null value. - The list of per-index settings that can be updated dynamically on live indices can be found in index module documentation. + The list of per-index settings that can be updated dynamically on live indices can be found in index settings documentation. To preserve existing settings from being updated, set the preserve_existing parameter to true.

    +

    For performance optimization during bulk indexing, you can disable the refresh interval. + Refer to disable refresh interval for an example. + There are multiple valid ways to represent index settings in the request body. You can specify only the setting, for example:

    +
    {
    +            "number_of_replicas": 1
    +          }
    +          
    +

    Or you can use an index setting object:

    +
    {
    +            "index": {
    +              "number_of_replicas": 1
    +            }
    +          }
    +          
    +

    Or you can use dot annotation:

    +
    {
    +            "index.number_of_replicas": 1
    +          }
    +          
    +

    Or you can embed any of the aforementioned options in a settings object. For example:

    +
    {
    +            "settings": {
    +              "index": {
    +                "number_of_replicas": 1
    +              }
    +            }
    +          }
    +          

    NOTE: You can only define new analyzers on closed indices. To add an analyzer, you must close the index, define the analyzer, and reopen the index. You cannot close the write index of a data stream. @@ -3870,7 +3889,8 @@ def put_settings( Then roll over the data stream to apply the new analyzer to the stream's write index and future backing indices. This affects searches and any new data added to the stream after the rollover. However, it does not affect the data stream's backing indices or their existing data. - To change the analyzer for existing backing indices, you must create a new data stream and reindex your data into it.

    + To change the analyzer for existing backing indices, you must create a new data stream and reindex your data into it. + Refer to updating analyzers on existing indices for step-by-step examples.

    ``_ @@ -4071,10 +4091,20 @@ def recovery( *, index: t.Optional[t.Union[str, t.Sequence[str]]] = None, active_only: t.Optional[bool] = None, + allow_no_indices: t.Optional[bool] = None, detailed: t.Optional[bool] = None, error_trace: t.Optional[bool] = None, + expand_wildcards: t.Optional[ + t.Union[ + t.Sequence[ + t.Union[str, t.Literal["all", "closed", "hidden", "none", "open"]] + ], + t.Union[str, t.Literal["all", "closed", "hidden", "none", "open"]], + ] + ] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, + ignore_unavailable: t.Optional[bool] = None, pretty: t.Optional[bool] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -4107,8 +4137,17 @@ def recovery( to limit the request. Supports wildcards (`*`). To target all data streams and indices, omit this parameter or use `*` or `_all`. :param active_only: If `true`, the response only includes ongoing shard recoveries. + :param allow_no_indices: If `false`, the request returns an error if any wildcard + expression, index alias, or `_all` value targets only missing or closed indices. + This behavior applies even if the request targets other open indices. :param detailed: If `true`, the response includes detailed information about shard recoveries. + :param expand_wildcards: Type of index that wildcard patterns can match. If the + request can target data streams, this argument determines whether wildcard + expressions match hidden data streams. Supports comma-separated values, such + as `open,hidden`. + :param ignore_unavailable: If `false`, the request returns an error if it targets + a missing or closed index. """ __path_parts: t.Dict[str, str] if index not in SKIP_IN_PATH: @@ -4120,14 +4159,20 @@ def recovery( __query: t.Dict[str, t.Any] = {} if active_only is not None: __query["active_only"] = active_only + if allow_no_indices is not None: + __query["allow_no_indices"] = allow_no_indices if detailed is not None: __query["detailed"] = detailed if error_trace is not None: __query["error_trace"] = error_trace + if expand_wildcards is not None: + __query["expand_wildcards"] = expand_wildcards if filter_path is not None: __query["filter_path"] = filter_path if human is not None: __query["human"] = human + if ignore_unavailable is not None: + __query["ignore_unavailable"] = ignore_unavailable if pretty is not None: __query["pretty"] = pretty __headers = {"accept": "application/json"} @@ -4186,7 +4231,7 @@ def refresh( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. """ @@ -4385,10 +4430,9 @@ def resolve_cluster( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. - NOTE: This option is only supported when specifying an index expression. - You will get an error if you specify index options to the `_resolve/cluster` - API endpoint that takes no index expression. + as `open,hidden`. NOTE: This option is only supported when specifying an + index expression. You will get an error if you specify index options to the + `_resolve/cluster` API endpoint that takes no index expression. :param ignore_throttled: If true, concrete, expanded, or aliased indices are ignored when frozen. NOTE: This option is only supported when specifying an index expression. You will get an error if you specify index options to @@ -4481,7 +4525,7 @@ def resolve_index( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. """ @@ -4695,7 +4739,7 @@ def segments( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param ignore_unavailable: If `false`, the request returns an error if it targets a missing or closed index. """ @@ -5519,7 +5563,7 @@ def validate_query( :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such - as `open,hidden`. Valid values are: `all`, `open`, `closed`, `hidden`, `none`. + as `open,hidden`. :param explain: If `true`, the response returns detailed information if an error has occurred. :param ignore_unavailable: If `false`, the request returns an error if it targets diff --git a/elasticsearch/_sync/client/inference.py b/elasticsearch/_sync/client/inference.py index fa679f6e3..2cd3dc0d9 100644 --- a/elasticsearch/_sync/client/inference.py +++ b/elasticsearch/_sync/client/inference.py @@ -366,6 +366,7 @@ def put( filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, ) -> ObjectApiResponse[t.Any]: """ .. raw:: html @@ -374,13 +375,35 @@ def put(

    IMPORTANT: The inference APIs enable you to use certain services, such as built-in machine learning models (ELSER, E5), models uploaded through Eland, Cohere, OpenAI, Mistral, Azure OpenAI, Google AI Studio, Google Vertex AI, Anthropic, Watsonx.ai, or Hugging Face. For built-in models and models uploaded through Eland, the inference APIs offer an alternative way to use and manage trained models. However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.

    +

    The following integrations are available through the inference API. You can find the available task types next to the integration name:

    +
      +
    • AlibabaCloud AI Search (completion, rerank, sparse_embedding, text_embedding)
    • +
    • Amazon Bedrock (completion, text_embedding)
    • +
    • Anthropic (completion)
    • +
    • Azure AI Studio (completion, text_embedding)
    • +
    • Azure OpenAI (completion, text_embedding)
    • +
    • Cohere (completion, rerank, text_embedding)
    • +
    • Elasticsearch (rerank, sparse_embedding, text_embedding - this service is for built-in models and models uploaded through Eland)
    • +
    • ELSER (sparse_embedding)
    • +
    • Google AI Studio (completion, text_embedding)
    • +
    • Google Vertex AI (rerank, text_embedding)
    • +
    • Hugging Face (text_embedding)
    • +
    • Mistral (text_embedding)
    • +
    • OpenAI (chat_completion, completion, text_embedding)
    • +
    • VoyageAI (text_embedding, rerank)
    • +
    • Watsonx inference integration (text_embedding)
    • +
    • JinaAI (text_embedding, rerank)
    • +
    ``_ :param inference_id: The inference Id :param inference_config: - :param task_type: The task type + :param task_type: The task type. Refer to the integration list in the API description + for the available task types. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if inference_id in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'inference_id'") @@ -411,6 +434,8 @@ def put( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout __body = inference_config if inference_config is not None else body __headers = {"accept": "application/json", "content-type": "application/json"} return self.perform_request( # type: ignore[return-value] @@ -446,6 +471,7 @@ def put_alibabacloud( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -466,6 +492,8 @@ def put_alibabacloud( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -492,6 +520,8 @@ def put_alibabacloud( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -537,13 +567,14 @@ def put_amazonbedrock( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ .. raw:: html

    Create an Amazon Bedrock inference endpoint.

    -

    Creates an inference endpoint to perform an inference task with the amazonbedrock service.

    +

    Create an inference endpoint to perform an inference task with the amazonbedrock service.

    info You need to provide the access and secret keys only once, during the inference model creation. The get inference API does not retrieve your access or secret keys. After creating the inference model, you cannot change the associated key pairs. If you want to use a different access and secret key pair, delete the inference model and recreate it with the same name and the updated keys.

    @@ -561,6 +592,8 @@ def put_amazonbedrock( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -587,6 +620,8 @@ def put_amazonbedrock( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -632,6 +667,7 @@ def put_anthropic( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -653,6 +689,8 @@ def put_anthropic( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -679,6 +717,8 @@ def put_anthropic( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -724,6 +764,7 @@ def put_azureaistudio( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -744,6 +785,8 @@ def put_azureaistudio( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -770,6 +813,8 @@ def put_azureaistudio( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -815,6 +860,7 @@ def put_azureopenai( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -843,6 +889,8 @@ def put_azureopenai( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -869,6 +917,8 @@ def put_azureopenai( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -914,6 +964,7 @@ def put_cohere( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -934,6 +985,8 @@ def put_cohere( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -958,6 +1011,8 @@ def put_cohere( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1005,6 +1060,7 @@ def put_elasticsearch( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -1039,6 +1095,8 @@ def put_elasticsearch( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -1065,6 +1123,8 @@ def put_elasticsearch( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1104,6 +1164,7 @@ def put_elser( filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -1136,6 +1197,8 @@ def put_elser( :param service_settings: Settings used to install the inference model. These settings are specific to the `elser` service. :param chunking_settings: The chunking configuration object. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -1160,6 +1223,8 @@ def put_elser( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1197,6 +1262,7 @@ def put_googleaistudio( filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -1215,6 +1281,8 @@ def put_googleaistudio( :param service_settings: Settings used to install the inference model. These settings are specific to the `googleaistudio` service. :param chunking_settings: The chunking configuration object. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -1241,6 +1309,8 @@ def put_googleaistudio( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1284,6 +1354,7 @@ def put_googlevertexai( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -1304,6 +1375,8 @@ def put_googlevertexai( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -1330,6 +1403,8 @@ def put_googlevertexai( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1369,6 +1444,7 @@ def put_hugging_face( filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -1400,6 +1476,8 @@ def put_hugging_face( :param service_settings: Settings used to install the inference model. These settings are specific to the `hugging_face` service. :param chunking_settings: The chunking configuration object. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -1426,6 +1504,8 @@ def put_hugging_face( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1469,6 +1549,7 @@ def put_jinaai( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -1491,6 +1572,8 @@ def put_jinaai( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -1515,6 +1598,8 @@ def put_jinaai( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1554,6 +1639,7 @@ def put_mistral( filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -1573,6 +1659,8 @@ def put_mistral( :param service_settings: Settings used to install the inference model. These settings are specific to the `mistral` service. :param chunking_settings: The chunking configuration object. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -1597,6 +1685,8 @@ def put_mistral( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1642,6 +1732,7 @@ def put_openai( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -1664,6 +1755,8 @@ def put_openai( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -1688,6 +1781,8 @@ def put_openai( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1733,6 +1828,7 @@ def put_voyageai( human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, task_settings: t.Optional[t.Mapping[str, t.Any]] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -1754,6 +1850,8 @@ def put_voyageai( :param chunking_settings: The chunking configuration object. :param task_settings: Settings to configure the inference task. These settings are specific to the task type you specified. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -1778,6 +1876,8 @@ def put_voyageai( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1816,6 +1916,7 @@ def put_watsonx( filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, + timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, body: t.Optional[t.Dict[str, t.Any]] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -1836,6 +1937,8 @@ def put_watsonx( this case, `watsonxai`. :param service_settings: Settings used to install the inference model. These settings are specific to the `watsonxai` service. + :param timeout: Specifies the amount of time to wait for the inference endpoint + to be created. """ if task_type in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'task_type'") @@ -1860,6 +1963,8 @@ def put_watsonx( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if timeout is not None: + __query["timeout"] = timeout if not __body: if service is not None: __body["service"] = service @@ -1900,7 +2005,7 @@ def rerank( """ .. raw:: html -

    Perform rereanking inference on the service

    +

    Perform reranking inference on the service

    ``_ diff --git a/elasticsearch/_sync/client/ingest.py b/elasticsearch/_sync/client/ingest.py index 798653d1f..14b8912dc 100644 --- a/elasticsearch/_sync/client/ingest.py +++ b/elasticsearch/_sync/client/ingest.py @@ -288,7 +288,6 @@ def get_ip_location_database( error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, - master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, pretty: t.Optional[bool] = None, ) -> ObjectApiResponse[t.Any]: """ @@ -302,10 +301,6 @@ def get_ip_location_database( :param id: Comma-separated list of database configuration IDs to retrieve. Wildcard (`*`) expressions are supported. To get all database configurations, omit this parameter or use `*`. - :param master_timeout: The period to wait for a connection to the master node. - If no response is received before the timeout expires, the request fails - and returns an error. A value of `-1` indicates that the request should never - time out. """ __path_parts: t.Dict[str, str] if id not in SKIP_IN_PATH: @@ -321,8 +316,6 @@ def get_ip_location_database( __query["filter_path"] = filter_path if human is not None: __query["human"] = human - if master_timeout is not None: - __query["master_timeout"] = master_timeout if pretty is not None: __query["pretty"] = pretty __headers = {"accept": "application/json"} diff --git a/elasticsearch/_sync/client/license.py b/elasticsearch/_sync/client/license.py index 452cbd20c..adb53fd86 100644 --- a/elasticsearch/_sync/client/license.py +++ b/elasticsearch/_sync/client/license.py @@ -353,7 +353,7 @@ def post_start_trial( human: t.Optional[bool] = None, master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, pretty: t.Optional[bool] = None, - type_query_string: t.Optional[str] = None, + type: t.Optional[str] = None, ) -> ObjectApiResponse[t.Any]: """ .. raw:: html @@ -370,7 +370,7 @@ def post_start_trial( :param acknowledge: whether the user has acknowledged acknowledge messages (default: false) :param master_timeout: Period to wait for a connection to the master node. - :param type_query_string: + :param type: The type of trial license to generate (default: "trial") """ __path_parts: t.Dict[str, str] = {} __path = "/_license/start_trial" @@ -387,8 +387,8 @@ def post_start_trial( __query["master_timeout"] = master_timeout if pretty is not None: __query["pretty"] = pretty - if type_query_string is not None: - __query["type_query_string"] = type_query_string + if type is not None: + __query["type"] = type __headers = {"accept": "application/json"} return self.perform_request( # type: ignore[return-value] "POST", diff --git a/elasticsearch/_sync/client/ml.py b/elasticsearch/_sync/client/ml.py index 7d2a632a9..9c12dae5e 100644 --- a/elasticsearch/_sync/client/ml.py +++ b/elasticsearch/_sync/client/ml.py @@ -3549,7 +3549,8 @@ def put_datafeed( Datafeeds retrieve data from Elasticsearch for analysis by an anomaly detection job. You can associate only one datafeed with each anomaly detection job. The datafeed contains a query that runs at a defined interval (frequency). - If you are concerned about delayed data, you can add a delay (query_delay') at each interval. By default, the datafeed uses the following query: {"match_all": {"boost": 1}}`.

    + If you are concerned about delayed data, you can add a delay (query_delay) at each interval. + By default, the datafeed uses the following query: {"match_all": {"boost": 1}}.

    When Elasticsearch security features are enabled, your datafeed remembers which roles the user who created it had at the time of creation and runs the query using those same roles. If you provide secondary authorization headers, those credentials are used instead. @@ -3871,13 +3872,7 @@ def put_job( :param description: A description of the job. :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard - expressions match hidden data streams. Supports comma-separated values. Valid - values are: * `all`: Match any data stream or index, including hidden ones. - * `closed`: Match closed, non-hidden indices. Also matches any non-hidden - data stream. Data streams cannot be closed. * `hidden`: Match hidden data - streams and hidden indices. Must be combined with `open`, `closed`, or both. - * `none`: Wildcard patterns are not accepted. * `open`: Match open, non-hidden - indices. Also matches any non-hidden data stream. + expressions match hidden data streams. Supports comma-separated values. :param groups: A list of job groups. A job can belong to no groups or many. :param ignore_throttled: If `true`, concrete, expanded or aliased indices are ignored when frozen. @@ -4999,7 +4994,7 @@ def update_data_frame_analytics(

    Update a data frame analytics job.

    - ``_ + ``_ :param id: Identifier for the data frame analytics job. This identifier can contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and underscores. @@ -5140,13 +5135,7 @@ def update_datafeed( check runs only on real-time datafeeds. :param expand_wildcards: Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard - expressions match hidden data streams. Supports comma-separated values. Valid - values are: * `all`: Match any data stream or index, including hidden ones. - * `closed`: Match closed, non-hidden indices. Also matches any non-hidden - data stream. Data streams cannot be closed. * `hidden`: Match hidden data - streams and hidden indices. Must be combined with `open`, `closed`, or both. - * `none`: Wildcard patterns are not accepted. * `open`: Match open, non-hidden - indices. Also matches any non-hidden data stream. + expressions match hidden data streams. Supports comma-separated values. :param frequency: The interval at which scheduled queries are made while the datafeed runs in real time. The default value is either the bucket span for short bucket spans, or, for longer bucket spans, a sensible fraction of the @@ -5801,7 +5790,7 @@ def validate_detector(

    Validate an anomaly detection job.

    - ``_ + ``_ :param detector: """ diff --git a/elasticsearch/_sync/client/monitoring.py b/elasticsearch/_sync/client/monitoring.py index b075447d5..59cee2235 100644 --- a/elasticsearch/_sync/client/monitoring.py +++ b/elasticsearch/_sync/client/monitoring.py @@ -48,7 +48,7 @@ def bulk( This API is used by the monitoring features to send monitoring data.

    - ``_ + ``_ :param interval: Collection interval (e.g., '10s' or '10000ms') of the payload :param operations: diff --git a/elasticsearch/_sync/client/rollup.py b/elasticsearch/_sync/client/rollup.py index cc88f0a06..f336554df 100644 --- a/elasticsearch/_sync/client/rollup.py +++ b/elasticsearch/_sync/client/rollup.py @@ -419,28 +419,7 @@ def rollup_search( The following functionality is not available:

    size: Because rollups work on pre-aggregated data, no search hits can be returned and so size must be set to zero or omitted entirely. highlighter, suggestors, post_filter, profile, explain: These are similarly disallowed.

    -

    Searching both historical rollup and non-rollup data

    -

    The rollup search API has the capability to search across both "live" non-rollup data and the aggregated rollup data. - This is done by simply adding the live indices to the URI. For example:

    -
    GET sensor-1,sensor_rollup/_rollup_search
    -          {
    -            "size": 0,
    -            "aggregations": {
    -               "max_temperature": {
    -                "max": {
    -                  "field": "temperature"
    -                }
    -              }
    -            }
    -          }
    -          
    -

    The rollup search endpoint does two things when the search runs:

    -
      -
    • The original request is sent to the non-rollup index unaltered.
    • -
    • A rewritten version of the original request is sent to the rollup index.
    • -
    -

    When the two responses are received, the endpoint rewrites the rollup response and merges the two together. - During the merging process, if there is any overlap in buckets between the two responses, the buckets from the non-rollup index are used.

    +

    For more detailed examples of using the rollup search API, including querying rolled-up data only or combining rolled-up and live data, refer to the External documentation.

    ``_ diff --git a/elasticsearch/_sync/client/security.py b/elasticsearch/_sync/client/security.py index 8ebed4b1d..5839ad34b 100644 --- a/elasticsearch/_sync/client/security.py +++ b/elasticsearch/_sync/client/security.py @@ -2213,13 +2213,10 @@ def get_user( def get_user_privileges( self, *, - application: t.Optional[str] = None, error_trace: t.Optional[bool] = None, filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None, human: t.Optional[bool] = None, pretty: t.Optional[bool] = None, - priviledge: t.Optional[str] = None, - username: t.Optional[t.Union[None, str]] = None, ) -> ObjectApiResponse[t.Any]: """ .. raw:: html @@ -2232,19 +2229,10 @@ def get_user_privileges( ``_ - - :param application: The name of the application. Application privileges are always - associated with exactly one application. If you do not specify this parameter, - the API returns information about all privileges for all applications. - :param priviledge: The name of the privilege. If you do not specify this parameter, - the API returns information about all privileges for the requested application. - :param username: """ __path_parts: t.Dict[str, str] = {} __path = "/_security/user/_privileges" __query: t.Dict[str, t.Any] = {} - if application is not None: - __query["application"] = application if error_trace is not None: __query["error_trace"] = error_trace if filter_path is not None: @@ -2253,10 +2241,6 @@ def get_user_privileges( __query["human"] = human if pretty is not None: __query["pretty"] = pretty - if priviledge is not None: - __query["priviledge"] = priviledge - if username is not None: - __query["username"] = username __headers = {"accept": "application/json"} return self.perform_request( # type: ignore[return-value] "GET", @@ -2345,6 +2329,9 @@ def grant_api_key( human: t.Optional[bool] = None, password: t.Optional[str] = None, pretty: t.Optional[bool] = None, + refresh: t.Optional[ + t.Union[bool, str, t.Literal["false", "true", "wait_for"]] + ] = None, run_as: t.Optional[str] = None, username: t.Optional[str] = None, body: t.Optional[t.Dict[str, t.Any]] = None, @@ -2382,6 +2369,9 @@ def grant_api_key( types. :param password: The user's password. If you specify the `password` grant type, this parameter is required. It is not valid with other grant types. + :param refresh: If 'true', Elasticsearch refreshes the affected shards to make + this operation visible to search. If 'wait_for', it waits for a refresh to + make this operation visible to search. If 'false', nothing is done with refreshes. :param run_as: The name of the user to be impersonated. :param username: The user name that identifies the user. If you specify the `password` grant type, this parameter is required. It is not valid with other grant @@ -2403,6 +2393,8 @@ def grant_api_key( __query["human"] = human if pretty is not None: __query["pretty"] = pretty + if refresh is not None: + __query["refresh"] = refresh if not __body: if api_key is not None: __body["api_key"] = api_key @@ -3553,7 +3545,8 @@ def query_api_keys( You can optionally filter the results with a query.

    To use this API, you must have at least the manage_own_api_key or the read_security cluster privileges. If you have only the manage_own_api_key privilege, this API returns only the API keys that you own. - If you have the read_security, manage_api_key, or greater privileges (including manage_security), this API returns all API keys regardless of ownership.

    + If you have the read_security, manage_api_key, or greater privileges (including manage_security), this API returns all API keys regardless of ownership. + Refer to the linked documentation for examples of how to find API keys:

    ``_ @@ -4466,6 +4459,7 @@ def update_cross_cluster_api_key(

    This API supports updates to an API key's access scope, metadata, and expiration. The owner user's information, such as the username and realm, is also updated automatically on every call.

    NOTE: This API cannot update REST API keys, which should be updated by either the update API key or bulk update API keys API.

    +

    To learn more about how to use this API, refer to the Update cross cluter API key API examples page.

    ``_ diff --git a/elasticsearch/_sync/client/snapshot.py b/elasticsearch/_sync/client/snapshot.py index 0f8ce9f13..476b54272 100644 --- a/elasticsearch/_sync/client/snapshot.py +++ b/elasticsearch/_sync/client/snapshot.py @@ -403,6 +403,7 @@ def delete( human: t.Optional[bool] = None, master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None, pretty: t.Optional[bool] = None, + wait_for_completion: t.Optional[bool] = None, ) -> ObjectApiResponse[t.Any]: """ .. raw:: html @@ -418,6 +419,9 @@ def delete( :param master_timeout: The period to wait for the master node. If the master node is not available before the timeout expires, the request fails and returns an error. To indicate that the request should never timeout, set it to `-1`. + :param wait_for_completion: If `true`, the request returns a response when the + matching snapshots are all deleted. If `false`, the request returns a response + as soon as the deletes are scheduled. """ if repository in SKIP_IN_PATH: raise ValueError("Empty value passed for parameter 'repository'") @@ -439,6 +443,8 @@ def delete( __query["master_timeout"] = master_timeout if pretty is not None: __query["pretty"] = pretty + if wait_for_completion is not None: + __query["wait_for_completion"] = wait_for_completion __headers = {"accept": "application/json"} return self.perform_request( # type: ignore[return-value] "DELETE", diff --git a/elasticsearch/_sync/client/synonyms.py b/elasticsearch/_sync/client/synonyms.py index 37d5530b6..9faefba56 100644 --- a/elasticsearch/_sync/client/synonyms.py +++ b/elasticsearch/_sync/client/synonyms.py @@ -309,6 +309,7 @@ def put_synonym( If you need to manage more synonym rules, you can create multiple synonym sets.

    When an existing synonyms set is updated, the search analyzers that use the synonyms set are reloaded automatically for all indices. This is equivalent to invoking the reload search analyzers API for all indices that use the synonyms set.

    +

    For practical examples of how to create or update a synonyms set, refer to the External documentation.

    ``_ diff --git a/elasticsearch/_sync/client/watcher.py b/elasticsearch/_sync/client/watcher.py index 8a235d7a5..130537743 100644 --- a/elasticsearch/_sync/client/watcher.py +++ b/elasticsearch/_sync/client/watcher.py @@ -45,7 +45,8 @@ def ack_watch(

    IMPORTANT: If the specified watch is currently being executed, this API will return an error The reason for this behavior is to prevent overwriting the watch status from a watch execution.

    Acknowledging an action throttles further executions of that action until its ack.state is reset to awaits_successful_execution. - This happens when the condition of the watch is not met (the condition evaluates to false).

    + This happens when the condition of the watch is not met (the condition evaluates to false). + To demonstrate how throttling works in practice and how it can be configured for individual actions within a watch, refer to External documentation.

    ``_ @@ -274,7 +275,8 @@ def execute_watch( This serves as great tool for testing and debugging your watches prior to adding them to Watcher.

    When Elasticsearch security features are enabled on your cluster, watches are run with the privileges of the user that stored the watches. If your user is allowed to read index a, but not index b, then the exact same set of rules will apply during execution of a watch.

    -

    When using the run watch API, the authorization data of the user that called the API will be used as a base, instead of the information who stored the watch.

    +

    When using the run watch API, the authorization data of the user that called the API will be used as a base, instead of the information who stored the watch. + Refer to the external documentation for examples of watch execution requests, including existing, customized, and inline watches.

    ``_ diff --git a/elasticsearch/dsl/aggs.py b/elasticsearch/dsl/aggs.py index 802d6eca0..97ef48d59 100644 --- a/elasticsearch/dsl/aggs.py +++ b/elasticsearch/dsl/aggs.py @@ -373,12 +373,6 @@ class Boxplot(Agg[_R]): :arg compression: Limits the maximum number of nodes used by the underlying TDigest algorithm to `20 * compression`, enabling control of memory usage and approximation error. - :arg execution_hint: The default implementation of TDigest is - optimized for performance, scaling to millions or even billions of - sample values while maintaining acceptable accuracy levels (close - to 1% relative error for millions of samples in some cases). To - use an implementation optimized for accuracy, set this parameter - to high_accuracy instead. Defaults to `default` if omitted. :arg field: The field on which to run the aggregation. :arg missing: The value to apply to documents that do not have a value. By default, documents without a value are ignored. @@ -391,9 +385,6 @@ def __init__( self, *, compression: Union[float, "DefaultType"] = DEFAULT, - execution_hint: Union[ - Literal["default", "high_accuracy"], "DefaultType" - ] = DEFAULT, field: Union[str, "InstrumentedField", "DefaultType"] = DEFAULT, missing: Union[str, int, float, bool, "DefaultType"] = DEFAULT, script: Union["types.Script", Dict[str, Any], "DefaultType"] = DEFAULT, @@ -401,7 +392,6 @@ def __init__( ): super().__init__( compression=compression, - execution_hint=execution_hint, field=field, missing=missing, script=script, @@ -1910,12 +1900,6 @@ class MedianAbsoluteDeviation(Agg[_R]): underlying TDigest algorithm to `20 * compression`, enabling control of memory usage and approximation error. Defaults to `1000` if omitted. - :arg execution_hint: The default implementation of TDigest is - optimized for performance, scaling to millions or even billions of - sample values while maintaining acceptable accuracy levels (close - to 1% relative error for millions of samples in some cases). To - use an implementation optimized for accuracy, set this parameter - to high_accuracy instead. Defaults to `default` if omitted. :arg format: :arg field: The field on which to run the aggregation. :arg missing: The value to apply to documents that do not have a @@ -1929,9 +1913,6 @@ def __init__( self, *, compression: Union[float, "DefaultType"] = DEFAULT, - execution_hint: Union[ - Literal["default", "high_accuracy"], "DefaultType" - ] = DEFAULT, format: Union[str, "DefaultType"] = DEFAULT, field: Union[str, "InstrumentedField", "DefaultType"] = DEFAULT, missing: Union[str, int, float, bool, "DefaultType"] = DEFAULT, @@ -1940,7 +1921,6 @@ def __init__( ): super().__init__( compression=compression, - execution_hint=execution_hint, format=format, field=field, missing=missing, diff --git a/elasticsearch/dsl/field.py b/elasticsearch/dsl/field.py index 73108bf3f..1aa7a4bca 100644 --- a/elasticsearch/dsl/field.py +++ b/elasticsearch/dsl/field.py @@ -3849,14 +3849,6 @@ class SemanticText(Field): by using the Update mapping API. Use the Create inference API to create the endpoint. If not specified, the inference endpoint defined by inference_id will be used at both index and query time. - :arg index_options: Settings for index_options that override any - defaults used by semantic_text, for example specific quantization - settings. - :arg chunking_settings: Settings for chunking text into smaller - passages. If specified, these will override the chunking settings - sent in the inference endpoint associated with inference_id. If - chunking settings are updated, they will not be applied to - existing documents until they are reindexed. """ name = "semantic_text" @@ -3867,12 +3859,6 @@ def __init__( meta: Union[Mapping[str, str], "DefaultType"] = DEFAULT, inference_id: Union[str, "DefaultType"] = DEFAULT, search_inference_id: Union[str, "DefaultType"] = DEFAULT, - index_options: Union[ - "types.SemanticTextIndexOptions", Dict[str, Any], "DefaultType" - ] = DEFAULT, - chunking_settings: Union[ - "types.ChunkingSettings", Dict[str, Any], "DefaultType" - ] = DEFAULT, **kwargs: Any, ): if meta is not DEFAULT: @@ -3881,10 +3867,6 @@ def __init__( kwargs["inference_id"] = inference_id if search_inference_id is not DEFAULT: kwargs["search_inference_id"] = search_inference_id - if index_options is not DEFAULT: - kwargs["index_options"] = index_options - if chunking_settings is not DEFAULT: - kwargs["chunking_settings"] = chunking_settings super().__init__(*args, **kwargs) diff --git a/elasticsearch/dsl/query.py b/elasticsearch/dsl/query.py index 0a2cef032..de57aac44 100644 --- a/elasticsearch/dsl/query.py +++ b/elasticsearch/dsl/query.py @@ -1084,7 +1084,7 @@ class Knn(Query): :arg similarity: The minimum similarity for a vector to be considered a match :arg rescore_vector: Apply oversampling and rescoring to quantized - vectors + vectors * :arg boost: Floating point number used to decrease or increase the relevance scores of the query. Boost values are relative to the default value of 1.0. A boost value between 0 and 1.0 decreases diff --git a/elasticsearch/dsl/response/__init__.py b/elasticsearch/dsl/response/__init__.py index 712cda27b..2ae863fff 100644 --- a/elasticsearch/dsl/response/__init__.py +++ b/elasticsearch/dsl/response/__init__.py @@ -363,7 +363,7 @@ class UpdateByQueryResponse(AttrDict[Any], Generic[_R]): deleted: int requests_per_second: float retries: "types.Retries" - task: str + task: Union[str, int] timed_out: bool took: Any total: int diff --git a/elasticsearch/dsl/types.py b/elasticsearch/dsl/types.py index 7aaf52da6..3d4f88baf 100644 --- a/elasticsearch/dsl/types.py +++ b/elasticsearch/dsl/types.py @@ -142,48 +142,6 @@ def __init__( super().__init__(kwargs) -class ChunkingSettings(AttrDict[Any]): - """ - :arg strategy: (required) The chunking strategy: `sentence` or `word`. - Defaults to `sentence` if omitted. - :arg max_chunk_size: (required) The maximum size of a chunk in words. - This value cannot be higher than `300` or lower than `20` (for - `sentence` strategy) or `10` (for `word` strategy). Defaults to - `250` if omitted. - :arg overlap: The number of overlapping words for chunks. It is - applicable only to a `word` chunking strategy. This value cannot - be higher than half the `max_chunk_size` value. Defaults to `100` - if omitted. - :arg sentence_overlap: The number of overlapping sentences for chunks. - It is applicable only for a `sentence` chunking strategy. It can - be either `1` or `0`. Defaults to `1` if omitted. - """ - - strategy: Union[str, DefaultType] - max_chunk_size: Union[int, DefaultType] - overlap: Union[int, DefaultType] - sentence_overlap: Union[int, DefaultType] - - def __init__( - self, - *, - strategy: Union[str, DefaultType] = DEFAULT, - max_chunk_size: Union[int, DefaultType] = DEFAULT, - overlap: Union[int, DefaultType] = DEFAULT, - sentence_overlap: Union[int, DefaultType] = DEFAULT, - **kwargs: Any, - ): - if strategy is not DEFAULT: - kwargs["strategy"] = strategy - if max_chunk_size is not DEFAULT: - kwargs["max_chunk_size"] = max_chunk_size - if overlap is not DEFAULT: - kwargs["overlap"] = overlap - if sentence_overlap is not DEFAULT: - kwargs["sentence_overlap"] = sentence_overlap - super().__init__(kwargs) - - class ClassificationInferenceOptions(AttrDict[Any]): """ :arg num_top_classes: Specifies the number of top class predictions to @@ -371,9 +329,6 @@ class DenseVectorIndexOptions(AttrDict[Any]): :arg m: The number of neighbors each node will be connected to in the HNSW graph. Only applicable to `hnsw`, `int8_hnsw`, `bbq_hnsw`, and `int4_hnsw` index types. Defaults to `16` if omitted. - :arg rescore_vector: The rescore vector options. This is only - applicable to `bbq_hnsw`, `int4_hnsw`, `int8_hnsw`, `bbq_flat`, - `int4_flat`, and `int8_flat` index types. """ type: Union[ @@ -392,9 +347,6 @@ class DenseVectorIndexOptions(AttrDict[Any]): confidence_interval: Union[float, DefaultType] ef_construction: Union[int, DefaultType] m: Union[int, DefaultType] - rescore_vector: Union[ - "DenseVectorIndexOptionsRescoreVector", Dict[str, Any], DefaultType - ] def __init__( self, @@ -415,9 +367,6 @@ def __init__( confidence_interval: Union[float, DefaultType] = DEFAULT, ef_construction: Union[int, DefaultType] = DEFAULT, m: Union[int, DefaultType] = DEFAULT, - rescore_vector: Union[ - "DenseVectorIndexOptionsRescoreVector", Dict[str, Any], DefaultType - ] = DEFAULT, **kwargs: Any, ): if type is not DEFAULT: @@ -428,29 +377,6 @@ def __init__( kwargs["ef_construction"] = ef_construction if m is not DEFAULT: kwargs["m"] = m - if rescore_vector is not DEFAULT: - kwargs["rescore_vector"] = rescore_vector - super().__init__(kwargs) - - -class DenseVectorIndexOptionsRescoreVector(AttrDict[Any]): - """ - :arg oversample: (required) The oversampling factor to use when - searching for the nearest neighbor. This is only applicable to the - quantized formats: `bbq_*`, `int4_*`, and `int8_*`. When provided, - `oversample * k` vectors will be gathered and then their scores - will be re-computed with the original vectors. valid values are - between `1.0` and `10.0` (inclusive), or `0` exactly to disable - oversampling. - """ - - oversample: Union[float, DefaultType] - - def __init__( - self, *, oversample: Union[float, DefaultType] = DEFAULT, **kwargs: Any - ): - if oversample is not DEFAULT: - kwargs["oversample"] = oversample super().__init__(kwargs) @@ -1211,7 +1137,6 @@ class Highlight(AttrDict[Any]): fields: Union[ Mapping[Union[str, InstrumentedField], "HighlightField"], - Sequence[Mapping[Union[str, InstrumentedField], "HighlightField"]], Dict[str, Any], DefaultType, ] @@ -1243,7 +1168,6 @@ def __init__( *, fields: Union[ Mapping[Union[str, InstrumentedField], "HighlightField"], - Sequence[Mapping[Union[str, InstrumentedField], "HighlightField"]], Dict[str, Any], DefaultType, ] = DEFAULT, @@ -3139,26 +3063,6 @@ def __init__( super().__init__(kwargs) -class SemanticTextIndexOptions(AttrDict[Any]): - """ - :arg dense_vector: - """ - - dense_vector: Union["DenseVectorIndexOptions", Dict[str, Any], DefaultType] - - def __init__( - self, - *, - dense_vector: Union[ - "DenseVectorIndexOptions", Dict[str, Any], DefaultType - ] = DEFAULT, - **kwargs: Any, - ): - if dense_vector is not DEFAULT: - kwargs["dense_vector"] = dense_vector - super().__init__(kwargs) - - class ShapeFieldQuery(AttrDict[Any]): """ :arg indexed_shape: Queries using a pre-indexed shape. @@ -3236,15 +3140,10 @@ def __init__( class SourceFilter(AttrDict[Any]): """ - :arg exclude_vectors: If `true`, vector fields are excluded from the - returned source. This option takes precedence over `includes`: - any vector field will remain excluded even if it matches an - `includes` rule. - :arg excludes: A list of fields to exclude from the returned source. - :arg includes: A list of fields to include in the returned source. + :arg excludes: + :arg includes: """ - exclude_vectors: Union[bool, DefaultType] excludes: Union[ Union[str, InstrumentedField], Sequence[Union[str, InstrumentedField]], @@ -3259,7 +3158,6 @@ class SourceFilter(AttrDict[Any]): def __init__( self, *, - exclude_vectors: Union[bool, DefaultType] = DEFAULT, excludes: Union[ Union[str, InstrumentedField], Sequence[Union[str, InstrumentedField]], @@ -3272,8 +3170,6 @@ def __init__( ] = DEFAULT, **kwargs: Any, ): - if exclude_vectors is not DEFAULT: - kwargs["exclude_vectors"] = exclude_vectors if excludes is not DEFAULT: kwargs["excludes"] = str(excludes) if includes is not DEFAULT: @@ -3761,30 +3657,15 @@ class TDigest(AttrDict[Any]): :arg compression: Limits the maximum number of nodes used by the underlying TDigest algorithm to `20 * compression`, enabling control of memory usage and approximation error. - :arg execution_hint: The default implementation of TDigest is - optimized for performance, scaling to millions or even billions of - sample values while maintaining acceptable accuracy levels (close - to 1% relative error for millions of samples in some cases). To - use an implementation optimized for accuracy, set this parameter - to high_accuracy instead. Defaults to `default` if omitted. """ compression: Union[int, DefaultType] - execution_hint: Union[Literal["default", "high_accuracy"], DefaultType] def __init__( - self, - *, - compression: Union[int, DefaultType] = DEFAULT, - execution_hint: Union[ - Literal["default", "high_accuracy"], DefaultType - ] = DEFAULT, - **kwargs: Any, + self, *, compression: Union[int, DefaultType] = DEFAULT, **kwargs: Any ): if compression is not DEFAULT: kwargs["compression"] = compression - if execution_hint is not DEFAULT: - kwargs["execution_hint"] = execution_hint super().__init__(kwargs) @@ -4254,7 +4135,7 @@ class WeightedTokensQuery(AttrDict[Any]): :arg _name: """ - tokens: Union[Mapping[str, float], Sequence[Mapping[str, float]], DefaultType] + tokens: Union[Mapping[str, float], DefaultType] pruning_config: Union["TokenPruningConfig", Dict[str, Any], DefaultType] boost: Union[float, DefaultType] _name: Union[str, DefaultType] @@ -4262,9 +4143,7 @@ class WeightedTokensQuery(AttrDict[Any]): def __init__( self, *, - tokens: Union[ - Mapping[str, float], Sequence[Mapping[str, float]], DefaultType - ] = DEFAULT, + tokens: Union[Mapping[str, float], DefaultType] = DEFAULT, pruning_config: Union[ "TokenPruningConfig", Dict[str, Any], DefaultType ] = DEFAULT, @@ -5166,9 +5045,11 @@ def buckets_as_dict(self) -> Mapping[str, "FiltersBucket"]: class FiltersBucket(AttrDict[Any]): """ :arg doc_count: (required) + :arg key: """ doc_count: int + key: str class FrequentItemSetsAggregate(AttrDict[Any]): From 5f7371c7c7688f357ebbd2ff0f44b24353326e0e Mon Sep 17 00:00:00 2001 From: Miguel Grinberg Date: Wed, 30 Jul 2025 11:57:23 +0100 Subject: [PATCH 52/57] Release 9.0.3 (#3015) --- docs/release-notes/index.md | 31 +++++++++++++++++++++++++++++++ elasticsearch/_version.py | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/index.md b/docs/release-notes/index.md index 314030cdd..ca50b56af 100644 --- a/docs/release-notes/index.md +++ b/docs/release-notes/index.md @@ -18,6 +18,37 @@ To check for security updates, go to [Security announcements for the Elastic sta % * % ### Fixes [elasticsearch-python-client-next-fixes] +## 9.0.3 (2025-07-30) + +Enhancements + +* ES|QL query builder (technical preview) ([#2997](https://github.com/elastic/elasticsearch-py/pull/2997)) +* Add option to disable accurate reporting of file and line location in warnings (Fixes #3003) ([#3006](https://github.com/elastic/elasticsearch-py/pull/3006)) + +APIs + +* Remove `if_primary_term`, `if_seq_no` and `op_type` from Create API +* Remove `stored_fields` from Get Source API +* Remove `master_timeout` from Ingest Get Ip Location Database API +* Remove `application`, `priviledge` and `username` from the Security Get User API +* Rename `type_query_string` to `type` in License Post Start Trial API +* Add `require_data_stream` to Index API +* Add `settings_filter` to Cluster Get Component Template API +* Add `cause` to Cluster Put Component Template API +* Add `ccs_minimize_roundtrips` to EQL Search API +* Add `keep_alive` and `keep_on_completion` to ES|QL Async Query API +* Add `format` to ES|QL Async Query Get API +* Add `allow_no_indices`, `expand_wildcards` and `ignore_available` to Indices Recovery API +* Add `timeout` to all Inference Put APIs +* Add `refresh` to Security Get User Profile API +* Add `wait_for_completion` to the Snapshot Delete API + +DSL + +* Handle lists in `copy_to` field option correctly (Fixes #2992) ([#2993](https://github.com/elastic/elasticsearch-py/pull/2993)) +* Add `key` to FiltersBucket type + + ## 9.0.2 (2025-06-05) [elasticsearch-python-client-902-release-notes] diff --git a/elasticsearch/_version.py b/elasticsearch/_version.py index 0624a7ff1..a6bef7e1d 100644 --- a/elasticsearch/_version.py +++ b/elasticsearch/_version.py @@ -15,4 +15,4 @@ # specific language governing permissions and limitations # under the License. -__versionstr__ = "9.0.2" +__versionstr__ = "9.0.3" From 25c199c0c33f943888d15899d74d7775b51643e9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Aug 2025 17:01:50 +0100 Subject: [PATCH 53/57] Address integration test failures in Python 3.8 (#3018) (#3022) (cherry picked from commit 67c444c8143bcbaf7c9d80516538575c989e6cd6) Co-authored-by: Miguel Grinberg --- test_elasticsearch/test_server/test_rest_api_spec.py | 9 ++++++++- test_elasticsearch/utils.py | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/test_elasticsearch/test_server/test_rest_api_spec.py b/test_elasticsearch/test_server/test_rest_api_spec.py index a84f0822a..f12db87aa 100644 --- a/test_elasticsearch/test_server/test_rest_api_spec.py +++ b/test_elasticsearch/test_server/test_rest_api_spec.py @@ -78,6 +78,7 @@ "cluster/voting_config_exclusions", "entsearch/10_basic", "indices/clone", + "indices/data_stream_mappings[0]", "indices/resolve_cluster", "indices/settings", "indices/split", @@ -501,7 +502,13 @@ def remove_implicit_resolver(cls, tag_to_remove): ) # Download the zip and start reading YAML from the files in memory - package_zip = zipfile.ZipFile(io.BytesIO(http.request("GET", yaml_tests_url).data)) + package_zip = zipfile.ZipFile( + io.BytesIO( + http.request( + "GET", yaml_tests_url, retries=urllib3.Retry(3, redirect=10) + ).data + ) + ) for yaml_file in package_zip.namelist(): if not re.match(r"^.*\/tests\/.*\.ya?ml$", yaml_file): diff --git a/test_elasticsearch/utils.py b/test_elasticsearch/utils.py index 021deb76e..cfcb5259c 100644 --- a/test_elasticsearch/utils.py +++ b/test_elasticsearch/utils.py @@ -179,7 +179,7 @@ def wipe_data_streams(client): def wipe_indices(client): indices = client.cat.indices().strip().splitlines() if len(indices) > 0: - index_names = [i.split(" ")[2] for i in indices] + index_names = [i.split()[2] for i in indices] client.options(ignore_status=404).indices.delete( index=",".join(index_names), expand_wildcards="all", From 709bc9f6b29a26a6a2e82eade7bb5d6b4192dd73 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Aug 2025 17:29:22 +0100 Subject: [PATCH 54/57] ES|QL query builder robustness fixes (#3017) (#3024) * Add note on how to prevent ES|QL injection attacks * Various additional query builder fixes * linter fixes (cherry picked from commit e3e85ed38c303b792cd44f892c961c3c45804c55) Co-authored-by: Miguel Grinberg --- docs/reference/esql-query-builder.md | 22 +++- elasticsearch/esql/__init__.py | 1 + elasticsearch/esql/esql.py | 119 +++++++++++++----- elasticsearch/esql/functions.py | 56 +++++---- .../_async/test_esql.py | 12 +- .../{ => test_integration}/_sync/test_esql.py | 12 +- test_elasticsearch/test_esql.py | 16 ++- 7 files changed, 175 insertions(+), 63 deletions(-) rename test_elasticsearch/test_dsl/{ => test_integration}/_async/test_esql.py (88%) rename test_elasticsearch/test_dsl/{ => test_integration}/_sync/test_esql.py (88%) diff --git a/docs/reference/esql-query-builder.md b/docs/reference/esql-query-builder.md index 1cdc0c5b3..8390ea983 100644 --- a/docs/reference/esql-query-builder.md +++ b/docs/reference/esql-query-builder.md @@ -203,6 +203,26 @@ query = ( ) ``` +### Preventing injection attacks + +ES|QL, like most query languages, is vulnerable to [code injection attacks](https://en.wikipedia.org/wiki/Code_injection) if untrusted data provided by users is added to a query. To eliminate this risk, ES|QL allows untrusted data to be given separately from the query as parameters. + +Continuing with the example above, let's assume that the application needs a `find_employee_by_name()` function that searches for the name given as an argument. If this argument is received by the application from users, then it is considered untrusted and should not be added to the query directly. Here is how to code the function in a secure manner: + +```python +def find_employee_by_name(name): + query = ( + ESQL.from_("employees") + .keep("first_name", "last_name", "height") + .where(E("first_name") == E("?")) + ) + return client.esql.query(query=str(query), params=[name]) +``` + +Here the part of the query in which the untrusted data needs to be inserted is replaced with a parameter, which in ES|QL is defined by the question mark. When using Python expressions, the parameter must be given as `E("?")` so that it is treated as an expression and not as a literal string. + +The list of values given in the `params` argument to the query endpoint are assigned in order to the parameters defined in the query. + ## Using ES|QL functions The ES|QL language includes a rich set of functions that can be used in expressions and conditionals. These can be included in expressions given as strings, as shown in the example below: @@ -235,6 +255,6 @@ query = ( ) ``` -Note that arguments passed to functions are assumed to be literals. When passing field names, it is necessary to wrap them with the `E()` helper function so that they are interpreted correctly. +Note that arguments passed to functions are assumed to be literals. When passing field names, parameters or other ES|QL expressions, it is necessary to wrap them with the `E()` helper function so that they are interpreted correctly. You can find the complete list of available functions in the Python client's [ES|QL API reference documentation](https://elasticsearch-py.readthedocs.io/en/stable/esql.html#module-elasticsearch.esql.functions). diff --git a/elasticsearch/esql/__init__.py b/elasticsearch/esql/__init__.py index d872c329a..8da8f852a 100644 --- a/elasticsearch/esql/__init__.py +++ b/elasticsearch/esql/__init__.py @@ -15,4 +15,5 @@ # specific language governing permissions and limitations # under the License. +from ..dsl import E # noqa: F401 from .esql import ESQL, and_, not_, or_ # noqa: F401 diff --git a/elasticsearch/esql/esql.py b/elasticsearch/esql/esql.py index 07ccdf839..05f4e3e3e 100644 --- a/elasticsearch/esql/esql.py +++ b/elasticsearch/esql/esql.py @@ -16,6 +16,7 @@ # under the License. import json +import re from abc import ABC, abstractmethod from typing import Any, Dict, Optional, Tuple, Type, Union @@ -111,6 +112,29 @@ def render(self) -> str: def _render_internal(self) -> str: pass + @staticmethod + def _format_index(index: IndexType) -> str: + return index._index._name if hasattr(index, "_index") else str(index) + + @staticmethod + def _format_id(id: FieldType, allow_patterns: bool = False) -> str: + s = str(id) # in case it is an InstrumentedField + if allow_patterns and "*" in s: + return s # patterns cannot be escaped + if re.fullmatch(r"[a-zA-Z_@][a-zA-Z0-9_\.]*", s): + return s + # this identifier needs to be escaped + s.replace("`", "``") + return f"`{s}`" + + @staticmethod + def _format_expr(expr: ExpressionType) -> str: + return ( + json.dumps(expr) + if not isinstance(expr, (str, InstrumentedExpression)) + else str(expr) + ) + def _is_forked(self) -> bool: if self.__class__.__name__ == "Fork": return True @@ -427,7 +451,7 @@ def sample(self, probability: float) -> "Sample": """ return Sample(self, probability) - def sort(self, *columns: FieldType) -> "Sort": + def sort(self, *columns: ExpressionType) -> "Sort": """The ``SORT`` processing command sorts a table on one or more columns. :param columns: The columns to sort on. @@ -570,15 +594,12 @@ def metadata(self, *fields: FieldType) -> "From": return self def _render_internal(self) -> str: - indices = [ - index if isinstance(index, str) else index._index._name - for index in self._indices - ] + indices = [self._format_index(index) for index in self._indices] s = f'{self.__class__.__name__.upper()} {", ".join(indices)}' if self._metadata_fields: s = ( s - + f' METADATA {", ".join([str(field) for field in self._metadata_fields])}' + + f' METADATA {", ".join([self._format_id(field) for field in self._metadata_fields])}' ) return s @@ -594,7 +615,11 @@ class Row(ESQLBase): def __init__(self, **params: ExpressionType): super().__init__() self._params = { - k: json.dumps(v) if not isinstance(v, InstrumentedExpression) else v + self._format_id(k): ( + json.dumps(v) + if not isinstance(v, InstrumentedExpression) + else self._format_expr(v) + ) for k, v in params.items() } @@ -615,7 +640,7 @@ def __init__(self, item: str): self._item = item def _render_internal(self) -> str: - return f"SHOW {self._item}" + return f"SHOW {self._format_id(self._item)}" class Branch(ESQLBase): @@ -667,11 +692,11 @@ def as_(self, type_name: str, pvalue_name: str) -> "ChangePoint": return self def _render_internal(self) -> str: - key = "" if not self._key else f" ON {self._key}" + key = "" if not self._key else f" ON {self._format_id(self._key)}" names = ( "" if not self._type_name and not self._pvalue_name - else f' AS {self._type_name or "type"}, {self._pvalue_name or "pvalue"}' + else f' AS {self._format_id(self._type_name or "type")}, {self._format_id(self._pvalue_name or "pvalue")}' ) return f"CHANGE_POINT {self._value}{key}{names}" @@ -709,12 +734,13 @@ def with_(self, inference_id: str) -> "Completion": def _render_internal(self) -> str: if self._inference_id is None: raise ValueError("The completion command requires an inference ID") + with_ = {"inference_id": self._inference_id} if self._named_prompt: column = list(self._named_prompt.keys())[0] prompt = list(self._named_prompt.values())[0] - return f"COMPLETION {column} = {prompt} WITH {self._inference_id}" + return f"COMPLETION {self._format_id(column)} = {self._format_id(prompt)} WITH {json.dumps(with_)}" else: - return f"COMPLETION {self._prompt[0]} WITH {self._inference_id}" + return f"COMPLETION {self._format_id(self._prompt[0])} WITH {json.dumps(with_)}" class Dissect(ESQLBase): @@ -742,9 +768,13 @@ def append_separator(self, separator: str) -> "Dissect": def _render_internal(self) -> str: sep = ( - "" if self._separator is None else f' APPEND_SEPARATOR="{self._separator}"' + "" + if self._separator is None + else f" APPEND_SEPARATOR={json.dumps(self._separator)}" + ) + return ( + f"DISSECT {self._format_id(self._input)} {json.dumps(self._pattern)}{sep}" ) - return f"DISSECT {self._input} {json.dumps(self._pattern)}{sep}" class Drop(ESQLBase): @@ -760,7 +790,7 @@ def __init__(self, parent: ESQLBase, *columns: FieldType): self._columns = columns def _render_internal(self) -> str: - return f'DROP {", ".join([str(col) for col in self._columns])}' + return f'DROP {", ".join([self._format_id(col, allow_patterns=True) for col in self._columns])}' class Enrich(ESQLBase): @@ -814,12 +844,18 @@ def with_(self, *fields: FieldType, **named_fields: FieldType) -> "Enrich": return self def _render_internal(self) -> str: - on = "" if self._match_field is None else f" ON {self._match_field}" + on = ( + "" + if self._match_field is None + else f" ON {self._format_id(self._match_field)}" + ) with_ = "" if self._named_fields: - with_ = f' WITH {", ".join([f"{name} = {field}" for name, field in self._named_fields.items()])}' + with_ = f' WITH {", ".join([f"{self._format_id(name)} = {self._format_id(field)}" for name, field in self._named_fields.items()])}' elif self._fields is not None: - with_ = f' WITH {", ".join([str(field) for field in self._fields])}' + with_ = ( + f' WITH {", ".join([self._format_id(field) for field in self._fields])}' + ) return f"ENRICH {self._policy}{on}{with_}" @@ -832,7 +868,10 @@ class Eval(ESQLBase): """ def __init__( - self, parent: ESQLBase, *columns: FieldType, **named_columns: FieldType + self, + parent: ESQLBase, + *columns: ExpressionType, + **named_columns: ExpressionType, ): if columns and named_columns: raise ValueError( @@ -844,10 +883,13 @@ def __init__( def _render_internal(self) -> str: if isinstance(self._columns, dict): cols = ", ".join( - [f"{name} = {value}" for name, value in self._columns.items()] + [ + f"{self._format_id(name)} = {self._format_expr(value)}" + for name, value in self._columns.items() + ] ) else: - cols = ", ".join([f"{col}" for col in self._columns]) + cols = ", ".join([f"{self._format_expr(col)}" for col in self._columns]) return f"EVAL {cols}" @@ -900,7 +942,7 @@ def __init__(self, parent: ESQLBase, input: FieldType, pattern: str): self._pattern = pattern def _render_internal(self) -> str: - return f"GROK {self._input} {json.dumps(self._pattern)}" + return f"GROK {self._format_id(self._input)} {json.dumps(self._pattern)}" class Keep(ESQLBase): @@ -916,7 +958,7 @@ def __init__(self, parent: ESQLBase, *columns: FieldType): self._columns = columns def _render_internal(self) -> str: - return f'KEEP {", ".join([f"{col}" for col in self._columns])}' + return f'KEEP {", ".join([f"{self._format_id(col, allow_patterns=True)}" for col in self._columns])}' class Limit(ESQLBase): @@ -932,7 +974,7 @@ def __init__(self, parent: ESQLBase, max_number_of_rows: int): self._max_number_of_rows = max_number_of_rows def _render_internal(self) -> str: - return f"LIMIT {self._max_number_of_rows}" + return f"LIMIT {json.dumps(self._max_number_of_rows)}" class LookupJoin(ESQLBase): @@ -967,7 +1009,9 @@ def _render_internal(self) -> str: if isinstance(self._lookup_index, str) else self._lookup_index._index._name ) - return f"LOOKUP JOIN {index} ON {self._field}" + return ( + f"LOOKUP JOIN {self._format_index(index)} ON {self._format_id(self._field)}" + ) class MvExpand(ESQLBase): @@ -983,7 +1027,7 @@ def __init__(self, parent: ESQLBase, column: FieldType): self._column = column def _render_internal(self) -> str: - return f"MV_EXPAND {self._column}" + return f"MV_EXPAND {self._format_id(self._column)}" class Rename(ESQLBase): @@ -999,7 +1043,7 @@ def __init__(self, parent: ESQLBase, **columns: FieldType): self._columns = columns def _render_internal(self) -> str: - return f'RENAME {", ".join([f"{old_name} AS {new_name}" for old_name, new_name in self._columns.items()])}' + return f'RENAME {", ".join([f"{self._format_id(old_name)} AS {self._format_id(new_name)}" for old_name, new_name in self._columns.items()])}' class Sample(ESQLBase): @@ -1015,7 +1059,7 @@ def __init__(self, parent: ESQLBase, probability: float): self._probability = probability def _render_internal(self) -> str: - return f"SAMPLE {self._probability}" + return f"SAMPLE {json.dumps(self._probability)}" class Sort(ESQLBase): @@ -1026,12 +1070,16 @@ class Sort(ESQLBase): in a single expression. """ - def __init__(self, parent: ESQLBase, *columns: FieldType): + def __init__(self, parent: ESQLBase, *columns: ExpressionType): super().__init__(parent) self._columns = columns def _render_internal(self) -> str: - return f'SORT {", ".join([f"{col}" for col in self._columns])}' + sorts = [ + " ".join([self._format_id(term) for term in str(col).split(" ")]) + for col in self._columns + ] + return f'SORT {", ".join([f"{sort}" for sort in sorts])}' class Stats(ESQLBase): @@ -1062,14 +1110,17 @@ def by(self, *grouping_expressions: ExpressionType) -> "Stats": def _render_internal(self) -> str: if isinstance(self._expressions, dict): - exprs = [f"{key} = {value}" for key, value in self._expressions.items()] + exprs = [ + f"{self._format_id(key)} = {self._format_expr(value)}" + for key, value in self._expressions.items() + ] else: - exprs = [f"{expr}" for expr in self._expressions] + exprs = [f"{self._format_expr(expr)}" for expr in self._expressions] expression_separator = ",\n " by = ( "" if self._grouping_expressions is None - else f'\n BY {", ".join([f"{expr}" for expr in self._grouping_expressions])}' + else f'\n BY {", ".join([f"{self._format_expr(expr)}" for expr in self._grouping_expressions])}' ) return f'STATS {expression_separator.join([f"{expr}" for expr in exprs])}{by}' @@ -1087,7 +1138,7 @@ def __init__(self, parent: ESQLBase, *expressions: ExpressionType): self._expressions = expressions def _render_internal(self) -> str: - return f'WHERE {" AND ".join([f"{expr}" for expr in self._expressions])}' + return f'WHERE {" AND ".join([f"{self._format_expr(expr)}" for expr in self._expressions])}' def and_(*expressions: InstrumentedExpression) -> "InstrumentedExpression": diff --git a/elasticsearch/esql/functions.py b/elasticsearch/esql/functions.py index 515e3ddfc..91f18d2d8 100644 --- a/elasticsearch/esql/functions.py +++ b/elasticsearch/esql/functions.py @@ -19,11 +19,15 @@ from typing import Any from elasticsearch.dsl.document_base import InstrumentedExpression -from elasticsearch.esql.esql import ExpressionType +from elasticsearch.esql.esql import ESQLBase, ExpressionType def _render(v: Any) -> str: - return json.dumps(v) if not isinstance(v, InstrumentedExpression) else str(v) + return ( + json.dumps(v) + if not isinstance(v, InstrumentedExpression) + else ESQLBase._format_expr(v) + ) def abs(number: ExpressionType) -> InstrumentedExpression: @@ -69,7 +73,9 @@ def atan2( :param y_coordinate: y coordinate. If `null`, the function returns `null`. :param x_coordinate: x coordinate. If `null`, the function returns `null`. """ - return InstrumentedExpression(f"ATAN2({y_coordinate}, {x_coordinate})") + return InstrumentedExpression( + f"ATAN2({_render(y_coordinate)}, {_render(x_coordinate)})" + ) def avg(number: ExpressionType) -> InstrumentedExpression: @@ -114,7 +120,7 @@ def bucket( :param to: End of the range. Can be a number, a date or a date expressed as a string. """ return InstrumentedExpression( - f"BUCKET({_render(field)}, {_render(buckets)}, {from_}, {_render(to)})" + f"BUCKET({_render(field)}, {_render(buckets)}, {_render(from_)}, {_render(to)})" ) @@ -169,7 +175,7 @@ def cidr_match(ip: ExpressionType, block_x: ExpressionType) -> InstrumentedExpre :param ip: IP address of type `ip` (both IPv4 and IPv6 are supported). :param block_x: CIDR block to test the IP against. """ - return InstrumentedExpression(f"CIDR_MATCH({_render(ip)}, {block_x})") + return InstrumentedExpression(f"CIDR_MATCH({_render(ip)}, {_render(block_x)})") def coalesce(first: ExpressionType, rest: ExpressionType) -> InstrumentedExpression: @@ -264,7 +270,7 @@ def date_diff( :param end_timestamp: A string representing an end timestamp """ return InstrumentedExpression( - f"DATE_DIFF({_render(unit)}, {start_timestamp}, {end_timestamp})" + f"DATE_DIFF({_render(unit)}, {_render(start_timestamp)}, {_render(end_timestamp)})" ) @@ -285,7 +291,9 @@ def date_extract( the function returns `null`. :param date: Date expression. If `null`, the function returns `null`. """ - return InstrumentedExpression(f"DATE_EXTRACT({date_part}, {_render(date)})") + return InstrumentedExpression( + f"DATE_EXTRACT({_render(date_part)}, {_render(date)})" + ) def date_format( @@ -301,7 +309,7 @@ def date_format( """ if date_format is not None: return InstrumentedExpression( - f"DATE_FORMAT({json.dumps(date_format)}, {_render(date)})" + f"DATE_FORMAT({_render(date_format)}, {_render(date)})" ) else: return InstrumentedExpression(f"DATE_FORMAT({_render(date)})") @@ -317,7 +325,9 @@ def date_parse( :param date_string: Date expression as a string. If `null` or an empty string, the function returns `null`. """ - return InstrumentedExpression(f"DATE_PARSE({date_pattern}, {date_string})") + return InstrumentedExpression( + f"DATE_PARSE({_render(date_pattern)}, {_render(date_string)})" + ) def date_trunc( @@ -929,7 +939,7 @@ def replace( :param new_string: Replacement string. """ return InstrumentedExpression( - f"REPLACE({_render(string)}, {_render(regex)}, {new_string})" + f"REPLACE({_render(string)}, {_render(regex)}, {_render(new_string)})" ) @@ -1004,7 +1014,7 @@ def scalb(d: ExpressionType, scale_factor: ExpressionType) -> InstrumentedExpres :param scale_factor: Numeric expression for the scale factor. If `null`, the function returns `null`. """ - return InstrumentedExpression(f"SCALB({_render(d)}, {scale_factor})") + return InstrumentedExpression(f"SCALB({_render(d)}, {_render(scale_factor)})") def sha1(input: ExpressionType) -> InstrumentedExpression: @@ -1116,7 +1126,7 @@ def st_contains( first. This means it is not possible to combine `geo_*` and `cartesian_*` parameters. """ - return InstrumentedExpression(f"ST_CONTAINS({geom_a}, {geom_b})") + return InstrumentedExpression(f"ST_CONTAINS({_render(geom_a)}, {_render(geom_b)})") def st_disjoint( @@ -1135,7 +1145,7 @@ def st_disjoint( first. This means it is not possible to combine `geo_*` and `cartesian_*` parameters. """ - return InstrumentedExpression(f"ST_DISJOINT({geom_a}, {geom_b})") + return InstrumentedExpression(f"ST_DISJOINT({_render(geom_a)}, {_render(geom_b)})") def st_distance( @@ -1153,7 +1163,7 @@ def st_distance( also have the same coordinate system as the first. This means it is not possible to combine `geo_point` and `cartesian_point` parameters. """ - return InstrumentedExpression(f"ST_DISTANCE({geom_a}, {geom_b})") + return InstrumentedExpression(f"ST_DISTANCE({_render(geom_a)}, {_render(geom_b)})") def st_envelope(geometry: ExpressionType) -> InstrumentedExpression: @@ -1208,7 +1218,7 @@ def st_geohash_to_long(grid_id: ExpressionType) -> InstrumentedExpression: :param grid_id: Input geohash grid-id. The input can be a single- or multi-valued column or an expression. """ - return InstrumentedExpression(f"ST_GEOHASH_TO_LONG({grid_id})") + return InstrumentedExpression(f"ST_GEOHASH_TO_LONG({_render(grid_id)})") def st_geohash_to_string(grid_id: ExpressionType) -> InstrumentedExpression: @@ -1218,7 +1228,7 @@ def st_geohash_to_string(grid_id: ExpressionType) -> InstrumentedExpression: :param grid_id: Input geohash grid-id. The input can be a single- or multi-valued column or an expression. """ - return InstrumentedExpression(f"ST_GEOHASH_TO_STRING({grid_id})") + return InstrumentedExpression(f"ST_GEOHASH_TO_STRING({_render(grid_id)})") def st_geohex( @@ -1254,7 +1264,7 @@ def st_geohex_to_long(grid_id: ExpressionType) -> InstrumentedExpression: :param grid_id: Input geohex grid-id. The input can be a single- or multi-valued column or an expression. """ - return InstrumentedExpression(f"ST_GEOHEX_TO_LONG({grid_id})") + return InstrumentedExpression(f"ST_GEOHEX_TO_LONG({_render(grid_id)})") def st_geohex_to_string(grid_id: ExpressionType) -> InstrumentedExpression: @@ -1264,7 +1274,7 @@ def st_geohex_to_string(grid_id: ExpressionType) -> InstrumentedExpression: :param grid_id: Input Geohex grid-id. The input can be a single- or multi-valued column or an expression. """ - return InstrumentedExpression(f"ST_GEOHEX_TO_STRING({grid_id})") + return InstrumentedExpression(f"ST_GEOHEX_TO_STRING({_render(grid_id)})") def st_geotile( @@ -1300,7 +1310,7 @@ def st_geotile_to_long(grid_id: ExpressionType) -> InstrumentedExpression: :param grid_id: Input geotile grid-id. The input can be a single- or multi-valued column or an expression. """ - return InstrumentedExpression(f"ST_GEOTILE_TO_LONG({grid_id})") + return InstrumentedExpression(f"ST_GEOTILE_TO_LONG({_render(grid_id)})") def st_geotile_to_string(grid_id: ExpressionType) -> InstrumentedExpression: @@ -1310,7 +1320,7 @@ def st_geotile_to_string(grid_id: ExpressionType) -> InstrumentedExpression: :param grid_id: Input geotile grid-id. The input can be a single- or multi-valued column or an expression. """ - return InstrumentedExpression(f"ST_GEOTILE_TO_STRING({grid_id})") + return InstrumentedExpression(f"ST_GEOTILE_TO_STRING({_render(grid_id)})") def st_intersects( @@ -1330,7 +1340,9 @@ def st_intersects( first. This means it is not possible to combine `geo_*` and `cartesian_*` parameters. """ - return InstrumentedExpression(f"ST_INTERSECTS({geom_a}, {geom_b})") + return InstrumentedExpression( + f"ST_INTERSECTS({_render(geom_a)}, {_render(geom_b)})" + ) def st_within(geom_a: ExpressionType, geom_b: ExpressionType) -> InstrumentedExpression: @@ -1346,7 +1358,7 @@ def st_within(geom_a: ExpressionType, geom_b: ExpressionType) -> InstrumentedExp first. This means it is not possible to combine `geo_*` and `cartesian_*` parameters. """ - return InstrumentedExpression(f"ST_WITHIN({geom_a}, {geom_b})") + return InstrumentedExpression(f"ST_WITHIN({_render(geom_a)}, {_render(geom_b)})") def st_x(point: ExpressionType) -> InstrumentedExpression: diff --git a/test_elasticsearch/test_dsl/_async/test_esql.py b/test_elasticsearch/test_dsl/test_integration/_async/test_esql.py similarity index 88% rename from test_elasticsearch/test_dsl/_async/test_esql.py rename to test_elasticsearch/test_dsl/test_integration/_async/test_esql.py index 7aacb833c..27d26ca99 100644 --- a/test_elasticsearch/test_dsl/_async/test_esql.py +++ b/test_elasticsearch/test_dsl/test_integration/_async/test_esql.py @@ -17,7 +17,7 @@ import pytest -from elasticsearch.dsl import AsyncDocument, M +from elasticsearch.dsl import AsyncDocument, E, M from elasticsearch.esql import ESQL, functions @@ -91,3 +91,13 @@ async def test_esql(async_client): ) r = await async_client.esql.query(query=str(query)) assert r.body["values"] == [[1.95]] + + # find employees by name using a parameter + query = ( + ESQL.from_(Employee) + .where(Employee.first_name == E("?")) + .keep(Employee.last_name) + .sort(Employee.last_name.desc()) + ) + r = await async_client.esql.query(query=str(query), params=["Maria"]) + assert r.body["values"] == [["Luna"], ["Cannon"]] diff --git a/test_elasticsearch/test_dsl/_sync/test_esql.py b/test_elasticsearch/test_dsl/test_integration/_sync/test_esql.py similarity index 88% rename from test_elasticsearch/test_dsl/_sync/test_esql.py rename to test_elasticsearch/test_dsl/test_integration/_sync/test_esql.py index 1c4084fc7..85ceee5ae 100644 --- a/test_elasticsearch/test_dsl/_sync/test_esql.py +++ b/test_elasticsearch/test_dsl/test_integration/_sync/test_esql.py @@ -17,7 +17,7 @@ import pytest -from elasticsearch.dsl import Document, M +from elasticsearch.dsl import Document, E, M from elasticsearch.esql import ESQL, functions @@ -91,3 +91,13 @@ def test_esql(client): ) r = client.esql.query(query=str(query)) assert r.body["values"] == [[1.95]] + + # find employees by name using a parameter + query = ( + ESQL.from_(Employee) + .where(Employee.first_name == E("?")) + .keep(Employee.last_name) + .sort(Employee.last_name.desc()) + ) + r = client.esql.query(query=str(query), params=["Maria"]) + assert r.body["values"] == [["Luna"], ["Cannon"]] diff --git a/test_elasticsearch/test_esql.py b/test_elasticsearch/test_esql.py index 70c9ec679..35b026fb5 100644 --- a/test_elasticsearch/test_esql.py +++ b/test_elasticsearch/test_esql.py @@ -84,7 +84,7 @@ def test_completion(): assert ( query.render() == """ROW question = "What is Elasticsearch?" -| COMPLETION question WITH test_completion_model +| COMPLETION question WITH {"inference_id": "test_completion_model"} | KEEP question, completion""" ) @@ -97,7 +97,7 @@ def test_completion(): assert ( query.render() == """ROW question = "What is Elasticsearch?" -| COMPLETION answer = question WITH test_completion_model +| COMPLETION answer = question WITH {"inference_id": "test_completion_model"} | KEEP question, answer""" ) @@ -128,7 +128,7 @@ def test_completion(): "Synopsis: ", synopsis, "\\n", "Actors: ", MV_CONCAT(actors, ", "), "\\n", ) -| COMPLETION summary = prompt WITH test_completion_model +| COMPLETION summary = prompt WITH {"inference_id": "test_completion_model"} | KEEP title, summary, rating""" ) @@ -160,7 +160,7 @@ def test_completion(): | SORT rating DESC | LIMIT 10 | EVAL prompt = CONCAT("Summarize this movie using the following information: \\n", "Title: ", title, "\\n", "Synopsis: ", synopsis, "\\n", "Actors: ", MV_CONCAT(actors, ", "), "\\n") -| COMPLETION summary = prompt WITH test_completion_model +| COMPLETION summary = prompt WITH {"inference_id": "test_completion_model"} | KEEP title, summary, rating""" ) @@ -713,3 +713,11 @@ def test_match_operator(): == """FROM books | WHERE author:"Faulkner\"""" ) + + +def test_parameters(): + query = ESQL.from_("employees").where("name == ?") + assert query.render() == "FROM employees\n| WHERE name == ?" + + query = ESQL.from_("employees").where(E("name") == E("?")) + assert query.render() == "FROM employees\n| WHERE name == ?" From 6bc9a397318aa7db044be6a16ba8a42f7ace44e4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 5 Aug 2025 15:17:26 +0100 Subject: [PATCH 55/57] Minor improvement to fix in #3018 (#3031) (#3035) (cherry picked from commit a67c2eef139b1f55fca8ffa79f8c19d6a03dc6cc) Co-authored-by: Miguel Grinberg --- test_elasticsearch/test_server/test_rest_api_spec.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/test_elasticsearch/test_server/test_rest_api_spec.py b/test_elasticsearch/test_server/test_rest_api_spec.py index f12db87aa..768453c10 100644 --- a/test_elasticsearch/test_server/test_rest_api_spec.py +++ b/test_elasticsearch/test_server/test_rest_api_spec.py @@ -495,20 +495,14 @@ def remove_implicit_resolver(cls, tag_to_remove): # Try loading the REST API test specs from the Elastic Artifacts API try: # Construct the HTTP and Elasticsearch client - http = urllib3.PoolManager(retries=10) + http = urllib3.PoolManager(retries=urllib3.Retry(total=10)) yaml_tests_url = ( "https://api.github.com/repos/elastic/elasticsearch-clients-tests/zipball/main" ) # Download the zip and start reading YAML from the files in memory - package_zip = zipfile.ZipFile( - io.BytesIO( - http.request( - "GET", yaml_tests_url, retries=urllib3.Retry(3, redirect=10) - ).data - ) - ) + package_zip = zipfile.ZipFile(io.BytesIO(http.request("GET", yaml_tests_url).data)) for yaml_file in package_zip.namelist(): if not re.match(r"^.*\/tests\/.*\.ya?ml$", yaml_file): From 15f8c927ec574b6234248dbf11c9a2eaed99e51f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 13:38:13 +0400 Subject: [PATCH 56/57] Fix new parameter name in breaking changes docs (#3038) (#3039) (cherry picked from commit 6bfbdaf031186202fcc2250ee6703362878f1342) Co-authored-by: Quentin Pradet --- docs/release-notes/breaking-changes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/release-notes/breaking-changes.md b/docs/release-notes/breaking-changes.md index 640a57036..0a354b9ce 100644 --- a/docs/release-notes/breaking-changes.md +++ b/docs/release-notes/breaking-changes.md @@ -28,7 +28,7 @@ For more information, check [PR #2840](https://github.com/elastic/elasticsearch- * `host_info_callback` is now `sniffed_node_callback` * `sniffer_timeout` is now `min_delay_between_sniffing` * `sniff_on_connection_fail` is now `sniff_on_node_failure` - * `maxsize` is now `connection_per_node` + * `maxsize` is now `connections_per_node` :::: ::::{dropdown} Remove deprecated url_prefix and use_ssl host keys @@ -50,4 +50,4 @@ Elasticsearch 9 removed the kNN search and Unfreeze index APIs. **Action**
    * The kNN search API has been replaced by the `knn` option in the search API since Elasticsearch 8.4. * The Unfreeze index API was deprecated in Elasticsearch 7.14 and has been removed in Elasticsearch 9. - :::: \ No newline at end of file + :::: From cf55ab522a996215ea33f79c8b46d4e7b1eb3799 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 20 Aug 2025 16:21:51 +0100 Subject: [PATCH 57/57] DSL: preserve the `skip_empty` setting in `to_dict()` recursive serializations (#3041) (#3046) * Try reproducing DSL issue 1577 * better attempt to reproduce * preserve skip_empty setting in recursive serializations --------- (cherry picked from commit 4761d56405437929e67080ec7890204175cc2513) Co-authored-by: Quentin Pradet Co-authored-by: Miguel Grinberg --- elasticsearch/dsl/field.py | 33 +++++++++++++------ elasticsearch/dsl/utils.py | 2 +- .../test_integration/_async/test_document.py | 11 +++++-- .../test_integration/_sync/test_document.py | 11 +++++-- utils/templates/field.py.tpl | 27 +++++++++------ 5 files changed, 59 insertions(+), 25 deletions(-) diff --git a/elasticsearch/dsl/field.py b/elasticsearch/dsl/field.py index 1aa7a4bca..d4c5a6e76 100644 --- a/elasticsearch/dsl/field.py +++ b/elasticsearch/dsl/field.py @@ -119,9 +119,16 @@ def __init__( def __getitem__(self, subfield: str) -> "Field": return cast(Field, self._params.get("fields", {})[subfield]) - def _serialize(self, data: Any) -> Any: + def _serialize(self, data: Any, skip_empty: bool) -> Any: return data + def _safe_serialize(self, data: Any, skip_empty: bool) -> Any: + try: + return self._serialize(data, skip_empty) + except TypeError: + # older method signature, without skip_empty + return self._serialize(data) # type: ignore[call-arg] + def _deserialize(self, data: Any) -> Any: return data @@ -133,10 +140,16 @@ def empty(self) -> Optional[Any]: return AttrList([]) return self._empty() - def serialize(self, data: Any) -> Any: + def serialize(self, data: Any, skip_empty: bool = True) -> Any: if isinstance(data, (list, AttrList, tuple)): - return list(map(self._serialize, cast(Iterable[Any], data))) - return self._serialize(data) + return list( + map( + self._safe_serialize, + cast(Iterable[Any], data), + [skip_empty] * len(data), + ) + ) + return self._safe_serialize(data, skip_empty) def deserialize(self, data: Any) -> Any: if isinstance(data, (list, AttrList, tuple)): @@ -186,7 +199,7 @@ def _deserialize(self, data: Any) -> Range["_SupportsComparison"]: data = {k: self._core_field.deserialize(v) for k, v in data.items()} # type: ignore[union-attr] return Range(data) - def _serialize(self, data: Any) -> Optional[Dict[str, Any]]: + def _serialize(self, data: Any, skip_empty: bool) -> Optional[Dict[str, Any]]: if data is None: return None if not isinstance(data, collections.abc.Mapping): @@ -550,7 +563,7 @@ def _deserialize(self, data: Any) -> "InnerDoc": return self._wrap(data) def _serialize( - self, data: Optional[Union[Dict[str, Any], "InnerDoc"]] + self, data: Optional[Union[Dict[str, Any], "InnerDoc"]], skip_empty: bool ) -> Optional[Dict[str, Any]]: if data is None: return None @@ -559,7 +572,7 @@ def _serialize( if isinstance(data, collections.abc.Mapping): return data - return data.to_dict() + return data.to_dict(skip_empty=skip_empty) def clean(self, data: Any) -> Any: data = super().clean(data) @@ -768,7 +781,7 @@ def clean(self, data: str) -> str: def _deserialize(self, data: Any) -> bytes: return base64.b64decode(data) - def _serialize(self, data: Any) -> Optional[str]: + def _serialize(self, data: Any, skip_empty: bool) -> Optional[str]: if data is None: return None return base64.b64encode(data).decode() @@ -2619,7 +2632,7 @@ def _deserialize(self, data: Any) -> Union["IPv4Address", "IPv6Address"]: # the ipaddress library for pypy only accepts unicode. return ipaddress.ip_address(unicode(data)) - def _serialize(self, data: Any) -> Optional[str]: + def _serialize(self, data: Any, skip_empty: bool) -> Optional[str]: if data is None: return None return str(data) @@ -3367,7 +3380,7 @@ def __init__( def _deserialize(self, data: Any) -> "Query": return Q(data) # type: ignore[no-any-return] - def _serialize(self, data: Any) -> Optional[Dict[str, Any]]: + def _serialize(self, data: Any, skip_empty: bool) -> Optional[Dict[str, Any]]: if data is None: return None return data.to_dict() # type: ignore[no-any-return] diff --git a/elasticsearch/dsl/utils.py b/elasticsearch/dsl/utils.py index 127a48cc2..cce3c052c 100644 --- a/elasticsearch/dsl/utils.py +++ b/elasticsearch/dsl/utils.py @@ -603,7 +603,7 @@ def to_dict(self, skip_empty: bool = True) -> Dict[str, Any]: # if this is a mapped field, f = self.__get_field(k) if f and f._coerce: - v = f.serialize(v) + v = f.serialize(v, skip_empty=skip_empty) # if someone assigned AttrList, unwrap it if isinstance(v, AttrList): diff --git a/test_elasticsearch/test_dsl/test_integration/_async/test_document.py b/test_elasticsearch/test_dsl/test_integration/_async/test_document.py index 99f475cf1..3d769c606 100644 --- a/test_elasticsearch/test_dsl/test_integration/_async/test_document.py +++ b/test_elasticsearch/test_dsl/test_integration/_async/test_document.py @@ -630,7 +630,9 @@ async def test_can_save_to_different_index( async def test_save_without_skip_empty_will_include_empty_fields( async_write_client: AsyncElasticsearch, ) -> None: - test_repo = Repository(field_1=[], field_2=None, field_3={}, meta={"id": 42}) + test_repo = Repository( + field_1=[], field_2=None, field_3={}, owner={"name": None}, meta={"id": 42} + ) assert await test_repo.save(index="test-document", skip_empty=False) assert_doc_equals( @@ -638,7 +640,12 @@ async def test_save_without_skip_empty_will_include_empty_fields( "found": True, "_index": "test-document", "_id": "42", - "_source": {"field_1": [], "field_2": None, "field_3": {}}, + "_source": { + "field_1": [], + "field_2": None, + "field_3": {}, + "owner": {"name": None}, + }, }, await async_write_client.get(index="test-document", id=42), ) diff --git a/test_elasticsearch/test_dsl/test_integration/_sync/test_document.py b/test_elasticsearch/test_dsl/test_integration/_sync/test_document.py index 05dd05fd9..a005d45bf 100644 --- a/test_elasticsearch/test_dsl/test_integration/_sync/test_document.py +++ b/test_elasticsearch/test_dsl/test_integration/_sync/test_document.py @@ -624,7 +624,9 @@ def test_can_save_to_different_index( def test_save_without_skip_empty_will_include_empty_fields( write_client: Elasticsearch, ) -> None: - test_repo = Repository(field_1=[], field_2=None, field_3={}, meta={"id": 42}) + test_repo = Repository( + field_1=[], field_2=None, field_3={}, owner={"name": None}, meta={"id": 42} + ) assert test_repo.save(index="test-document", skip_empty=False) assert_doc_equals( @@ -632,7 +634,12 @@ def test_save_without_skip_empty_will_include_empty_fields( "found": True, "_index": "test-document", "_id": "42", - "_source": {"field_1": [], "field_2": None, "field_3": {}}, + "_source": { + "field_1": [], + "field_2": None, + "field_3": {}, + "owner": {"name": None}, + }, }, write_client.get(index="test-document", id=42), ) diff --git a/utils/templates/field.py.tpl b/utils/templates/field.py.tpl index 8a4c73f33..8699d852e 100644 --- a/utils/templates/field.py.tpl +++ b/utils/templates/field.py.tpl @@ -119,9 +119,16 @@ class Field(DslBase): def __getitem__(self, subfield: str) -> "Field": return cast(Field, self._params.get("fields", {})[subfield]) - def _serialize(self, data: Any) -> Any: + def _serialize(self, data: Any, skip_empty: bool) -> Any: return data + def _safe_serialize(self, data: Any, skip_empty: bool) -> Any: + try: + return self._serialize(data, skip_empty) + except TypeError: + # older method signature, without skip_empty + return self._serialize(data) # type: ignore[call-arg] + def _deserialize(self, data: Any) -> Any: return data @@ -133,10 +140,10 @@ class Field(DslBase): return AttrList([]) return self._empty() - def serialize(self, data: Any) -> Any: + def serialize(self, data: Any, skip_empty: bool = True) -> Any: if isinstance(data, (list, AttrList, tuple)): - return list(map(self._serialize, cast(Iterable[Any], data))) - return self._serialize(data) + return list(map(self._safe_serialize, cast(Iterable[Any], data), [skip_empty] * len(data))) + return self._safe_serialize(data, skip_empty) def deserialize(self, data: Any) -> Any: if isinstance(data, (list, AttrList, tuple)): @@ -186,7 +193,7 @@ class RangeField(Field): data = {k: self._core_field.deserialize(v) for k, v in data.items()} # type: ignore[union-attr] return Range(data) - def _serialize(self, data: Any) -> Optional[Dict[str, Any]]: + def _serialize(self, data: Any, skip_empty: bool) -> Optional[Dict[str, Any]]: if data is None: return None if not isinstance(data, collections.abc.Mapping): @@ -318,7 +325,7 @@ class {{ k.name }}({{ k.parent }}): return self._wrap(data) def _serialize( - self, data: Optional[Union[Dict[str, Any], "InnerDoc"]] + self, data: Optional[Union[Dict[str, Any], "InnerDoc"]], skip_empty: bool ) -> Optional[Dict[str, Any]]: if data is None: return None @@ -327,7 +334,7 @@ class {{ k.name }}({{ k.parent }}): if isinstance(data, collections.abc.Mapping): return data - return data.to_dict() + return data.to_dict(skip_empty=skip_empty) def clean(self, data: Any) -> Any: data = super().clean(data) @@ -433,7 +440,7 @@ class {{ k.name }}({{ k.parent }}): # the ipaddress library for pypy only accepts unicode. return ipaddress.ip_address(unicode(data)) - def _serialize(self, data: Any) -> Optional[str]: + def _serialize(self, data: Any, skip_empty: bool) -> Optional[str]: if data is None: return None return str(data) @@ -448,7 +455,7 @@ class {{ k.name }}({{ k.parent }}): def _deserialize(self, data: Any) -> bytes: return base64.b64decode(data) - def _serialize(self, data: Any) -> Optional[str]: + def _serialize(self, data: Any, skip_empty: bool) -> Optional[str]: if data is None: return None return base64.b64encode(data).decode() @@ -458,7 +465,7 @@ class {{ k.name }}({{ k.parent }}): def _deserialize(self, data: Any) -> "Query": return Q(data) # type: ignore[no-any-return] - def _serialize(self, data: Any) -> Optional[Dict[str, Any]]: + def _serialize(self, data: Any, skip_empty: bool) -> Optional[Dict[str, Any]]: if data is None: return None return data.to_dict() # type: ignore[no-any-return]
  • GPT-3.5