From e0f5956f3efa3fbfad34c1cdd626f2e3ac303d9c Mon Sep 17 00:00:00 2001 From: Quentin Pradet Date: Wed, 26 Nov 2025 14:03:20 +0400 Subject: [PATCH] Add back private knn_search API for rest-api-spec generation (#5737) * Revert "Remove knn_search API (#4276)" This reverts commit 2a24e33865256e85eaa8e2de9e793646f147c4df since _knn_search is still needed in rest-api-spec to run YAML tests against it, as the API is still available with v8 compatibility mode. However, we make the API private so that it does not get back into clients, as it would fail with v9 compatibility. * Add UpdateForV10 annotation * Fix lint (cherry picked from commit 709ff2494b0fe79f86afc9301529624084ab6297) --- compiler/src/model/utils.ts | 4 +- output/schema/schema.json | 342 +++++++++++++++++- output/typescript/types.ts | 29 ++ .../_global/knn_search/KnnSearchRequest.ts | 99 +++++ .../_global/knn_search/KnnSearchResponse.ts | 54 +++ .../_global/knn_search/_types/Knn.ts | 33 ++ 6 files changed, 555 insertions(+), 6 deletions(-) create mode 100644 specification/_global/knn_search/KnnSearchRequest.ts create mode 100644 specification/_global/knn_search/KnnSearchResponse.ts create mode 100644 specification/_global/knn_search/_types/Knn.ts diff --git a/compiler/src/model/utils.ts b/compiler/src/model/utils.ts index ea61184934..6e8ff5a809 100644 --- a/compiler/src/model/utils.ts +++ b/compiler/src/model/utils.ts @@ -1074,7 +1074,9 @@ export function parseJsDocTags (jsDoc: JSDoc[]): Record { value: tag.getComment() ?? '' } }) - const mapped = tags.reduce((acc, curr) => ({ ...acc, [curr.name]: curr.value }), {}) + // Ignore UpdateForV10 which is only useful at the eslint level + const filteredTags = tags.filter(tag => tag.name !== 'UpdateForV10') + const mapped = filteredTags.reduce((acc, curr) => ({ ...acc, [curr.name]: curr.value }), {}) return mapped } diff --git a/output/schema/schema.json b/output/schema/schema.json index 2c532fbadc..1a4a517a54 100644 --- a/output/schema/schema.json +++ b/output/schema/schema.json @@ -11827,19 +11827,32 @@ { "availability": { "stack": { + "since": "8.0.0", "stability": "experimental", - "visibility": "public" + "visibility": "private" } }, - "description": "Performs a kNN search", - "docUrl": null, + "deprecation": { + "description": "The kNN search API has been replaced by the `knn` option in the search API.", + "version": "8.4.0" + }, + "description": "Run a knn search.\n\nNOTE: The kNN search API has been replaced by the `knn` option in the search API.", + "docId": "search-knn", + "docTag": "search", + "docUrl": "https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-knn-search", "name": "knn_search", - "request": null, + "request": { + "name": "Request", + "namespace": "_global.knn_search" + }, "requestBodyRequired": true, "requestMediaType": [ "application/json" ], - "response": null, + "response": { + "name": "Response", + "namespace": "_global.knn_search" + }, "responseMediaType": [ "application/json" ], @@ -32680,6 +32693,325 @@ }, "specLocation": "_global/info/RootNodeInfoResponse.ts#L23-L40" }, + { + "kind": "request", + "attachedBehaviors": [ + "CommonQueryParameters" + ], + "body": { + "kind": "properties", + "properties": [ + { + "description": "Indicates which source fields are returned for matching documents. These\nfields are returned in the `hits._source` property of the search response.", + "name": "_source", + "required": false, + "serverDefault": "true", + "type": { + "kind": "instance_of", + "type": { + "name": "SourceConfig", + "namespace": "_global.search._types" + } + } + }, + { + "description": "The request returns doc values for field names matching these patterns\nin the `hits.fields` property of the response.\nIt accepts wildcard (`*`) patterns.", + "name": "docvalue_fields", + "required": false, + "type": { + "kind": "array_of", + "value": { + "kind": "instance_of", + "type": { + "name": "FieldAndFormat", + "namespace": "_types.query_dsl" + } + } + } + }, + { + "description": "A list of stored fields to return as part of a hit. If no fields are specified,\nno stored fields are included in the response. If this field is specified, the `_source`\nparameter defaults to `false`. You can pass `_source: true` to return both source fields\nand stored fields in the search response.", + "name": "stored_fields", + "required": false, + "type": { + "kind": "instance_of", + "type": { + "name": "Fields", + "namespace": "_types" + } + } + }, + { + "description": "The request returns values for field names matching these patterns\nin the `hits.fields` property of the response.\nIt accepts wildcard (`*`) patterns.", + "name": "fields", + "required": false, + "type": { + "kind": "instance_of", + "type": { + "name": "Fields", + "namespace": "_types" + } + } + }, + { + "availability": { + "serverless": {}, + "stack": { + "since": "8.2.0" + } + }, + "description": "A query to filter the documents that can match. The kNN search will return the top\n`k` documents that also match this filter. The value can be a single query or a\nlist of queries. If `filter` isn't provided, all documents are allowed to match.", + "name": "filter", + "required": false, + "type": { + "kind": "union_of", + "items": [ + { + "kind": "instance_of", + "type": { + "name": "QueryContainer", + "namespace": "_types.query_dsl" + } + }, + { + "kind": "array_of", + "value": { + "kind": "instance_of", + "type": { + "name": "QueryContainer", + "namespace": "_types.query_dsl" + } + } + } + ] + } + }, + { + "description": "The kNN query to run.", + "extDocId": "query-dsl-knn-query", + "extDocUrl": "https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-knn-query", + "name": "knn", + "required": true, + "type": { + "kind": "instance_of", + "type": { + "name": "KnnSearchQuery", + "namespace": "_global.knn_search._types" + } + } + } + ] + }, + "deprecation": { + "description": "The kNN search API has been replaced by the `knn` option in the search API.", + "version": "8.4.0" + }, + "description": "Run a knn search.\n\nNOTE: The kNN search API has been replaced by the `knn` option in the search API.", + "inherits": { + "type": { + "name": "RequestBase", + "namespace": "_types" + } + }, + "name": { + "name": "Request", + "namespace": "_global.knn_search" + }, + "path": [ + { + "description": "A comma-separated list of index names to search;\nuse `_all` or to perform the operation on all indices.", + "name": "index", + "required": true, + "type": { + "kind": "instance_of", + "type": { + "name": "Indices", + "namespace": "_types" + } + } + } + ], + "query": [ + { + "description": "A comma-separated list of specific routing values.", + "name": "routing", + "required": false, + "type": { + "kind": "instance_of", + "type": { + "name": "Routing", + "namespace": "_types" + } + } + } + ], + "specLocation": "_global/knn_search/KnnSearchRequest.ts#L26-L99" + }, + { + "kind": "response", + "body": { + "kind": "properties", + "properties": [ + { + "description": "The milliseconds it took Elasticsearch to run the request.", + "name": "took", + "required": true, + "type": { + "kind": "instance_of", + "type": { + "name": "long", + "namespace": "_types" + } + } + }, + { + "description": "If true, the request timed out before completion;\nreturned results may be partial or empty.", + "name": "timed_out", + "required": true, + "type": { + "kind": "instance_of", + "type": { + "name": "boolean", + "namespace": "_builtins" + } + } + }, + { + "description": "A count of shards used for the request.", + "name": "_shards", + "required": true, + "type": { + "kind": "instance_of", + "type": { + "name": "ShardStatistics", + "namespace": "_types" + } + } + }, + { + "description": "The returned documents and metadata.", + "name": "hits", + "required": true, + "type": { + "kind": "instance_of", + "generics": [ + { + "kind": "instance_of", + "type": { + "name": "TDocument", + "namespace": "_global.knn_search.Response" + } + } + ], + "type": { + "name": "HitsMetadata", + "namespace": "_global.search._types" + } + } + }, + { + "description": "The field values for the documents. These fields\nmust be specified in the request using the `fields` parameter.", + "name": "fields", + "required": false, + "type": { + "kind": "dictionary_of", + "key": { + "kind": "instance_of", + "type": { + "name": "string", + "namespace": "_builtins" + } + }, + "singleKey": false, + "value": { + "kind": "user_defined_value" + } + } + }, + { + "description": "The highest returned document score. This value is null for requests\nthat do not sort by score.", + "name": "max_score", + "required": false, + "type": { + "kind": "instance_of", + "type": { + "name": "double", + "namespace": "_types" + } + } + } + ] + }, + "generics": [ + { + "name": "TDocument", + "namespace": "_global.knn_search.Response" + } + ], + "name": { + "name": "Response", + "namespace": "_global.knn_search" + }, + "specLocation": "_global/knn_search/KnnSearchResponse.ts#L26-L54" + }, + { + "kind": "interface", + "name": { + "name": "KnnSearchQuery", + "namespace": "_global.knn_search._types" + }, + "properties": [ + { + "description": "The name of the vector field to search against", + "name": "field", + "required": true, + "type": { + "kind": "instance_of", + "type": { + "name": "Field", + "namespace": "_types" + } + } + }, + { + "description": "The query vector", + "name": "query_vector", + "required": true, + "type": { + "kind": "instance_of", + "type": { + "name": "QueryVector", + "namespace": "_types" + } + } + }, + { + "description": "The final number of nearest neighbors to return as top hits", + "name": "k", + "required": true, + "type": { + "kind": "instance_of", + "type": { + "name": "integer", + "namespace": "_types" + } + } + }, + { + "description": "The number of nearest neighbor candidates to consider per shard", + "name": "num_candidates", + "required": true, + "type": { + "kind": "instance_of", + "type": { + "name": "integer", + "namespace": "_types" + } + } + } + ], + "specLocation": "_global/knn_search/_types/Knn.ts#L24-L33" + }, { "kind": "interface", "name": { diff --git a/output/typescript/types.ts b/output/typescript/types.ts index 2a2ac99326..ee8eb2ec56 100644 --- a/output/typescript/types.ts +++ b/output/typescript/types.ts @@ -690,6 +690,35 @@ export interface InfoResponse { version: ElasticsearchVersionInfo } +export interface KnnSearchRequest extends RequestBase { + index: Indices + routing?: Routing + body?: { + _source?: SearchSourceConfig + docvalue_fields?: (QueryDslFieldAndFormat | Field)[] + stored_fields?: Fields + fields?: Fields + filter?: QueryDslQueryContainer | QueryDslQueryContainer[] + knn: KnnSearchKnnSearchQuery + } +} + +export interface KnnSearchResponse { + took: long + timed_out: boolean + _shards: ShardStatistics + hits: SearchHitsMetadata + fields?: Record + max_score?: double +} + +export interface KnnSearchKnnSearchQuery { + field: Field + query_vector: QueryVector + k: integer + num_candidates: integer +} + export interface MgetMultiGetError { error: ErrorCause _id: Id diff --git a/specification/_global/knn_search/KnnSearchRequest.ts b/specification/_global/knn_search/KnnSearchRequest.ts new file mode 100644 index 0000000000..1ac4647f21 --- /dev/null +++ b/specification/_global/knn_search/KnnSearchRequest.ts @@ -0,0 +1,99 @@ +/* + * 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 { RequestBase } from '@_types/Base' +import { Fields, Indices, Routing } from '@_types/common' +import { FieldAndFormat, QueryContainer } from '@_types/query_dsl/abstractions' +import { SourceConfig } from '@global/search/_types/SourceFilter' +import { KnnSearchQuery } from './_types/Knn' + +/** + * Run a knn search. + * + * NOTE: The kNN search API has been replaced by the `knn` option in the search API. + * + * @UpdateForV10 Remove this API when it's no longer needed for compatibility mode with Elasticsearch 8 in rest-api-spec. + * + * @rest_spec_name knn_search + * @availability stack since=8.0.0 stability=experimental visibility=private + * @deprecated 8.4.0 The kNN search API has been replaced by the `knn` option in the search API. + * @doc_tag search + * @doc_id search-knn + */ +export interface Request extends RequestBase { + urls: [ + { + path: '/{index}/_knn_search' + methods: ['GET', 'POST'] + } + ] + path_parts: { + /** + * A comma-separated list of index names to search; + * use `_all` or to perform the operation on all indices. + */ + index: Indices + } + query_parameters: { + /** + * A comma-separated list of specific routing values. + */ + routing?: Routing + } + body: { + /** + * Indicates which source fields are returned for matching documents. These + * fields are returned in the `hits._source` property of the search response. + * @server_default true + */ + _source?: SourceConfig + /** + * The request returns doc values for field names matching these patterns + * in the `hits.fields` property of the response. + * It accepts wildcard (`*`) patterns. + */ + docvalue_fields?: FieldAndFormat[] + /** + * 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. + */ + stored_fields?: Fields + /** + * The request returns values for field names matching these patterns + * in the `hits.fields` property of the response. + * It accepts wildcard (`*`) patterns. + */ + fields?: Fields + /** + * 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. + * @availability stack since=8.2.0 + * @availability serverless + */ + filter?: QueryContainer | QueryContainer[] + /** + * The kNN query to run. + * @ext_doc_id query-dsl-knn-query + */ + knn: KnnSearchQuery + } +} diff --git a/specification/_global/knn_search/KnnSearchResponse.ts b/specification/_global/knn_search/KnnSearchResponse.ts new file mode 100644 index 0000000000..cbc2e0b360 --- /dev/null +++ b/specification/_global/knn_search/KnnSearchResponse.ts @@ -0,0 +1,54 @@ +/* + * 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 { double, long } from '@_types/Numeric' +import { ShardStatistics } from '@_types/Stats' +import { HitsMetadata } from '@global/search/_types/hits' +import { Dictionary } from '@spec_utils/Dictionary' +import { UserDefinedValue } from '@spec_utils/UserDefinedValue' + +export class Response { + body: { + /** The milliseconds it took Elasticsearch to run the request. */ + took: long + /** + * If true, the request timed out before completion; + * returned results may be partial or empty. + */ + timed_out: boolean + /** + * A count of shards used for the request. + */ + _shards: ShardStatistics + /** + * The returned documents and metadata. + */ + hits: HitsMetadata + /** + * The field values for the documents. These fields + * must be specified in the request using the `fields` parameter. + */ + fields?: Dictionary + /** + * The highest returned document score. This value is null for requests + * that do not sort by score. + */ + max_score?: double + } +} diff --git a/specification/_global/knn_search/_types/Knn.ts b/specification/_global/knn_search/_types/Knn.ts new file mode 100644 index 0000000000..755b4bb57d --- /dev/null +++ b/specification/_global/knn_search/_types/Knn.ts @@ -0,0 +1,33 @@ +/* + * 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 { Field } from '@_types/common' +import { QueryVector } from '@_types/Knn' +import { integer } from '@_types/Numeric' + +export interface KnnSearchQuery { + /** The name of the vector field to search against */ + field: Field + /** The query vector */ + query_vector: QueryVector + /** The final number of nearest neighbors to return as top hits */ + k: integer + /** The number of nearest neighbor candidates to consider per shard */ + num_candidates: integer +}