From 853f4865ed3a3b9981853cbd06ec7caf881d3c2d Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Thu, 20 Aug 2026 13:11:22 +0200 Subject: [PATCH 1/2] docs: state Boost as added in v1.38 The note said v1.39. Boost shipped in v1.38.0 and its API surface is unchanged between stable/v1.38 and stable/v1.39. --- _includes/feature-notes/boost.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_includes/feature-notes/boost.mdx b/_includes/feature-notes/boost.mdx index b522d781e..fdab4a11f 100644 --- a/_includes/feature-notes/boost.mdx +++ b/_includes/feature-notes/boost.mdx @@ -1,2 +1,2 @@ -:::info Added in `v1.39` +:::info Added in `v1.38` ::: From 7b83e2281715d55b86494534eef1f8e8204a7729 Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Thu, 20 Aug 2026 13:11:22 +0200 Subject: [PATCH 2/2] docs(specs): refresh the OpenAPI spec and rewrite the refresh instructions Refreshes the committed spec from v1-39/openapi-for-docs: 77 to 81 paths, adding /aggregate/{collection} and the bm25, hybrid and near-object search endpoints. info.version is 1.39.0 either way. The README now leads with the weekly refresh workflow added in #518 and keeps the manual recipe as a fallback. The old recipe's ${BRANCH} placeholder was a trap: pasting a branch name into the braces yields a valid parameter expansion, not a substitution, so the shell silently requests the wrong ref. Because > truncates before gh runs and gh api writes its error body to stdout, that replaced the committed spec with a 404 object. The recipe now assigns the branch on its own line and fetches to a temp file before installing. --- static/specs/README.md | 79 +++- static/specs/weaviate-openapi.json | 606 ++++++++++++++++++++++++++++- 2 files changed, 672 insertions(+), 13 deletions(-) diff --git a/static/specs/README.md b/static/specs/README.md index 4845464ea..5372c0592 100644 --- a/static/specs/README.md +++ b/static/specs/README.md @@ -19,17 +19,84 @@ its models, so it defines the API rather than describing it after the fact. ### Refreshing it -**Do not edit this file by hand** — an edited copy would describe an API that +**Do not edit this file by hand.** An edited copy would describe an API that Weaviate does not implement. Replace it whole, from the newest -`v*/openapi-for-docs` branch: +`v*/openapi-for-docs` branch. + +**A weekly job owns this.** +[`.github/workflows/openapi_spec_refresh.yml`](../../.github/workflows/openapi_spec_refresh.yml) +resolves the newest `v*/openapi-for-docs` branch, downloads the spec, checks that +it really is a Swagger document with paths, and compares it byte for byte against +the committed copy. When they differ it opens or updates a PR on branch +`chore/refresh-openapi-spec`, carrying the `info.version` and path-count delta in +the body so review is a glance rather than a diff of 11,000 lines. It runs +Sundays at 21:00 UTC and never commits to `main`, so a human still reviews before +the published API contract changes, and this copy lags upstream by at most a week +plus review time. + +It sorts candidate branches numerically on major and minor version, so it will +not pin itself to an old release the way a lexical sort would, where `v1-9` sorts +as greater than `v1-10`. + +To refresh without waiting for Sunday, run it from the repository's Actions tab, +or dispatch it from the command line: ```bash -# BRANCH is the whole branch name, slash included: v1-39/openapi-for-docs -gh api "repos/weaviate/weaviate/contents/openapi-specs/schema.json?ref=${BRANCH}" \ - -H "Accept: application/vnd.github.raw" > static/specs/weaviate-openapi.json +gh workflow run openapi_spec_refresh.yml ``` -Refreshing is manual, so this copy can lag the newest Weaviate release. +**If the job appears to do nothing**, its header comment records the two usual +causes. The repository or organization needs "Allow GitHub Actions to create and +approve pull requests" enabled, or the final step fails with a 403 from +`gh pr create`. And a push made with `GITHUB_TOKEN` does not start other +workflows, so the PR it opens arrives without the usual build and link checks. +Close and reopen that PR to run them before merging. + +**Refreshing by hand.** Use this for a one-off or an urgent refresh, or when you +are debugging the job itself. It is the same sequence the workflow follows. + +First find the newest branch. The refspec pattern keeps the versioned branches +and drops the unversioned `openapi-for-docs`, and `sort -V` orders them +numerically, putting the newest last: + +```bash +git ls-remote --heads https://github.com/weaviate/weaviate.git "refs/heads/v*/openapi-for-docs" \ + | awk '{print $2}' | sed 's|refs/heads/||' | sort -V +``` + +Then fetch, validate, and only then install: + +```bash +BRANCH=v1-39/openapi-for-docs + +gh api "repos/weaviate/weaviate/contents/openapi-specs/schema.json?ref=$BRANCH" \ + -H "Accept: application/vnd.github.raw" > /tmp/weaviate-openapi.json + +python3 -c " +import json +spec = json.load(open('/tmp/weaviate-openapi.json')) +print('version:', spec['info']['version'], '| paths:', len(spec['paths'])) +" + +mv /tmp/weaviate-openapi.json static/specs/weaviate-openapi.json +``` + +Edit only the branch name after the `=`. Both the assignment and the `$BRANCH` +reference are correct as written. Do not paste a branch name into a `${...}` +placeholder instead: `${v1-39/openapi-for-docs}` is not a placeholder but a valid +parameter expansion, meaning "the value of `$v1`, or `39/openapi-for-docs` if +`$v1` is unset", so the shell silently asks GitHub for the wrong ref. + +**Why the temp file matters.** `>` truncates the target before `gh` runs, and +`gh api` writes its error body to stdout, so redirecting straight onto +`static/specs/weaviate-openapi.json` overwrites a good spec with a 141-byte +GitHub 404 object. `gh` does exit non-zero, but the file is already gone by then. +Fetching to a temp file keeps the committed copy intact until you have seen what +arrived. + +Check the printed version against the branch you asked for, and the path count +against the copy you are replacing. `git diff --stat` should then show a +spec-to-spec diff of a few hundred lines, not a whole-file deletion. ### Why it is served the way it is diff --git a/static/specs/weaviate-openapi.json b/static/specs/weaviate-openapi.json index 4805f2fd2..e5b323675 100644 --- a/static/specs/weaviate-openapi.json +++ b/static/specs/weaviate-openapi.json @@ -730,7 +730,8 @@ "type": "string" }, "status": { - "type": "string" + "type": "string", + "description": "What the server did. `STARTED`: a reindex task was submitted and `taskId` names it. `CANCELLED`: a cancel stopped the in-flight task named by `taskId`. `NO_OP`: a cancel found nothing in flight, and `taskId` is absent. Not a closed set: a newer server may answer with a value this client does not know, so report an unrecognized status rather than rejecting the response." } } }, @@ -1145,12 +1146,14 @@ "k1": { "description": "Calibrates term-weight scaling based on the term frequency within a document (default: 1.2).", "format": "float", - "type": "number" + "type": "number", + "x-omitempty": false }, "b": { "description": "Calibrates term-weight scaling based on the document length (default: 0.75).", "format": "float", - "type": "number" + "type": "number", + "x-omitempty": false } }, "type": "object" @@ -2247,6 +2250,13 @@ "type": "string" } }, + "includeRoles": { + "description": "List of RBAC roles to include in the backup. Permits `*` and `?` wildcards, e.g. `*` or `prefix*`. When omitted, the whole RBAC state is captured as part of the cluster snapshot; when set, the RBAC blob is filtered to the matching roles. Built-in roles are rejected and are never selected by wildcards (they are re-applied automatically on restore). No per-role permission check is applied.", + "type": "array", + "items": { + "type": "string" + } + }, "incremental_base_backup_id": { "description": "The ID of an existing backup to use as the base for a file-based incremental backup. If set, only files that have changed since the base backup will be included in the new backup.", "type": "string", @@ -3781,8 +3791,144 @@ "$ref": "#/definitions/Namespace" } }, + "AggregateRequest": { + "description": "Request body for the aggregate endpoint. Phase 1 supports counts: the number of matching objects, in total or per group. Unknown fields are ignored (platform parity with the other endpoints). Reserved fields are accepted by the schema but rejected by the server with 422 until the corresponding feature ships. An empty body `{}` returns the collection's total object count.", + "type": "object", + "properties": { + "groupBy": { + "description": "The property to group by, as a bare property name. Each distinct value of the property forms one group (an object whose property holds several values counts toward each of them). Omitted or empty aggregates over all matching objects without grouping.", + "type": "string" + }, + "returnMetrics": { + "description": "The aggregation metrics to return. Phase 1 supports only `count` (the number of matching objects, per group when `groupBy` is set); omitted or empty is equivalent to `[\"count\"]`. The property-scoped `property:statistic` grammar (e.g. `price:mean`) is reserved and returns 422 (not yet supported).", + "type": "array", + "items": { + "type": "string" + } + }, + "where": { + "description": "A conditional filter to limit the objects that are aggregated.", + "$ref": "#/definitions/WhereFilter" + }, + "limit": { + "description": "The maximum number of groups to return, largest first. Must be positive and requires `groupBy`; omitted falls back to the server default (100 groups).", + "type": "integer", + "format": "int64", + "x-nullable": true + }, + "tenant": { + "description": "The tenant to aggregate in a multi-tenant collection.", + "type": "string" + }, + "over": { + "description": "Reserved for aggregate-over-search (aggregating the results of a vector, keyword or hybrid search). Returns 422 (not yet supported).", + "type": "object", + "x-nullable": true + }, + "objectLimit": { + "description": "Reserved for aggregate-over-search (the maximum number of search results to aggregate). Returns 422 (not yet supported).", + "type": "integer", + "format": "int64", + "x-nullable": true + } + } + }, + "AggregateResponse": { + "description": "The result of an aggregation. An ungrouped aggregation returns the flat form (`count` plus `tookMs`); a grouped aggregation returns `groups` plus `tookMs`. Exactly one of `count`/`groups` is present, except that a grouped aggregation which produced no groups (nothing matched, or no matching object carries the property) omits `groups` entirely.", + "type": "object", + "required": [ + "tookMs" + ], + "properties": { + "count": { + "description": "The number of matching objects. Present only for ungrouped aggregations.", + "type": "integer", + "format": "int64", + "x-nullable": true + }, + "groups": { + "description": "The groups, ordered by descending count. Present only for grouped aggregations.", + "type": "array", + "items": { + "$ref": "#/definitions/AggregateGroup" + }, + "x-omitempty": true + }, + "tookMs": { + "description": "Server-side processing time in milliseconds.", + "type": "integer", + "format": "int64", + "x-omitempty": false + } + } + }, + "AggregateGroup": { + "description": "One group of a grouped aggregation: the group's identity under `groupedBy` and its aggregated metrics (phase 1: `count`).", + "type": "object", + "required": [ + "groupedBy", + "count" + ], + "properties": { + "groupedBy": { + "$ref": "#/definitions/AggregateGroupedBy" + }, + "count": { + "description": "The number of objects in the group.", + "type": "integer", + "format": "int64" + } + } + }, + "AggregateGroupedBy": { + "description": "The identity of one group: the `groupBy` property (as a one-element path) and the property value that formed the group.", + "type": "object", + "required": [ + "path", + "value" + ], + "properties": { + "path": { + "description": "The grouped property, as a one-element path.", + "type": "array", + "items": { + "type": "string" + } + }, + "value": { + "description": "The property value that formed the group. Typed as the property is: text values are strings, numeric values numbers, boolean values booleans; grouping by a reference property yields the reference's beacon URI as a string." + } + } + }, + "SearchBm25Request": { + "description": "Request body for the bm25 search endpoint. Performs a keyword (BM25F) search over the collection's searchable text properties and returns the best-scoring objects. Extends the shared search fields (`SearchCommon`) with the bm25-specific `query` and `queryProperties`.", + "allOf": [ + { + "$ref": "#/definitions/SearchCommon" + }, + { + "type": "object", + "required": [ + "query" + ], + "properties": { + "query": { + "description": "The keyword query to score objects against, as a plain string. Must not be empty.", + "type": "string" + }, + "queryProperties": { + "description": "The properties to keyword-search, each optionally weighted with a `^boost` suffix (e.g. `title^2`). Omitted or empty searches every searchable text property. A property without a searchable index is rejected with 422.", + "type": "array", + "items": { + "type": "string" + } + } + } + } + ] + }, "SearchCommon": { - "description": "Fields shared by every REST search request (near-text, and — when built — hybrid, bm25, near-object). Unknown fields are ignored (platform parity with the other endpoints). Reserved fields are accepted by the schema but rejected by the server with 422 until the corresponding feature ships.", + "description": "Fields shared by every REST search request (near-text, bm25, hybrid, near-object). Unknown fields are ignored (platform parity with the other endpoints). Reserved fields are accepted by the schema but rejected by the server with 422 until the corresponding feature ships.", "type": "object", "properties": { "where": { @@ -3892,6 +4038,94 @@ } } }, + "SearchHybridRequest": { + "description": "Request body for the hybrid search endpoint. Combines a keyword (BM25F) search and a vector search over the same query string, fusing both rankings into one result list. Extends the shared search fields (`SearchCommon`) with the hybrid-specific `query`, `alpha`, `fusionType`, `maxVectorDistance`, `queryProperties` and `targetVector`.", + "allOf": [ + { + "$ref": "#/definitions/SearchCommon" + }, + { + "type": "object", + "required": [ + "query" + ], + "properties": { + "query": { + "description": "The query, as a plain string. It is scored with BM25F for the keyword part of the search and vectorized server-side for the vector part. Must not be empty.", + "type": "string" + }, + "alpha": { + "description": "The weight of the vector part of the search, between 0 and 1. `0` is a pure keyword search, `1` a pure vector search. Omitted defaults to `0.75`. With `0` the query is never vectorized, so a collection without a vectorizer module is searchable.", + "type": "number", + "format": "float64", + "x-nullable": true + }, + "fusionType": { + "description": "The algorithm that fuses the keyword and vector rankings: `ranked` (reciprocal-rank fusion) or `relativeScore` (normalized-score fusion). Omitted defaults to `relativeScore`.", + "type": "string", + "enum": [ + "ranked", + "relativeScore" + ] + }, + "maxVectorDistance": { + "description": "The maximum vector distance of a match: objects farther than this from the query vector are excluded, from the keyword ranking too.", + "type": "number", + "format": "float64", + "x-nullable": true + }, + "queryProperties": { + "description": "The properties the keyword part of the search scores against, each optionally weighted with a `^boost` suffix (e.g. `title^2`). Omitted or empty searches every searchable text property. A property without a searchable index is rejected with 422.", + "type": "array", + "items": { + "type": "string" + } + }, + "targetVector": { + "description": "The named vector to search. Required when the collection has more than one named vector.", + "type": "string" + } + } + } + ] + }, + "SearchNearObjectRequest": { + "description": "Request body for the near-object search endpoint. The stored vector of an existing object (the source object, referenced by `id`) anchors the search and the closest objects are returned. No query is vectorized — collections without a vectorizer module are fully searchable. Extends the shared search fields (`SearchCommon`) with the near-object-specific `id`, `certainty`, `distance` and `targetVector`.", + "allOf": [ + { + "$ref": "#/definitions/SearchCommon" + }, + { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "description": "The UUID of the source object whose stored vector anchors the search. A structurally invalid UUID is rejected at request validation; a well-formed UUID that matches no object in the collection is rejected with 400.", + "type": "string", + "format": "uuid" + }, + "certainty": { + "description": "Minimum normalized certainty of a match. Only for cosine-distance vector indexes. Mutually exclusive with `distance`.", + "type": "number", + "format": "float64", + "x-nullable": true + }, + "distance": { + "description": "Maximum vector distance of a match. Mutually exclusive with `certainty`.", + "type": "number", + "format": "float64", + "x-nullable": true + }, + "targetVector": { + "description": "The named vector to search (the source object's vector for this name anchors the search). Required when the collection has more than one named vector.", + "type": "string" + } + } + } + ] + }, "SearchNearTextRequest": { "description": "Request body for the near-text search endpoint. The query is vectorized server-side by the collection's vectorizer module and the closest objects are returned. Extends the shared search fields (`SearchCommon`) with the near-text-specific `query`, `certainty`, `distance` and `targetVector`.", "allOf": [ @@ -9130,7 +9364,7 @@ "/schema/{className}/properties/{propertyName}/index/{indexName}/cancel": { "post": { "summary": "Cancel the in-flight reindex task on a property's inverted index", - "description": "Cancels the in-flight reindex task targeting this property's index. No request body. Idempotent: succeeds whether or not a task was in flight (a `202` with `{\"status\":\"NO_OP\"}` is returned when there is nothing to cancel). `indexName` accepts `rangeable` as an alias for `rangeFilters`.", + "description": "Cancels the in-flight reindex task targeting this property's index. No request body. Idempotent: succeeds whether or not a task was in flight (a `202` with `{\"status\":\"NO_OP\"}` is returned when there is nothing to cancel). A task that is in flight but no longer cancellable is refused with `409`. `indexName` accepts `rangeable` as an alias for `rangeFilters`.", "operationId": "schema.objects.index.cancel", "x-serviceIds": [ "weaviate.local.manipulate.meta" @@ -9169,7 +9403,7 @@ ], "responses": { "202": { - "description": "Cancellation processed. Body carries `{\"status\":\"CANCELLED\",\"taskId\":...}` when a live task was cancelled, or `{\"status\":\"NO_OP\"}` when there was nothing to cancel.", + "description": "Cancellation processed. Body carries `{\"status\":\"CANCELLED\",\"taskId\":...}` when a STARTED task was cancelled, or `{\"status\":\"NO_OP\"}` when there was nothing to cancel.", "schema": { "$ref": "#/definitions/IndexUpdateResponse" } @@ -9189,6 +9423,12 @@ "$ref": "#/definitions/ErrorResponse" } }, + "409": { + "description": "The target task could not be cancelled, and this request cancelled nothing. This happens for one of three reasons. It is in a cluster-wide coordination phase (PREPARING or SWAPPING) and past the point at which cancelling is safe, so the caller must wait for it to reach a terminal state. It carries a status this build does not recognize and has to terminate on the nodes that do. Or it stopped being cancellable between the read and the cancel. In the first two cases the task is still in flight and will reach a terminal state on its own. In the third it isn't possible to tell whether the task moved into a coordination phase or already reached a terminal state, possibly CANCELLED if a concurrent cancel won the race — re-read the index status to see where it landed.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, "422": { "description": "Invalid `indexName` path value.", "schema": { @@ -11518,6 +11758,354 @@ } } }, + "/aggregate/{collection}": { + "post": { + "summary": "Aggregate over a collection", + "description": "Aggregates over the objects of a collection. Phase 1 supports counts: the number of matching objects, either in total (flat `count` response) or per group of a `groupBy` property (`groups` response). A `where` filter limits the objects that are aggregated; an empty body returns the collection's total object count.", + "tags": [ + "aggregate" + ], + "operationId": "aggregate", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "name": "collection", + "description": "The name (or alias) of the collection to aggregate over. A lowercase first letter is normalized to the canonical uppercase form.", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "description": "The aggregate request.", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/AggregateRequest" + } + } + ], + "responses": { + "200": { + "description": "Aggregation performed successfully.", + "schema": { + "$ref": "#/definitions/AggregateResponse" + } + }, + "400": { + "description": "An invalid parameter value (e.g. an unknown groupBy property, a non-positive limit, limit without groupBy, an unknown filter property) or an unparseable request body.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "401": { + "description": "Unauthorized or invalid credentials.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "404": { + "description": "Unknown collection or tenant.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "422": { + "description": "Either a request-schema violation (an invalid enum or field type in the where filter), or a well-formed request that cannot run: a reserved (not yet supported) parameter or returnMetrics entry is present, the tenant usage does not match the collection's multi-tenancy configuration, a where filter targets a property whose inverted index is disabled, or the experimental REST Search API is not enabled (set EXPERIMENTAL_REST_SEARCH_ENABLED=true).", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "500": { + "description": "An error has occurred while trying to fulfill the request. Most likely the ErrorResponse will contain more information about the error.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "503": { + "description": "The server is in an operational mode that blocks aggregations (e.g. WRITE_ONLY); retry once the server returns to normal operation.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "/search/{collection}/bm25": { + "post": { + "summary": "Search a collection with bm25", + "description": "Performs a keyword (BM25F) search over the objects of a collection. Objects are scored against the query with the BM25F ranking function over the searchable text properties (all of them, or the `queryProperties` subset) and the best-scoring objects are returned, each as an envelope of its `id`, the selected `properties`, the selected `references` and, when requested, its retrieval `metadata`.", + "tags": [ + "search" + ], + "operationId": "search.bm25", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "name": "collection", + "description": "The name (or alias) of the collection to search. A lowercase first letter is normalized to the canonical uppercase form.", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "description": "The bm25 search request.", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/SearchBm25Request" + } + } + ], + "responses": { + "200": { + "description": "Search performed successfully.", + "schema": { + "$ref": "#/definitions/SearchResponse" + } + }, + "400": { + "description": "An invalid parameter value (e.g. empty query, negative paging, unknown property) or an unparseable request body.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "401": { + "description": "Unauthorized or invalid credentials.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "404": { + "description": "Unknown collection or tenant.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "422": { + "description": "Either a request-schema violation (a missing or null required `query`, or an invalid enum value), or a well-formed request that cannot run: a queried property has no searchable index, a reserved (not yet supported) parameter is present, the tenant usage does not match the collection's multi-tenancy configuration, a where filter targets a property whose inverted index is disabled, or the experimental REST Search API is not enabled (set EXPERIMENTAL_REST_SEARCH_ENABLED=true).", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "429": { + "description": "The server's query rate limit was reached; retry later.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "500": { + "description": "An error has occurred while trying to fulfill the request. Most likely the ErrorResponse will contain more information about the error.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "503": { + "description": "The server is in an operational mode that blocks searches (e.g. WRITE_ONLY); retry once the server returns to normal operation.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "/search/{collection}/hybrid": { + "post": { + "summary": "Search a collection with hybrid", + "description": "Performs a hybrid search over the objects of a collection: the query is scored with the BM25F ranking function over the searchable text properties (all of them, or the `queryProperties` subset) and, in parallel, vectorized server-side and searched against the vector index; the two rankings are fused (per `fusionType`, weighted by `alpha`) and the best objects are returned, each as an envelope of its `id`, the selected `properties`, the selected `references` and, when requested, its retrieval `metadata`.", + "tags": [ + "search" + ], + "operationId": "search.hybrid", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "name": "collection", + "description": "The name (or alias) of the collection to search. A lowercase first letter is normalized to the canonical uppercase form.", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "description": "The hybrid search request.", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/SearchHybridRequest" + } + } + ], + "responses": { + "200": { + "description": "Search performed successfully.", + "schema": { + "$ref": "#/definitions/SearchResponse" + } + }, + "400": { + "description": "An invalid parameter value (e.g. empty query, alpha outside [0, 1], negative paging, unknown property) or an unparseable request body.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "401": { + "description": "Unauthorized or invalid credentials.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "404": { + "description": "Unknown collection or tenant.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "422": { + "description": "Either a request-schema violation (a missing or null required `query`, or an invalid enum value), or a well-formed request that cannot run: no vectorizer module is configured for the collection while `alpha` is above 0, targetVector is missing on a multi-named-vector collection, a queried property has no searchable index, a reserved (not yet supported) parameter is present, the tenant usage does not match the collection's multi-tenancy configuration, a where filter targets a property whose inverted index is disabled, or the experimental REST Search API is not enabled (set EXPERIMENTAL_REST_SEARCH_ENABLED=true).", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "429": { + "description": "The server's query rate limit was reached; retry later.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "500": { + "description": "An error has occurred while trying to fulfill the request. Most likely the ErrorResponse will contain more information about the error.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "502": { + "description": "The embedding provider failed to vectorize the query for the vector part of the search; the search cannot run.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "503": { + "description": "The server is in an operational mode that blocks searches (e.g. WRITE_ONLY); retry once the server returns to normal operation.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "/search/{collection}/near-object": { + "post": { + "summary": "Search a collection with near-object", + "description": "Performs a similarity search over the objects of a collection, anchored at an existing object: the stored vector of the source object (referenced by `id`) is searched against the vector index and the closest objects are returned — the source object itself included — each as an envelope of its `id`, the selected `properties`, the selected `references` and, when requested, its retrieval `metadata`. No query is vectorized, so collections without a vectorizer module are fully searchable.", + "tags": [ + "search" + ], + "operationId": "search.nearObject", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "name": "collection", + "description": "The name (or alias) of the collection to search. A lowercase first letter is normalized to the canonical uppercase form.", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "description": "The near-object search request.", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/SearchNearObjectRequest" + } + } + ], + "responses": { + "200": { + "description": "Search performed successfully.", + "schema": { + "$ref": "#/definitions/SearchResponse" + } + }, + "400": { + "description": "An invalid parameter value (e.g. an id that matches no object in the collection, negative paging, unknown property) or an unparseable request body.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "401": { + "description": "Unauthorized or invalid credentials.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "404": { + "description": "Unknown collection or tenant.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "422": { + "description": "Either a request-schema violation (a missing, null or structurally invalid required `id`, or an invalid enum value), or a well-formed request that cannot run: the source object has no stored vector for the (target) vector searched, targetVector is missing on a multi-named-vector collection, certainty is used on a non-cosine index, a reserved (not yet supported) parameter is present, the tenant usage does not match the collection's multi-tenancy configuration, a where filter targets a property whose inverted index is disabled, or the experimental REST Search API is not enabled (set EXPERIMENTAL_REST_SEARCH_ENABLED=true).", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "429": { + "description": "The server's query rate limit was reached; retry later.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "500": { + "description": "An error has occurred while trying to fulfill the request. Most likely the ErrorResponse will contain more information about the error.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + }, + "503": { + "description": "The server is in an operational mode that blocks searches (e.g. WRITE_ONLY); retry once the server returns to normal operation.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, "/search/{collection}/near-text": { "post": { "summary": "Search a collection with near-text", @@ -11652,7 +12240,11 @@ }, { "name": "search", - "description": "Operations for querying collections over REST. The near-text endpoint performs semantic vector search with server-side embedding of the query text; each result carries the object's `id`, the selected `properties`, the selected `references` and, when requested, its retrieval `metadata`." + "description": "Operations for querying collections over REST. The near-text endpoint performs semantic vector search with server-side embedding of the query text; the bm25 endpoint performs keyword (BM25F) search over the searchable text properties. Each result carries the object's `id`, the selected `properties`, the selected `references` and, when requested, its retrieval `metadata`." + }, + { + "name": "aggregate", + "description": "Operations for aggregating over collections. The aggregate endpoint counts the objects that match an optional `where` filter, in total or grouped by a property's distinct values." }, { "name": "backups",