diff --git a/CHANGELOG.md b/CHANGELOG.md index 06b9b151b..97f0dbfdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +## Release 8.11.0 + +- Added 5 new EXPERIMENTAL APIs: + - `Esql.query ` + - API: https://github.com/elastic/elasticsearch/blob/v8.11.0/rest-api-spec/src/main/resources/rest-api-spec/api/esql.query.json + - Documentation: https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-query-api.html + - `Inference.deleteModel` + - API: https://github.com/elastic/elasticsearch/blob/v8.11.0/rest-api-spec/src/main/resources/rest-api-spec/api/inference.delete_model.json + - Documentation: https://www.elastic.co/guide/en/elasticsearch/reference/master/delete-inference-api.html + - `Inference.getModel` + - API: https://github.com/elastic/elasticsearch/blob/v8.11.0/rest-api-spec/src/main/resources/rest-api-spec/api/inference.get_model.json + - Documentation: https://www.elastic.co/guide/en/elasticsearch/reference/master/get-inference-api.html + - `Inference.inference` + - API: https://github.com/elastic/elasticsearch/blob/v8.11.0/rest-api-spec/src/main/resources/rest-api-spec/api/inference.inference.json + - Documentation: https://www.elastic.co/guide/en/elasticsearch/reference/master/post-inference-api.html + - `Inference.putModel` + - API: https://github.com/elastic/elasticsearch/blob/v8.11.0/rest-api-spec/src/main/resources/rest-api-spec/api/inference.put_model.json + - Documentation: https://www.elastic.co/guide/en/elasticsearch/reference/master/put-inference-api.html + ## Release 8.10.0 - Added 10 new APIs: 8 EXPERIMENTAL and 2 stable: diff --git a/src/Client.php b/src/Client.php index e4fa85116..c4acf3cff 100644 --- a/src/Client.php +++ b/src/Client.php @@ -28,7 +28,7 @@ final class Client implements ClientInterface { const CLIENT_NAME = 'es'; - const VERSION = '8.10.0'; + const VERSION = '8.11.0'; const API_COMPATIBILITY_HEADER = '%s/vnd.elasticsearch+%s; compatible-with=8'; use ClientEndpointsTrait; diff --git a/src/Endpoints/Esql.php b/src/Endpoints/Esql.php new file mode 100644 index 000000000..c19392459 --- /dev/null +++ b/src/Endpoints/Esql.php @@ -0,0 +1,67 @@ +checkRequiredParameters(['body'], $params); + $url = '/_query'; + $method = 'POST'; + + $url = $this->addQueryString($url, $params, ['format','delimiter','pretty','human','error_trace','source','filter_path']); + $headers = [ + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + ]; + return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); + } +} diff --git a/src/Endpoints/Indices.php b/src/Endpoints/Indices.php index c44b663d1..a1c2fab40 100644 --- a/src/Endpoints/Indices.php +++ b/src/Endpoints/Indices.php @@ -502,7 +502,7 @@ public function deleteDataStream(array $params = []) /** * Deletes an index template. * - * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-delete-template.html * * @param array{ * name: string, // (REQUIRED) The name of the template @@ -539,7 +539,7 @@ public function deleteIndexTemplate(array $params = []) /** * Deletes an index template. * - * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-delete-template-v1.html * * @param array{ * name: string, // (REQUIRED) The name of the template @@ -741,7 +741,7 @@ public function existsAlias(array $params = []) /** * Returns information about whether a particular index template exists. * - * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/index-templates.html * * @param array{ * name: string, // (REQUIRED) The name of the template @@ -779,7 +779,7 @@ public function existsIndexTemplate(array $params = []) /** * Returns information about whether a particular index template exists. * - * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-template-exists-v1.html * * @param array{ * name: list, // (REQUIRED) The comma separated names of the index templates @@ -1194,7 +1194,7 @@ public function getFieldMapping(array $params = []) /** * Returns an index template. * - * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-get-template.html * * @param array{ * name: string, // A pattern that returned template names must match @@ -1328,7 +1328,7 @@ public function getSettings(array $params = []) /** * Returns an index template. * - * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-get-template-v1.html * * @param array{ * name: list, // The comma separated names of the index templates @@ -1594,7 +1594,7 @@ public function putDataLifecycle(array $params = []) /** * Creates or updates an index template. * - * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-put-template.html * * @param array{ * name: string, // (REQUIRED) The name of the template @@ -1724,7 +1724,7 @@ public function putSettings(array $params = []) /** * Creates or updates an index template. * - * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates-v1.html * * @param array{ * name: string, // (REQUIRED) The name of the template @@ -2088,7 +2088,7 @@ public function shrink(array $params = []) /** * Simulate matching the given index name against the index templates in the system * - * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-simulate-index.html * * @param array{ * name: string, // (REQUIRED) The name of the index (it must be a concrete index name) @@ -2129,7 +2129,7 @@ public function simulateIndexTemplate(array $params = []) /** * Simulate resolving the given template name or body * - * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-simulate-template.html * * @param array{ * name: string, // The name of the index template diff --git a/src/Endpoints/Inference.php b/src/Endpoints/Inference.php new file mode 100644 index 000000000..835d59c49 --- /dev/null +++ b/src/Endpoints/Inference.php @@ -0,0 +1,181 @@ +checkRequiredParameters(['task_type','model_id'], $params); + $url = '/_inference/' . $this->encode($params['task_type']) . '/' . $this->encode($params['model_id']); + $method = 'DELETE'; + + $url = $this->addQueryString($url, $params, ['pretty','human','error_trace','source','filter_path']); + $headers = [ + 'Accept' => 'application/json', + ]; + return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); + } + + + /** + * Get a model in the Inference API + * + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/get-inference-api.html + * @internal This API is EXPERIMENTAL and may be changed or removed completely in a future release + * + * @param array{ + * task_type: string, // (REQUIRED) The model task type + * model_id: string, // (REQUIRED) The model Id + * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) + * human: boolean, // Return human readable values for statistics. (DEFAULT: true) + * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) + * source: string, // The URL-encoded request definition. Useful for libraries that do not accept a request body for non-POST requests. + * filter_path: list, // A comma-separated list of filters used to reduce the response. + * } $params + * + * @throws MissingParameterException if a required parameter is missing + * @throws NoNodeAvailableException if all the hosts are offline + * @throws ClientResponseException if the status code of response is 4xx + * @throws ServerResponseException if the status code of response is 5xx + * + * @return Elasticsearch|Promise + */ + public function getModel(array $params = []) + { + $this->checkRequiredParameters(['task_type','model_id'], $params); + $url = '/_inference/' . $this->encode($params['task_type']) . '/' . $this->encode($params['model_id']); + $method = 'GET'; + + $url = $this->addQueryString($url, $params, ['pretty','human','error_trace','source','filter_path']); + $headers = [ + 'Accept' => 'application/json', + ]; + return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); + } + + + /** + * Perform inference on a model + * + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/post-inference-api.html + * @internal This API is EXPERIMENTAL and may be changed or removed completely in a future release + * + * @param array{ + * task_type: string, // (REQUIRED) The model task type + * model_id: string, // (REQUIRED) The model Id + * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) + * human: boolean, // Return human readable values for statistics. (DEFAULT: true) + * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) + * source: string, // The URL-encoded request definition. Useful for libraries that do not accept a request body for non-POST requests. + * filter_path: list, // A comma-separated list of filters used to reduce the response. + * body: array, // The inference payload + * } $params + * + * @throws MissingParameterException if a required parameter is missing + * @throws NoNodeAvailableException if all the hosts are offline + * @throws ClientResponseException if the status code of response is 4xx + * @throws ServerResponseException if the status code of response is 5xx + * + * @return Elasticsearch|Promise + */ + public function inference(array $params = []) + { + $this->checkRequiredParameters(['task_type','model_id'], $params); + $url = '/_inference/' . $this->encode($params['task_type']) . '/' . $this->encode($params['model_id']); + $method = 'POST'; + + $url = $this->addQueryString($url, $params, ['pretty','human','error_trace','source','filter_path']); + $headers = [ + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + ]; + return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); + } + + + /** + * Configure a model for use in the Inference API + * + * @see https://www.elastic.co/guide/en/elasticsearch/reference/master/put-inference-api.html + * @internal This API is EXPERIMENTAL and may be changed or removed completely in a future release + * + * @param array{ + * task_type: string, // (REQUIRED) The model task type + * model_id: string, // (REQUIRED) The model Id + * pretty: boolean, // Pretty format the returned JSON response. (DEFAULT: false) + * human: boolean, // Return human readable values for statistics. (DEFAULT: true) + * error_trace: boolean, // Include the stack trace of returned errors. (DEFAULT: false) + * source: string, // The URL-encoded request definition. Useful for libraries that do not accept a request body for non-POST requests. + * filter_path: list, // A comma-separated list of filters used to reduce the response. + * body: array, // The model's task and service settings + * } $params + * + * @throws MissingParameterException if a required parameter is missing + * @throws NoNodeAvailableException if all the hosts are offline + * @throws ClientResponseException if the status code of response is 4xx + * @throws ServerResponseException if the status code of response is 5xx + * + * @return Elasticsearch|Promise + */ + public function putModel(array $params = []) + { + $this->checkRequiredParameters(['task_type','model_id'], $params); + $url = '/_inference/' . $this->encode($params['task_type']) . '/' . $this->encode($params['model_id']); + $method = 'PUT'; + + $url = $this->addQueryString($url, $params, ['pretty','human','error_trace','source','filter_path']); + $headers = [ + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + ]; + return $this->client->sendRequest($this->createRequest($method, $url, $headers, $params['body'] ?? null)); + } +} diff --git a/src/Traits/NamespaceTrait.php b/src/Traits/NamespaceTrait.php index dee8b3c51..857f7ace8 100644 --- a/src/Traits/NamespaceTrait.php +++ b/src/Traits/NamespaceTrait.php @@ -24,11 +24,13 @@ use Elastic\Elasticsearch\Endpoints\DanglingIndices; use Elastic\Elasticsearch\Endpoints\Enrich; use Elastic\Elasticsearch\Endpoints\Eql; +use Elastic\Elasticsearch\Endpoints\Esql; use Elastic\Elasticsearch\Endpoints\Features; use Elastic\Elasticsearch\Endpoints\Fleet; use Elastic\Elasticsearch\Endpoints\Graph; use Elastic\Elasticsearch\Endpoints\Ilm; use Elastic\Elasticsearch\Endpoints\Indices; +use Elastic\Elasticsearch\Endpoints\Inference; use Elastic\Elasticsearch\Endpoints\Ingest; use Elastic\Elasticsearch\Endpoints\License; use Elastic\Elasticsearch\Endpoints\Logstash; @@ -134,6 +136,15 @@ public function eql(): Eql } + public function esql(): Esql + { + if (!isset($this->namespace['Esql'])) { + $this->namespace['Esql'] = new Esql($this); + } + return $this->namespace['Esql']; + } + + public function features(): Features { if (!isset($this->namespace['Features'])) { @@ -179,6 +190,15 @@ public function indices(): Indices } + public function inference(): Inference + { + if (!isset($this->namespace['Inference'])) { + $this->namespace['Inference'] = new Inference($this); + } + return $this->namespace['Inference']; + } + + public function ingest(): Ingest { if (!isset($this->namespace['Ingest'])) { diff --git a/tests/Utility.php b/tests/Utility.php index f8c46134e..45ea0a562 100644 --- a/tests/Utility.php +++ b/tests/Utility.php @@ -514,7 +514,7 @@ private static function wipeAllIndices(Client $client): void } try { $client->indices()->delete([ - 'index' => '*,-.ds-ilm-history-*', + 'index' => '*,-.ds-ilm-history-*,-.ds-.slm-history-*', 'expand_wildcards' => $expand ]); } catch (ClientResponseException $e) { @@ -648,6 +648,9 @@ private static function wipeClusterSettings(Client $client): void */ private static function isXPackTemplate(string $name): bool { + if (strpos($name, '@') !== false) { + return true; + } if (strpos($name, '.monitoring-') !== false) { return true; } @@ -678,6 +681,10 @@ private static function isXPackTemplate(string $name): bool if (strpos($name, 'elastic-connectors') !== false) { return true; } + if (strpos($name, 'apm-') === 0 || strpos($name, 'traces-apm') === 0 || + strpos($name, 'metrics-apm') === 0 || strpos($name, 'logs-apm') === 0) { + return true; + } switch ($name) { case ".watches": case "security_audit_log": @@ -699,7 +706,6 @@ private static function isXPackTemplate(string $name): bool case "logstash-index-template": case "security-index-template": case "data-streams-mappings": - case "ecs@dynamic_templates": case "search-acl-filter": case ".kibana-reporting": return true; @@ -721,14 +727,24 @@ private static function preserveILMPolicyIds(): array "watch-history-ilm-policy", "watch-history-ilm-policy-16", "ml-size-based-ilm-policy", - "logs", + "logs", + "logs@lifecycle", "metrics", + "metrics@lifecycle", + "profiling", + "profiling@lifecycle", "synthetics", + "synthetics@lifecycle", "7-days-default", + "7-days@lifecycle", "30-days-default", + "30-days@lifecycle", "90-days-default", + "90-days@lifecycle", "180-days-default", + "180-days@lifecycle", "365-days-default", + "365-days@lifecycle", ".fleet-files-ilm-policy", ".fleet-file-data-ilm-policy", ".fleet-actions-results-ilm-policy", diff --git a/util/YamlTests.php b/util/YamlTests.php index c78008ad2..b87d8d8bc 100644 --- a/util/YamlTests.php +++ b/util/YamlTests.php @@ -56,6 +56,7 @@ class YamlTests 'Indices\PutTemplate\_10_BasicTest::PutTemplateCreate' => 'index_template [test] already exists', 'Indices\Refresh\_10_BasicTest::IndicesRefreshTestEmptyArray' => 'empty array?', 'Indices\SimulateIndexTemplate\_10_BasicTest::SimulateIndexTemplateWithIndexNotMatchingAnyTemplate' => 'Bool mismatch', + 'Search\Vectors\_90_Sparse_VectorTest::SparseVectorIn800X8110' => 'Undefined array key error', 'Snapshot\Create\_10_BasicTest::CreateASnapshot' => 'Invalid snapshot name [test_snapshot]', 'Snapshot\Create\_10_BasicTest::CreateASnapshotAndCleanUpRepository' => 'Invalid snapshot name [test_snapshot]', 'Tsdb\_20_MappingTest::UnsupportedMetricTypePosition' => 'Fixed in Elasticsearch 8.9', @@ -79,6 +80,7 @@ class YamlTests 'Ml\_Explain_Data_Frame_AnalyticsTest::TestNonemptyDataFrameGivenBody' => 'Expected a different value', 'Ml\_Get_Trained_Model_StatsTest::*' => 'Skipped all tests', 'Ml\_Get_Trained_Model_StatsTest::TestGetStatsGivenTrainedModels' => 'cannot assign model_alias', + 'Ml\_Inference_RescoreTest::*' => 'unknown field [learn_to_rank]', 'Rollup\_Put_JobTest::TestPutJobWithTemplates' => 'version not converted from variable', 'RuntimeFields\_100_Geo_PointTest::GetMapping' => 'Substring mismatch', 'RuntimeFields\_10_KeywordTest::GetMapping' => 'Substring mismatch',