Files
milvus/internal/distributed/proxy/httpserver/constant.go
T
5def5ced4a enhance: enforce function-field binding principle for function DDL (#51360)
## What

Enforce a function–field binding principle for function DDL (add / drop
/ alter function on an existing collection), so a function and its
output field stay coupled and already-stored vectors can never be
silently invalidated by DDL.

BM25 and MinHash follow the strict binding: add/drop only via the
unified `add_function_field` / `drop_function_field`, output field
always coupled. **TextEmbedding is a temporary carve-out** — its legacy
`AddCollectionFunction` / `DropCollectionFunction` paths are retained,
so attach-over-existing-field and detach are still possible for it,
because `add_function_field` embedding backfill is not yet implemented.
It will be folded into the unified path in a follow-up. So the "always
coupled" invariant currently holds for BM25/MinHash, not TextEmbedding.

## Changes

- **AlterCollectionSchema invariant**: reject standalone add-function (a
function must be added together with its new output field), reject
detaching a function without dropping its output field, and reject
function cascade (a new function's input being another function's
output).
- **Legacy RPCs**: `AddCollectionFunction` / `DropCollectionFunction`
are rejected for BM25/MinHash (must use `add_function_field` /
`drop_function_field`) and retained only for TextEmbedding (see
carve-out). `AlterCollectionFunction` is kept and gains the whitelist
below. In the alter and legacy-add paths, function field IDs are always
re-derived from field names (never trusted from the request), so a
request cannot inject an unrelated field ID that a later
`drop_function_field` would delete.
- **alter_function whitelist**: only connection/runtime params may
change (TextEmbedding: `url`, `credential`, `timeout_ms`,
`max_client_batch_size`, `region`, `location`, `projectid`, `user`);
BM25/MinHash have no alterable params. Function identity (type, name,
input/output fields) and output-shaping params (`dim`, `model_name`,
`endpoint` — the TEI model identity, `normalize`, `truncate*`, prompts,
...) are immutable. Params are normalized (keys lowercased, duplicate
keys rejected) so a crafted duplicate key cannot bypass the diff.
- **drop_function_field**: allow any output-producing function (dropping
needs no backfill), removing the previous BM25/MinHash-only restriction.

## Not in scope / follow-up

- Extending `add_function_field` to TextEmbedding (post-creation add
would require backfilling every existing row through the external
embedding model) — deferred; folding the TextEmbedding legacy paths into
the unified binding follows this.
- MinHash input-field analyzer immutability lives on a different DDL
path (`AlterCollectionField`); tracked as a separate follow-up.

## Breaking changes

- `DropCollectionFunction` on a **MinHash** function (detach — remove
the function but keep its output field) is no longer supported; use
`drop_function_field` instead (drops the function together with its
output field). If a released version supported MinHash detach, migrate
any such call to `drop_function_field`.

issue: #51348

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Signed-off-by: MrPresent-Han <chun.han@gmail.com>
Co-authored-by: MrPresent-Han <chun.han@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 05:04:39 +08:00

227 lines
8.5 KiB
Go

// Licensed to the LF AI & Data foundation under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF 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.
package httpserver
import (
"github.com/milvus-io/milvus/internal/proxy"
"github.com/milvus-io/milvus/pkg/v3/common"
"github.com/milvus-io/milvus/pkg/v3/util/metric"
)
// v2
const (
// --- category ---
DataBaseCategory = "/databases/"
CollectionCategory = "/collections/"
EntityCategory = "/entities/"
PartitionCategory = "/partitions/"
UserCategory = "/users/"
RoleCategory = "/roles/"
IndexCategory = "/indexes/"
AliasCategory = "/aliases/"
ImportJobCategory = "/jobs/import/"
SnapshotJobCategory = "/jobs/snapshot/"
ExternalCollectionJobCategory = "/jobs/external_collection/"
PrivilegeGroupCategory = "/privilege_groups/"
CollectionFieldCategory = "/collections/fields/"
CollectionStructFieldCategory = "/collections/struct_fields/"
ResourceGroupCategory = "/resource_groups/"
SegmentCategory = "/segments/"
QuotaCenterCategory = "/quotacenter/"
CommonCategory = "/common/"
ListAction = "list"
HasAction = "has"
DescribeAction = "describe"
CreateAction = "create"
DropAction = "drop"
StatsAction = "get_stats"
LoadStateAction = "get_load_state"
RenameAction = "rename"
LoadAction = "load"
RefreshLoadAction = "refresh_load"
ReleaseAction = "release"
QueryAction = "query"
GetAction = "get"
DeleteAction = "delete"
InsertAction = "insert"
UpsertAction = "upsert"
SearchAction = "search"
AdvancedSearchAction = "advanced_search"
HybridSearchAction = "hybrid_search"
UpdatePasswordAction = "update_password"
GrantRoleAction = "grant_role"
RevokeRoleAction = "revoke_role"
GrantPrivilegeAction = "grant_privilege"
RevokePrivilegeAction = "revoke_privilege"
GrantPrivilegeActionV2 = "grant_privilege_v2"
RevokePrivilegeActionV2 = "revoke_privilege_v2"
AlterAction = "alter"
AlterPropertiesAction = "alter_properties"
AddFunctionAction = "add_function"
AlterFunctionAction = "alter_function"
DropFunctionAction = "drop_function"
AddFunctionFieldAction = "add_function_field"
DropFunctionFieldAction = "drop_function_field"
AddAction = `add`
DropPropertiesAction = "drop_properties"
CompactAction = "compact"
CompactionStateAction = "get_compaction_state"
FlushAction = "flush"
TruncateAction = "truncate"
GetProgressAction = "get_progress" // deprecated, keep it for compatibility, use `/v2/vectordb/jobs/import/describe` instead
RestoreExternalAction = "restore_external"
ExportAction = "export"
RefreshAction = "refresh"
AddPrivilegesToGroupAction = "add_privileges_to_group"
RemovePrivilegesFromGroupAction = "remove_privileges_from_group"
TransferReplicaAction = "transfer_replica"
RunAnalyzerAction = "run_analyzer"
CommitAction = "commit"
AbortAction = "abort"
)
const (
ContextRequest = "request"
ContextResponse = "response"
ContextUsername = "username"
ContextToken = "token"
VectorCollectionsPath = "/vector/collections"
VectorCollectionsCreatePath = "/vector/collections/create"
VectorCollectionsDescribePath = "/vector/collections/describe"
VectorCollectionsDropPath = "/vector/collections/drop"
VectorInsertPath = "/vector/insert"
VectorUpsertPath = "/vector/upsert"
VectorSearchPath = "/vector/search"
VectorGetPath = "/vector/get"
VectorQueryPath = "/vector/query"
VectorDeletePath = "/vector/delete"
ShardNumDefault = 1
EnableDynamic = true
EnableAutoID = true
DisableAutoID = false
HTTPCollectionName = "collectionName"
HTTPCollectionID = "collectionID"
HTTPDbName = "dbName"
HTTPDbID = "dbID"
HTTPProperties = "properties"
HTTPPartitionName = "partitionName"
HTTPPartitionNames = "partitionNames"
HTTPUserName = "userName"
HTTPRoleName = "roleName"
HTTPIndexName = "indexName"
HTTPIndexField = "fieldName"
HTTPAliasName = "aliasName"
HTTPRequestData = "data"
HTTPRequestDefaultValue = "defaultValue"
DefaultDbName = "default"
DefaultIndexName = "vector_idx"
DefaultAliasName = "the_alias"
DefaultOutputFields = "*"
HTTPHeaderAllowInt64 = "Accept-Type-Allow-Int64"
HTTPHeaderDBName = "DB-Name"
HTTPHeaderRequestTimeout = "Request-Timeout"
HTTPHeaderMilvusTraceID = "X-Milvus-Trace-Id"
HTTPReturnCode = "code"
HTTPReturnMessage = "message"
HTTPReturnData = "data"
HTTPReturnCost = "cost"
HTTPReturnRecalls = "recalls"
HTTPReturnLoadState = "loadState"
HTTPReturnLoadProgress = "loadProgress"
HTTPReturnTopks = "topks"
HTTPReturnAggTopks = "aggTopks"
HTTPReturnHas = "has"
HTTPReturnScannedRemoteBytes = "scanned_remote_bytes"
HTTPReturnScannedTotalBytes = "scanned_total_bytes"
HTTPReturnCacheHitRatio = "cache_hit_ratio"
HTTPReturnFieldName = "name"
HTTPReturnFieldID = "id"
HTTPReturnFieldType = "type"
HTTPReturnFieldPrimaryKey = "primaryKey"
HTTPReturnFieldPartitionKey = "partitionKey"
HTTPReturnFieldClusteringKey = "clusteringKey"
HTTPReturnFieldNullable = "nullable"
HTTPReturnFieldDefaultValue = "defaultValue"
HTTPReturnFieldAutoID = "autoId"
HTTPReturnFieldElementType = "elementType"
HTTPReturnDescription = "description"
HTTPReturnFieldIsFunctionOutput = "isFunctionOutput"
HTTPReturnFunctionName = "name"
HTTPReturnFunctionID = "id"
HTTPReturnFunctionType = "type"
HTTPReturnFunctionInputFieldNames = "inputFieldNames"
HTTPReturnFunctionOutputFieldNames = "outputFieldNames"
HTTPReturnFunctionParams = "params"
HTTPReturnIndexMetricType = "metricType"
HTTPReturnIndexType = "indexType"
HTTPIndexOffsetCacheEnabledKey = "indexoffsetcache.enabled"
HTTPMmapEnabledKey = "mmap.enabled"
HTTPReturnIndexTotalRows = "totalRows"
HTTPReturnIndexPendingRows = "pendingRows"
HTTPReturnIndexIndexedRows = "indexedRows"
HTTPReturnIndexState = "indexState"
HTTPReturnIndexFailReason = "failReason"
HTTPReturnMinIndexVersion = "minIndexVersion"
HTTPReturnMaxIndexVersion = "maxIndexVersion"
HTTPReturnIndexParams = "indexParams"
HTTPReturnDistance = "distance"
HTTPReturnRowCount = "rowCount"
HTTPReturnObjectType = "objectType"
HTTPReturnObjectName = "objectName"
HTTPReturnPrivilege = "privilege"
HTTPReturnGrantor = "grantor"
HTTPReturnDbName = "dbName"
HTTPReturnPrivilegeGroupName = "privilegeGroupName"
HTTPReturnPrivileges = "privileges"
HTTPReturnPrivilegeGroups = "privilegeGroups"
DefaultMetricType = metric.COSINE
DefaultPrimaryFieldName = "id"
DefaultVectorFieldName = "vector"
HTTPWarmupKey = common.WarmupKey
Dim = "dim"
)
const (
Params = proxy.ParamsKey
ParamRoundDecimal = proxy.RoundDecimalKey
ParamRadius = "radius"
ParamRangeFilter = "range_filter"
ParamGroupByField = "group_by_field"
ParamGroupSize = "group_size"
ParamStrictGroupSize = "strict_group_size"
BoundedTimestamp = 2
)